xhook android10.0监听文件关闭



背景

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

http://androidxref.com/9.0.0_r3/xref/libcore/luni/src/main/native/libcore_io_Linux.cpp

其实就是调用了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文档。

参考:

https://wwm0609.github.io/2019/11/07/fd-san/
https://android.googlesource.com/platform/bionic/+/master/docs/fdsan.md


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM