diff --git a/android.mk b/android.mk new file mode 100644 index 0000000..6252860 --- /dev/null +++ b/android.mk @@ -0,0 +1,5 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := shithook +LOCAL_SRC_FILES := main.cpp shithook.hpp +include $(BUILD_EXECUTABLE) \ No newline at end of file diff --git a/app.mk b/app.mk new file mode 100644 index 0000000..da0aaff --- /dev/null +++ b/app.mk @@ -0,0 +1,4 @@ +APP_PLATFORM := android-21 +APP_ABI := armeabi-v7a +APP_BUILD_SCRIPT := android.mk +APP_CPPFLAGS := -std=c++17 \ No newline at end of file diff --git a/hook.hpp b/hook.hpp deleted file mode 100644 index 9119ab8..0000000 --- a/hook.hpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - MIT License - - Copyright (c) 2020 xerox - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -#pragma once -#include -#include -#include -#include - -#if _M_IX86 - #define OFFSET_TO_ADDRESS 0x1 -#elif _M_X64 - #define OFFSET_TO_ADDRESS 0x2 -#endif - -namespace hook -{ - inline void write_to_readonly(void* addr, void* data, int size) - { - DWORD old_flags; - if(!VirtualProtect( - addr, - size, - PAGE_EXECUTE_READWRITE, - &old_flags - )) return; - - memcpy(addr, data, size); - - VirtualProtect( - addr, - size, - old_flags, - &old_flags - ); - } - - class detour - { - public: - detour(void* addr_to_hook, void* jmp_to, bool enable = true) - : hook_addr(addr_to_hook), detour_addr(jmp_to), hook_installed(false) - { - //setup hook - memcpy( - jmp_code + OFFSET_TO_ADDRESS, - &jmp_to, - sizeof(jmp_to) - ); - //save bytes - memcpy( - org_bytes, - hook_addr, - sizeof(org_bytes) - ); - if(enable) - install(); - } - - void install() - { - if (hook_installed.load()) - return; - write_to_readonly(hook_addr, jmp_code, sizeof(jmp_code)); - hook_installed.exchange(true); - } - void uninstall() - { - if (!hook_installed.load()) - return; - write_to_readonly(hook_addr, org_bytes, sizeof(org_bytes)); - hook_installed.exchange(false); - } - - ~detour() { uninstall(); } - bool installed() { return hook_installed; } - void* hook_address() { return hook_addr; } - void* detour_address() { return detour_addr; } - private: - std::atomic hook_installed; - void *hook_addr, *detour_addr; - -#if _M_IX86 - /* - 0: b8 ff ff ff ff mov eax, 0xffffffff - 5: ff e0 jmp eax - */ - unsigned char jmp_code[7] = { - 0xb8, 0x0, 0x0, 0x0, 0x0, - 0xFF, 0xE0 - }; -#elif _M_X64 - /* - 0: 48 c7 c0 ff ff ff ff mov rax,0xffffffffffffffff - 7: ff e0 jmp rax - */ - unsigned char jmp_code[12] = { - 0x48, 0xb8, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xff, 0xe0 - }; -#endif - std::uint8_t org_bytes[sizeof(jmp_code)]; - }; - - inline std::map> hooks{}; - - inline void make_hook(void* addr_to_hook, void* jmp_to_addr, bool enable = true) - { - if (!addr_to_hook) - return; - hooks.insert({ - addr_to_hook, - std::make_unique( - addr_to_hook, - jmp_to_addr, - enable - )} - ); - } - - inline void enable(void* addr) - { - if (!addr) - return; - hooks.at(addr)->install(); - } - - inline void disable(void* addr) - { - if (!addr) - return; - hooks.at(addr)->uninstall(); - } - - inline void remove(void* addr) - { - if (!addr) - return; - hooks.erase(addr); - } -} \ No newline at end of file diff --git a/main.cpp b/main.cpp index 23e26b9..596ad0d 100644 --- a/main.cpp +++ b/main.cpp @@ -1,56 +1,21 @@ #include -#include "hook.hpp" -using namespace std; +#include "shithook.hpp" -BOOL HookWriteFile( - HANDLE hFile, - LPCVOID lpBuffer, - DWORD nNumberOfBytesToWrite, - LPDWORD lpNumberOfBytesWritten, - LPOVERLAPPED lpOverlapped -) +__attribute__((noinline)) +FILE* hook_test(const char* filename, const char* open_type) { - //this will change the output to "shithooked!\n" - const char* shithooked = "shithooked!?"; - hook::disable(&WriteFile); - BOOL result = WriteFile( - hFile, - shithooked, - nNumberOfBytesToWrite, - lpNumberOfBytesWritten, - lpOverlapped - ); - hook::enable(&WriteFile); - return result; + std::printf("> filename = %s\n", filename); + std::printf("> open type = %s\n", open_type); + std::getchar(); + + return hook::get_func(&fopen)(filename, open_type); } int main() { - //make hook - hook::make_hook( - &WriteFile, - &HookWriteFile, - false // you can choose not to install it yet - ); - - //make file - OFSTRUCT ofstruct{}; - auto result = std::unique_ptr, decltype(&CloseHandle)>( - (HANDLE)(OpenFile( - "output.txt", - &ofstruct, - OF_READWRITE | OF_CREATE - )), &CloseHandle - ); - - if (reinterpret_cast(result.get()) != HFILE_ERROR) - { - // we can enable it after we open the file - hook::enable(&WriteFile); - - //write to file - const char aString[] = "Hello world!\n"; - WriteFile(result.get(), aString, sizeof(aString), NULL, NULL); - } -} + hook::make_hook(&fopen, &hook_test); + auto result = fopen("/proc/self/maps", "r"); + std::printf("> finished demo... handle = %p\n", result); + std::getchar(); +} \ No newline at end of file diff --git a/shithook.hpp b/shithook.hpp new file mode 100644 index 0000000..99fd2ae --- /dev/null +++ b/shithook.hpp @@ -0,0 +1,128 @@ +#pragma once +#include +#include +#include +#include + +#define __arm__ +#include +#include "sys/mman.h" + +#define ARM_JMP_CODE 0xE51FF004 // LDR PC, [PC, #-4] +#define PAGE_START(ptr) reinterpret_cast(reinterpret_cast(ptr) >> 12 << 12) + +namespace hook +{ + class detour + { + public: + detour(void* addr_to_hook, void* jmp_to, bool enable = true) + : + hook_addr(addr_to_hook), + detour_addr(jmp_to), + hook_installed(false) + { + reinterpret_cast(jmp_code)[0] = ARM_JMP_CODE; + reinterpret_cast(jmp_code)[1] = jmp_to; + memcpy(org_bytes, hook_addr, sizeof(org_bytes)); + + reinterpret_cast(landing_code)[2] = ARM_JMP_CODE; + memcpy(landing_code, org_bytes, sizeof(org_bytes)); + reinterpret_cast(landing_code)[3] = + reinterpret_cast(hook_addr) + 8; + + mprotect(PAGE_START(landing_code), getpagesize(), + PROT_EXEC | PROT_READ | PROT_WRITE); + + cacheflush(reinterpret_cast(PAGE_START(landing_code)), + reinterpret_cast( + PAGE_START(landing_code)) + getpagesize(), NULL); + + if (enable) install(); + } + ~detour() { uninstall(); } + + void install() + { + if (hook_installed.load()) + return; + + if (!mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC)) + { + memcpy((void*)((long)hook_addr), jmp_code, sizeof(jmp_code)); + mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_EXEC); + cacheflush(reinterpret_cast(hook_addr), reinterpret_cast(hook_addr) + getpagesize(), NULL); + hook_installed.exchange(true); + } + } + + void uninstall() + { + if (!hook_installed.load()) + return; + + if (!mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC)) + { + memcpy(hook_addr, org_bytes, sizeof(jmp_code)); + mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_EXEC); + cacheflush(reinterpret_cast(hook_addr), reinterpret_cast(hook_addr) + getpagesize(), NULL); + hook_installed.exchange(false); + } + } + + bool installed() { return hook_installed; } + void* hook_address() { return hook_addr; } + void* detour_address(){ return detour_addr; } + void* get_func() { return reinterpret_cast(landing_code); } + private: + std::atomic hook_installed; + void* hook_addr, * detour_addr; + unsigned char jmp_code[8]; + unsigned char landing_code[16]; + std::uint8_t org_bytes[sizeof(jmp_code)]; + }; + + inline std::map>* get_hooks() + { + static std::map> hooks{}; + return &hooks; + } + + template + inline void make_hook(T addr_to_hook, U jmp_to_addr, bool enable = true) + { + get_hooks()->insert({ + (void*)addr_to_hook, + std::make_unique( + (void*) addr_to_hook, + (void*) jmp_to_addr, + enable + )} + ); + } + + template + inline void enable(T addr) + { + get_hooks()->at((void*)addr)->install(); + } + + template + inline T get_func(T addr) + { + return reinterpret_cast( + get_hooks()->at((void*)addr)->get_func()); + } + + template + inline void disable(T addr) + { + get_hooks()->at((void*)addr)->uninstall(); + } + + template + inline void remove(T addr) + { + get_hooks()->erase((void*)addr); + } +} \ No newline at end of file diff --git a/shithook.sln b/shithook.sln deleted file mode 100644 index f77b49a..0000000 --- a/shithook.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29519.181 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shithook", "shithook.vcxproj", "{E5255EE2-A83E-4455-99E3-B5D236B76D36}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E5255EE2-A83E-4455-99E3-B5D236B76D36}.Debug|x64.ActiveCfg = Debug|x64 - {E5255EE2-A83E-4455-99E3-B5D236B76D36}.Debug|x64.Build.0 = Debug|x64 - {E5255EE2-A83E-4455-99E3-B5D236B76D36}.Debug|x86.ActiveCfg = Debug|Win32 - {E5255EE2-A83E-4455-99E3-B5D236B76D36}.Debug|x86.Build.0 = Debug|Win32 - {E5255EE2-A83E-4455-99E3-B5D236B76D36}.Release|x64.ActiveCfg = Release|x64 - {E5255EE2-A83E-4455-99E3-B5D236B76D36}.Release|x64.Build.0 = Release|x64 - {E5255EE2-A83E-4455-99E3-B5D236B76D36}.Release|x86.ActiveCfg = Release|Win32 - {E5255EE2-A83E-4455-99E3-B5D236B76D36}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {8D42E5D0-475A-4EA5-94EA-1ADB1F46CBF1} - EndGlobalSection -EndGlobal diff --git a/shithook.vcxproj b/shithook.vcxproj deleted file mode 100644 index df6c359..0000000 --- a/shithook.vcxproj +++ /dev/null @@ -1,170 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - - - - - - - 16.0 - {E5255EE2-A83E-4455-99E3-B5D236B76D36} - Win32Proj - shithook - 10.0 - - - - Application - true - v142 - Unicode - false - - - Application - false - v142 - true - Unicode - false - - - Application - true - v142 - Unicode - false - - - Application - false - v142 - true - Unicode - false - - - - - - - - - - - - - - - - - - - - - true - - - true - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - - - false - - - false - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - - - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp17 - - - Console - true - - - - - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp17 - - - Console - true - - - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp17 - - - Console - true - true - true - - - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp17 - - - Console - true - true - true - - - - - - \ No newline at end of file diff --git a/shithook.vcxproj.filters b/shithook.vcxproj.filters deleted file mode 100644 index 8d61e76..0000000 --- a/shithook.vcxproj.filters +++ /dev/null @@ -1,23 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - - - Source Files - - - - - Header Files - - - \ No newline at end of file diff --git a/shithook.vcxproj.user b/shithook.vcxproj.user deleted file mode 100644 index 88a5509..0000000 --- a/shithook.vcxproj.user +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file