背景
xhook注册了close方法,但是在android10上,还是无法拦截java层close一个io流
调研FileoutputStream是怎么关闭文件的
FileoutputStream.java
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
// Android-added: CloseGuard support.
guard.close();
if (channel != null) {
channel.close();
}
// BEGIN Android-changed: Close handling / notification of blocked threads.
if (isFdOwner) {
IoBridge.closeAndSignalBlockedThreads(fd);
}
// END Android-changed: Close handling / notification of blocked threads.
}
这里用到了IoBridge
closeAndSignalBlockedThreads(fd)代码
public static void closeAndSignalBlockedThreads(FileDescriptor fd) throws IOException {
if (fd == null || !fd.valid()) {
return;
}
int intFd = fd.getInt$();
fd.setInt$(-1);
FileDescriptor oldFd = new FileDescriptor();
oldFd.setInt$(intFd);
AsynchronousCloseMonitor.signalBlockedThreads(oldFd);
try {
Libcore.os.close(oldFd);
} catch (ErrnoException errnoException) {
// TODO: are there any cases in which we should throw?
}
}
这里用到Libcore
Libcore.os.close(oldFd); 代码
public final class Libcore {
private Libcore() { }
/**
* Direct access to syscalls. Code should strongly prefer using {@link #os}
* unless it has a strong reason to bypass the helpful checks/guards that it
* provides.
*/
public static Os rawOs = new Linux();
/**
* Access to syscalls with helpful checks/guards.
*/
public static Os os = new BlockGuardOs(rawOs);
}
libcore.os.Linux 代码
public native void close(FileDescriptor fd) throws ErrnoException;
java层就到此结束,我们可以在openGrok上搜索Linux_close
其实就是调用了close
static void Linux_close(JNIEnv* env, jobject, jobject javaFd) {
// Get the FileDescriptor's 'fd' field and clear it.
// We need to do this before we can throw an IOException (http://b/3222087).
int fd = jniGetFDFromFileDescriptor(env, javaFd);
jniSetFileDescriptorOfFD(env, javaFd, -1);
// Even if close(2) fails with EINTR, the fd will have been closed.
// Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone else's fd.
// http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
throwIfMinusOne(env, "close", close(fd));
}
疑问
那为啥xhook监听不到呢?难道androidQ代码有变?
来看看10.0的代码
static void Linux_close(JNIEnv* env, jobject, jobject javaFd) {
// Get the FileDescriptor's 'fd' field and clear it.
// We need to do this before we can throw an IOException (http://b/3222087).
if (javaFd == nullptr) {
jniThrowNullPointerException(env, "null fd");
return;
}
int fd = jniGetFDFromFileDescriptor(env, javaFd);
jniSetFileDescriptorOfFD(env, javaFd, -1);
#if defined(__BIONIC__)
jlong ownerId = jniGetOwnerIdFromFileDescriptor(env, javaFd);
// Close with bionic's fd ownership tracking (which returns 0 in the case of EINTR).
throwIfMinusOne(env, "close", android_fdsan_close_with_tag(fd, ownerId));
#else
// Even if close(2) fails with EINTR, the fd will have been closed.
// Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone else's fd.
// http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
throwIfMinusOne(env, "close", close(fd));
#endif
}
这里出现了两种可能:android_fdsan_close_with_tag(fd, ownerId) 和 close(fd)
于是hook:android_fdsan_close_with_tag,但是不知道libcore_io_Linux.cpp是哪个so
来看看/Users/seekting/work/projects/tsinghua/libcore/luni/src/main/native/Android.bp
filegroup {
name: "luni_native_srcs",
visibility: [
"//libcore",
],
srcs: [
"ExecStrings.cpp",
"IcuUtilities.cpp",
"JniConstants.cpp",
"JniException.cpp",
"NetworkUtilities.cpp",
"Register.cpp",
"ZipUtilities.cpp",
"android_system_OsConstants.cpp",
"cbigint.cpp",
"java_lang_StringToReal.cpp",
"java_lang_invoke_MethodHandle.cpp",
"java_lang_invoke_VarHandle.cpp",
"java_math_NativeBN.cpp",
"libcore_icu_ICU.cpp",
"libcore_icu_TimeZoneNames.cpp",
"libcore_io_AsynchronousCloseMonitor.cpp",
"libcore_io_Linux.cpp",
"libcore_io_Memory.cpp",
"libcore_util_NativeAllocationRegistry.cpp",
"org_apache_harmony_xml_ExpatParser.cpp",
"sun_misc_Unsafe.cpp",
"valueOf.cpp",
],
}
发现是libjavacore
cc_library_shared {
name: "libjavacore",
visibility: [
"//art/build/apex",
],
apex_available: [
"com.android.art.release",
"com.android.art.debug",
],
defaults: [
"core_native_default_flags",
"core_native_default_libs",
],
srcs: [
":luni_native_srcs",
"dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp",
],
shared_libs: [
"libandroidio",
"libbase",
"libcrypto",
"libexpat",
"libicuuc",
"libicui18n",
"libnativehelper",
"libz",
],
static_libs: [
"libandroidicuinit",
"libziparchive",
],
target: {
android: {
cflags: [
// -DANDROID_LINK_SHARED_ICU4C to enable access to the full ICU4C.
// See external/icu/android_icu4c/include/uconfig_local.h
// for more information.
"-DANDROID_LINK_SHARED_ICU4C",
],
},
},
}
所以最后只需要xhook加上android_fdsan_close_with_tag的hook就可以了
static int (*original_android_fdsan_close_with_tag)(int fd, uint64_t expected_tag);
int hook_android_fdsan_close_with_tag(int fd, uint64_t expected_tag) {
std::string fileName = read_link(fd);
int ret = original_android_fdsan_close_with_tag(fd, expected_tag);
__android_log_print(ANDROID_LOG_WARN, "seekting",
"hook_android_fdsan_close_with_tag %d fileName=%s", fd, fileName.c_str());
return ret;
}
void hook(){
xhook_register("libjavacore.so", "android_fdsan_close_with_tag", (void *) hook_android_fdsan_close_with_tag, (void **) &original_android_fdsan_close_with_tag);
}
看日志:
2021-02-20 19:05:09.218 26130-26130/com.seekting.xhookdemo I/xhook: hooking android_fdsan_close_with_tag in /apex/com.android.vndk.v30/lib64/libbase.so
2021-02-20 19:05:09.218 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at symidx: 21 (GNU_HASH UNDEF)
2021-02-20 19:05:09.218 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at .rela.plt offset: 0x3b648
2021-02-20 19:05:09.219 26130-26130/com.seekting.xhookdemo I/xhook: XH_HK_OK 0x79c10fc648: 0x7c70f80d04 -> 0x79728ebf74 android_fdsan_close_with_tag /apex/com.android.vndk.v30/lib64/libbase.so
2021-02-20 19:05:09.219 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at .rela.android offset: 0x3b488
2021-02-20 19:05:09.219 26130-26130/com.seekting.xhookdemo I/xhook: XH_HK_OK 0x79c10fc488: 0x7c70f80d04 -> 0x79728ebf74 android_fdsan_close_with_tag /apex/com.android.vndk.v30/lib64/libbase.so
2021-02-20 19:05:09.221 26130-26130/com.seekting.xhookdemo I/xhook: hooking android_fdsan_close_with_tag in /apex/com.android.art/lib64/libopenjdkjvm.so
2021-02-20 19:05:09.224 26130-26130/com.seekting.xhookdemo I/xhook: hooking android_fdsan_close_with_tag in /apex/com.android.art/lib64/libopenjdk.so
2021-02-20 19:05:09.225 26130-26130/com.seekting.xhookdemo I/xhook: hooking android_fdsan_close_with_tag in /apex/com.android.art/lib64/libjavacore.so
2021-02-20 19:05:09.225 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at symidx: 171 (GNU_HASH UNDEF)
2021-02-20 19:05:09.225 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at .rela.plt offset: 0x389a8
2021-02-20 19:05:09.226 26130-26130/com.seekting.xhookdemo I/xhook: XH_HK_OK 0x79d48789a8: 0x7c70f80d04 -> 0x79728ebf74 android_fdsan_close_with_tag /apex/com.android.art/lib64/libjavacore.so
2021-02-20 19:05:09.226 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at .rela.android offset: 0x382c8
2021-02-20 19:05:09.227 26130-26130/com.seekting.xhookdemo I/xhook: XH_HK_OK 0x79d48782c8: 0x7c70f80d04 -> 0x79728ebf74 android_fdsan_close_with_tag /apex/com.android.art/lib64/libjavacore.so
2021-02-20 19:05:09.230 26130-26130/com.seekting.xhookdemo I/xhook: hooking android_fdsan_close_with_tag in /apex/com.android.art/lib64/libart.so
2021-02-20 19:05:09.230 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at symidx: 252 (GNU_HASH UNDEF)
2021-02-20 19:05:09.230 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at .rela.plt offset: 0x6a4bb0
2021-02-20 19:05:09.231 26130-26130/com.seekting.xhookdemo I/xhook: XH_HK_OK 0x79dceaebb0: 0x7c70f80d04 -> 0x79728ebf74 android_fdsan_close_with_tag /apex/com.android.art/lib64/libart.so
2021-02-20 19:05:09.231 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at .rela.android offset: 0x6a3c70
2021-02-20 19:05:09.232 26130-26130/com.seekting.xhookdemo I/xhook: XH_HK_OK 0x79dceadc70: 0x7c70f80d04 -> 0x79728ebf74 android_fdsan_close_with_tag /apex/com.android.art/lib64/libart.so
2021-02-20 19:05:09.236 26130-26130/com.seekting.xhookdemo I/xhook: hooking android_fdsan_close_with_tag in /system/lib64/libbase.so
2021-02-20 19:05:09.236 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at symidx: 21 (GNU_HASH UNDEF)
2021-02-20 19:05:09.236 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at .rela.plt offset: 0x3b648
2021-02-20 19:05:09.237 26130-26130/com.seekting.xhookdemo I/xhook: XH_HK_OK 0x7c6db7c648: 0x7c70f80d04 -> 0x79728ebf74 android_fdsan_close_with_tag /system/lib64/libbase.so
2021-02-20 19:05:09.237 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at .rela.android offset: 0x3b488
2021-02-20 19:05:09.238 26130-26130/com.seekting.xhookdemo I/xhook: XH_HK_OK 0x7c6db7c488: 0x7c70f80d04 -> 0x79728ebf74 android_fdsan_close_with_tag /system/lib64/libbase.so
2021-02-20 19:05:09.249 26130-26130/com.seekting.xhookdemo I/xhook: hooking android_fdsan_close_with_tag in /apex/com.android.runtime/lib64/bionic/libc.so
2021-02-20 19:05:09.249 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at symidx: 381 (GNU_HASH DEF)
2021-02-20 19:05:09.249 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at .rela.plt offset: 0xb8f48
2021-02-20 19:05:09.251 26130-26130/com.seekting.xhookdemo I/xhook: XH_HK_OK 0x7c70fe7f48: 0x7c70f80d04 -> 0x79728ebf74 android_fdsan_close_with_tag /apex/com.android.runtime/lib64/bionic/libc.so
2021-02-20 19:05:09.262 26130-26130/com.seekting.xhookdemo I/xhook: hooking android_fdsan_close_with_tag in /apex/com.android.art/lib64/libartbase.so
2021-02-20 19:05:09.262 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at symidx: 86 (GNU_HASH UNDEF)
2021-02-20 19:05:09.262 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at .rela.plt offset: 0x70eb8
2021-02-20 19:05:09.265 26130-26130/com.seekting.xhookdemo I/xhook: XH_HK_OK 0x7c72171eb8: 0x7c70f80d04 -> 0x79728ebf74 android_fdsan_close_with_tag /apex/com.android.art/lib64/libartbase.so
2021-02-20 19:05:09.265 26130-26130/com.seekting.xhookdemo I/xhook: found android_fdsan_close_with_tag at .rela.android offset: 0x70b30
2021-02-20 19:05:09.269 26130-26130/com.seekting.xhookdemo I/xhook: XH_HK_OK 0x7c72171b30: 0x7c70f80d04 -> 0x79728ebf74 android_fdsan_close_with_tag /apex/com.android.art/lib64/libartbase.so
扩展
看看android_fdsan_close_with_tag底层实现
前提要android10源码
/Users/seekting/work/projects/tsinghua/bionic/libc/bionic/fdsan.cpp
int android_fdsan_close_with_tag(int fd, uint64_t expected_tag) {
FdEntry* fde = GetFdEntry(fd);
if (!fde) {
return ___close(fd);
}
uint64_t tag = expected_tag;
if (!atomic_compare_exchange_strong(&fde->close_tag, &tag, 0)) {
const char* expected_type = android_fdsan_get_tag_type(expected_tag);
uint64_t expected_owner = android_fdsan_get_tag_value(expected_tag);
const char* actual_type = android_fdsan_get_tag_type(tag);
uint64_t actual_owner = android_fdsan_get_tag_value(tag);
if (expected_tag && tag) {
fdsan_error(
"attempted to close file descriptor %d, "
"expected to be owned by %s 0x%" PRIx64 ", actually owned by %s 0x%" PRIx64,
fd, expected_type, expected_owner, actual_type, actual_owner);
} else if (expected_tag && !tag) {
fdsan_error(
"attempted to close file descriptor %d, "
"expected to be owned by %s 0x%" PRIx64 ", actually unowned",
fd, expected_type, expected_owner);
} else if (!expected_tag && tag) {
fdsan_error(
"attempted to close file descriptor %d, "
"expected to be unowned, actually owned by %s 0x%" PRIx64,
fd, actual_type, actual_owner);
} else if (!expected_tag && !tag) {
// This should never happen: our CAS failed, but expected == actual?
async_safe_fatal("fdsan atomic_compare_exchange_strong failed unexpectedly while closing");
}
}
int rc = ___close(fd);
// If we were expecting to close with a tag, abort on EBADF.
if (expected_tag && rc == -1 && errno == EBADF) {
fdsan_error("double-close of file descriptor %d detected", fd);
}
return rc;
}
___close在哪里申明了,但是这个方法无法hook不知道为啥
android_fdsan_close_with_tag是什么机制
fdsan是File descriptor sanitizer的缩写
Android 10引入了fdsan(文件描述符清理程序)。 fdsan可检测到文件描述符所有权的不当处理,例如使用后关闭和两次关闭。 fdsan的默认模式在Android 11中更改。fdsan现在在检测到错误时中止;以前的行为是记录警告并继续。如果您在应用程序中看到由于fdsan导致的崩溃,请参阅fdsan文档。
参考: