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