diff --git a/.gitmodules b/.gitmodules index 2ce2626..a2aeccd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/module/src/main/cpp/CMakeLists.txt b/module/src/main/cpp/CMakeLists.txt index eeaeb89..b6f703c 100644 --- a/module/src/main/cpp/CMakeLists.txt +++ b/module/src/main/cpp/CMakeLists.txt @@ -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) diff --git a/module/src/main/cpp/binder_interceptor.cpp b/module/src/main/cpp/binder_interceptor.cpp index 505f482..5da4cef 100644 --- a/module/src/main/cpp/binder_interceptor.cpp +++ b/module/src/main/cpp/binder_interceptor.cpp @@ -16,7 +16,7 @@ #include #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 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 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 target, uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags, status_t &result) { @@ -366,15 +321,26 @@ BinderInterceptor::handleIntercept(sp 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::make(); gBinderStub = sp::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; } diff --git a/module/src/main/cpp/external/CMakeLists.txt b/module/src/main/cpp/external/CMakeLists.txt index 51ce573..9a80db1 100644 --- a/module/src/main/cpp/external/CMakeLists.txt +++ b/module/src/main/cpp/external/CMakeLists.txt @@ -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 diff --git a/module/src/main/cpp/external/LSPlt b/module/src/main/cpp/external/LSPlt new file mode 160000 index 0000000..cef80a9 --- /dev/null +++ b/module/src/main/cpp/external/LSPlt @@ -0,0 +1 @@ +Subproject commit cef80a97a73184b4def9b3e1148884365fc173fd diff --git a/module/src/main/cpp/external/dobby b/module/src/main/cpp/external/dobby deleted file mode 160000 index 6813ca7..0000000 --- a/module/src/main/cpp/external/dobby +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6813ca76ddeafcaece525bf8c6cde7ff4c21d3ce diff --git a/module/src/main/cpp/lspmparser/include/lsplt.hpp b/module/src/main/cpp/lspmparser/include/lsplt.hpp deleted file mode 100644 index 3124871..0000000 --- a/module/src/main/cpp/lspmparser/include/lsplt.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include - -#include -#include - -/// \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 Scan(std::string proc = "self", - std::function 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 Scan(std::string proc = "self", - std::function filter = []( - auto &map) -> bool { return true; }); - - std::string display() const override; - }; - } -} \ No newline at end of file diff --git a/module/src/main/cpp/lspmparser/lsplt.cpp b/module/src/main/cpp/lspmparser/lsplt.cpp deleted file mode 100644 index 660b11a..0000000 --- a/module/src/main/cpp/lspmparser/lsplt.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "lsplt.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace lsplt { - inline namespace v2 { - [[maybe_unused]] std::vector - MapInfo::Scan(std::string proc, std::function filter) { - constexpr static auto kPermLength = 5; - constexpr static auto kMapEntry = 7; - std::vector info; - auto name = std::string("/proc/") + proc + "/maps"; - auto maps = std::unique_ptr{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 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(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::Scan(std::string proc, std::function filter) { - constexpr static auto kPermLength = 5; - constexpr static auto kMapEntry = 7; - std::vector info; - auto name = std::string("/proc/") + proc + "/smaps"; - auto maps = std::unique_ptr{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 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(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 ¤t = *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; - } - } -} diff --git a/module/template/sepolicy.rule b/module/template/sepolicy.rule index edb5e42..c1d02a4 100644 --- a/module/template/sepolicy.rule +++ b/module/template/sepolicy.rule @@ -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 *