[core] Hash for looking up symbols (#424)
This commit is contained in:
parent
63065646fe
commit
f3e9fd6b8f
|
|
@ -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})
|
||||||
else ()
|
|
||||||
message(WARNING "Could not find CCache program.")
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
include_directories(external/libcxx/include)
|
include_directories(external/libcxx/include)
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1dfc61263314ab10369d45f7ca10cf38b6546d68
|
Subproject commit 5c1ccd55836e4bf43cdb6adbad40443d18cd43db
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit cca5298bc3fbb19b607008925b10acd0ee06e03d
|
Subproject commit f61fcee091736dd0ae38670876157e9862ac6ff8
|
||||||
|
|
@ -148,7 +148,7 @@ namespace art {
|
||||||
}
|
}
|
||||||
|
|
||||||
void *thiz = *reinterpret_cast<void **>(
|
void *thiz = *reinterpret_cast<void **>(
|
||||||
reinterpret_cast<size_t>(Runtime::Current()->Get()) + OFFSET_classlinker);
|
reinterpret_cast<uintptr_t>(Runtime::Current()->Get()) + OFFSET_classlinker);
|
||||||
// ClassLinker* GetClassLinker() but inlined
|
// ClassLinker* GetClassLinker() but inlined
|
||||||
LOGD("Classlinker object: %p", thiz);
|
LOGD("Classlinker object: %p", thiz);
|
||||||
instance_ = new ClassLinker(thiz);
|
instance_ = new ClassLinker(thiz);
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,11 @@ namespace lspd {
|
||||||
|
|
||||||
template<char... chars>
|
template<char... chars>
|
||||||
struct tstring : public std::integer_sequence<char, chars...> {
|
struct tstring : public std::integer_sequence<char, chars...> {
|
||||||
const char *c_str() const {
|
constexpr const char *c_str() const {
|
||||||
return str_;
|
return str_;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator std::string_view() const {
|
constexpr operator std::string_view() const {
|
||||||
return c_str();
|
return c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,22 @@
|
||||||
// From https://github.com/ganyao114/SandHook/blob/master/hooklib/src/main/cpp/utils/elf_util.cpp
|
/*
|
||||||
//
|
* This file is part of LSPosed.
|
||||||
// Created by Swift Gan on 2019/3/14.
|
*
|
||||||
//
|
* LSPosed is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LSPosed is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Swift Gan
|
||||||
|
* Copyright (C) 2021 LSPosed Contributors
|
||||||
|
*/
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
@ -16,76 +31,164 @@
|
||||||
using namespace SandHook;
|
using namespace SandHook;
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
ElfImg::ElfImg(const char *elf) {
|
template<typename T>
|
||||||
this->elf = elf;
|
inline auto offsetOf(ElfW(Ehdr) *head, ElfW(Off) off) {
|
||||||
|
return reinterpret_cast<std::conditional_t<std::is_pointer_v<T>, T, T *>>(
|
||||||
|
reinterpret_cast<uintptr_t>(head) + off);
|
||||||
|
}
|
||||||
|
|
||||||
|
ElfImg::ElfImg(std::string_view elf) : elf(elf) {
|
||||||
//load elf
|
//load elf
|
||||||
int fd = open(elf, O_RDONLY);
|
int fd = open(elf.data(), O_RDONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
LOGE("failed to open %s", elf);
|
LOGE("failed to open %s", elf.data());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = lseek(fd, 0, SEEK_END);
|
size = lseek(fd, 0, SEEK_END);
|
||||||
if (size <= 0) {
|
if (size <= 0) {
|
||||||
LOGE("lseek() failed for %s", elf);
|
LOGE("lseek() failed for %s", elf.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
header = reinterpret_cast<Elf_Ehdr *>(mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0));
|
header = reinterpret_cast<decltype(header)>(mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0));
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
section_header = reinterpret_cast<Elf_Shdr *>(((size_t) header) + header->e_shoff);
|
section_header = offsetOf<decltype(section_header)>(header, header->e_shoff);
|
||||||
|
|
||||||
auto shoff = reinterpret_cast<size_t>(section_header);
|
auto shoff = reinterpret_cast<uintptr_t>(section_header);
|
||||||
char *section_str = reinterpret_cast<char *>(section_header[header->e_shstrndx].sh_offset +
|
char *section_str = offsetOf<char *>(header, section_header[header->e_shstrndx].sh_offset);
|
||||||
((size_t) header));
|
|
||||||
|
|
||||||
for (int i = 0; i < header->e_shnum; i++, shoff += header->e_shentsize) {
|
for (int i = 0; i < header->e_shnum; i++, shoff += header->e_shentsize) {
|
||||||
auto *section_h = (Elf_Shdr *) shoff;
|
auto *section_h = (ElfW(Shdr) *) shoff;
|
||||||
char *sname = section_h->sh_name + section_str;
|
char *sname = section_h->sh_name + section_str;
|
||||||
Elf_Off entsize = section_h->sh_entsize;
|
auto entsize = section_h->sh_entsize;
|
||||||
switch (section_h->sh_type) {
|
switch (section_h->sh_type) {
|
||||||
case SHT_DYNSYM:
|
case SHT_DYNSYM: {
|
||||||
if (bias == -4396) {
|
if (bias == -4396) {
|
||||||
dynsym = section_h;
|
dynsym = section_h;
|
||||||
dynsym_offset = section_h->sh_offset;
|
dynsym_offset = section_h->sh_offset;
|
||||||
dynsym_size = section_h->sh_size;
|
dynsym_size = section_h->sh_size;
|
||||||
dynsym_count = dynsym_size / entsize;
|
dynsym_start = offsetOf<decltype(dynsym_start)>(header, dynsym_offset);
|
||||||
dynsym_start = reinterpret_cast<Elf_Sym *>(((size_t) header) + dynsym_offset);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SHT_SYMTAB:
|
}
|
||||||
|
case SHT_SYMTAB: {
|
||||||
if (strcmp(sname, ".symtab") == 0) {
|
if (strcmp(sname, ".symtab") == 0) {
|
||||||
symtab = section_h;
|
symtab = section_h;
|
||||||
symtab_offset = section_h->sh_offset;
|
symtab_offset = section_h->sh_offset;
|
||||||
symtab_size = section_h->sh_size;
|
symtab_size = section_h->sh_size;
|
||||||
symtab_count = symtab_size / entsize;
|
symtab_count = symtab_size / entsize;
|
||||||
symtab_start = reinterpret_cast<Elf_Sym *>(((size_t) header) + symtab_offset);
|
symtab_start = offsetOf<decltype(symtab_start)>(header, symtab_offset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SHT_STRTAB:
|
}
|
||||||
|
case SHT_STRTAB: {
|
||||||
if (bias == -4396) {
|
if (bias == -4396) {
|
||||||
strtab = section_h;
|
strtab = section_h;
|
||||||
symstr_offset = section_h->sh_offset;
|
symstr_offset = section_h->sh_offset;
|
||||||
strtab_start = reinterpret_cast<Elf_Sym *>(((size_t) header) + symstr_offset);
|
strtab_start = offsetOf<decltype(strtab_start)>(header, symstr_offset);
|
||||||
}
|
}
|
||||||
if (strcmp(sname, ".strtab") == 0) {
|
if (strcmp(sname, ".strtab") == 0) {
|
||||||
symstr_offset_for_symtab = section_h->sh_offset;
|
symstr_offset_for_symtab = section_h->sh_offset;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SHT_PROGBITS:
|
}
|
||||||
|
case SHT_PROGBITS: {
|
||||||
if (strtab == nullptr || dynsym == nullptr) break;
|
if (strtab == nullptr || dynsym == nullptr) break;
|
||||||
if (bias == -4396) {
|
if (bias == -4396) {
|
||||||
bias = (off_t) section_h->sh_addr - (off_t) section_h->sh_offset;
|
bias = (off_t) section_h->sh_addr - (off_t) section_h->sh_offset;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SHT_HASH: {
|
||||||
|
auto *d_un = offsetOf<ElfW(Word)>(header, section_h->sh_offset);
|
||||||
|
nbucket_ = d_un[0];
|
||||||
|
bucket_ = d_un + 2;
|
||||||
|
chain_ = bucket_ + nbucket_;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SHT_GNU_HASH: {
|
||||||
|
auto *d_buf = reinterpret_cast<ElfW(Word) *>(((size_t) header) +
|
||||||
|
section_h->sh_offset);
|
||||||
|
gnu_nbucket_ = d_buf[0];
|
||||||
|
gnu_symndx_ = d_buf[1];
|
||||||
|
gnu_bloom_size_ = d_buf[2];
|
||||||
|
gnu_shift2_ = d_buf[3];
|
||||||
|
gnu_bloom_filter_ = reinterpret_cast<decltype(gnu_bloom_filter_)>(d_buf + 4);
|
||||||
|
gnu_bucket_ = d_buf + 4 + gnu_bloom_size_ *
|
||||||
|
(header->e_ident[EI_CLASS] == ELFCLASS64 ? 2 : 1);
|
||||||
|
gnu_chain_ = gnu_bucket_ + gnu_nbucket_ - gnu_symndx_;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//load module base
|
//load module base
|
||||||
base = getModuleBase();
|
base = getModuleBase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ElfW(Addr) ElfImg::ElfLookup(std::string_view name, uint32_t hash) const {
|
||||||
|
if (nbucket_ == 0) return 0;
|
||||||
|
|
||||||
|
char *strings = (char *) strtab_start;
|
||||||
|
|
||||||
|
for (auto n = bucket_[hash % nbucket_]; n != 0; n = chain_[n]) {
|
||||||
|
auto *sym = dynsym_start + n;
|
||||||
|
if (name == strings + sym->st_name) {
|
||||||
|
return sym->st_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElfW(Addr) ElfImg::GnuLookup(std::string_view name, uint32_t hash) const {
|
||||||
|
static constexpr auto bloom_mask_bits = sizeof(ElfW(Addr)) * 8;
|
||||||
|
|
||||||
|
if (gnu_nbucket_ == 0 || gnu_bloom_size_ == 0) return 0;
|
||||||
|
|
||||||
|
auto bloom_word = gnu_bloom_filter_[(hash / bloom_mask_bits) % gnu_bloom_size_];
|
||||||
|
uintptr_t mask = 0
|
||||||
|
| (uintptr_t) 1 << (hash % bloom_mask_bits)
|
||||||
|
| (uintptr_t) 1 << ((hash >> gnu_shift2_) % bloom_mask_bits);
|
||||||
|
if ((mask & bloom_word) == mask) {
|
||||||
|
auto sym_index = gnu_bucket_[hash % gnu_nbucket_];
|
||||||
|
if (sym_index >= gnu_symndx_) {
|
||||||
|
char *strings = (char *) strtab_start;
|
||||||
|
do {
|
||||||
|
auto *sym = dynsym_start + sym_index;
|
||||||
|
if (((gnu_chain_[sym_index] ^ hash) >> 1) == 0
|
||||||
|
&& name == strings + sym->st_name) {
|
||||||
|
return sym->st_value;
|
||||||
|
}
|
||||||
|
} while ((gnu_chain_[sym_index++] & 1) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElfW(Addr) ElfImg::LinearLookup(std::string_view name) const {
|
||||||
|
if (symtabs_.empty()) {
|
||||||
|
symtabs_.reserve(symtab_count);
|
||||||
|
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);
|
||||||
|
const char *st_name = offsetOf<const char *>(header, symstr_offset_for_symtab +
|
||||||
|
symtab_start[i].st_name);
|
||||||
|
if ((st_type == STT_FUNC || st_type == STT_OBJECT) && symtab_start[i].st_size) {
|
||||||
|
symtabs_.emplace(st_name, &symtab_start[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (auto i = symtabs_.find(name); i != symtabs_.end()) {
|
||||||
|
return i->second->st_value;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ElfImg::~ElfImg() {
|
ElfImg::~ElfImg() {
|
||||||
//open elf file local
|
//open elf file local
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
|
|
@ -98,54 +201,23 @@ ElfImg::~ElfImg() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Elf_Addr ElfImg::getSymbOffset(const char *name) const {
|
ElfW(Addr) ElfImg::getSymbOffset(std::string_view name, uint32_t gnu_hash, uint32_t elf_hash) const {
|
||||||
Elf_Addr _offset;
|
if (auto offset = GnuLookup(name, gnu_hash); offset > 0) {
|
||||||
|
LOGD("found %s %p in %s in dynsym by gnuhash", name.data(),
|
||||||
//search dynmtab
|
reinterpret_cast<void *>(offset), elf.data());
|
||||||
if (dynsym_start != nullptr && strtab_start != nullptr) {
|
return offset;
|
||||||
Elf_Sym *sym = dynsym_start;
|
} else if (offset = ElfLookup(name, elf_hash); offset > 0) {
|
||||||
char *strings = (char *) strtab_start;
|
LOGD("found %s %p in %s in dynsym by elfhash", name.data(),
|
||||||
int k;
|
reinterpret_cast<void *>(offset), elf.data());
|
||||||
for (k = 0; k < dynsym_count; k++, sym++)
|
return offset;
|
||||||
if (strcmp(strings + sym->st_name, name) == 0) {
|
} else if (offset = LinearLookup(name); offset > 0) {
|
||||||
_offset = sym->st_value;
|
LOGD("found %s %p in %s in symtab by linear lookup", name.data(),
|
||||||
LOGD("find %s: %p", elf, reinterpret_cast<void *>(_offset));
|
reinterpret_cast<void *>(offset), elf.data());
|
||||||
return _offset;
|
return offset;
|
||||||
}
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
//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;
|
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 {
|
void *ElfImg::getModuleBase() const {
|
||||||
|
|
@ -156,7 +228,7 @@ void *ElfImg::getModuleBase() const {
|
||||||
|
|
||||||
char name[PATH_MAX] = {'\0'};
|
char name[PATH_MAX] = {'\0'};
|
||||||
|
|
||||||
strncpy(name, elf, PATH_MAX);
|
strncpy(name, elf.data(), PATH_MAX);
|
||||||
{
|
{
|
||||||
struct stat buf{};
|
struct stat buf{};
|
||||||
while (lstat(name, &buf) == 0 && S_ISLNK(buf.st_mode)) {
|
while (lstat(name, &buf) == 0 && S_ISLNK(buf.st_mode)) {
|
||||||
|
|
@ -170,8 +242,6 @@ void *ElfImg::getModuleBase() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// fs::path name(elf);
|
// fs::path name(elf);
|
||||||
// std::error_code ec;
|
// std::error_code ec;
|
||||||
// while(fs::is_symlink(name, ec) && !ec) {
|
// while(fs::is_symlink(name, ec) && !ec) {
|
||||||
|
|
@ -192,12 +262,14 @@ void *ElfImg::getModuleBase() const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sscanf(buff, "%lx", &load_addr) != 1)
|
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", name);
|
||||||
|
}
|
||||||
|
|
||||||
fclose(maps);
|
fclose(maps);
|
||||||
|
|
||||||
LOGD("get module base %s: %lu", name, load_addr);
|
LOGD("get module base %s: %lx", name, load_addr);
|
||||||
|
|
||||||
return reinterpret_cast<void *>(load_addr);
|
return reinterpret_cast<void *>(load_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,74 +1,125 @@
|
||||||
// From https://github.com/ganyao114/SandHook/blob/master/hooklib/src/main/cpp/includes/elf_util.h
|
/*
|
||||||
//
|
* This file is part of LSPosed.
|
||||||
// Created by Swift Gan on 2019/3/14.
|
*
|
||||||
//
|
* LSPosed is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LSPosed is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Swift Gan
|
||||||
|
* Copyright (C) 2021 LSPosed Contributors
|
||||||
|
*/
|
||||||
#ifndef SANDHOOK_ELF_UTIL_H
|
#ifndef SANDHOOK_ELF_UTIL_H
|
||||||
#define SANDHOOK_ELF_UTIL_H
|
#define SANDHOOK_ELF_UTIL_H
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
#include <unordered_map>
|
||||||
#include <linux/elf.h>
|
#include <linux/elf.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <link.h>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#if defined(__LP64__)
|
#define SHT_GNU_HASH 0x6ffffff6
|
||||||
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 {
|
namespace SandHook {
|
||||||
|
|
||||||
class ElfImg {
|
class ElfImg {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ElfImg(const char* elf);
|
ElfImg(std::string_view elf);
|
||||||
|
|
||||||
Elf_Addr getSymbOffset(const char* name) const;
|
constexpr ElfW(Addr) getSymbOffset(std::string_view name) const {
|
||||||
|
return getSymbOffset(name, GnuHash(name), ElfHash(name));
|
||||||
|
}
|
||||||
|
|
||||||
void* getModuleBase() const;
|
void *getModuleBase() const;
|
||||||
|
|
||||||
Elf_Addr getSymbAddress(const char* name) 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~ElfImg();
|
~ElfImg();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char* elf = nullptr;
|
ElfW(Addr) getSymbOffset(std::string_view name, uint32_t gnu_hash, uint32_t elf_hash) const;
|
||||||
void* base = nullptr;
|
|
||||||
char* buffer = nullptr;
|
ElfW(Addr) ElfLookup(std::string_view name, uint32_t hash) const;
|
||||||
|
|
||||||
|
ElfW(Addr) GnuLookup(std::string_view name, uint32_t hash) const;
|
||||||
|
|
||||||
|
ElfW(Addr) LinearLookup(std::string_view name) const;
|
||||||
|
|
||||||
|
constexpr static uint32_t ElfHash(std::string_view name);
|
||||||
|
|
||||||
|
constexpr static uint32_t GnuHash(std::string_view name);
|
||||||
|
|
||||||
|
std::string_view elf;
|
||||||
|
void *base = nullptr;
|
||||||
|
char *buffer = nullptr;
|
||||||
off_t size = 0;
|
off_t size = 0;
|
||||||
off_t bias = -4396;
|
off_t bias = -4396;
|
||||||
Elf_Ehdr* header = nullptr;
|
ElfW(Ehdr) *header = nullptr;
|
||||||
Elf_Shdr* section_header = nullptr;
|
ElfW(Shdr) *section_header = nullptr;
|
||||||
Elf_Shdr* symtab = nullptr;
|
ElfW(Shdr) *symtab = nullptr;
|
||||||
Elf_Shdr* strtab = nullptr;
|
ElfW(Shdr) *strtab = nullptr;
|
||||||
Elf_Shdr* dynsym = nullptr;
|
ElfW(Shdr) *dynsym = nullptr;
|
||||||
Elf_Off dynsym_count = 0;
|
ElfW(Sym) *symtab_start = nullptr;
|
||||||
Elf_Sym* symtab_start = nullptr;
|
ElfW(Sym) *dynsym_start = nullptr;
|
||||||
Elf_Sym* dynsym_start = nullptr;
|
ElfW(Sym) *strtab_start = nullptr;
|
||||||
Elf_Sym* strtab_start = nullptr;
|
ElfW(Off) symtab_count = 0;
|
||||||
Elf_Off symtab_count = 0;
|
ElfW(Off) symstr_offset = 0;
|
||||||
Elf_Off symstr_offset = 0;
|
ElfW(Off) symstr_offset_for_symtab = 0;
|
||||||
Elf_Off symstr_offset_for_symtab = 0;
|
ElfW(Off) symtab_offset = 0;
|
||||||
Elf_Off symtab_offset = 0;
|
ElfW(Off) dynsym_offset = 0;
|
||||||
Elf_Off dynsym_offset = 0;
|
ElfW(Off) symtab_size = 0;
|
||||||
Elf_Off symtab_size = 0;
|
ElfW(Off) dynsym_size = 0;
|
||||||
Elf_Off dynsym_size = 0;
|
|
||||||
|
uint32_t nbucket_{};
|
||||||
|
uint32_t *bucket_ = nullptr;
|
||||||
|
uint32_t *chain_ = nullptr;
|
||||||
|
|
||||||
|
uint32_t gnu_nbucket_{};
|
||||||
|
uint32_t gnu_symndx_{};
|
||||||
|
uint32_t gnu_bloom_size_;
|
||||||
|
uint32_t gnu_shift2_;
|
||||||
|
uintptr_t *gnu_bloom_filter_;
|
||||||
|
uint32_t *gnu_bucket_;
|
||||||
|
uint32_t *gnu_chain_;
|
||||||
|
|
||||||
|
mutable std::unordered_map<std::string_view, ElfW(Sym) *> symtabs_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t ElfImg::ElfHash(std::string_view name) {
|
||||||
|
uint32_t h = 0, g;
|
||||||
|
for (unsigned char p: name) {
|
||||||
|
h = (h << 4) + p;
|
||||||
|
g = h & 0xf0000000;
|
||||||
|
h ^= g;
|
||||||
|
h ^= g >> 24;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr uint32_t ElfImg::GnuHash(std::string_view name) {
|
||||||
|
uint32_t h = 5381;
|
||||||
|
for (unsigned char p: name) {
|
||||||
|
h += (h << 5) + p;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //SANDHOOK_ELF_UTIL_H
|
#endif //SANDHOOK_ELF_UTIL_H
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ namespace lspd {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noinline)) RIRU_EXPORT RiruVersionedModuleInfo *init(Riru *riru) {
|
RIRU_EXPORT RiruVersionedModuleInfo *init(Riru *riru) {
|
||||||
LOGD("using riru %d", riru->riruApiVersion);
|
LOGD("using riru %d", riru->riruApiVersion);
|
||||||
LOGD("module path: %s", riru->magiskModulePath);
|
LOGD("module path: %s", riru->magiskModulePath);
|
||||||
lspd::magiskPath = riru->magiskModulePath;
|
lspd::magiskPath = riru->magiskModulePath;
|
||||||
|
|
@ -125,5 +125,4 @@ __attribute__((noinline)) RIRU_EXPORT RiruVersionedModuleInfo *init(Riru *riru)
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
init(nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,8 @@ namespace lspd {
|
||||||
soinfo *somain = nullptr;
|
soinfo *somain = nullptr;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T *getStaticVariable(const SandHook::ElfImg &linker, std::string_view name) {
|
constexpr inline T *getStaticVariable(const SandHook::ElfImg &linker, std::string_view name) {
|
||||||
auto *addr = reinterpret_cast<T **>(linker.getSymbAddress(name.data()));
|
auto *addr = reinterpret_cast<T **>(linker.getSymbAddress(name));
|
||||||
return addr == nullptr ? nullptr : *addr;
|
return addr == nullptr ? nullptr : *addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue