[core] Completely switch to ElfImg (#730)

This commit is contained in:
LoveSy 2021-06-04 02:07:53 +08:00 committed by GitHub
parent c39b294d0f
commit 4cb731c1fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 115 additions and 199 deletions

View File

@ -42,8 +42,7 @@ namespace art {
return PrettyMethod(thiz, true);
}
static void Setup(void *handle) {
LOGD("art_method hook setup, handle=%p", handle);
static void Setup(const SandHook::ElfImg &handle) {
RETRIEVE_MEM_FUNC_SYMBOL(PrettyMethod, "_ZN3art9ArtMethod12PrettyMethodEb");
}
}

View File

@ -107,8 +107,7 @@ namespace art {
}
// @ApiSensitive(Level.MIDDLE)
static void Setup(void *handle) {
LOGD("Classlinker hook setup, handle=%p", handle);
static void Setup(const SandHook::ElfImg &handle) {
int api_level = lspd::GetAndroidApiLevel();
size_t OFFSET_classlinker; // Get offset from art::Runtime::RunRootClinits() call in IDA
switch (api_level) {

View File

@ -51,7 +51,7 @@ namespace art {
destructor(this);
}
static void Setup(void *handle) {
static void Setup(const SandHook::ElfImg &handle) {
RETRIEVE_MEM_FUNC_SYMBOL(constructor, "_ZN3art2gc23ScopedGCCriticalSectionC2EPNS_6ThreadENS0_7GcCauseENS0_13CollectorTypeE");
RETRIEVE_MEM_FUNC_SYMBOL(destructor, "_ZN3art2gc23ScopedGCCriticalSectionD2Ev");
}

View File

@ -115,7 +115,7 @@ namespace art {
}
);
static void DisableHiddenApi(void *handle) {
static void DisableHiddenApi(const SandHook::ElfImg &handle) {
const int api_level = lspd::GetAndroidApiLevel();
if (api_level < __ANDROID_API_P__) {

View File

@ -38,7 +38,7 @@ namespace art {
}
});
static void DisableUpdateHookedMethodsCode(void *handle) {
static void DisableUpdateHookedMethodsCode(const SandHook::ElfImg &handle) {
lspd::HookSym(handle, UpdateMethodsCode);
}
}

View File

@ -40,7 +40,7 @@ namespace art {
JNIEnvExt(void *thiz) : HookedObject(thiz) {}
// @ApiSensitive(Level.MIDDLE)
static void Setup(void *handle) {
static void Setup(const SandHook::ElfImg &handle) {
RETRIEVE_MEM_FUNC_SYMBOL(NewLocalRef, "_ZN3art9JNIEnvExt11NewLocalRefEPNS_6mirror6ObjectE");
RETRIEVE_MEM_FUNC_SYMBOL(DeleteLocalRef, "_ZN3art9JNIEnvExt14DeleteLocalRefEP8_jobject");
}
@ -55,4 +55,4 @@ namespace art {
};
}
}

View File

@ -51,7 +51,7 @@ namespace art {
Class(void *thiz) : HookedObject(thiz) {}
// @ApiSensitive(Level.MIDDLE)
static void Setup(void *handle) {
static void Setup(const SandHook::ElfImg &handle) {
RETRIEVE_MEM_FUNC_SYMBOL(GetDescriptor, "_ZN3art6mirror5Class13GetDescriptorEPNSt3__112"
"basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE");
RETRIEVE_MEM_FUNC_SYMBOL(GetClassDef, "_ZN3art6mirror5Class11GetClassDefEv");

View File

@ -45,7 +45,7 @@ namespace art {
}
// @ApiSensitive(Level.LOW)
static void Setup(void *handle) {
static void Setup(const SandHook::ElfImg &handle) {
RETRIEVE_FIELD_SYMBOL(instance, "_ZN3art7Runtime9instance_E");
RETRIEVE_MEM_FUNC_SYMBOL(SetJavaDebuggable, "_ZN3art7Runtime17SetJavaDebuggableEb");
void *thiz = *reinterpret_cast<void **>(instance);

View File

@ -32,22 +32,24 @@ namespace art {
else
return {.data=nullptr};
}
CREATE_FUNC_SYMBOL_ENTRY(void *, CurrentFromGdb) {
if (LIKELY(CurrentFromGdbSym))
return CurrentFromGdbSym();
return CurrentFromGdbSym();
else
return nullptr;
}
public:
Thread(void *thiz) : HookedObject(thiz) {}
static Thread Current() {
return Thread(CurrentFromGdb());
}
static void Setup(void *handle) {
static void Setup(const SandHook::ElfImg &handle) {
RETRIEVE_MEM_FUNC_SYMBOL(DecodeJObject,
"_ZNK3art6Thread13DecodeJObjectEP8_jobject");
"_ZNK3art6Thread13DecodeJObjectEP8_jobject");
RETRIEVE_FUNC_SYMBOL(CurrentFromGdb,
"_ZN3art6Thread14CurrentFromGdbEv");
}

View File

@ -42,7 +42,7 @@ namespace art {
destructor(this);
}
static void Setup(void *handle) {
static void Setup(const SandHook::ElfImg &handle) {
RETRIEVE_MEM_FUNC_SYMBOL(constructor, "_ZN3art16ScopedSuspendAllC2EPKcb");
RETRIEVE_MEM_FUNC_SYMBOL(destructor, "_ZN3art16ScopedSuspendAllD2Ev");
}

View File

@ -25,6 +25,7 @@
#include <sys/mman.h>
#include "config.h"
#include "native_hook.h"
#include "elf_util.h"
#include <concepts>
#define _uintval(p) reinterpret_cast<uintptr_t>(p)
@ -114,13 +115,18 @@ namespace lspd {
return dlsym(handle, name);
}
template<class T, class ... Args>
inline void *Dlsym(void *handle, T first, Args... last) {
auto ret = Dlsym(handle, first);
[[gnu::always_inline]]
inline void *Dlsym(const SandHook::ElfImg &handle, const char *name) {
return handle.getSymbAddress<void *>(name);
}
template<class H, class T, class ... Args>
inline void *Dlsym(H &&handle, T first, Args... last) {
auto ret = Dlsym(std::forward<H>(handle), first);
if (ret) {
return ret;
}
return Dlsym(handle, last...);
return Dlsym(std::forward<H>(handle), last...);
}
inline int HookFunction(void *original, void *replace, void **backup) {
@ -250,15 +256,16 @@ namespace lspd {
}
}
template<HookerType T>
inline static bool HookSym(void *handle, T &arg) {
auto original = Dlsym(handle, arg.sym);
template<typename H, HookerType T>
inline static bool HookSym(H &&handle, T &arg) {
auto original = Dlsym(std::forward<H>(handle), arg.sym);
return HookSymNoHandle(original, arg);
}
template<HookerType T, HookerType...Args>
inline static bool HookSyms(void *handle, T &first, Args &...rest) {
if (!(HookSym(handle, first) || ... || HookSym(handle, rest))) {
template<typename H, HookerType T, HookerType...Args>
inline static bool HookSyms(H &&handle, T &first, Args &...rest) {
if (!(HookSym(std::forward<H>(handle), first) || ... || HookSym(std::forward<H>(handle),
rest))) {
LOGW("Hook Fails: %s", first.sym);
return false;
}

View File

@ -65,20 +65,6 @@ namespace lspd {
inline static constexpr auto kLibArtName = "libart.so"_tstr;
inline static constexpr auto kLibFwName = "libandroidfw.so"_tstr;
inline static constexpr auto kLinkerName = LP_SELECT("linker"_tstr, "linker64"_tstr);
inline static constexpr auto kLibcName = "libc.so"_tstr;
inline static constexpr auto kLibbaseName = "libbase.so"_tstr;
inline static constexpr auto kLibBasePath =
LP_SELECT("/system/lib/"_tstr,
"/system/lib64/"_tstr);
inline static constexpr auto kBinBasePath = "/system/bin/"_tstr;
inline static constexpr auto kLibFwPath = kLibBasePath + kLibFwName;
inline static constexpr auto kLinkerPath = kBinBasePath + kLinkerName;
inline static constexpr auto kLibcPath = kLibBasePath + kLibcName;
inline static constexpr auto kLibbasePath = kLibBasePath + kLibbaseName;
inline constexpr const char *BoolToString(bool b) {
return b ? "true" : "false";

View File

@ -173,7 +173,7 @@ namespace android {
return {nullptr, 0u};
}
static bool setup(void* handle) {
static bool setup(const SandHook::ElfImg &handle) {
RETRIEVE_MEM_FUNC_SYMBOL(stringAt, LP_SELECT("_ZNK7android13ResStringPool8stringAtEjPj", "_ZNK7android13ResStringPool8stringAtEmPm"));
RETRIEVE_MEM_FUNC_SYMBOL(stringAtS, LP_SELECT("_ZNK7android13ResStringPool8stringAtEj", "_ZNK7android13ResStringPool8stringAtEm"));
return !stringAtSym || !stringAtSSym;

View File

@ -35,7 +35,12 @@ inline constexpr auto offsetOf(ElfW(Ehdr) *head, ElfW(Off) off) {
reinterpret_cast<uintptr_t>(head) + off);
}
ElfImg::ElfImg(std::string_view elf) : elf(elf) {
ElfImg::ElfImg(std::string_view base_name) : elf(base_name) {
if (!findModuleBase()) {
base = nullptr;
return;
}
//load elf
int fd = open(elf.data(), O_RDONLY);
if (fd < 0) {
@ -120,9 +125,6 @@ ElfImg::ElfImg(std::string_view elf) : elf(elf) {
}
}
}
//load module base
base = getModuleBase();
}
ElfW(Addr) ElfImg::ElfLookup(std::string_view name, uint32_t hash) const {
@ -218,56 +220,44 @@ ElfImg::getSymbOffset(std::string_view name, uint32_t gnu_hash, uint32_t elf_has
}
void *ElfImg::getModuleBase() const {
bool ElfImg::findModuleBase() {
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.data(), 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)) {
if ((strstr(buff, "r-xp") || strstr(buff, "r--p")) && strstr(buff, elf.data())) {
found = 1;
LOGD("found: %s", buff);
std::string_view b = buff;
if (auto begin = b.find_last_of(' '); begin != std::string_view::npos) {
elf = b.substr(begin + 1);
if (elf.back() == '\n') elf.pop_back();
} else {
return false;
}
LOGD("update path: %s", elf.data());
break;
}
}
if (!found) {
LOGE("failed to read load address for %s", name);
LOGE("failed to read load address for %s", elf.data());
fclose(maps);
return nullptr;
return false;
}
if (char *next = buff; load_addr = strtoul(buff, &next, 16), next == buff) {
LOGE("failed to read load address for %s", name);
LOGE("failed to read load address for %s", elf.data());
}
fclose(maps);
LOGD("get module base %s: %lx", name, load_addr);
LOGD("get module base %s: %lx", elf.data(), load_addr);
return reinterpret_cast<void *>(load_addr);
base = reinterpret_cast<void *>(load_addr);
return true;
}

View File

@ -39,18 +39,25 @@ namespace SandHook {
return getSymbOffset(name, GnuHash(name), ElfHash(name));
}
void *getModuleBase() const;
constexpr ElfW(Addr) getSymbAddress(std::string_view name) const {
ElfW(Addr) offset = getSymbOffset(name);
if (offset > 0 && base != nullptr) {
return static_cast<ElfW(Addr)>((uintptr_t) base + offset - bias);
} else {
LOGE("fail to get symbol %s from %s ", name.data(), elf.data());
return 0;
}
}
template<typename T>
requires(std::is_pointer_v<T>)
constexpr T getSymbAddress(std::string_view name) const {
return reinterpret_cast<T>(getSymbAddress(name));
}
bool isValid() const {
return base != nullptr;
}
~ElfImg();
private:
@ -66,7 +73,9 @@ namespace SandHook {
constexpr static uint32_t GnuHash(std::string_view name);
std::string_view elf;
bool findModuleBase();
std::string elf;
void *base = nullptr;
char *buffer = nullptr;
off_t size = 0;

View File

@ -26,6 +26,7 @@
#include <framework/androidfw/resource_types.h>
#include <byte_order.h>
#include <HookMain.h>
#include <elf_util.h>
#include "native_util.h"
#include "resources_hook.h"
@ -49,24 +50,24 @@ namespace lspd {
static TYPE_GET_ATTR_NAME_ID ResXMLParser_getAttributeNameID = nullptr;
static bool PrepareSymbols() {
ScopedDlHandle fw_handle(kLibFwPath.c_str());
if (!fw_handle.IsValid()) {
SandHook::ElfImg fw(kLibFwName);
if (!fw.isValid()) {
return false;
};
if (!(ResXMLParser_next = fw_handle.DlSym<TYPE_NEXT>(
if (!(ResXMLParser_next = fw.getSymbAddress<TYPE_NEXT>(
"_ZN7android12ResXMLParser4nextEv"))) {
return false;
}
if (!(ResXMLParser_restart = fw_handle.DlSym<TYPE_RESTART>(
if (!(ResXMLParser_restart = fw.getSymbAddress<TYPE_RESTART>(
"_ZN7android12ResXMLParser7restartEv"))) {
return false;
};
if (!(ResXMLParser_getAttributeNameID = fw_handle.DlSym<TYPE_GET_ATTR_NAME_ID>(
if (!(ResXMLParser_getAttributeNameID = fw.getSymbAddress<TYPE_GET_ATTR_NAME_ID>(
LP_SELECT("_ZNK7android12ResXMLParser18getAttributeNameIDEj",
"_ZNK7android12ResXMLParser18getAttributeNameIDEm")))) {
return false;
}
return android::ResStringPool::setup(fw_handle.Get());
return android::ResStringPool::setup(fw);
}
LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, initXResourcesNative) {

View File

@ -47,6 +47,10 @@ namespace lspd {
return;
}
LOGD("Start to install inline hooks");
SandHook::ElfImg &handle_libart = *art_img;
if (!handle_libart.isValid()) {
LOGE("Failed to fetch libart.so");
}
art::Runtime::Setup(handle_libart);
art::hidden_api::DisableHiddenApi(handle_libart);
art::art_method::Setup(handle_libart);
@ -57,6 +61,7 @@ namespace lspd {
art::instrumentation::DisableUpdateHookedMethodsCode(handle_libart);
art::thread_list::ScopedSuspendAll::Setup(handle_libart);
art::gc::ScopedGCCriticalSection::Setup(handle_libart);
art_img.reset();
LOGD("Inline hooks installed");
}
}

View File

@ -131,10 +131,7 @@ namespace lspd {
auto binderClass = JNI_FindClass(env, "android/os/Binder");
exec_transact_backup_methodID_ = JNI_GetMethodID(env, binderClass, "execTransact",
"(IJJI)Z");
auto set_table_override = reinterpret_cast<void (*)(
JNINativeInterface *)>(Dlsym(handle_libart,
"_ZN3art9JNIEnvExt16SetTableOverrideEPK18JNINativeInterface"));
if (!set_table_override) {
if (!sym_set_table_override) {
LOGE("set table override not found");
}
memcpy(&native_interface_replace_, env->functions, sizeof(JNINativeInterface));
@ -142,8 +139,9 @@ namespace lspd {
call_boolean_method_va_backup_ = env->functions->CallBooleanMethodV;
native_interface_replace_.CallBooleanMethodV = &call_boolean_method_va_replace;
if (set_table_override != nullptr) {
set_table_override(&native_interface_replace_);
if (sym_set_table_override != nullptr) {
reinterpret_cast<void (*)(JNINativeInterface *)>(sym_set_table_override)(
&native_interface_replace_);
}
LOGD("Done InitService");

View File

@ -33,129 +33,43 @@
namespace lspd {
bool sym_initialized = false;
void *sym_do_dlopen = nullptr;
void *handle_libart = nullptr;
void *sym_openInMemoryDexFilesNative = nullptr;
void *sym_createCookieWithArray = nullptr;
void *sym_createCookieWithDirectBuffer = nullptr;
void *sym_openDexFileNative = nullptr;
void *sym_setTrusted = nullptr;
void *sym_set_table_override = nullptr;
std::unique_ptr<SandHook::ElfImg> art_img = nullptr;
struct soinfo;
soinfo *solist = nullptr;
soinfo *somain = nullptr;
template<typename T>
constexpr inline T *getStaticVariable(const SandHook::ElfImg &linker, std::string_view name) {
auto *addr = reinterpret_cast<T **>(linker.getSymbAddress(name));
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)) {
auto art = SandHook::ElfImg(real_path);
auto api_level = GetAndroidApiLevel();
if (api_level < __ANDROID_API_P__ || (
(sym_openDexFileNative = reinterpret_cast<void *>(art.getSymbAddress(
"_ZN3artL25DexFile_openDexFileNativeEP7_JNIEnvP7_jclassP8_jstringS5_iP8_jobjectP13_jobjectArray"))) &&
bool findLibArt() {
art_img = std::make_unique<SandHook::ElfImg>(kLibArtName);
if (!art_img->isValid()) return false;
auto api_level = GetAndroidApiLevel();
return (sym_set_table_override = art_img->getSymbAddress<void *>(
"_ZN3art9JNIEnvExt16SetTableOverrideEPK18JNINativeInterface")) != nullptr
&& (api_level < __ANDROID_API_P__ || (
(sym_openDexFileNative = art_img->getSymbAddress<void *>(
"_ZN3artL25DexFile_openDexFileNativeEP7_JNIEnvP7_jclassP8_jstringS5_iP8_jobjectP13_jobjectArray")) &&
(
(sym_openInMemoryDexFilesNative = art_img->getSymbAddress<void *>(
"_ZN3artL34DexFile_openInMemoryDexFilesNativeEP7_JNIEnvP7_jclassP13_jobjectArrayS5_P10_jintArrayS7_P8_jobjectS5_")) ||
(
(sym_openInMemoryDexFilesNative = reinterpret_cast<void *>(art.getSymbAddress(
"_ZN3artL34DexFile_openInMemoryDexFilesNativeEP7_JNIEnvP7_jclassP13_jobjectArrayS5_P10_jintArrayS7_P8_jobjectS5_"))) ||
(
(sym_createCookieWithArray = reinterpret_cast<void *>(art.getSymbAddress(
"_ZN3artL29DexFile_createCookieWithArrayEP7_JNIEnvP7_jclassP11_jbyteArrayii"))) &&
(sym_createCookieWithDirectBuffer = reinterpret_cast<void *>(art.getSymbAddress(
"_ZN3artL36DexFile_createCookieWithDirectBufferEP7_JNIEnvP7_jclassP8_jobjectii")))
)
) &&
(sym_setTrusted = reinterpret_cast<void *>(art.getSymbAddress(
"_ZN3artL18DexFile_setTrustedEP7_JNIEnvP7_jclassP8_jobject")))))
return soinfo->to_handle();
}
}
return nullptr;
(sym_createCookieWithArray = art_img->getSymbAddress<void *>(
"_ZN3artL29DexFile_createCookieWithArrayEP7_JNIEnvP7_jclassP11_jbyteArrayii")) &&
(sym_createCookieWithDirectBuffer = art_img->getSymbAddress<void *>(
"_ZN3artL36DexFile_createCookieWithDirectBufferEP7_JNIEnvP7_jclassP8_jobjectii"))
)
) &&
(sym_setTrusted = art_img->getSymbAddress<void *>(
"_ZN3artL18DexFile_setTrustedEP7_JNIEnvP7_jclassP8_jobject"))));
}
void InitSymbolCache() {
if (UNLIKELY(sym_initialized)) return;
LOGD("InitSymbolCache");
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"))) &&
soinfo::setup(linker) && (handle_libart = findLibArt());
sym_initialized = findLibArt();
if (UNLIKELY(!sym_initialized)) {
art_img.reset();
LOGE("Init symbol cache failed");
}
}

View File

@ -25,15 +25,21 @@
#ifndef LSPOSED_SYMBOL_CACHE_H
#define LSPOSED_SYMBOL_CACHE_H
#include <memory>
namespace SandHook {
class ElfImg;
}
namespace lspd {
extern bool sym_initialized;
extern std::unique_ptr<SandHook::ElfImg> art_img;
extern void *sym_do_dlopen;
extern void *handle_libart;
extern void *sym_openInMemoryDexFilesNative;
extern void *sym_createCookieWithArray;
extern void *sym_createCookieWithDirectBuffer;
extern void *sym_openDexFileNative;
extern void *sym_setTrusted;
extern void *sym_set_table_override;
void InitSymbolCache();
}