[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
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
path: ~/.ccache
|
path: ~/.ccache
|
||||||
key: ccache-${{ github.sha }}
|
key: ccache-cache-${{ github.sha }}
|
||||||
restore-keys: ccache
|
restore-keys: ccache-cache-
|
||||||
- name: Install ccache
|
- name: Install ccache
|
||||||
run: sudo apt-get install -y ccache
|
run: sudo apt-get install -y ccache
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
|
|
|
||||||
|
|
@ -185,8 +185,6 @@ task("buildLibcxx", Exec::class) {
|
||||||
println("using ccache $it")
|
println("using ccache $it")
|
||||||
environment("NDK_CCACHE", it)
|
environment("NDK_CCACHE", it)
|
||||||
environment("USE_CCACHE", "1")
|
environment("USE_CCACHE", "1")
|
||||||
environment("CCACHE_COMPILERCHECK", "content")
|
|
||||||
environment("CCACHE_MAXSIZE", "100M")
|
|
||||||
} ?: run {
|
} ?: run {
|
||||||
println("not using ccache")
|
println("not using ccache")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,6 @@ find_program(CCACHE ccache)
|
||||||
if (CCACHE)
|
if (CCACHE)
|
||||||
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})
|
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})
|
||||||
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE})
|
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE})
|
||||||
set(ENV{CCACHE_COMPILERCHECK} "content")
|
|
||||||
set(ENV{CCACHE_MAXSIZE} "100M")
|
|
||||||
else ()
|
else ()
|
||||||
message(WARNING "Could not find CCache program.")
|
message(WARNING "Could not find CCache program.")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,11 @@ macro(SET_OPTION option value)
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
SET_OPTION(DOBBY_GENERATE_SHARED OFF)
|
SET_OPTION(DOBBY_GENERATE_SHARED OFF)
|
||||||
SET_OPTION(Plugin.Android.BionicLinkerRestriction ON)
|
|
||||||
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
SET_OPTION(DOBBY_DEBUG OFF)
|
SET_OPTION(DOBBY_DEBUG OFF)
|
||||||
endif (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
endif (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
add_subdirectory(Dobby)
|
add_subdirectory(Dobby)
|
||||||
target_include_directories(dobby PUBLIC Dobby/include)
|
target_include_directories(dobby PUBLIC Dobby/include)
|
||||||
target_include_directories(dobby PUBLIC Dobby/builtin-plugin/BionicLinkerRestriction)
|
|
||||||
|
|
||||||
add_library(libcxx STATIC IMPORTED GLOBAL)
|
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)
|
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
|
//#define DEBUG
|
||||||
|
|
||||||
|
|
||||||
inline bool constexpr Is64() {
|
inline bool constexpr Is64() {
|
||||||
#if defined(__LP64__)
|
#if defined(__LP64__)
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline constexpr bool is64 = Is64();
|
inline constexpr bool is64 = Is64();
|
||||||
|
|
||||||
#if defined(__LP64__)
|
#if defined(__LP64__)
|
||||||
# define LP_SELECT(lp32, lp64) 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 kLibArtName = "libart.so"_tstr;
|
||||||
static constexpr auto kLibFwName = "libandroidfw.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 =
|
static constexpr auto kLibBasePath =
|
||||||
LP_SELECT("/system/lib/"_tstr,
|
LP_SELECT("/system/lib/"_tstr,
|
||||||
"/system/lib64/"_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 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) {
|
inline constexpr const char *const BoolToString(bool b) {
|
||||||
return b ? "true" : "false";
|
return b ? "true" : "false";
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include "jni/logger.h"
|
#include "jni/logger.h"
|
||||||
#include "jni/native_api.h"
|
#include "jni/native_api.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
#include "symbol_cache.h"
|
||||||
|
|
||||||
namespace lspd {
|
namespace lspd {
|
||||||
extern int *allowUnload;
|
extern int *allowUnload;
|
||||||
|
|
@ -168,22 +169,24 @@ namespace lspd {
|
||||||
void
|
void
|
||||||
Context::OnNativeForkSystemServerPre(JNIEnv *env) {
|
Context::OnNativeForkSystemServerPre(JNIEnv *env) {
|
||||||
Service::instance()->InitService(env);
|
Service::instance()->InitService(env);
|
||||||
skip_ = false;
|
skip_ = !sym_initialized;
|
||||||
setAllowUnload(false);
|
setAllowUnload(skip_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Context::OnNativeForkSystemServerPost(JNIEnv *env, jint res) {
|
Context::OnNativeForkSystemServerPost(JNIEnv *env, jint res) {
|
||||||
if (res != 0) return;
|
if (res != 0) return;
|
||||||
LoadDex(env);
|
if (!skip_) {
|
||||||
Service::instance()->HookBridge(*this, env);
|
LoadDex(env);
|
||||||
auto binder = Service::instance()->RequestBinderForSystemServer(env);
|
Service::instance()->HookBridge(*this, env);
|
||||||
if (binder && !skip_) {
|
auto binder = Service::instance()->RequestBinderForSystemServer(env);
|
||||||
InstallInlineHooks();
|
if (binder) {
|
||||||
Init(env);
|
InstallInlineHooks();
|
||||||
FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", binder);
|
Init(env);
|
||||||
|
FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", binder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setAllowUnload(false);
|
setAllowUnload(skip_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Context::OnNativeForkAndSpecializePre(JNIEnv *env,
|
void Context::OnNativeForkAndSpecializePre(JNIEnv *env,
|
||||||
|
|
@ -195,7 +198,7 @@ namespace lspd {
|
||||||
const auto app_id = uid % PER_USER_RANGE;
|
const auto app_id = uid % PER_USER_RANGE;
|
||||||
nice_name_ = nice_name;
|
nice_name_ = nice_name;
|
||||||
JUTFString process_name(env, nice_name);
|
JUTFString process_name(env, nice_name);
|
||||||
skip_ = false;
|
skip_ = !sym_initialized;
|
||||||
if (!skip_ && !app_data_dir) {
|
if (!skip_ && !app_data_dir) {
|
||||||
LOGD("skip injecting into %s because it has no data dir", process_name.get());
|
LOGD("skip injecting into %s because it has no data dir", process_name.get());
|
||||||
skip_ = true;
|
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;
|
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());
|
LOGD("native_api: Registered %s", library_name.c_str());
|
||||||
moduleNativeLibs.push_back(library_name);
|
moduleNativeLibs.push_back(library_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasEnding(std::string_view fullString, std::string_view ending) {
|
bool hasEnding(std::string_view fullString, std::string_view ending) {
|
||||||
if (fullString.length() >= ending.length()) {
|
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 {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -89,13 +90,14 @@ namespace lspd {
|
||||||
// the so is a module so
|
// the so is a module so
|
||||||
if (UNLIKELY(hasEnding(ns, module_lib))) {
|
if (UNLIKELY(hasEnding(ns, module_lib))) {
|
||||||
LOGI("Loading module native library %s", module_lib.data());
|
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)) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
auto native_init = reinterpret_cast<NativeInit>(native_init_sym);
|
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() {
|
void InstallNativeAPI() {
|
||||||
symbol_do_dlopen = DobbySymbolResolver(nullptr, "__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv");
|
LOGD("InstallNativeAPI: %p", sym_do_dlopen);
|
||||||
LOGD("InstallNativeAPI: %p", symbol_do_dlopen);
|
if (sym_do_dlopen)
|
||||||
HookSymNoHandle(symbol_do_dlopen, do_dlopen);
|
HookSymNoHandle(sym_do_dlopen, do_dlopen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@
|
||||||
#include <dl_util.h>
|
#include <dl_util.h>
|
||||||
#include <art/runtime/jni_env_ext.h>
|
#include <art/runtime/jni_env_ext.h>
|
||||||
#include <dobby.h>
|
#include <dobby.h>
|
||||||
#include "bionic_linker_restriction.h"
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "symbol_cache.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "native_api.h"
|
#include "native_api.h"
|
||||||
#include "native_hook.h"
|
#include "native_hook.h"
|
||||||
|
|
@ -63,28 +63,7 @@ namespace lspd {
|
||||||
LOGI("Using api level %d", api_level);
|
LOGI("Using api level %d", api_level);
|
||||||
InstallRiruHooks();
|
InstallRiruHooks();
|
||||||
// install ART hooks
|
// install ART hooks
|
||||||
if (api_level >= __ANDROID_API_Q__) {
|
InstallArtHooks(handle_libart);
|
||||||
// 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());
|
|
||||||
}
|
|
||||||
|
|
||||||
InstallNativeAPI();
|
InstallNativeAPI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
#include <logging.h>
|
#include <logging.h>
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "riru_hook.h"
|
#include "riru_hook.h"
|
||||||
#include <dobby.h>
|
#include "symbol_cache.h"
|
||||||
|
|
||||||
namespace lspd {
|
namespace lspd {
|
||||||
|
|
||||||
|
|
@ -123,21 +123,18 @@ namespace lspd {
|
||||||
|
|
||||||
api_level = GetAndroidApiLevel();
|
api_level = GetAndroidApiLevel();
|
||||||
|
|
||||||
auto *sym = DobbySymbolResolver(nullptr, "__system_property_get");
|
if (!sym_system_property_get) {
|
||||||
if (!sym) {
|
|
||||||
LOGE("Failed to get symbol of __system_property_get");
|
LOGE("Failed to get symbol of __system_property_get");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
HookSymNoHandle(sym, __system_property_get);
|
HookSymNoHandle(sym_system_property_get, __system_property_get);
|
||||||
|
|
||||||
if (GetAndroidApiLevel() >= __ANDROID_API_P__) {
|
if (GetAndroidApiLevel() >= __ANDROID_API_P__) {
|
||||||
sym = DobbySymbolResolver(nullptr,
|
if (!sym_get_property) {
|
||||||
"_ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_");
|
|
||||||
if (!sym) {
|
|
||||||
LOGE("Failed to get symbol of _ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_");
|
LOGE("Failed to get symbol of _ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
HookSymNoHandle(sym, GetProperty);
|
HookSymNoHandle(sym_get_property, GetProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("Riru hooks installed");
|
LOGI("Riru hooks installed");
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include "jni_helper.h"
|
#include "jni_helper.h"
|
||||||
|
#include "symbol_cache.h"
|
||||||
|
|
||||||
namespace lspd {
|
namespace lspd {
|
||||||
jboolean
|
jboolean
|
||||||
|
|
@ -84,7 +85,7 @@ namespace lspd {
|
||||||
"(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z");
|
"(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z");
|
||||||
|
|
||||||
binder_class_ = env->FindClass("android/os/Binder");
|
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");
|
binder_ctor_ = env->GetMethodID(binder_class_, "<init>", "()V");
|
||||||
|
|
||||||
// Parcel
|
// Parcel
|
||||||
|
|
@ -133,8 +134,8 @@ namespace lspd {
|
||||||
exec_transact_backup_methodID_ = JNI_GetMethodID(env, binderClass.get(), "execTransact",
|
exec_transact_backup_methodID_ = JNI_GetMethodID(env, binderClass.get(), "execTransact",
|
||||||
"(IJJI)Z");
|
"(IJJI)Z");
|
||||||
auto set_table_override = reinterpret_cast<void (*)(
|
auto set_table_override = reinterpret_cast<void (*)(
|
||||||
JNINativeInterface *)>(DobbySymbolResolver(nullptr,
|
JNINativeInterface *)>(Dlsym(handle_libart,
|
||||||
"_ZN3art9JNIEnvExt16SetTableOverrideEPK18JNINativeInterface"));
|
"_ZN3art9JNIEnvExt16SetTableOverrideEPK18JNINativeInterface"));
|
||||||
if (!set_table_override) {
|
if (!set_table_override) {
|
||||||
LOGE("set table override not found");
|
LOGE("set table override not found");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,126 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "symbol_cache.h"
|
#include "symbol_cache.h"
|
||||||
|
#include "elf_util.h"
|
||||||
#include <dobby.h>
|
#include <dobby.h>
|
||||||
#include "macros.h"
|
#include "macros.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <vector>
|
||||||
#include <logging.h>
|
#include <logging.h>
|
||||||
|
|
||||||
namespace lspd {
|
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() {
|
void InitSymbolCache() {
|
||||||
if (LIKELY(initialized)) return;
|
if (UNLIKELY(sym_initialized)) return;
|
||||||
LOGD("InitSymbolCache");
|
LOGD("InitSymbolCache");
|
||||||
// TODO: set image name
|
auto linker = SandHook::ElfImg(kLinkerPath.c_str());
|
||||||
symbol_do_dlopen = DobbySymbolResolver(nullptr, "__dl__Z9do_dlopenPKciPK17android_dlextinfoPKv");
|
auto libc = SandHook::ElfImg(kLibcPath.c_str());
|
||||||
initialized = true;
|
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
|
#ifndef LSPOSED_SYMBOL_CACHE_H
|
||||||
#define LSPOSED_SYMBOL_CACHE_H
|
#define LSPOSED_SYMBOL_CACHE_H
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
namespace lspd {
|
namespace lspd {
|
||||||
static std::atomic_bool initialized;
|
extern bool sym_initialized;
|
||||||
static void* symbol_do_dlopen = nullptr;
|
extern void *sym_do_dlopen;
|
||||||
|
extern void *sym_system_property_get;
|
||||||
|
extern void *sym_get_property;
|
||||||
|
extern void *handle_libart;
|
||||||
|
|
||||||
void InitSymbolCache();
|
void InitSymbolCache();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue