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 (!RETRIEVE_FUNC_SYMBOL(GetMethodShorty,
"_ZN3artL15GetMethodShortyEP7_JNIEnvP10_jmethodID") &&
"_ZN3artL15GetMethodShortyEP7_JNIEnvP10_jmethodID", true) &&
!RETRIEVE_FUNC_SYMBOL(GetMethodShorty,
"_ZN3art15GetMethodShortyEP7_JNIEnvP10_jmethodID")) {
LOGE("Failed to find GetMethodShorty");

View File

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

View File

@ -7,7 +7,7 @@
/// \namespace namespace of LSPlant
namespace lsplant {
inline namespace v1 {
inline namespace v2 {
/// \struct InitInfo
/// \brief Information and configuration that are needed to call #Init()
struct InitInfo {
@ -31,6 +31,14 @@ struct InitInfo {
/// \note It should be able to resolve symbols from both .dynsym and .symtab.
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.
InlineHookFunType inline_hooker;
/// \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.
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
/// and they could be set by \p generated_field_name and \p generated_method_name respectively.
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;
}
inline void *Dlsym(const HookHandler &handle, const char *name) {
return handle.art_symbol_resolver(name);
inline void *Dlsym(const HookHandler &handle, const char *name, bool match_prefix = false) {
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>

View File

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

View File

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

View File

@ -166,9 +166,8 @@ ElfW(Addr) ElfImg::GnuLookup(std::string_view name, uint32_t hash) const {
return 0;
}
ElfW(Addr) ElfImg::LinearLookup(std::string_view name) const {
void ElfImg::MayInitLinearMap() const {
if (symtabs_.empty()) {
symtabs_.reserve(symtab_count);
if (symtab_start != nullptr && symstr_offset_for_symtab != 0) {
for (ElfW(Off) i = 0; i < symtab_count; i++) {
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()) {
return i->second->st_value;
} 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() {
//open elf file local

View File

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

View File

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