use plt hook

This commit is contained in:
5ec1cff
2024-07-18 11:55:12 +08:00
parent c620cecc2f
commit 1fe5bee3d2
9 changed files with 34 additions and 341 deletions

6
.gitmodules vendored
View File

@@ -1,6 +1,6 @@
[submodule "module/src/main/cpp/external/libcxx"]
path = module/src/main/cpp/external/libcxx
url = https://github.com/topjohnwu/libcxx
[submodule "module/src/main/cpp/external/dobby"]
path = module/src/main/cpp/external/dobby
url = https://github.com/LSPosed/dobby
[submodule "module/src/main/cpp/external/LSPlt"]
path = module/src/main/cpp/external/LSPlt
url = https://github.com/LSPosed/LSPlt

View File

@@ -10,20 +10,17 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
add_library(elf_util STATIC elf_util/elf_util.cpp)
add_library(my_logging STATIC logging/logging.cpp)
add_subdirectory(external)
link_libraries(cxx)
add_library(elf_util STATIC elf_util/elf_util.cpp)
add_library(lspmparser STATIC lspmparser/lsplt.cpp)
add_library(my_logging STATIC logging/logging.cpp)
target_include_directories(my_logging PUBLIC logging/include)
target_include_directories(elf_util PUBLIC elf_util/include)
target_include_directories(lspmparser PUBLIC lspmparser/include)
target_link_libraries(my_logging cxx log)
target_link_libraries(elf_util cxx lspmparser my_logging)
target_link_libraries(lspmparser cxx)
target_link_libraries(elf_util cxx lsplt my_logging)
# libutils stub
add_library(utils SHARED binder/stub_utils.cpp)
@@ -35,11 +32,11 @@ target_include_directories(binder PUBLIC binder/include)
target_link_libraries(binder utils)
add_executable(libinject.so inject/main.cpp inject/utils.cpp)
target_link_libraries(libinject.so lspmparser my_logging)
target_link_libraries(libinject.so lsplt my_logging)
target_compile_options(libinject.so PRIVATE -fvisibility=hidden -fvisibility-inlines-hidden)
add_library(${MODULE_NAME} SHARED binder_interceptor.cpp)
target_link_libraries(${MODULE_NAME} log binder utils dobby elf_util my_logging)
target_link_libraries(${MODULE_NAME} log binder utils elf_util my_logging)
target_compile_options(${MODULE_NAME} PRIVATE -fvisibility=hidden -fvisibility-inlines-hidden)
add_library(tszygisk SHARED zygisk/main.cpp)

View File

@@ -16,7 +16,7 @@
#include <queue>
#include "logging.hpp"
#include "dobby.h"
#include "lsplt.hpp"
#include "elf_util.h"
#include "hook_util/hook_helper.hpp"
@@ -101,6 +101,7 @@ class BinderStub : public BBinder {
static sp<BinderStub> gBinderStub = nullptr;
// FIXME: when use ioctl hooking, some already blocked ioctl calls will not be hooked
int (*old_ioctl)(int fd, int request, ...) = nullptr;
int new_ioctl(int fd, int request, ...) {
va_list list;
@@ -242,52 +243,6 @@ BinderInterceptor::onTransact(uint32_t code, const android::Parcel &data, androi
return UNKNOWN_TRANSACTION;
}
class HookHandler : public hook_helper::HookHandler {
public:
ElfImg img;
explicit HookHandler(ElfInfo info) : img{std::move(info)} {}
bool isValid() const {
return img.isValid();
}
void *get_symbol(const char *name) const override {
auto addr = img.getSymbAddress(name);
if (!addr) {
LOGE("%s: symbol not found", name);
}
return addr;
}
void *get_symbol_prefix(const char *prefix) const override {
auto addr = img.getSymbPrefixFirstOffset(prefix);
if (!addr) {
LOGE("%s: prefix symbol not found", prefix);
}
return addr;
}
void *hook(void *original, void *replacement) const override {
void *result = nullptr;
if (DobbyHook(original, (dobby_dummy_func_t) replacement, (dobby_dummy_func_t *) &result) ==
0) {
return result;
} else {
return nullptr;
}
}
std::pair<uintptr_t, size_t> get_symbol_info(const char *name) const override {
auto p = img.getSymInfo(name);
if (!p.first) {
LOGE("%s: info not found", name);
}
return p;
}
};
bool
BinderInterceptor::handleIntercept(sp<BBinder> target, uint32_t code, const Parcel &data, Parcel *reply,
uint32_t flags, status_t &result) {
@@ -366,15 +321,26 @@ BinderInterceptor::handleIntercept(sp<BBinder> target, uint32_t code, const Parc
}
bool hookBinder() {
ElfImg img{ElfInfo::getElfInfoForName("libc.so")};
if (!img.isValid()) {
auto maps = lsplt::MapInfo::Scan();
dev_t dev;
ino_t ino;
bool found = false;
for (auto &m: maps) {
if (m.path.ends_with("/libbinder.so")) {
dev = m.dev;
ino = m.inode;
found = true;
break;
}
}
if (!found) {
LOGE("libbinder not found!");
return false;
}
gBinderInterceptor = sp<BinderInterceptor>::make();
gBinderStub = sp<BinderStub>::make();
auto ioctlAddr = img.getSymbAddress("ioctl");
if (DobbyHook(ioctlAddr, (dobby_dummy_func_t) new_ioctl, (dobby_dummy_func_t*) &old_ioctl) != 0) {
lsplt::RegisterHook(dev, ino, "ioctl", (void *) new_ioctl, (void **) &old_ioctl);
if (!lsplt::CommitHook()) {
LOGE("hook failed!");
return false;
}

View File

@@ -1,17 +1,14 @@
project(external)
# lsplt
set(SOURCES lsplt/lsplt/src/main/jni/lsplt.cc lsplt/lsplt/src/main/jni/elf_util.cc)
# dobby
macro(SET_OPTION option value)
set(${option} ${value} CACHE INTERNAL "" FORCE)
endmacro()
add_library(lsplt STATIC ${SOURCES})
target_include_directories(lsplt PUBLIC lsplt/lsplt/src/main/jni/include)
target_include_directories(lsplt PRIVATE lsplt/lsplt/src/main/jni)
SET_OPTION(DOBBY_GENERATE_SHARED OFF)
SET_OPTION(Plugin.SymbolResolver OFF)
add_subdirectory(dobby)
target_link_libraries(dobby cxx)
# end dobby
target_link_libraries(lsplt PUBLIC my_logging cxx)
# end lsplt
# cxx
set(LIBCXX_SOURCES

View File

@@ -1,67 +0,0 @@
#pragma once
#include <sys/types.h>
#include <string>
#include <string_view>
/// \namespace lsplt
namespace lsplt {
inline namespace v2 {
/// \struct MapInfo
/// \brief An entry that describes a line in /proc/self/maps. You can obtain a list of these entries
/// by calling #Scan().
struct MapInfo {
/// \brief The start address of the memory region.
uintptr_t start;
/// \brief The end address of the memory region.
uintptr_t end;
/// \brief The permissions of the memory region. This is a bit mask of the following values:
/// - PROT_READ
/// - PROT_WRITE
/// - PROT_EXEC
uint8_t perms;
/// \brief Whether the memory region is private.
bool is_private;
/// \brief The offset of the memory region.
uintptr_t offset;
/// \brief The device number of the memory region.
/// Major can be obtained by #major()
/// Minor can be obtained by #minor()
dev_t dev;
/// \brief The inode number of the memory region.
ino_t inode;
/// \brief The path of the memory region.
std::string path;
/// \brief Scans /proc/self/maps and returns a list of \ref MapInfo entries.
/// This is useful to find out the inode of the library to hook.
/// \return A list of \ref MapInfo entries.
[[maybe_unused, gnu::visibility("default")]]
static std::vector<MapInfo> Scan(std::string proc = "self",
std::function<bool(const MapInfo &)> filter = [](
auto &map) -> bool { return true; });
virtual std::string display() const;
};
struct SMapInfo : public MapInfo {
ssize_t size;
ssize_t rss;
ssize_t pss;
ssize_t shared_clean;
ssize_t shared_dirty;
ssize_t private_clean;
ssize_t private_dirty;
ssize_t referenced;
ssize_t anonymous;
[[maybe_unused, gnu::visibility("default")]]
static std::vector<SMapInfo> Scan(std::string proc = "self",
std::function<bool(const MapInfo &)> filter = [](
auto &map) -> bool { return true; });
std::string display() const override;
};
}
}

View File

@@ -1,199 +0,0 @@
#include "lsplt.hpp"
#include <sys/mman.h>
#include <sys/sysmacros.h>
#include <array>
#include <cinttypes>
#include <list>
#include <map>
#include <mutex>
#include <vector>
namespace lsplt {
inline namespace v2 {
[[maybe_unused]] std::vector<MapInfo>
MapInfo::Scan(std::string proc, std::function<bool(const MapInfo &)> filter) {
constexpr static auto kPermLength = 5;
constexpr static auto kMapEntry = 7;
std::vector<MapInfo> info;
auto name = std::string("/proc/") + proc + "/maps";
auto maps = std::unique_ptr<FILE, decltype(&fclose)>{fopen(name.c_str(), "r"),
&fclose};
if (maps) {
char *line = nullptr;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, maps.get())) > 0) {
line[read - 1] = '\0';
uintptr_t start = 0;
uintptr_t end = 0;
uintptr_t off = 0;
ino_t inode = 0;
unsigned int dev_major = 0;
unsigned int dev_minor = 0;
std::array<char, kPermLength> perm{'\0'};
int path_off;
if (sscanf(line, "%" PRIxPTR"-%"
PRIxPTR
" %4s %"
PRIxPTR
" %x:%x %lu %n%*s", &start,
&end, perm.data(), &off, &dev_major, &dev_minor, &inode,
&path_off) == kMapEntry) {
while (path_off < read && isspace(line[path_off])) path_off++;
MapInfo sm{};
sm.start = start;
sm.end = end;
sm.perms = 0;
sm.is_private = perm[3] == 'p';
sm.offset = off;
sm.dev = static_cast<dev_t>(makedev(dev_major, dev_minor));
sm.inode = inode;
sm.path = line + path_off;
if (perm[0] == 'r') sm.perms |= PROT_READ;
if (perm[1] == 'w') sm.perms |= PROT_WRITE;
if (perm[2] == 'x') sm.perms |= PROT_EXEC;
if (filter(sm)) info.emplace_back(sm);
continue;
}
}
free(line);
}
return info;
}
// https://cs.android.com/android/kernel/superproject/+/common-android-mainline:common/fs/proc/task_mmu.c;l=827;drc=08582d678fcf11fc86188f0b92239d3d49667d8e
[[maybe_unused]] std::vector<SMapInfo>
SMapInfo::Scan(std::string proc, std::function<bool(const MapInfo &)> filter) {
constexpr static auto kPermLength = 5;
constexpr static auto kMapEntry = 7;
std::vector<SMapInfo> info;
auto name = std::string("/proc/") + proc + "/smaps";
auto maps = std::unique_ptr<FILE, decltype(&fclose)>{fopen(name.c_str(), "r"),
&fclose};
if (!maps) {
return info;
}
char *line = nullptr;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, maps.get())) > 0) {
line[read - 1] = '\0';
uintptr_t start = 0;
uintptr_t end = 0;
uintptr_t off = 0;
ino_t inode = 0;
unsigned int dev_major = 0;
unsigned int dev_minor = 0;
std::array<char, kPermLength> perm{'\0'};
int path_off;
if (sscanf(line, "%" PRIxPTR"-%"
PRIxPTR
" %4s %"
PRIxPTR
" %x:%x %lu %n%*s", &start,
&end, perm.data(), &off, &dev_major, &dev_minor, &inode,
&path_off) == kMapEntry) {
while (path_off < read && isspace(line[path_off])) path_off++;
SMapInfo sm{};
sm.start = start;
sm.end = end;
sm.perms = 0;
sm.is_private = perm[3] == 'p';
sm.offset = off;
sm.dev = static_cast<dev_t>(makedev(dev_major, dev_minor));
sm.inode = inode;
sm.path = line + path_off;
if (perm[0] == 'r') sm.perms |= PROT_READ;
if (perm[1] == 'w') sm.perms |= PROT_WRITE;
if (perm[2] == 'x') sm.perms |= PROT_EXEC;
if (filter(sm)) info.emplace_back(sm);
continue;
}
if (info.empty()) continue;
auto &current = *info.rbegin();
ssize_t value;
auto s = strstr(line, ":");
if (s == nullptr) continue;
*s = 0;
if (sscanf(s + 1, "%zu", &value) != 1) continue;
std::string_view ss{line};
if (ss == "Size") current.size = value;
else if (ss == "Rss") current.rss = value;
else if (ss == "Pss") current.pss = value;
else if (ss == "Shared_Clean") current.shared_clean = value;
else if (ss == "Shared_Dirty") current.shared_dirty = value;
else if (ss == "Private_Clean") current.private_clean = value;
else if (ss == "Private_Dirty") current.private_dirty = value;
else if (ss == "Referenced") current.referenced = value;
else if (ss == "Anonymous") current.anonymous = value;
}
free(line);
return info;
}
std::string MapInfo::display() const {
char buf[sizeof(long) * 2 + 1];
std::string result;
snprintf(buf, sizeof(buf), "%" PRIxPTR, start);
result += buf;
result += "-";
snprintf(buf, sizeof(buf), "%" PRIxPTR, end);
result += buf;
result += ' ';
result += (perms & PROT_READ) ? 'r' : '-';
result += (perms & PROT_WRITE) ? 'w' : '-';
result += (perms & PROT_EXEC) ? 'x' : '-';
result += is_private ? 'p' : 's';
result += ' ';
snprintf(buf, sizeof(buf), "%08" PRIxPTR, offset);
result += buf;
result += ' ';
snprintf(buf, sizeof(buf), "%02" PRIxPTR, major(dev));
result += buf;
result += ':';
snprintf(buf, sizeof(buf), "%02" PRIxPTR, minor(dev));
result += buf;
result += ' ';
snprintf(buf, sizeof(buf), "%lu", inode);
result += buf;
result += ' ';
result += path;
return result;
}
std::string SMapInfo::display() const {
auto result = MapInfo::display();
char buf[sizeof(long) * 2 + 1];
result += '\n';
result += "SZ:";
snprintf(buf, sizeof(buf), "%zu", size);
result += buf;
result += " RSS:";
snprintf(buf, sizeof(buf), "%zu", rss);
result += buf;
result += " PSS:";
snprintf(buf, sizeof(buf), "%zu", pss);
result += buf;
result += " SC:";
snprintf(buf, sizeof(buf), "%zu", shared_clean);
result += buf;
result += " SD:";
snprintf(buf, sizeof(buf), "%zu", shared_dirty);
result += buf;
result += " PC:";
snprintf(buf, sizeof(buf), "%zu", private_clean);
result += buf;
result += " PD:";
snprintf(buf, sizeof(buf), "%zu", private_dirty);
result += buf;
result += " REF:";
snprintf(buf, sizeof(buf), "%zu", referenced);
result += buf;
result += " ANON:";
snprintf(buf, sizeof(buf), "%zu", anonymous);
result += buf;
return result;
}
}
}

View File

@@ -1,4 +1,3 @@
allow keystore keystore process execmem
allow keystore system_file unix_dgram_socket *
allow system_file keystore unix_dgram_socket *
allow keystore system_file file *