[core] Use ElfImg instead of DobbySymbolResolver (#419)
This commit is contained in:
parent
3f80d37364
commit
69e5feffce
|
|
@ -49,8 +49,8 @@ jobs:
|
|||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ccache-${{ github.sha }}
|
||||
restore-keys: ccache
|
||||
key: ccache-cache-${{ github.sha }}
|
||||
restore-keys: ccache-cache-
|
||||
- name: Install ccache
|
||||
run: sudo apt-get install -y ccache
|
||||
- name: Build with Gradle
|
||||
|
|
|
|||
|
|
@ -185,8 +185,6 @@ task("buildLibcxx", Exec::class) {
|
|||
println("using ccache $it")
|
||||
environment("NDK_CCACHE", it)
|
||||
environment("USE_CCACHE", "1")
|
||||
environment("CCACHE_COMPILERCHECK", "content")
|
||||
environment("CCACHE_MAXSIZE", "100M")
|
||||
} ?: run {
|
||||
println("not using ccache")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ find_program(CCACHE ccache)
|
|||
if (CCACHE)
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})
|
||||
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE})
|
||||
set(ENV{CCACHE_COMPILERCHECK} "content")
|
||||
set(ENV{CCACHE_MAXSIZE} "100M")
|
||||
else ()
|
||||
message(WARNING "Could not find CCache program.")
|
||||
endif ()
|
||||
|
|
|
|||
|
|
@ -10,13 +10,11 @@ macro(SET_OPTION option value)
|
|||
endmacro()
|
||||
|
||||
SET_OPTION(DOBBY_GENERATE_SHARED OFF)
|
||||
SET_OPTION(Plugin.Android.BionicLinkerRestriction ON)
|
||||
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
SET_OPTION(DOBBY_DEBUG OFF)
|
||||
endif (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_subdirectory(Dobby)
|
||||
target_include_directories(dobby PUBLIC Dobby/include)
|
||||
target_include_directories(dobby PUBLIC Dobby/builtin-plugin/BionicLinkerRestriction)
|
||||
|
||||
add_library(libcxx STATIC IMPORTED GLOBAL)
|
||||
set_property(TARGET libcxx PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../../../../build/intermediates/ndk/obj/local/${CMAKE_ANDROID_ARCH_ABI}/libcxx.a)
|
||||
|
|
|
|||
|
|
@ -32,15 +32,15 @@ namespace lspd {
|
|||
//#define DEBUG
|
||||
|
||||
|
||||
inline bool constexpr Is64() {
|
||||
inline bool constexpr Is64() {
|
||||
#if defined(__LP64__)
|
||||
return true;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline constexpr bool is64 = Is64();
|
||||
inline constexpr bool is64 = Is64();
|
||||
|
||||
#if defined(__LP64__)
|
||||
# define LP_SELECT(lp32, lp64) lp64
|
||||
|
|
@ -55,12 +55,20 @@ inline constexpr bool is64 = Is64();
|
|||
|
||||
static constexpr auto kLibArtName = "libart.so"_tstr;
|
||||
static constexpr auto kLibFwName = "libandroidfw.so"_tstr;
|
||||
static constexpr auto kLinkerName = LP_SELECT("linker"_tstr, "linker64"_tstr);
|
||||
static constexpr auto kLibcName = "libc.so"_tstr;
|
||||
static constexpr auto kLibbaseName = "libbase.so"_tstr;
|
||||
|
||||
static constexpr auto kLibBasePath =
|
||||
LP_SELECT("/system/lib/"_tstr,
|
||||
"/system/lib64/"_tstr);
|
||||
static constexpr auto kLibArtLegacyPath = kLibBasePath + kLibArtName;
|
||||
|
||||
static constexpr auto kBinBasePath = "/system/bin/"_tstr;
|
||||
|
||||
static constexpr auto kLibFwPath = kLibBasePath + kLibFwName;
|
||||
static constexpr auto kLinkerPath = kBinBasePath + kLinkerName;
|
||||
static constexpr auto kLibcPath = kLibBasePath + kLibcName;
|
||||
static constexpr auto kLibbasePath = kLibBasePath + kLibbaseName;
|
||||
|
||||
inline constexpr const char *const BoolToString(bool b) {
|
||||
return b ? "true" : "false";
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "jni/logger.h"
|
||||
#include "jni/native_api.h"
|
||||
#include "service.h"
|
||||
#include "symbol_cache.h"
|
||||
|
||||
namespace lspd {
|
||||
extern int *allowUnload;
|
||||
|
|
@ -168,22 +169,24 @@ namespace lspd {
|
|||
void
|
||||
Context::OnNativeForkSystemServerPre(JNIEnv *env) {
|
||||
Service::instance()->InitService(env);
|
||||
skip_ = false;
|
||||
setAllowUnload(false);
|
||||
skip_ = !sym_initialized;
|
||||
setAllowUnload(skip_);
|
||||
}
|
||||
|
||||
void
|
||||
Context::OnNativeForkSystemServerPost(JNIEnv *env, jint res) {
|
||||
if (res != 0) return;
|
||||
LoadDex(env);
|
||||
Service::instance()->HookBridge(*this, env);
|
||||
auto binder = Service::instance()->RequestBinderForSystemServer(env);
|
||||
if (binder && !skip_) {
|
||||
InstallInlineHooks();
|
||||
Init(env);
|
||||
FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", binder);
|
||||
if (!skip_) {
|
||||
LoadDex(env);
|
||||
Service::instance()->HookBridge(*this, env);
|
||||
auto binder = Service::instance()->RequestBinderForSystemServer(env);
|
||||
if (binder) {
|
||||
InstallInlineHooks();
|
||||
Init(env);
|
||||
FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", binder);
|
||||
}
|
||||
}
|
||||
setAllowUnload(false);
|
||||
setAllowUnload(skip_);
|
||||
}
|
||||
|
||||
void Context::OnNativeForkAndSpecializePre(JNIEnv *env,
|
||||
|
|
@ -195,7 +198,7 @@ namespace lspd {
|
|||
const auto app_id = uid % PER_USER_RANGE;
|
||||
nice_name_ = nice_name;
|
||||
JUTFString process_name(env, nice_name);
|
||||
skip_ = false;
|
||||
skip_ = !sym_initialized;
|
||||
if (!skip_ && !app_data_dir) {
|
||||
LOGD("skip injecting into %s because it has no data dir", process_name.get());
|
||||
skip_ = true;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,203 @@
|
|||
// From https://github.com/ganyao114/SandHook/blob/master/hooklib/src/main/cpp/utils/elf_util.cpp
|
||||
//
|
||||
// Created by Swift Gan on 2019/3/14.
|
||||
//
|
||||
#include <malloc.h>
|
||||
#include <cstring>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <cassert>
|
||||
#include <filesystem>
|
||||
#include <sys/stat.h>
|
||||
#include "logging.h"
|
||||
#include "elf_util.h"
|
||||
|
||||
using namespace SandHook;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
ElfImg::ElfImg(const char *elf) {
|
||||
this->elf = elf;
|
||||
//load elf
|
||||
int fd = open(elf, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
LOGE("failed to open %s", elf);
|
||||
return;
|
||||
}
|
||||
|
||||
size = lseek(fd, 0, SEEK_END);
|
||||
if (size <= 0) {
|
||||
LOGE("lseek() failed for %s", elf);
|
||||
}
|
||||
|
||||
header = reinterpret_cast<Elf_Ehdr *>(mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0));
|
||||
|
||||
close(fd);
|
||||
|
||||
section_header = reinterpret_cast<Elf_Shdr *>(((size_t) header) + header->e_shoff);
|
||||
|
||||
auto shoff = reinterpret_cast<size_t>(section_header);
|
||||
char *section_str = reinterpret_cast<char *>(section_header[header->e_shstrndx].sh_offset +
|
||||
((size_t) header));
|
||||
|
||||
for (int i = 0; i < header->e_shnum; i++, shoff += header->e_shentsize) {
|
||||
auto *section_h = (Elf_Shdr *) shoff;
|
||||
char *sname = section_h->sh_name + section_str;
|
||||
Elf_Off entsize = section_h->sh_entsize;
|
||||
switch (section_h->sh_type) {
|
||||
case SHT_DYNSYM:
|
||||
if (bias == -4396) {
|
||||
dynsym = section_h;
|
||||
dynsym_offset = section_h->sh_offset;
|
||||
dynsym_size = section_h->sh_size;
|
||||
dynsym_count = dynsym_size / entsize;
|
||||
dynsym_start = reinterpret_cast<Elf_Sym *>(((size_t) header) + dynsym_offset);
|
||||
}
|
||||
break;
|
||||
case SHT_SYMTAB:
|
||||
if (strcmp(sname, ".symtab") == 0) {
|
||||
symtab = section_h;
|
||||
symtab_offset = section_h->sh_offset;
|
||||
symtab_size = section_h->sh_size;
|
||||
symtab_count = symtab_size / entsize;
|
||||
symtab_start = reinterpret_cast<Elf_Sym *>(((size_t) header) + symtab_offset);
|
||||
}
|
||||
break;
|
||||
case SHT_STRTAB:
|
||||
if (bias == -4396) {
|
||||
strtab = section_h;
|
||||
symstr_offset = section_h->sh_offset;
|
||||
strtab_start = reinterpret_cast<Elf_Sym *>(((size_t) header) + symstr_offset);
|
||||
}
|
||||
if (strcmp(sname, ".strtab") == 0) {
|
||||
symstr_offset_for_symtab = section_h->sh_offset;
|
||||
}
|
||||
break;
|
||||
case SHT_PROGBITS:
|
||||
if (strtab == nullptr || dynsym == nullptr) break;
|
||||
if (bias == -4396) {
|
||||
bias = (off_t) section_h->sh_addr - (off_t) section_h->sh_offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//load module base
|
||||
base = getModuleBase();
|
||||
}
|
||||
|
||||
ElfImg::~ElfImg() {
|
||||
//open elf file local
|
||||
if (buffer) {
|
||||
free(buffer);
|
||||
buffer = nullptr;
|
||||
}
|
||||
//use mmap
|
||||
if (header) {
|
||||
munmap(header, size);
|
||||
}
|
||||
}
|
||||
|
||||
Elf_Addr ElfImg::getSymbOffset(const char *name) const {
|
||||
Elf_Addr _offset;
|
||||
|
||||
//search dynmtab
|
||||
if (dynsym_start != nullptr && strtab_start != nullptr) {
|
||||
Elf_Sym *sym = dynsym_start;
|
||||
char *strings = (char *) strtab_start;
|
||||
int k;
|
||||
for (k = 0; k < dynsym_count; k++, sym++)
|
||||
if (strcmp(strings + sym->st_name, name) == 0) {
|
||||
_offset = sym->st_value;
|
||||
LOGD("find %s: %p", elf, reinterpret_cast<void *>(_offset));
|
||||
return _offset;
|
||||
}
|
||||
}
|
||||
|
||||
//search symtab
|
||||
if (symtab_start != nullptr && symstr_offset_for_symtab != 0) {
|
||||
for (int i = 0; i < symtab_count; i++) {
|
||||
unsigned int st_type = ELF_ST_TYPE(symtab_start[i].st_info);
|
||||
char *st_name = reinterpret_cast<char *>(((size_t) header) + symstr_offset_for_symtab +
|
||||
symtab_start[i].st_name);
|
||||
if ((st_type == STT_FUNC || st_type == STT_OBJECT) && symtab_start[i].st_size) {
|
||||
if (strcmp(st_name, name) == 0) {
|
||||
_offset = symtab_start[i].st_value;
|
||||
LOGD("find %s: %p", elf, reinterpret_cast<void *>(_offset));
|
||||
return _offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Elf_Addr ElfImg::getSymbAddress(const char *name) const {
|
||||
Elf_Addr offset = getSymbOffset(name);
|
||||
Elf_Addr res;
|
||||
if (offset > 0 && base != nullptr) {
|
||||
res = static_cast<Elf_Addr>((size_t) base + offset - bias);
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
if (res == 0) {
|
||||
LOGE("fail to get symbol %s from %s ", name, elf);
|
||||
} else {
|
||||
LOGD("got symbol %s form %s with %p", name, elf, (void *) res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void *ElfImg::getModuleBase() const {
|
||||
char buff[256];
|
||||
off_t load_addr;
|
||||
int found = 0;
|
||||
FILE *maps = fopen("/proc/self/maps", "r");
|
||||
|
||||
char name[PATH_MAX] = {'\0'};
|
||||
|
||||
strncpy(name, elf, PATH_MAX);
|
||||
{
|
||||
struct stat buf{};
|
||||
while (lstat(name, &buf) == 0 && S_ISLNK(buf.st_mode)) {
|
||||
if (auto s = readlink(name, name, PATH_MAX); s >= 0) {
|
||||
name[s] = '\0';
|
||||
} else {
|
||||
fclose(maps);
|
||||
LOGE("cannot read link for %s with %s", name, strerror(errno));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// fs::path name(elf);
|
||||
// std::error_code ec;
|
||||
// while(fs::is_symlink(name, ec) && !ec) {
|
||||
// name = fs::read_symlink(name);
|
||||
// }
|
||||
|
||||
while (fgets(buff, sizeof(buff), maps)) {
|
||||
if ((strstr(buff, "r-xp") || strstr(buff, "r--p")) && strstr(buff, name)) {
|
||||
found = 1;
|
||||
LOGD("found: %s", buff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
LOGE("failed to read load address for %s", name);
|
||||
fclose(maps);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (sscanf(buff, "%lx", &load_addr) != 1)
|
||||
LOGE("failed to read load address for %s", name);
|
||||
|
||||
fclose(maps);
|
||||
|
||||
LOGD("get module base %s: %lu", name, load_addr);
|
||||
|
||||
return reinterpret_cast<void *>(load_addr);
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// From https://github.com/ganyao114/SandHook/blob/master/hooklib/src/main/cpp/includes/elf_util.h
|
||||
//
|
||||
// Created by Swift Gan on 2019/3/14.
|
||||
//
|
||||
#ifndef SANDHOOK_ELF_UTIL_H
|
||||
#define SANDHOOK_ELF_UTIL_H
|
||||
|
||||
#include <linux/elf.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(__LP64__)
|
||||
typedef Elf64_Ehdr Elf_Ehdr;
|
||||
typedef Elf64_Shdr Elf_Shdr;
|
||||
typedef Elf64_Addr Elf_Addr;
|
||||
typedef Elf64_Dyn Elf_Dyn;
|
||||
typedef Elf64_Rela Elf_Rela;
|
||||
typedef Elf64_Sym Elf_Sym;
|
||||
typedef Elf64_Off Elf_Off;
|
||||
|
||||
#define ELF_R_SYM(i) ELF64_R_SYM(i)
|
||||
#else
|
||||
typedef Elf32_Ehdr Elf_Ehdr;
|
||||
typedef Elf32_Shdr Elf_Shdr;
|
||||
typedef Elf32_Addr Elf_Addr;
|
||||
typedef Elf32_Dyn Elf_Dyn;
|
||||
typedef Elf32_Rel Elf_Rela;
|
||||
typedef Elf32_Sym Elf_Sym;
|
||||
typedef Elf32_Off Elf_Off;
|
||||
|
||||
#define ELF_R_SYM(i) ELF32_R_SYM(i)
|
||||
#endif
|
||||
|
||||
namespace SandHook {
|
||||
|
||||
class ElfImg {
|
||||
public:
|
||||
|
||||
ElfImg(const char* elf);
|
||||
|
||||
Elf_Addr getSymbOffset(const char* name) const;
|
||||
|
||||
void* getModuleBase() const;
|
||||
|
||||
Elf_Addr getSymbAddress(const char* name) const;
|
||||
|
||||
~ElfImg();
|
||||
|
||||
private:
|
||||
const char* elf = nullptr;
|
||||
void* base = nullptr;
|
||||
char* buffer = nullptr;
|
||||
off_t size = 0;
|
||||
off_t bias = -4396;
|
||||
Elf_Ehdr* header = nullptr;
|
||||
Elf_Shdr* section_header = nullptr;
|
||||
Elf_Shdr* symtab = nullptr;
|
||||
Elf_Shdr* strtab = nullptr;
|
||||
Elf_Shdr* dynsym = nullptr;
|
||||
Elf_Off dynsym_count = 0;
|
||||
Elf_Sym* symtab_start = nullptr;
|
||||
Elf_Sym* dynsym_start = nullptr;
|
||||
Elf_Sym* strtab_start = nullptr;
|
||||
Elf_Off symtab_count = 0;
|
||||
Elf_Off symstr_offset = 0;
|
||||
Elf_Off symstr_offset_for_symtab = 0;
|
||||
Elf_Off symtab_offset = 0;
|
||||
Elf_Off dynsym_offset = 0;
|
||||
Elf_Off symtab_size = 0;
|
||||
Elf_Off dynsym_size = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //SANDHOOK_ELF_UTIL_H
|
||||
|
|
@ -57,14 +57,15 @@ namespace lspd {
|
|||
return ret;
|
||||
}
|
||||
|
||||
void RegisterNativeLib(const std::string& library_name) {
|
||||
void RegisterNativeLib(const std::string &library_name) {
|
||||
LOGD("native_api: Registered %s", library_name.c_str());
|
||||
moduleNativeLibs.push_back(library_name);
|
||||
}
|
||||
|
||||
bool hasEnding(std::string_view fullString, std::string_view ending) {
|
||||
if (fullString.length() >= ending.length()) {
|
||||
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
|
||||
return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(),
|
||||
ending));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -89,13 +90,14 @@ namespace lspd {
|
|||
// the so is a module so
|
||||
if (UNLIKELY(hasEnding(ns, module_lib))) {
|
||||
LOGI("Loading module native library %s", module_lib.data());
|
||||
void* native_init_sym = dlsym(handle, "native_init");
|
||||
void *native_init_sym = dlsym(handle, "native_init");
|
||||
if (UNLIKELY(native_init_sym == nullptr)) {
|
||||
LOGE("Failed to get symbol \"native_init\" from library %s", module_lib.data());
|
||||
LOGE("Failed to get symbol \"native_init\" from library %s",
|
||||
module_lib.data());
|
||||
break;
|
||||
}
|
||||
auto native_init = reinterpret_cast<NativeInit>(native_init_sym);
|
||||
native_init(reinterpret_cast<void*>(init));
|
||||
native_init(reinterpret_cast<void *>(init));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,8 +109,8 @@ namespace lspd {
|
|||
});
|
||||
|
||||
void InstallNativeAPI() {
|
||||
symbol_do_dlopen = DobbySymbolResolver(nullptr, "__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv");
|
||||
LOGD("InstallNativeAPI: %p", symbol_do_dlopen);
|
||||
HookSymNoHandle(symbol_do_dlopen, do_dlopen);
|
||||
LOGD("InstallNativeAPI: %p", sym_do_dlopen);
|
||||
if (sym_do_dlopen)
|
||||
HookSymNoHandle(sym_do_dlopen, do_dlopen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
#include <dl_util.h>
|
||||
#include <art/runtime/jni_env_ext.h>
|
||||
#include <dobby.h>
|
||||
#include "bionic_linker_restriction.h"
|
||||
#include "utils.h"
|
||||
#include "symbol_cache.h"
|
||||
#include "logging.h"
|
||||
#include "native_api.h"
|
||||
#include "native_hook.h"
|
||||
|
|
@ -63,28 +63,7 @@ namespace lspd {
|
|||
LOGI("Using api level %d", api_level);
|
||||
InstallRiruHooks();
|
||||
// install ART hooks
|
||||
if (api_level >= __ANDROID_API_Q__) {
|
||||
// From Riru v22 we can't get ART handle by hooking dlopen, so we get libart.so from soinfo.
|
||||
// Ref: https://android.googlesource.com/platform/bionic/+/master/linker/linker_soinfo.h
|
||||
linker_iterate_soinfo([](auto soinfo) {
|
||||
const char *real_path = linker_soinfo_get_realpath(soinfo);
|
||||
if (real_path != nullptr &&
|
||||
strstr(real_path, kLibArtName.c_str()) != nullptr){
|
||||
InstallArtHooks(soinfo);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
if (!art_hooks_installed) {
|
||||
LOGE("Android 10+ detected and libart.so can't be found in memory.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// do dlopen directly in Android 9-
|
||||
ScopedDlHandle art_handle(kLibArtLegacyPath.c_str());
|
||||
InstallArtHooks(art_handle.Get());
|
||||
}
|
||||
|
||||
InstallArtHooks(handle_libart);
|
||||
InstallNativeAPI();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
#include <logging.h>
|
||||
#include "utils.h"
|
||||
#include "riru_hook.h"
|
||||
#include <dobby.h>
|
||||
#include "symbol_cache.h"
|
||||
|
||||
namespace lspd {
|
||||
|
||||
|
|
@ -123,21 +123,18 @@ namespace lspd {
|
|||
|
||||
api_level = GetAndroidApiLevel();
|
||||
|
||||
auto *sym = DobbySymbolResolver(nullptr, "__system_property_get");
|
||||
if (!sym) {
|
||||
if (!sym_system_property_get) {
|
||||
LOGE("Failed to get symbol of __system_property_get");
|
||||
return;
|
||||
}
|
||||
HookSymNoHandle(sym, __system_property_get);
|
||||
HookSymNoHandle(sym_system_property_get, __system_property_get);
|
||||
|
||||
if (GetAndroidApiLevel() >= __ANDROID_API_P__) {
|
||||
sym = DobbySymbolResolver(nullptr,
|
||||
"_ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_");
|
||||
if (!sym) {
|
||||
if (!sym_get_property) {
|
||||
LOGE("Failed to get symbol of _ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_");
|
||||
return;
|
||||
}
|
||||
HookSymNoHandle(sym, GetProperty);
|
||||
HookSymNoHandle(sym_get_property, GetProperty);
|
||||
}
|
||||
|
||||
LOGI("Riru hooks installed");
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "service.h"
|
||||
#include "context.h"
|
||||
#include "jni_helper.h"
|
||||
#include "symbol_cache.h"
|
||||
|
||||
namespace lspd {
|
||||
jboolean
|
||||
|
|
@ -84,7 +85,7 @@ namespace lspd {
|
|||
"(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z");
|
||||
|
||||
binder_class_ = env->FindClass("android/os/Binder");
|
||||
if (binder_class_) binder_class_ = (jclass)env->NewGlobalRef(binder_class_);
|
||||
if (binder_class_) binder_class_ = (jclass) env->NewGlobalRef(binder_class_);
|
||||
binder_ctor_ = env->GetMethodID(binder_class_, "<init>", "()V");
|
||||
|
||||
// Parcel
|
||||
|
|
@ -133,8 +134,8 @@ namespace lspd {
|
|||
exec_transact_backup_methodID_ = JNI_GetMethodID(env, binderClass.get(), "execTransact",
|
||||
"(IJJI)Z");
|
||||
auto set_table_override = reinterpret_cast<void (*)(
|
||||
JNINativeInterface *)>(DobbySymbolResolver(nullptr,
|
||||
"_ZN3art9JNIEnvExt16SetTableOverrideEPK18JNINativeInterface"));
|
||||
JNINativeInterface *)>(Dlsym(handle_libart,
|
||||
"_ZN3art9JNIEnvExt16SetTableOverrideEPK18JNINativeInterface"));
|
||||
if (!set_table_override) {
|
||||
LOGE("set table override not found");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,16 +23,126 @@
|
|||
//
|
||||
|
||||
#include "symbol_cache.h"
|
||||
#include "elf_util.h"
|
||||
#include <dobby.h>
|
||||
#include "macros.h"
|
||||
#include "config.h"
|
||||
#include <vector>
|
||||
#include <logging.h>
|
||||
|
||||
namespace lspd {
|
||||
bool sym_initialized = false;
|
||||
void *sym_do_dlopen = nullptr;
|
||||
void *sym_system_property_get = nullptr;
|
||||
void *sym_get_property = nullptr;
|
||||
void *handle_libart = nullptr;
|
||||
|
||||
struct soinfo;
|
||||
|
||||
soinfo *solist = nullptr;
|
||||
soinfo *somain = nullptr;
|
||||
|
||||
template<typename T>
|
||||
inline T *getStaticVariable(const SandHook::ElfImg &linker, std::string_view name) {
|
||||
auto *addr = reinterpret_cast<T **>(linker.getSymbAddress(name.data()));
|
||||
return addr == nullptr ? nullptr : *addr;
|
||||
}
|
||||
|
||||
struct soinfo {
|
||||
soinfo *next() {
|
||||
return *(soinfo **) ((uintptr_t) this + solist_next_offset);
|
||||
}
|
||||
|
||||
const char *get_realpath() {
|
||||
return get_realpath_sym ? get_realpath_sym(this) : ((std::string *) (
|
||||
(uintptr_t) this +
|
||||
solist_realpath_offset))->c_str();
|
||||
}
|
||||
|
||||
const char *get_soname() {
|
||||
return get_soname_sym ? get_soname_sym(this) : *((const char **) (
|
||||
(uintptr_t) this +
|
||||
solist_realpath_offset - sizeof(void *)));
|
||||
}
|
||||
|
||||
void *to_handle() {
|
||||
return to_handle_sym ? to_handle_sym(this) : nullptr;
|
||||
}
|
||||
|
||||
static bool setup(const SandHook::ElfImg &linker) {
|
||||
get_realpath_sym = reinterpret_cast<decltype(get_realpath_sym)>(linker.getSymbAddress(
|
||||
"__dl__ZNK6soinfo12get_realpathEv"));
|
||||
get_soname_sym = reinterpret_cast<decltype(get_soname_sym)>(linker.getSymbAddress(
|
||||
"__dl__ZNK6soinfo10get_sonameEv"));
|
||||
to_handle_sym = reinterpret_cast<decltype(to_handle_sym)>(linker.getSymbAddress(
|
||||
"__dl__ZN6soinfo9to_handleEv"));
|
||||
auto vsdo = getStaticVariable<soinfo>(linker, "__dl__ZL4vdso");
|
||||
for (size_t i = 0; i < 1024 / sizeof(void *); i++) {
|
||||
auto *possible_next = *(void **) ((uintptr_t) solist + i * sizeof(void *));
|
||||
if (possible_next == somain || (vsdo && possible_next == vsdo)) {
|
||||
solist_next_offset = i * sizeof(void *);
|
||||
return (get_realpath_sym && get_soname_sym && to_handle_sym);
|
||||
}
|
||||
}
|
||||
LOGW("%s", "failed to search next offset");
|
||||
// shortcut
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __LP64__
|
||||
inline static size_t solist_next_offset = 0x30;
|
||||
constexpr static size_t solist_realpath_offset = 0x1a8;
|
||||
#else
|
||||
inline static size_t solist_next_offset = 0xa4;
|
||||
constexpr static size_t solist_realpath_offset = 0x174;
|
||||
#endif
|
||||
|
||||
// since Android 8
|
||||
inline static const char *(*get_realpath_sym)(soinfo *) = nullptr;
|
||||
|
||||
inline static const char *(*get_soname_sym)(soinfo *) = nullptr;
|
||||
|
||||
inline static void *(*to_handle_sym)(soinfo *) = nullptr;
|
||||
};
|
||||
|
||||
std::vector<soinfo *> linker_get_solist() {
|
||||
std::vector<soinfo *> linker_solist{};
|
||||
for (auto *iter = solist; iter; iter = iter->next()) {
|
||||
linker_solist.push_back(iter);
|
||||
}
|
||||
return linker_solist;
|
||||
}
|
||||
|
||||
void *findLibArt() {
|
||||
for (const auto &soinfo : linker_get_solist()) {
|
||||
if (const auto &real_path = soinfo->get_realpath(), &soname = soinfo->get_soname();
|
||||
(real_path &&
|
||||
std::string_view(real_path).find(kLibArtName) != std::string_view::npos) ||
|
||||
(soname &&
|
||||
std::string_view(soname).find(kLibArtName) != std::string_view::npos)) {
|
||||
return soinfo->to_handle();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void InitSymbolCache() {
|
||||
if (LIKELY(initialized)) return;
|
||||
if (UNLIKELY(sym_initialized)) return;
|
||||
LOGD("InitSymbolCache");
|
||||
// TODO: set image name
|
||||
symbol_do_dlopen = DobbySymbolResolver(nullptr, "__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv");
|
||||
initialized = true;
|
||||
auto linker = SandHook::ElfImg(kLinkerPath.c_str());
|
||||
auto libc = SandHook::ElfImg(kLibcPath.c_str());
|
||||
auto libbase = SandHook::ElfImg(kLibbasePath.c_str());
|
||||
sym_initialized = (solist = getStaticVariable<soinfo>(linker, "__dl__ZL6solist")) &&
|
||||
(somain = getStaticVariable<soinfo>(linker, "__dl__ZL6somain")) &&
|
||||
(sym_do_dlopen = reinterpret_cast<void *>(linker.getSymbAddress(
|
||||
"__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv"))) &&
|
||||
(sym_system_property_get = reinterpret_cast<void *>(libc.getSymbAddress(
|
||||
"__system_property_get"))) &&
|
||||
(sym_get_property = reinterpret_cast<void *>(libbase.getSymbAddress(
|
||||
"_ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_"))) &&
|
||||
soinfo::setup(linker) && (handle_libart = findLibArt());
|
||||
if (UNLIKELY(!sym_initialized)) {
|
||||
LOGE("Init symbol cache failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,13 @@
|
|||
|
||||
#ifndef LSPOSED_SYMBOL_CACHE_H
|
||||
#define LSPOSED_SYMBOL_CACHE_H
|
||||
#include <atomic>
|
||||
|
||||
namespace lspd {
|
||||
static std::atomic_bool initialized;
|
||||
static void* symbol_do_dlopen = nullptr;
|
||||
extern bool sym_initialized;
|
||||
extern void *sym_do_dlopen;
|
||||
extern void *sym_system_property_get;
|
||||
extern void *sym_get_property;
|
||||
extern void *handle_libart;
|
||||
|
||||
void InitSymbolCache();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue