From 0e092895baad1a23d3e1ad695896e8a5c2214d77 Mon Sep 17 00:00:00 2001 From: CAI Kelun Date: Wed, 9 Nov 2022 15:30:51 +0800 Subject: [PATCH] Add xdl_info(). --- README.md | 25 ++++++++++++++++++------ README.zh-CN.md | 33 ++++++++++++++++++++++---------- build.gradle | 2 +- xdl/src/main/cpp/include/xdl.h | 33 +++++++++++++++++++------------- xdl/src/main/cpp/xdl.c | 18 ++++++++++++++++- xdl/src/main/cpp/xdl.map.txt | 1 + xdl_sample/build.gradle | 2 +- xdl_sample/src/main/cpp/sample.c | 13 +++++++++++-- 8 files changed, 93 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 68244af..df758d1 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat) ![](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat) -![](https://img.shields.io/badge/release-1.1.5-red.svg?style=flat) +![](https://img.shields.io/badge/release-1.2.0-red.svg?style=flat) ![](https://img.shields.io/badge/Android-4.1%20--%2013-blue.svg?style=flat) ![](https://img.shields.io/badge/arch-armeabi--v7a%20%7C%20arm64--v8a%20%7C%20x86%20%7C%20x86__64-blue.svg?style=flat) @@ -61,7 +61,7 @@ android { } dependencies { - implementation 'io.hexhacking:xdl:1.1.5' + implementation 'io.hexhacking:xdl:1.2.0' } ``` @@ -202,21 +202,21 @@ typedef struct size_t dli_ssize; const ElfW(Phdr) *dlpi_phdr; size_t dlpi_phnum; -} xdl_info; +} xdl_info_t; -int xdl_addr(void *addr, xdl_info *info, void **cache); +int xdl_addr(void *addr, xdl_info_t *info, void **cache); void xdl_addr_clean(void **cache); ``` `xdl_addr()` is similar to [`dladdr()`](https://man7.org/linux/man-pages/man3/dladdr.3.html). But there are a few differences: * `xdl_addr()` can lookup not only dynamic link symbols, but also debugging symbols. -* `xdl_addr()` uses the `xdl_info` structure instead of the `Dl_info` structure, which contains more extended information: `dli_ssize` is the number of bytes occupied by the current symbol; `dlpi_phdr` points to the program headers array of the ELF where the current symbol is located; `dlpi_phnum` is the number of elements in the `dlpi_phdr` array. +* `xdl_addr()` uses the `xdl_info_t` structure instead of the `Dl_info` structure, which contains more extended information: `dli_ssize` is the number of bytes occupied by the current symbol; `dlpi_phdr` points to the program headers array of the ELF where the current symbol is located; `dlpi_phnum` is the number of elements in the `dlpi_phdr` array. * `xdl_addr()` needs to pass an additional parameter (`cache`), which will cache the ELF handle opened during the execution of `xdl_addr()`. The purpose of caching is to make subsequent executions of `xdl_addr()` of the same ELF faster. When you do not need to execute `xdl_addr()`, please use `xdl_addr_clean()` to clear the cache. For example: ```C void *cache = NULL; -xdl_info info; +xdl_info_t info; xdl_addr(addr_1, &info, &cache); xdl_addr(addr_2, &info, &cache); xdl_addr(addr_3, &info, &cache); @@ -241,6 +241,19 @@ int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), voi These flags are needed because these capabilities require additional execution time, and you don't always need them. +### 5. `xdl_info()` + +```C +#define XDL_DI_DLINFO 1 // type of info: xdl_info_t + +int xdl_info(void *handle, int request, void *info); +``` + +`xdl_info()` is similar to [`dlinfo()`](https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html). `xdl_info()` obtains information about the dynamically loaded object referred to by `handle` (obtained by an earlier call to `xdl_open`). + +The only `request` parameter currently supported is `XDL_DI_DLINFO`, which means to return data of type `xdl_info_t` through the `info` parameter (note that the values of `dli_sname`, `dli_saddr`, `dli_ssize` in the returned `xdl_info_t` at this time both are `0`). + +On success, `xdl_info()` returns `0`. On failure, it returns `-1`. ## Support diff --git a/README.zh-CN.md b/README.zh-CN.md index 03ff4cd..11a163b 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -2,7 +2,7 @@ ![](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat) ![](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat) -![](https://img.shields.io/badge/release-1.1.5-red.svg?style=flat) +![](https://img.shields.io/badge/release-1.2.0-red.svg?style=flat) ![](https://img.shields.io/badge/Android-4.1%20--%2013-blue.svg?style=flat) ![](https://img.shields.io/badge/arch-armeabi--v7a%20%7C%20arm64--v8a%20%7C%20x86%20%7C%20x86__64-blue.svg?style=flat) @@ -61,7 +61,7 @@ android { } dependencies { - implementation 'io.hexhacking:xdl:1.1.5' + implementation 'io.hexhacking:xdl:1.2.0' } ``` @@ -142,7 +142,7 @@ void *xdl_open(const char *filename, int flags); void *xdl_close(void *handle); ``` -它们和 [`dlopen()`](https://man7.org/linux/man-pages/man3/dlopen.3.html) / [`dlclose()`](https://man7.org/linux/man-pages/man3/dlclose.3.html) 很相似。但是 `xdl_open()` 可以绕过 Android 7.0+ linker namespace 的限制。 +它们和 [`dlopen()`](https://man7.org/linux/man-pages/man3/dlopen.3.html) / [`dlclose()`](https://man7.org/linux/man-pages/man3/dlclose.3.html) 类似。但是 `xdl_open()` 可以绕过 Android 7.0+ linker namespace 的限制。 根据 `flags` 参数值的不同,`xdl_open()` 的行为会有一些差异: @@ -176,7 +176,7 @@ void *xdl_sym(void *handle, const char *symbol, size_t *symbol_size); void *xdl_dsym(void *handle, const char *symbol, size_t *symbol_size); ``` -它们和 [`dlsym()`](https://man7.org/linux/man-pages/man3/dlsym.3.html) 很相似。 它们都需要传递一个 `xdl_open()` 返回的 “handle”,和一个 null 结尾的符号名字,返回该符号在内存中的加载地址。 +它们和 [`dlsym()`](https://man7.org/linux/man-pages/man3/dlsym.3.html) 类似。 它们都需要传递一个 `xdl_open()` 返回的 “handle”,和一个 null 结尾的符号名字,返回该符号在内存中的加载地址。 如果 `symbol_size` 参数不为 `NULL`,它将被赋值为“符号对应的内容在 ELF 中占用的字节数”,如果你不需要这个信息,传递 `NULL` 就可以了。 @@ -202,21 +202,21 @@ typedef struct size_t dli_ssize; const ElfW(Phdr) *dlpi_phdr; size_t dlpi_phnum; -} xdl_info; +} xdl_info_t; -int xdl_addr(void *addr, xdl_info *info, void **cache); +int xdl_addr(void *addr, xdl_info_t *info, void **cache); void xdl_addr_clean(void **cache); ``` -`xdl_addr()` 和 [`dladdr()`](https://man7.org/linux/man-pages/man3/dladdr.3.html) 很相似。但有以下几点不同: +`xdl_addr()` 和 [`dladdr()`](https://man7.org/linux/man-pages/man3/dladdr.3.html) 类似。但有以下几点不同: * `xdl_addr()` 不仅能查询动态链接符号,还能查询调试符号。 -* `xdl_addr()` 使用 `dl_info` 结构体代替了 `Dl_info` 结构体,它包含了更多的扩展信息:`dli_ssize` 是当前符号所占用的字节数;`dlpi_phdr` 指向当前符号所在 ELF 的 program headers 数组;`dlpi_phnum` 是 `dlpi_phdr` 数组的元素个数。 +* `xdl_addr()` 使用 `xdl_info_t` 结构体代替了 `Dl_info` 结构体,它包含了更多的扩展信息:`dli_ssize` 是当前符号所占用的字节数;`dlpi_phdr` 指向当前符号所在 ELF 的 program headers 数组;`dlpi_phnum` 是 `dlpi_phdr` 数组的元素个数。 * `xdl_addr()` 需要传递一个附加的参数(cache),其中会缓存 `xdl_addr()` 执行过程中打开的 ELF handle,缓存的目的是使后续对同一个 ELF 的 `xdl_addr()` 执行的更快。当不需要再执行 `xdl_addr()` 时,请使用 `xdl_addr_clean()` 清除缓存。举例: ```C void *cache = NULL; -Dl_info info; +xdl_info_t info; xdl_addr(addr_1, &info, &cache); xdl_addr(addr_2, &info, &cache); xdl_addr(addr_3, &info, &cache); @@ -232,7 +232,7 @@ xdl_addr_clean(&cache); int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data, int flags); ``` -`xdl_iterate_phdr()` 和 [`dl_iterate_phdr()`](https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html) 很相似。但是 `xdl_iterate_phdr()` 兼容 ARM32 平台的 Android 4.x 系统,并且总是包含 linker / linker64。 +`xdl_iterate_phdr()` 和 [`dl_iterate_phdr()`](https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html) 类似。但是 `xdl_iterate_phdr()` 兼容 ARM32 平台的 Android 4.x 系统,并且总是包含 linker / linker64。 `xdl_iterate_phdr()` 有一个额外的“flags”参数,一个或多个“flag”可以按位“或”后传递给它: @@ -241,6 +241,19 @@ int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), voi 需要这些 flags 的原因是,这些额外的能力也需要花费额外的执行时间,而你并不总是需要这些能力。 +### 5. `xdl_info()` + +```C +#define XDL_DI_DLINFO 1 // type of info: xdl_info_t + +int xdl_info(void *handle, int request, void *info); +``` + +`xdl_info()` 和 [`dlinfo()`](https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html) 类似。`xdl_info()` 通过 `handle`(`xdl_open` 的返回值)来获取动态加载对象的信息。 + +目前唯一支持的 `request` 参数是 `XDL_DI_DLINFO`,表示通过 `info` 参数返回 `xdl_info_t` 类型的数据(注意,此时返回的 `xdl_info_t` 中 `dli_sname`、`dli_saddr`、`dli_ssize` 的值均为 `0`)。 + +成功时 `xdl_info()` 返回 `0`,失败时返回 `-1`。 ## 技术支持 diff --git a/build.gradle b/build.gradle index 13fbcdc..ef506b9 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ ext { POM_GROUP_ID = "io.hexhacking" POM_ARTIFACT_ID = "xdl" - POM_VERSION_NAME = "1.1.5" + POM_VERSION_NAME = "1.2.0" POM_NAME = "xDL Android Lib" POM_DESCRIPTION = "xDL is an enhanced implementation of the Android DL series functions." diff --git a/xdl/src/main/cpp/include/xdl.h b/xdl/src/main/cpp/include/xdl.h index 63dc9c7..1cb6db6 100644 --- a/xdl/src/main/cpp/include/xdl.h +++ b/xdl/src/main/cpp/include/xdl.h @@ -22,7 +22,7 @@ // Created by caikelun on 2020-10-04. // -// xDL version: 1.1.5 +// xDL version: 1.2.0 // // xDL is an enhanced implementation of the Android DL series functions. // For more information, documentation, and the latest version please check: @@ -40,6 +40,18 @@ extern "C" { #endif +typedef struct { + // same as Dl_info: + const char *dli_fname; // Pathname of shared object that contains address. + void *dli_fbase; // Address at which shared object is loaded. + const char *dli_sname; // Name of nearest symbol with address lower than addr. + void *dli_saddr; // Exact address of symbol named in dli_sname. + // added by xDL: + size_t dli_ssize; // Symbol size of nearest symbol with address lower than addr. + const ElfW(Phdr) *dlpi_phdr; // Pointer to array of ELF program headers for this object. + size_t dlpi_phnum; // Number of items in dlpi_phdr. +} xdl_info_t; + // // Default value for flags in both xdl_open() and xdl_iterate_phdr(). // @@ -58,18 +70,7 @@ void *xdl_dsym(void *handle, const char *symbol, size_t *symbol_size); // // Enhanced dladdr(). // -typedef struct { - // same as Dl_info: - const char *dli_fname; // Pathname of shared object that contains address. - void *dli_fbase; // Address at which shared object is loaded. - const char *dli_sname; // Name of nearest symbol with address lower than addr. - void *dli_saddr; // Exact address of symbol named in dli_sname. - // added by xDL: - size_t dli_ssize; // Symbol size of nearest symbol with address lower than addr. - const ElfW(Phdr) *dlpi_phdr; // Pointer to array of ELF program headers for this object. - size_t dlpi_phnum; // Number of items in dlpi_phdr. -} xdl_info; -int xdl_addr(void *addr, xdl_info *info, void **cache); +int xdl_addr(void *addr, xdl_info_t *info, void **cache); void xdl_addr_clean(void **cache); // @@ -78,6 +79,12 @@ void xdl_addr_clean(void **cache); #define XDL_FULL_PATHNAME 0x01 int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data, int flags); +// +// Custom dlinfo(). +// +#define XDL_DI_DLINFO 1 // type of info: xdl_info_t +int xdl_info(void *handle, int request, void *info); + #ifdef __cplusplus } #endif diff --git a/xdl/src/main/cpp/xdl.c b/xdl/src/main/cpp/xdl.c index 86b4d7b..9267f26 100644 --- a/xdl/src/main/cpp/xdl.c +++ b/xdl/src/main/cpp/xdl.c @@ -792,7 +792,7 @@ static ElfW(Sym) *xdl_dsym_by_addr(void *handle, void *addr) { return NULL; } -int xdl_addr(void *addr, xdl_info *info, void **cache) { +int xdl_addr(void *addr, xdl_info_t *info, void **cache) { if (NULL == addr || NULL == info || NULL == cache) return 0; memset(info, 0, sizeof(Dl_info)); @@ -851,3 +851,19 @@ int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), voi return xdl_iterate_phdr_impl(callback, data, flags); } + +int xdl_info(void *handle, int request, void *info) { + if (NULL == handle || XDL_DI_DLINFO != request || NULL == info) return -1; + + xdl_t *self = (xdl_t *)handle; + xdl_info_t *dlinfo = (xdl_info_t *)info; + + dlinfo->dli_fbase = (void *)self->load_bias; + dlinfo->dli_fname = self->pathname; + dlinfo->dli_sname = NULL; + dlinfo->dli_saddr = 0; + dlinfo->dli_ssize = 0; + dlinfo->dlpi_phdr = self->dlpi_phdr; + dlinfo->dlpi_phnum = (size_t)self->dlpi_phnum; + return 0; +} diff --git a/xdl/src/main/cpp/xdl.map.txt b/xdl/src/main/cpp/xdl.map.txt index e7a735c..53bb28b 100644 --- a/xdl/src/main/cpp/xdl.map.txt +++ b/xdl/src/main/cpp/xdl.map.txt @@ -7,6 +7,7 @@ xdl_addr; xdl_addr_clean; xdl_iterate_phdr; + xdl_info; local: *; diff --git a/xdl_sample/build.gradle b/xdl_sample/build.gradle index 910f22c..944c786 100644 --- a/xdl_sample/build.gradle +++ b/xdl_sample/build.gradle @@ -66,7 +66,7 @@ dependencies { if (rootProject.ext.dependencyOnLocalLibrary) { implementation project(':xdl') } else { - implementation 'io.hexhacking:xdl:1.1.5' + implementation 'io.hexhacking:xdl:1.2.0' } } diff --git a/xdl_sample/src/main/cpp/sample.c b/xdl_sample/src/main/cpp/sample.c index c015877..2e6937c 100644 --- a/xdl_sample/src/main/cpp/sample.c +++ b/xdl_sample/src/main/cpp/sample.c @@ -65,18 +65,27 @@ static void sample_test_iterate(void) { static void *sample_test_dlsym(const char *filename, const char *symbol, bool debug_symbol, void **cache, bool try_force_dlopen) { + xdl_info_t info; + if (try_force_dlopen) { void *linker_handle = dlopen(filename, RTLD_NOW); LOG("--- dlopen(%s) : handle %" PRIxPTR, filename, (uintptr_t)linker_handle); if (NULL != linker_handle) dlclose(linker_handle); } - LOG("+++ xdl_open + %s + xdl_addr", debug_symbol ? "xdl_dsym" : "xdl_sym"); + LOG("+++ xdl_open + xdl_info + %s + xdl_addr", debug_symbol ? "xdl_dsym" : "xdl_sym"); // xdl_open void *handle = xdl_open(filename, try_force_dlopen ? XDL_TRY_FORCE_LOAD : XDL_DEFAULT); LOG(">>> xdl_open(%s) : handle %" PRIxPTR, filename, (uintptr_t)handle); + // xdl_info + memset(&info, 0, sizeof(xdl_info_t)); + xdl_info(handle, XDL_DI_DLINFO, &info); + LOG(">>> xdl_info(%" PRIxPTR ") : %" PRIxPTR " %s (phdr %" PRIxPTR ", phnum %zu)", (uintptr_t)handle, + (uintptr_t)info.dli_fbase, (NULL == info.dli_fname ? "(NULL)" : info.dli_fname), + (uintptr_t)info.dlpi_phdr, info.dlpi_phnum); + // xdl_dsym / xdl_sym size_t symbol_size = 0; void *symbol_addr = (debug_symbol ? xdl_dsym : xdl_sym)(handle, symbol, &symbol_size); @@ -87,7 +96,7 @@ static void *sample_test_dlsym(const char *filename, const char *symbol, bool de void *linker_handle = xdl_close(handle); // xdl_addr - xdl_info info; + memset(&info, 0, sizeof(xdl_info_t)); if (0 == xdl_addr(symbol_addr, &info, cache)) LOG(">>> xdl_addr(%" PRIxPTR ") : FAILED", (uintptr_t)symbol_addr); else