Update interface to v2 to support prefix resolver

This commit is contained in:
LoveSy 2022-04-27 10:58:11 +08:00
parent 9c63dcecf3
commit 050348fd08
9 changed files with 68 additions and 29 deletions

View File

@ -250,7 +250,7 @@ public:
if (sdk_int < __ANDROID_API_Q__) kAccFastInterpreterToInterpreterInvoke = 0; if (sdk_int < __ANDROID_API_Q__) kAccFastInterpreterToInterpreterInvoke = 0;
if (!RETRIEVE_FUNC_SYMBOL(GetMethodShorty, if (!RETRIEVE_FUNC_SYMBOL(GetMethodShorty,
"_ZN3artL15GetMethodShortyEP7_JNIEnvP10_jmethodID") && "_ZN3artL15GetMethodShortyEP7_JNIEnvP10_jmethodID", true) &&
!RETRIEVE_FUNC_SYMBOL(GetMethodShorty, !RETRIEVE_FUNC_SYMBOL(GetMethodShorty,
"_ZN3art15GetMethodShortyEP7_JNIEnvP10_jmethodID")) { "_ZN3art15GetMethodShortyEP7_JNIEnvP10_jmethodID")) {
LOGE("Failed to find GetMethodShorty"); LOGE("Failed to find GetMethodShorty");

View File

@ -103,9 +103,9 @@ public:
static bool Init(JNIEnv* env, const HookHandler& handler) { static bool Init(JNIEnv* env, const HookHandler& handler) {
auto sdk_int = GetAndroidApiLevel(); auto sdk_int = GetAndroidApiLevel();
if (sdk_int >= __ANDROID_API_P__) [[likely]] { if (sdk_int >= __ANDROID_API_P__) [[likely]] {
if (!RETRIEVE_FUNC_SYMBOL( if (!RETRIEVE_FUNC_SYMBOL(DexFile_setTrusted,
DexFile_setTrusted, "_ZN3artL18DexFile_setTrustedEP7_JNIEnvP7_jclassP8_jobject",
"_ZN3artL18DexFile_setTrustedEP7_JNIEnvP7_jclassP8_jobject")) { true)) {
return false; return false;
} }
} }

View File

@ -7,7 +7,7 @@
/// \namespace namespace of LSPlant /// \namespace namespace of LSPlant
namespace lsplant { namespace lsplant {
inline namespace v1 { inline namespace v2 {
/// \struct InitInfo /// \struct InitInfo
/// \brief Information and configuration that are needed to call #Init() /// \brief Information and configuration that are needed to call #Init()
struct InitInfo { struct InitInfo {
@ -31,6 +31,14 @@ struct InitInfo {
/// \note It should be able to resolve symbols from both .dynsym and .symtab. /// \note It should be able to resolve symbols from both .dynsym and .symtab.
using ArtSymbolResolver = std::function<void *(std::string_view symbol_name)>; using ArtSymbolResolver = std::function<void *(std::string_view symbol_name)>;
/// \brief Type of prefix symbol resolver to \p libart.so.
/// In \ref std::function form so that user can use lambda expression with capture list.<br>
/// \p symbol_prefix is the symbol prefix that needs to retrieve.<br>
/// \p return is the first absolute address in the memory that points to the target symbol.
/// It should be null if the symbol cannot be found. <br>
/// \note It should be able to resolve symbols from both .dynsym and .symtab.
using ArtSymbolPrefixResolver = std::function<void *(std::string_view symbol_prefix)>;
/// \brief The inline hooker function. Must not be null. /// \brief The inline hooker function. Must not be null.
InlineHookFunType inline_hooker; InlineHookFunType inline_hooker;
/// \brief The inline unhooker function. Must not be null. /// \brief The inline unhooker function. Must not be null.
@ -38,6 +46,9 @@ struct InitInfo {
/// \brief The symbol resolver to \p libart.so. Must not be null. /// \brief The symbol resolver to \p libart.so. Must not be null.
ArtSymbolResolver art_symbol_resolver; ArtSymbolResolver art_symbol_resolver;
/// \brief The symbol prefix resolver to \p libart.so. May be null.
ArtSymbolPrefixResolver art_symbol_prefix_resolver;
/// \brief The generated class name. Must not be empty. It contains a field and a method /// \brief The generated class name. Must not be empty. It contains a field and a method
/// and they could be set by \p generated_field_name and \p generated_method_name respectively. /// and they could be set by \p generated_field_name and \p generated_method_name respectively.
std::string_view generated_class_name = "LSPHooker_"; std::string_view generated_class_name = "LSPHooker_";

View File

@ -77,8 +77,13 @@ inline constexpr auto operator+(const tstring<as...> &, const std::string &b) {
return a + b; return a + b;
} }
inline void *Dlsym(const HookHandler &handle, const char *name) { inline void *Dlsym(const HookHandler &handle, const char *name, bool match_prefix = false) {
return handle.art_symbol_resolver(name); if (auto match = handle.art_symbol_resolver(name); match) {
return match;
} else if (match_prefix && handle.art_symbol_prefix_resolver) {
return handle.art_symbol_prefix_resolver(name);
}
return nullptr;
} }
template <typename Class, typename Return, typename T, typename... Args> template <typename Class, typename Return, typename T, typename... Args>

View File

@ -527,7 +527,7 @@ bool DoUnHook(ArtMethod *target, ArtMethod *backup) {
} // namespace } // namespace
inline namespace v1 { inline namespace v2 {
using ::lsplant::IsHooked; using ::lsplant::IsHooked;
@ -712,7 +712,7 @@ using ::lsplant::IsHooked;
if (!cookie) return false; if (!cookie) return false;
return DexFile::SetTrusted(env, cookie); return DexFile::SetTrusted(env, cookie);
} }
} // namespace v1 } // namespace v2
} // namespace lsplant } // namespace lsplant

View File

@ -5,8 +5,8 @@ pluginManagement {
mavenCentral() mavenCentral()
} }
plugins { plugins {
id("com.android.application") version "7.1.2" id("com.android.application") version "7.1.3"
id("com.android.library") version "7.1.2" id("com.android.library") version "7.1.3"
} }
} }
dependencyResolutionManagement { dependencyResolutionManagement {

View File

@ -166,9 +166,8 @@ ElfW(Addr) ElfImg::GnuLookup(std::string_view name, uint32_t hash) const {
return 0; return 0;
} }
ElfW(Addr) ElfImg::LinearLookup(std::string_view name) const { void ElfImg::MayInitLinearMap() const {
if (symtabs_.empty()) { if (symtabs_.empty()) {
symtabs_.reserve(symtab_count);
if (symtab_start != nullptr && symstr_offset_for_symtab != 0) { if (symtab_start != nullptr && symstr_offset_for_symtab != 0) {
for (ElfW(Off) i = 0; i < symtab_count; i++) { for (ElfW(Off) i = 0; i < symtab_count; i++) {
unsigned int st_type = ELF_ST_TYPE(symtab_start[i].st_info); unsigned int st_type = ELF_ST_TYPE(symtab_start[i].st_info);
@ -180,6 +179,11 @@ ElfW(Addr) ElfImg::LinearLookup(std::string_view name) const {
} }
} }
} }
}
ElfW(Addr) ElfImg::LinearLookup(std::string_view name) const {
MayInitLinearMap();
if (auto i = symtabs_.find(name); i != symtabs_.end()) { if (auto i = symtabs_.find(name); i != symtabs_.end()) {
return i->second->st_value; return i->second->st_value;
} else { } else {
@ -187,6 +191,16 @@ ElfW(Addr) ElfImg::LinearLookup(std::string_view name) const {
} }
} }
ElfW(Addr) ElfImg::PrefixLookupFirst(std::string_view prefix) const {
MayInitLinearMap();
if (auto i = symtabs_.lower_bound(prefix); i != symtabs_.end() && i->first.starts_with(prefix)) {
LOGD("found prefix %s of %s %p in %s in symtab by linear lookup", prefix.data(),
i->first.data(), reinterpret_cast<void *>(i->second->st_value), elf.data());
return i->second->st_value;
} else {
return 0;
}
}
ElfImg::~ElfImg() { ElfImg::~ElfImg() {
//open elf file local //open elf file local

View File

@ -21,7 +21,7 @@
#define SANDHOOK_ELF_UTIL_H #define SANDHOOK_ELF_UTIL_H
#include <string_view> #include <string_view>
#include <unordered_map> #include <map>
#include <linux/elf.h> #include <linux/elf.h>
#include <sys/types.h> #include <sys/types.h>
#include <string> #include <string>
@ -35,23 +35,26 @@ namespace SandHook {
ElfImg(std::string_view elf); ElfImg(std::string_view elf);
constexpr ElfW(Addr) getSymbOffset(std::string_view name) const { template<typename T = void*>
return getSymbOffset(name, GnuHash(name), ElfHash(name)); requires(std::is_pointer_v<T>)
} constexpr const T getSymbAddress(std::string_view name) const {
auto offset = getSymbOffset(name, GnuHash(name), ElfHash(name));
constexpr ElfW(Addr) getSymbAddress(std::string_view name) const {
ElfW(Addr) offset = getSymbOffset(name);
if (offset > 0 && base != nullptr) { if (offset > 0 && base != nullptr) {
return static_cast<ElfW(Addr)>((uintptr_t) base + offset - bias); return reinterpret_cast<T>(static_cast<ElfW(Addr)>((uintptr_t) base + offset - bias));
} else { } else {
return 0; return nullptr;
} }
} }
template<typename T> template<typename T = void*>
requires(std::is_pointer_v<T>) requires(std::is_pointer_v<T>)
constexpr T getSymbAddress(std::string_view name) const { constexpr const T getSymbPrefixFirstOffset(std::string_view prefix) const {
return reinterpret_cast<T>(getSymbAddress(name)); auto offset = PrefixLookupFirst(prefix);
if (offset > 0 && base != nullptr) {
return reinterpret_cast<T>(static_cast<ElfW(Addr)>((uintptr_t) base + offset - bias));
} else {
return nullptr;
}
} }
bool isValid() const { bool isValid() const {
@ -73,12 +76,16 @@ namespace SandHook {
ElfW(Addr) LinearLookup(std::string_view name) const; ElfW(Addr) LinearLookup(std::string_view name) const;
ElfW(Addr) PrefixLookupFirst(std::string_view prefix) const;
constexpr static uint32_t ElfHash(std::string_view name); constexpr static uint32_t ElfHash(std::string_view name);
constexpr static uint32_t GnuHash(std::string_view name); constexpr static uint32_t GnuHash(std::string_view name);
bool findModuleBase(); bool findModuleBase();
void MayInitLinearMap() const;
std::string elf; std::string elf;
void *base = nullptr; void *base = nullptr;
char *buffer = nullptr; char *buffer = nullptr;
@ -111,7 +118,7 @@ namespace SandHook {
uint32_t *gnu_bucket_; uint32_t *gnu_bucket_;
uint32_t *gnu_chain_; uint32_t *gnu_chain_;
mutable std::unordered_map<std::string_view, ElfW(Sym) *> symtabs_; mutable std::map<std::string_view, ElfW(Sym) *> symtabs_;
}; };
constexpr uint32_t ElfImg::ElfHash(std::string_view name) { constexpr uint32_t ElfImg::ElfHash(std::string_view name) {

View File

@ -60,9 +60,11 @@ JNI_OnLoad(JavaVM* vm, void* reserved) {
.inline_hooker = InlineHooker, .inline_hooker = InlineHooker,
.inline_unhooker = InlineUnhooker, .inline_unhooker = InlineUnhooker,
.art_symbol_resolver = [&art](std::string_view symbol) -> void* { .art_symbol_resolver = [&art](std::string_view symbol) -> void* {
auto* out = reinterpret_cast<void*>(art.getSymbAddress(symbol)); return art.getSymbAddress(symbol);
return out; },
} .art_symbol_prefix_resolver = [&art](auto symbol) {
return art.getSymbPrefixFirstOffset(symbol);
},
}; };
init_result = lsplant::Init(env, initInfo); init_result = lsplant::Init(env, initInfo);
return JNI_VERSION_1_6; return JNI_VERSION_1_6;