├── LOGO.png ├── built ├── IOS │ └── libwhale.dylib └── Android │ ├── x86 │ └── libwhale.so │ ├── x86_64 │ └── libwhale.so │ ├── arm64-v8a │ └── libwhale.so │ └── armeabi-v7a │ └── libwhale.so ├── .gitignore ├── whale ├── src │ ├── libffi │ │ ├── arm │ │ │ └── internal.h │ │ ├── ffi.h │ │ ├── ffitarget.h │ │ ├── fficonfig.h │ │ ├── x86 │ │ │ ├── asmnames.h │ │ │ ├── internal64.h │ │ │ └── internal.h │ │ ├── ffi_cfi.h │ │ ├── ffi_cxx.cc │ │ ├── aarch64 │ │ │ └── internal.h │ │ ├── debug.c │ │ ├── platform_include │ │ │ ├── ffitarget_arm64.h │ │ │ └── ffitarget_armv7.h │ │ ├── ffi_cxx.h │ │ ├── types.c │ │ └── ffi_common.h │ ├── assembler │ │ ├── value_object.h │ │ ├── memory_region.cc │ │ ├── x86 │ │ │ ├── registers_x86.h │ │ │ ├── managed_register_x86.cc │ │ │ └── constants_x86.h │ │ ├── x86_64 │ │ │ ├── registers_x86_64.h │ │ │ ├── managed_register_x86_64.cc │ │ │ └── constants_x86_64.h │ │ ├── managed_register.h │ │ ├── vixl │ │ │ ├── CMakeLists.txt │ │ │ ├── platform-vixl.h │ │ │ ├── macro-assembler-interface.h │ │ │ ├── aarch64 │ │ │ │ ├── cpu-aarch64.h │ │ │ │ └── instrument-aarch64.h │ │ │ └── assembler-base-vixl.h │ │ ├── assembler.cc │ │ └── label.h │ ├── android │ │ ├── art │ │ │ ├── art_jni_trampoline.h │ │ │ ├── native_on_load.h │ │ │ ├── scoped_thread_state_change.h │ │ │ ├── art_hook_param.h │ │ │ ├── well_known_classes.h │ │ │ ├── art_symbol_resolver.h │ │ │ ├── java_types.h │ │ │ ├── scoped_thread_state_change.cc │ │ │ ├── art_method.cc │ │ │ ├── java_types.cc │ │ │ ├── modifiers.h │ │ │ └── native_on_load.cc │ │ ├── android_build.h │ │ └── jni_helper.h │ ├── simulator │ │ ├── code_simulator_container.cc │ │ ├── code_simulator.cc │ │ ├── code_simulator.h │ │ ├── code_simulator_container.h │ │ ├── code_simulator_arm64.h │ │ └── code_simulator_arm64.cc │ ├── platform │ │ ├── memory.h │ │ ├── linux │ │ │ ├── process_map.h │ │ │ ├── process_map.cc │ │ │ └── elf_image.h │ │ └── memory.cc │ ├── base │ │ ├── primitive_types.h │ │ ├── stringprintf.h │ │ ├── enums.h │ │ ├── singleton.h │ │ ├── cxx_helper.h │ │ ├── offsets.h │ │ └── macros.h │ ├── dbi │ │ ├── arm64 │ │ │ ├── decoder_arm64.h │ │ │ ├── decoder_arm64.cc │ │ │ ├── inline_hook_arm64.h │ │ │ ├── instruction_rewriter_arm64.h │ │ │ └── inline_hook_arm64.cc │ │ ├── arm │ │ │ ├── decoder_arm.cc │ │ │ ├── decoder_arm.h │ │ │ ├── inline_hook_arm.h │ │ │ ├── decoder_thumb.h │ │ │ ├── decoder_thumb.cc │ │ │ ├── registers_arm.h │ │ │ ├── instruction_rewriter_arm.h │ │ │ └── inline_hook_arm.cc │ │ ├── x86 │ │ │ ├── intercept_syscall_x86.h │ │ │ ├── intercept_syscall_x86.cc │ │ │ ├── distorm │ │ │ │ ├── operands.h │ │ │ │ ├── wstring.c │ │ │ │ ├── decoder.h │ │ │ │ ├── wstring.h │ │ │ │ ├── textdefs.h │ │ │ │ ├── insts.h │ │ │ │ ├── x86defs.h │ │ │ │ └── prefix.h │ │ │ ├── inline_hook_x86.h │ │ │ ├── instruction_rewriter_x86.h │ │ │ ├── inline_hook_x86.cc │ │ │ └── instruction_rewriter_x86.cc │ │ ├── instruction_rewriter.h │ │ ├── x86_64 │ │ │ ├── inline_hook_x86_64.h │ │ │ ├── instruction_rewriter_x86_64.h │ │ │ ├── inline_hook_x86_64.cc │ │ │ └── instruction_rewriter_x86_64.cc │ │ ├── backup_code.h │ │ ├── hook_common.cc │ │ ├── darwin │ │ │ └── macho_import_hook.h │ │ ├── instruction_set.cc │ │ ├── hook_common.h │ │ └── instruction_set.h │ ├── interceptor.h │ ├── interceptor.cc │ └── whale.cc ├── include │ └── whale.h └── test │ ├── test_hook.cc │ └── test_emulator.cc ├── CMakeLists.txt ├── README.zh-CN.md ├── java └── com │ └── lody │ └── whale │ ├── WhaleRuntime.java │ ├── xposed │ └── XC_MethodReplacement.java │ └── VMHelper.java └── README.md /LOGO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/whale/HEAD/LOGO.png -------------------------------------------------------------------------------- /built/IOS/libwhale.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/whale/HEAD/built/IOS/libwhale.dylib -------------------------------------------------------------------------------- /built/Android/x86/libwhale.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/whale/HEAD/built/Android/x86/libwhale.so -------------------------------------------------------------------------------- /built/Android/x86_64/libwhale.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/whale/HEAD/built/Android/x86_64/libwhale.so -------------------------------------------------------------------------------- /built/Android/arm64-v8a/libwhale.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/whale/HEAD/built/Android/arm64-v8a/libwhale.so -------------------------------------------------------------------------------- /built/Android/armeabi-v7a/libwhale.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/whale/HEAD/built/Android/armeabi-v7a/libwhale.so -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | CMakeCache.txt 4 | CMakeFiles 5 | CMakeScripts 6 | Testing 7 | Makefile 8 | cmake_install.cmake 9 | install_manifest.txt 10 | compile_commands.json 11 | CTestTestfile.cmake 12 | -------------------------------------------------------------------------------- /whale/src/libffi/arm/internal.h: -------------------------------------------------------------------------------- 1 | #ifdef __arm__ 2 | 3 | #define ARM_TYPE_VFP_S 0 4 | #define ARM_TYPE_VFP_D 1 5 | #define ARM_TYPE_VFP_N 2 6 | #define ARM_TYPE_INT64 3 7 | #define ARM_TYPE_INT 4 8 | #define ARM_TYPE_VOID 5 9 | #define ARM_TYPE_STRUCT 6 10 | 11 | 12 | #endif -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4.1) 2 | 3 | set(CMAKE_CXX_STANDARD 14) 4 | add_subdirectory(whale) 5 | include_directories(whale/include) 6 | include_directories(whale/src) 7 | 8 | #add_executable(test whale/test/test_hook.cc) 9 | #target_link_libraries(test whale) 10 | -------------------------------------------------------------------------------- /whale/src/libffi/ffi.h: -------------------------------------------------------------------------------- 1 | #ifdef __aarch64__ 2 | 3 | #include 4 | 5 | 6 | #endif 7 | #ifdef __i386__ 8 | 9 | #include 10 | 11 | 12 | #endif 13 | #ifdef __arm__ 14 | 15 | #include 16 | 17 | 18 | #endif 19 | #ifdef __x86_64__ 20 | 21 | #include 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /whale/src/assembler/value_object.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ASSEMBLER_VALUE_OBJECT_H_ 2 | #define WHALE_ASSEMBLER_VALUE_OBJECT_H_ 3 | 4 | #include "base/macros.h" 5 | 6 | namespace whale { 7 | 8 | class ValueObject { 9 | private: 10 | DISALLOW_ALLOCATION(); 11 | }; 12 | 13 | } // namespace whale 14 | 15 | #endif // WHALE_ASSEMBLER_VALUE_OBJECT_H_ 16 | -------------------------------------------------------------------------------- /whale/src/libffi/ffitarget.h: -------------------------------------------------------------------------------- 1 | #ifdef __aarch64__ 2 | 3 | #include 4 | 5 | 6 | #endif 7 | #ifdef __i386__ 8 | 9 | #include 10 | 11 | 12 | #endif 13 | #ifdef __arm__ 14 | 15 | #include 16 | 17 | 18 | #endif 19 | #ifdef __x86_64__ 20 | 21 | #include 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /whale/src/libffi/fficonfig.h: -------------------------------------------------------------------------------- 1 | #if defined(__aarch64__) || defined(__arm64__) 2 | #include 3 | 4 | 5 | #endif 6 | #ifdef __i386__ 7 | 8 | #include 9 | 10 | 11 | #endif 12 | #ifdef __arm__ 13 | 14 | #include 15 | 16 | 17 | #endif 18 | #ifdef __x86_64__ 19 | 20 | #include 21 | #endif 22 | -------------------------------------------------------------------------------- /whale/src/android/art/art_jni_trampoline.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ANDROID_ART_JNI_TRAMPOLINE_H_ 2 | #define WHALE_ANDROID_ART_JNI_TRAMPOLINE_H_ 3 | 4 | #include "android/art/art_hook_param.h" 5 | 6 | namespace whale { 7 | namespace art { 8 | 9 | 10 | void BuildJniClosure(ArtHookParam *param); 11 | 12 | 13 | } // namespace art 14 | } // namespace whale 15 | 16 | #endif // WHALE_ANDROID_ART_JNI_TRAMPOLINE_H_ 17 | -------------------------------------------------------------------------------- /whale/src/simulator/code_simulator_container.cc: -------------------------------------------------------------------------------- 1 | #include "simulator/code_simulator_container.h" 2 | #include "simulator/code_simulator.h" 3 | 4 | namespace whale { 5 | 6 | 7 | CodeSimulatorContainer::CodeSimulatorContainer(InstructionSet target_isa) : simulator_(nullptr) { 8 | simulator_ = CodeSimulator::CreateCodeSimulator(target_isa); 9 | } 10 | 11 | 12 | CodeSimulatorContainer::~CodeSimulatorContainer() { 13 | delete simulator_; 14 | } 15 | 16 | 17 | } -------------------------------------------------------------------------------- /whale/src/platform/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef PLATFORM_SCOPED_MEMORY_ACCESS_H_ 2 | #define PLATFORM_SCOPED_MEMORY_ACCESS_H_ 3 | 4 | #include 5 | 6 | namespace whale { 7 | 8 | class ScopedMemoryPatch { 9 | public: 10 | ScopedMemoryPatch(void *address, void *patch, size_t size); 11 | 12 | ~ScopedMemoryPatch(); 13 | 14 | private: 15 | void *address_; 16 | void *patch_; 17 | size_t size_; 18 | }; 19 | 20 | } // namespace whale 21 | 22 | #endif // PLATFORM_SCOPED_MEMORY_ACCESS_H_ 23 | -------------------------------------------------------------------------------- /whale/src/assembler/memory_region.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "assembler/memory_region.h" 3 | 4 | namespace whale { 5 | 6 | void MemoryRegion::CopyFrom(size_t offset, const MemoryRegion &from) const { 7 | CHECK(from.pointer() != nullptr); 8 | CHECK_GT(from.size(), 0U); 9 | CHECK_GE(this->size(), from.size()); 10 | CHECK_LE(offset, this->size() - from.size()); 11 | memmove(reinterpret_cast(begin() + offset), from.pointer(), from.size()); 12 | } 13 | 14 | } // namespace whale 15 | -------------------------------------------------------------------------------- /whale/src/base/primitive_types.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_BASE_PRIMITIVE_TYPES_H_ 2 | #define WHALE_BASE_PRIMITIVE_TYPES_H_ 3 | 4 | #include 5 | #include 6 | 7 | typedef uint8_t byte; 8 | typedef uint8_t u1; 9 | typedef uint16_t u2; 10 | typedef uint32_t u4; 11 | typedef uint64_t u8; 12 | 13 | 14 | typedef int8_t s1; 15 | typedef int16_t s2; 16 | typedef int32_t s4; 17 | typedef int64_t s8; 18 | 19 | typedef size_t offset_t; 20 | typedef void* ptr_t; 21 | 22 | #endif // WHALE_BASE_PRIMITIVE_TYPES_H_ 23 | -------------------------------------------------------------------------------- /whale/src/dbi/arm64/decoder_arm64.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_ARM64_DECODER_H_ 2 | #define ARCH_ARM64_DECODER_H_ 3 | 4 | #include "base/primitive_types.h" 5 | 6 | namespace whale { 7 | namespace arm64 { 8 | 9 | enum A64InsnType { 10 | kA64_CBZ_CBNZ, 11 | kA64_B_COND, 12 | kA64_TBZ_TBNZ, 13 | kA64_B_BL, 14 | kA64_LDR_LIT, 15 | kA64_ADR_ADRP, 16 | kA64_UNHANDLED 17 | }; 18 | 19 | A64InsnType DecodeA64(u4 insn); 20 | 21 | } // namespace arm64 22 | } // namespace whale 23 | 24 | #endif // ARCH_ARM64_DECODER_H_ 25 | 26 | -------------------------------------------------------------------------------- /whale/src/dbi/arm/decoder_arm.cc: -------------------------------------------------------------------------------- 1 | #include "dbi/arm/decoder_arm.h" 2 | 3 | #define CASE(mask, val, type) \ 4 | if ((((insn) & (mask)) == val)) { \ 5 | return type; \ 6 | } 7 | 8 | namespace whale { 9 | namespace arm { 10 | 11 | ArmInsnType DecodeArm(u4 insn) { 12 | CASE(0xe5f0000, 0x41f0000, kARM_LDR); 13 | CASE(0xfef0010, 0x8f0000, kARM_ADD); 14 | CASE(0xdef0000, 0x1a00000, kARM_MOV); 15 | CASE(0xf000000, 0xa000000, kARM_B); 16 | CASE(0xf000000, 0xb000000, kARM_BL); 17 | return kARM_UNHANDLED; 18 | } 19 | 20 | } // namespace arm 21 | } // namespace whale 22 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/intercept_syscall_x86.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_DBI_X86_INTERCEPT_SYSCALL_HOOK_H_ 2 | #define WHALE_DBI_X86_INTERCEPT_SYSCALL_HOOK_H_ 3 | 4 | #include "dbi/hook_common.h" 5 | 6 | namespace whale { 7 | namespace x86 { 8 | 9 | class X86InterceptSysCallHook : public InterceptSysCallHook { 10 | public: 11 | X86InterceptSysCallHook(MemoryRangeCallback callback) : InterceptSysCallHook(callback) {} 12 | 13 | protected: 14 | void FindSysCalls(uintptr_t start, uintptr_t end); 15 | }; 16 | 17 | } // namespace x86 18 | } // namespace whale 19 | 20 | #endif // WHALE_DBI_X86_INTERCEPT_SYSCALL_HOOK_H_ 21 | -------------------------------------------------------------------------------- /whale/src/simulator/code_simulator.cc: -------------------------------------------------------------------------------- 1 | #include "simulator/code_simulator.h" 2 | #include "simulator/code_simulator_arm64.h" 3 | 4 | namespace whale { 5 | 6 | CodeSimulator *CodeSimulator::CreateCodeSimulator(InstructionSet target_isa) { 7 | switch (target_isa) { 8 | case InstructionSet::kArm64: 9 | return arm64::CodeSimulatorArm64::CreateCodeSimulatorArm64(); 10 | default: 11 | return nullptr; 12 | } 13 | } 14 | 15 | CodeSimulator *CreateCodeSimulator(InstructionSet target_isa) { 16 | return CodeSimulator::CreateCodeSimulator(target_isa); 17 | } 18 | 19 | } // namespace whale 20 | 21 | -------------------------------------------------------------------------------- /whale/include/whale.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_PUBLIC_H_ 2 | #define WHALE_PUBLIC_H_ 3 | 4 | #define NULLABLE 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif // __cplusplus 9 | 10 | void WInlineHookFunction(void *address, void *replace, void **backup); 11 | 12 | void WImportHookFunction(const char *name, NULLABLE const char *libname, void *replace, void **backup); 13 | 14 | void *WDynamicLibOpen(const char *name); 15 | 16 | void *WDynamicLibOpenAlias(const char *name, const char *path); 17 | 18 | void *WDynamicLibSymbol(void *handle, const char *name); 19 | 20 | #ifdef __cplusplus 21 | } 22 | #endif // __cplusplus 23 | #endif // WHALE_PUBLIC_H_ 24 | -------------------------------------------------------------------------------- /whale/src/android/art/native_on_load.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ANDROID_ART_NATIVE_ON_LOAD_H_ 2 | #define WHALE_ANDROID_ART_NATIVE_ON_LOAD_H_ 3 | 4 | #include 5 | 6 | constexpr const char *kMethodReserved0 = "reserved0"; 7 | constexpr const char *kMethodReserved1 = "reserved1"; 8 | 9 | /** 10 | * DO NOT rename the following function 11 | */ 12 | extern "C" { 13 | 14 | void WhaleRuntime_reserved0(JNIEnv *env, jclass cl); 15 | 16 | void WhaleRuntime_reserved1(JNIEnv *env, jclass cl); 17 | 18 | } 19 | 20 | #ifndef WHALE_ANDROID_AUTO_LOAD 21 | JNIEXPORT jint JNICALL Whale_OnLoad(JavaVM *vm, void *reserved); 22 | #endif 23 | 24 | 25 | #endif // WHALE_ANDROID_ART_NATIVE_ON_LOAD_H_ 26 | -------------------------------------------------------------------------------- /whale/src/dbi/arm/decoder_arm.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_ARM_DECODER_ARM_H_ 2 | #define ARCH_ARM_DECODER_ARM_H_ 3 | 4 | #include "base/primitive_types.h" 5 | 6 | namespace whale { 7 | namespace arm { 8 | 9 | enum ArmInsnType { 10 | kARM_LDR, 11 | kARM_ADD, 12 | kARM_MOV, 13 | kARM_B, 14 | kARM_BL, 15 | kARM_VFP_VSTM_DP, 16 | kARM_VFP_VSTM_SP, 17 | kARM_VFP_VLDM_SP, 18 | kARM_VFP_VLDM_DP, 19 | kARM_VFP_VSTR_DP, 20 | kARM_VFP_VSTR_SP, 21 | kARM_VFP_VLDR_DP, 22 | kARM_VFP_VLDR_SP, 23 | 24 | kARM_UNHANDLED, 25 | }; 26 | 27 | ArmInsnType DecodeArm(u4 insn); 28 | 29 | } // namespace arm 30 | } // namespace whale 31 | 32 | #endif // ARCH_ARM_DECODER_ARM_H_ 33 | -------------------------------------------------------------------------------- /whale/src/dbi/instruction_rewriter.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_INSTRUCTION_REWRITER_H_ 2 | #define ARCH_INSTRUCTION_REWRITER_H_ 3 | 4 | #include "assembler/vixl/code-buffer-vixl.h" 5 | #include "dbi/instruction_set.h" 6 | 7 | namespace whale { 8 | 9 | using CodeBuffer = vixl::CodeBuffer; 10 | 11 | template 12 | class InstructionReWriter { 13 | 14 | virtual const InstructionSet GetISA() { 15 | return InstructionSet::kNone; 16 | } 17 | 18 | virtual InsnType *GetStartAddress() = 0; 19 | 20 | virtual size_t GetCodeSize() = 0; 21 | 22 | virtual void Rewrite() = 0; 23 | 24 | }; 25 | 26 | } // namespace whale 27 | 28 | #endif // ARCH_INSTRUCTION_REWRITER_H_ 29 | 30 | 31 | -------------------------------------------------------------------------------- /whale/src/libffi/x86/asmnames.h: -------------------------------------------------------------------------------- 1 | #ifdef __x86_64__ 2 | 3 | #ifndef ASMNAMES_H 4 | #define ASMNAMES_H 5 | 6 | #define C2(X, Y) X ## Y 7 | #define C1(X, Y) C2(X, Y) 8 | #ifdef __USER_LABEL_PREFIX__ 9 | # define C(X) C1(__USER_LABEL_PREFIX__, X) 10 | #else 11 | # define C(X) X 12 | #endif 13 | 14 | #ifdef __APPLE__ 15 | # define L(X) C1(L, X) 16 | #else 17 | # define L(X) C1(.L, X) 18 | #endif 19 | 20 | #if defined(__ELF__) && defined(__PIC__) 21 | # define PLT(X) X@PLT 22 | #else 23 | # define PLT(X) X 24 | #endif 25 | 26 | #ifdef __ELF__ 27 | # define ENDF(X) .type X,@function; .size X, . - X 28 | #else 29 | # define ENDF(X) 30 | #endif 31 | 32 | #endif /* ASMNAMES_H */ 33 | 34 | 35 | #endif -------------------------------------------------------------------------------- /whale/src/dbi/arm64/decoder_arm64.cc: -------------------------------------------------------------------------------- 1 | #include "dbi/arm64/decoder_arm64.h" 2 | #include "base/macros.h" 3 | 4 | #define CASE(mask, val, type) \ 5 | if ((((insn) & (mask)) == val)) { \ 6 | return type; \ 7 | } 8 | 9 | namespace whale { 10 | namespace arm64 { 11 | 12 | A64InsnType DecodeA64(u4 insn) { 13 | CASE(0x7e000000, 0x34000000, kA64_CBZ_CBNZ); 14 | CASE(0xff000010, 0x54000000, kA64_B_COND); 15 | CASE(0x7e000000, 0x36000000, kA64_TBZ_TBNZ); 16 | CASE(0x7c000000, 0x14000000, kA64_B_BL); 17 | CASE(0x3b000000, 0x18000000, kA64_LDR_LIT); 18 | CASE(0x1f000000, 0x10000000, kA64_ADR_ADRP); 19 | return kA64_UNHANDLED; 20 | } 21 | 22 | } // namespace arm64 23 | } // namespace whale 24 | -------------------------------------------------------------------------------- /whale/src/libffi/x86/internal64.h: -------------------------------------------------------------------------------- 1 | #ifdef __x86_64__ 2 | 3 | #define UNIX64_RET_VOID 0 4 | #define UNIX64_RET_UINT8 1 5 | #define UNIX64_RET_UINT16 2 6 | #define UNIX64_RET_UINT32 3 7 | #define UNIX64_RET_SINT8 4 8 | #define UNIX64_RET_SINT16 5 9 | #define UNIX64_RET_SINT32 6 10 | #define UNIX64_RET_INT64 7 11 | #define UNIX64_RET_XMM32 8 12 | #define UNIX64_RET_XMM64 9 13 | #define UNIX64_RET_X87 10 14 | #define UNIX64_RET_X87_2 11 15 | #define UNIX64_RET_ST_XMM0_RAX 12 16 | #define UNIX64_RET_ST_RAX_XMM0 13 17 | #define UNIX64_RET_ST_XMM0_XMM1 14 18 | #define UNIX64_RET_ST_RAX_RDX 15 19 | 20 | #define UNIX64_RET_LAST 15 21 | 22 | #define UNIX64_FLAG_RET_IN_MEM (1 << 10) 23 | #define UNIX64_FLAG_XMM_ARGS (1 << 11) 24 | #define UNIX64_SIZE_SHIFT 12 25 | 26 | 27 | #endif -------------------------------------------------------------------------------- /whale/src/base/stringprintf.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_BASE_STRINGPRINTF_H_ 2 | #define WHALE_BASE_STRINGPRINTF_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace whale { 8 | 9 | // Returns a string corresponding to printf-like formatting of the arguments. 10 | std::string StringPrintf(const char *fmt, ...) 11 | __attribute__((__format__(__printf__, 1, 2))); 12 | 13 | // Appends a printf-like formatting of the arguments to 'dst'. 14 | void StringAppendF(std::string *dst, const char *fmt, ...) 15 | __attribute__((__format__(__printf__, 2, 3))); 16 | 17 | // Appends a printf-like formatting of the arguments to 'dst'. 18 | void StringAppendV(std::string *dst, const char *format, va_list ap); 19 | 20 | } // namespace art 21 | 22 | #endif // WHALE_BASE_STRINGPRINTF_H_ 23 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/intercept_syscall_x86.cc: -------------------------------------------------------------------------------- 1 | #include "dbi/x86/intercept_syscall_x86.h" 2 | #include "base/primitive_types.h" 3 | 4 | namespace whale { 5 | namespace x86 { 6 | 7 | 8 | void X86InterceptSysCallHook::FindSysCalls(uintptr_t start_addr, uintptr_t end_addr) { 9 | u1 *start = reinterpret_cast(start_addr); 10 | u1 *end = reinterpret_cast(end_addr) - 1; 11 | while (start < end) { 12 | // int 80h 13 | if (*start == 0xcd & *(++start) == 0x80) { 14 | // eax: sysnum 15 | // ebx: arg0 16 | // ecx: arg1 17 | // edx: arg2 18 | // esi: arg3 19 | // edi: arg4 20 | // ebp: arg5 21 | } 22 | } 23 | 24 | } 25 | 26 | 27 | } // namespace x86 28 | } // namespace whale 29 | -------------------------------------------------------------------------------- /whale/src/interceptor.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_CODE_INTERCEPTOR_H_ 2 | #define WHALE_CODE_INTERCEPTOR_H_ 3 | 4 | #include 5 | #include 6 | #include "base/logging.h" 7 | #include "dbi/instruction_set.h" 8 | #include "dbi/hook_common.h" 9 | 10 | namespace whale { 11 | 12 | class Interceptor { 13 | public: 14 | static Interceptor *Instance(); 15 | 16 | void AddHook(std::unique_ptr &hook); 17 | 18 | void RemoveHook(int id); 19 | 20 | void RemoveHook(std::unique_ptr &hook) { 21 | RemoveHook(hook->id_); 22 | } 23 | void TraverseHooks(std::function&)> visitor); 24 | 25 | private: 26 | std::list> hook_list_; 27 | }; 28 | 29 | } // namespace whale 30 | 31 | #endif // WHALE_CODE_INTERCEPTOR_H_ 32 | 33 | -------------------------------------------------------------------------------- /whale/src/libffi/x86/internal.h: -------------------------------------------------------------------------------- 1 | #ifdef __i386__ 2 | 3 | #define X86_RET_FLOAT 0 4 | #define X86_RET_DOUBLE 1 5 | #define X86_RET_LDOUBLE 2 6 | #define X86_RET_SINT8 3 7 | #define X86_RET_SINT16 4 8 | #define X86_RET_UINT8 5 9 | #define X86_RET_UINT16 6 10 | #define X86_RET_INT64 7 11 | #define X86_RET_INT32 8 12 | #define X86_RET_VOID 9 13 | #define X86_RET_STRUCTPOP 10 14 | #define X86_RET_STRUCTARG 11 15 | #define X86_RET_STRUCT_1B 12 16 | #define X86_RET_STRUCT_2B 13 17 | #define X86_RET_UNUSED14 14 18 | #define X86_RET_UNUSED15 15 19 | 20 | #define X86_RET_TYPE_MASK 15 21 | #define X86_RET_POP_SHIFT 4 22 | 23 | #define R_EAX 0 24 | #define R_EDX 1 25 | #define R_ECX 2 26 | 27 | #ifdef __PCC__ 28 | # define HAVE_FASTCALL 0 29 | #else 30 | # define HAVE_FASTCALL 1 31 | #endif 32 | 33 | 34 | #endif -------------------------------------------------------------------------------- /whale/src/android/art/scoped_thread_state_change.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ANDROID_ART__SCOPED_THREAD_STATE_CHANGE_H_ 2 | #define WHALE_ANDROID_ART__SCOPED_THREAD_STATE_CHANGE_H_ 3 | 4 | #include 5 | 6 | namespace whale { 7 | namespace art { 8 | 9 | class ScopedNoGCDaemons { 10 | static jclass java_lang_Daemons; 11 | static jmethodID java_lang_Daemons_start; 12 | static jmethodID java_lang_Daemons_stop; 13 | 14 | public: 15 | static void Load(JNIEnv *env); 16 | 17 | ScopedNoGCDaemons(JNIEnv *env); 18 | 19 | ~ScopedNoGCDaemons(); 20 | 21 | private: 22 | JNIEnv *env_; 23 | }; 24 | 25 | class ScopedSuspendAll { 26 | public: 27 | ScopedSuspendAll(); 28 | 29 | ~ScopedSuspendAll(); 30 | }; 31 | 32 | 33 | } // namespace art 34 | } // namespace whale 35 | 36 | #endif // WHALE_ANDROID_ART__SCOPED_THREAD_STATE_CHANGE_H_ 37 | 38 | -------------------------------------------------------------------------------- /whale/src/interceptor.cc: -------------------------------------------------------------------------------- 1 | #include "interceptor.h" 2 | 3 | namespace whale { 4 | 5 | Interceptor *Interceptor::Instance() { 6 | static Interceptor instance; 7 | return &instance; 8 | } 9 | 10 | void Interceptor::AddHook(std::unique_ptr &hook) { 11 | hook->id_ = static_cast(hook_list_.size()); 12 | hook->StartHook(); 13 | hook_list_.push_back(std::move(hook)); 14 | } 15 | 16 | void Interceptor::RemoveHook(int id) { 17 | for (auto &entry : hook_list_) { 18 | if (entry->id_ == id) { 19 | hook_list_.remove(entry); 20 | entry->StopHook(); 21 | break; 22 | } 23 | } 24 | } 25 | 26 | void Interceptor::TraverseHooks(std::function &)> visitor) { 27 | for (auto &hook : hook_list_) { 28 | visitor(hook); 29 | } 30 | } 31 | 32 | } // namespace whale 33 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/distorm/operands.h: -------------------------------------------------------------------------------- 1 | /* 2 | operands.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2018 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef OPERANDS_H 13 | #define OPERANDS_H 14 | 15 | #include "config.h" 16 | #include "decoder.h" 17 | #include "prefix.h" 18 | #include "instructions.h" 19 | 20 | 21 | extern uint32_t _REGISTERTORCLASS[]; 22 | 23 | int operands_extract(_CodeInfo* ci, _DInst* di, _InstInfo* ii, 24 | _iflags instFlags, _OpType type, _OperandNumberType opNum, 25 | unsigned int modrm, _PrefixState* ps, _DecodeType effOpSz, 26 | _DecodeType effAdrSz, int* lockableInstruction); 27 | 28 | #endif /* OPERANDS_H */ 29 | -------------------------------------------------------------------------------- /whale/src/android/art/art_hook_param.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ANDROID_ART_INTERCEPT_PARAM_H_ 2 | #define WHALE_ANDROID_ART_INTERCEPT_PARAM_H_ 3 | 4 | #include 5 | #include "base/primitive_types.h" 6 | #include "ffi_cxx.h" 7 | 8 | namespace whale { 9 | namespace art { 10 | 11 | struct ArtHookParam final { 12 | bool is_static_; 13 | const char *shorty_; 14 | jobject addition_info_; 15 | ptr_t origin_compiled_code_; 16 | ptr_t origin_jni_code_; 17 | u4 origin_access_flags; 18 | u4 origin_code_item_off; 19 | jobject origin_method_; 20 | jobject hooked_method_; 21 | volatile ptr_t decl_class_; 22 | jobject class_Loader_; 23 | jmethodID hooked_native_method_; 24 | jmethodID origin_native_method_; 25 | FFIClosure *jni_closure_; 26 | }; 27 | 28 | } // namespace art 29 | } // namespace whale 30 | 31 | #endif // WHALE_ANDROID_ART_INTERCEPT_PARAM_H_ 32 | -------------------------------------------------------------------------------- /whale/src/assembler/x86/registers_x86.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ASSEMBLER_X86_REGISTERS_X86_H_ 2 | #define WHALE_ASSEMBLER_X86_REGISTERS_X86_H_ 3 | 4 | #include 5 | 6 | namespace whale { 7 | namespace x86 { 8 | 9 | enum Register { 10 | EAX = 0, 11 | ECX = 1, 12 | EDX = 2, 13 | EBX = 3, 14 | ESP = 4, 15 | EBP = 5, 16 | ESI = 6, 17 | EDI = 7, 18 | kNumberOfCpuRegisters = 8, 19 | kFirstByteUnsafeRegister = 4, 20 | kNoRegister = -1 // Signals an illegal register. 21 | }; 22 | 23 | enum XmmRegister { 24 | XMM0 = 0, 25 | XMM1 = 1, 26 | XMM2 = 2, 27 | XMM3 = 3, 28 | XMM4 = 4, 29 | XMM5 = 5, 30 | XMM6 = 6, 31 | XMM7 = 7, 32 | kNumberOfXmmRegisters = 8, 33 | kNoXmmRegister = -1 // Signals an illegal register. 34 | }; 35 | 36 | } // namespace x86 37 | } // namespace whale 38 | 39 | #endif // WHALE_ASSEMBLER_X86_REGISTERS_X86_H_ 40 | -------------------------------------------------------------------------------- /whale/src/base/enums.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_BASE_ENUMS_H_ 2 | #define WHALE_BASE_ENUMS_H_ 3 | 4 | 5 | #include 6 | #include 7 | 8 | enum class PointerSize : size_t { 9 | k32 = 4, 10 | k64 = 8 11 | }; 12 | 13 | inline std::ostream &operator<<(std::ostream &os, const PointerSize &rhs) { 14 | switch (rhs) { 15 | case PointerSize::k32: 16 | os << "k32"; 17 | break; 18 | case PointerSize::k64: 19 | os << "k64"; 20 | break; 21 | default: 22 | os << "PointerSize[" << static_cast(rhs) << "]"; 23 | break; 24 | } 25 | return os; 26 | } 27 | 28 | static constexpr PointerSize kRuntimePointerSize = sizeof(void *) == 8U 29 | ? PointerSize::k64 30 | : PointerSize::k32; 31 | 32 | #endif // WHALE_BASE_ENUMS_H_ 33 | -------------------------------------------------------------------------------- /whale/src/base/singleton.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_BASE_SINGLETON_H_ 2 | #define WHALE_BASE_SINGLETON_H_ 3 | 4 | template 5 | class Singleton { 6 | public: 7 | Singleton(std::function init_function) : init_function_(init_function), 8 | initialized_(false) {} 9 | 10 | void Ensure() { 11 | if (!initialized_) { 12 | std::lock_guard guard(lock_); 13 | if (!initialized_) { 14 | init_function_(&instance_); 15 | initialized_ = true; 16 | } 17 | } 18 | } 19 | 20 | T Get() { 21 | Ensure(); 22 | return instance_; 23 | } 24 | 25 | private: 26 | typename std::conditional::value, bool, T>::type instance_; 27 | std::mutex lock_; 28 | std::function init_function_; 29 | bool initialized_; 30 | }; 31 | 32 | #endif // WHALE_BASE_SINGLETON_H_ 33 | -------------------------------------------------------------------------------- /whale/src/dbi/arm64/inline_hook_arm64.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_ARM64_INLINEHOOK_ARM64_H_ 2 | #define ARCH_ARM64_INLINEHOOK_ARM64_H_ 3 | 4 | #include "dbi/backup_code.h" 5 | #include "dbi/hook_common.h" 6 | #include "base/primitive_types.h" 7 | 8 | namespace whale { 9 | namespace arm64 { 10 | 11 | class Arm64InlineHook : public InlineHook { 12 | public: 13 | Arm64InlineHook(intptr_t address, intptr_t replace, intptr_t *backup) 14 | : InlineHook(address, replace, backup), backup_code_(nullptr), trampoline_addr_(nullptr) {} 15 | 16 | ~Arm64InlineHook() override { 17 | delete backup_code_; 18 | } 19 | 20 | void StartHook() override; 21 | 22 | void StopHook() override; 23 | 24 | private: 25 | BackupCode *backup_code_; 26 | void *trampoline_addr_; 27 | 28 | intptr_t BuildTrampoline(u8 tail); 29 | }; 30 | 31 | } // namespace arm64 32 | } // namespace whale 33 | 34 | #endif // ARCH_ARM64_INLINEHOOK_ARM64_H_ 35 | 36 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/inline_hook_x86.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ARCH_X86_INLINE_HOOK_X86_H_ 2 | #define WHALE_ARCH_X86_INLINE_HOOK_X86_H_ 3 | 4 | #include "dbi/hook_common.h" 5 | #include "base/primitive_types.h" 6 | #include "dbi/backup_code.h" 7 | 8 | namespace whale { 9 | namespace x86 { 10 | 11 | class X86InlineHook : public InlineHook { 12 | public: 13 | X86InlineHook(intptr_t address, intptr_t replace, intptr_t *backup) 14 | : InlineHook(address, replace, backup), backup_code_(nullptr), 15 | trampoline_addr_(nullptr) {} 16 | 17 | ~X86InlineHook() override { 18 | delete backup_code_; 19 | } 20 | 21 | void StartHook() override; 22 | 23 | void StopHook() override; 24 | 25 | private: 26 | BackupCode *backup_code_; 27 | void *trampoline_addr_; 28 | 29 | intptr_t BuildTrampoline(u4 tail); 30 | }; 31 | 32 | } // namespace x86 33 | } // namespace whale 34 | 35 | #endif // WHALE_ARCH_X86_INLINE_HOOK_X86_H_ 36 | -------------------------------------------------------------------------------- /whale/src/simulator/code_simulator.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_SIMULATOR_CODE_SIMULATOR_H_ 2 | #define WHALE_SIMULATOR_CODE_SIMULATOR_H_ 3 | 4 | #include 5 | #include "dbi/instruction_set.h" 6 | #include "base/primitive_types.h" 7 | 8 | namespace whale { 9 | 10 | class CodeSimulator { 11 | public: 12 | CodeSimulator() = default; 13 | 14 | virtual ~CodeSimulator() = default; 15 | 16 | // Returns a null pointer if a simulator cannot be found for target_isa. 17 | static CodeSimulator *CreateCodeSimulator(InstructionSet target_isa); 18 | 19 | virtual void RunFrom(intptr_t code_buffer) = 0; 20 | 21 | // Get return value according to C ABI. 22 | virtual bool GetCReturnBool() const = 0; 23 | 24 | virtual s4 GetCReturnInt32() const = 0; 25 | 26 | virtual s8 GetCReturnInt64() const = 0; 27 | 28 | private: 29 | DISALLOW_COPY_AND_ASSIGN(CodeSimulator); 30 | }; 31 | 32 | } // namespace whale 33 | 34 | #endif // WHALE_SIMULATOR_CODE_SIMULATOR_H_ 35 | 36 | -------------------------------------------------------------------------------- /whale/src/dbi/x86_64/inline_hook_x86_64.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ARCH_X86_64_INLINE_HOOK_X86_64_H_ 2 | #define WHALE_ARCH_X86_64_INLINE_HOOK_X86_64_H_ 3 | 4 | #include "dbi/hook_common.h" 5 | #include "base/primitive_types.h" 6 | #include "dbi/backup_code.h" 7 | 8 | namespace whale { 9 | namespace x86_64 { 10 | 11 | class X86_64InlineHook : public InlineHook { 12 | public: 13 | X86_64InlineHook(intptr_t address, intptr_t replace, intptr_t *backup) 14 | : InlineHook(address, replace, backup), backup_code_(nullptr), 15 | trampoline_addr_(nullptr) {} 16 | 17 | ~X86_64InlineHook() override { 18 | delete backup_code_; 19 | } 20 | 21 | void StartHook() override; 22 | 23 | void StopHook() override; 24 | 25 | private: 26 | BackupCode *backup_code_; 27 | void *trampoline_addr_; 28 | 29 | intptr_t BuildTrampoline(u8 tail); 30 | }; 31 | 32 | } // namespace x86 33 | } // namespace whale 34 | 35 | #endif // WHALE_ARCH_X86_64_INLINE_HOOK_X86_64_H_ 36 | -------------------------------------------------------------------------------- /whale/src/dbi/arm/inline_hook_arm.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_ARM_INLINEHOOK_ARM_H_ 2 | #define ARCH_ARM_INLINEHOOK_ARM_H_ 3 | 4 | #include "dbi/backup_code.h" 5 | #include "dbi/hook_common.h" 6 | #include "base/primitive_types.h" 7 | #include "base/align.h" 8 | 9 | namespace whale { 10 | namespace arm { 11 | 12 | class ArmInlineHook : public InlineHook { 13 | public: 14 | ArmInlineHook(intptr_t address, intptr_t replace, intptr_t *backup) 15 | : InlineHook(address, replace, backup) { 16 | is_thumb_ = static_cast(address & 0x1); 17 | if (is_thumb_) { 18 | address_ = RoundDown(address, 2); 19 | } 20 | } 21 | 22 | void StartHook() override; 23 | 24 | void StopHook() override; 25 | 26 | private: 27 | bool is_thumb_; 28 | BackupCode *backup_code_; 29 | void *trampoline_addr_; 30 | 31 | intptr_t BuildTrampoline(u4 tail); 32 | }; 33 | 34 | } // namespace arm 35 | } // namespace whale 36 | 37 | #endif // ARCH_ARM_INLINEHOOK_ARM_H_ 38 | 39 | -------------------------------------------------------------------------------- /whale/src/simulator/code_simulator_container.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_SIMULATOR_CODE_SIMULATOR_CONTAINER_H_ 2 | #define WHALE_SIMULATOR_CODE_SIMULATOR_CONTAINER_H_ 3 | 4 | #include 5 | #include "simulator/code_simulator.h" 6 | #include "base/logging.h" 7 | 8 | namespace whale { 9 | 10 | 11 | class CodeSimulatorContainer { 12 | public: 13 | explicit CodeSimulatorContainer(InstructionSet target_isa); 14 | 15 | ~CodeSimulatorContainer(); 16 | 17 | bool CanSimulate() const { 18 | return simulator_ != nullptr; 19 | } 20 | 21 | CodeSimulator *Get() { 22 | DCHECK(CanSimulate()); 23 | return simulator_; 24 | } 25 | 26 | const CodeSimulator *Get() const { 27 | DCHECK(CanSimulate()); 28 | return simulator_; 29 | } 30 | 31 | private: 32 | CodeSimulator *simulator_; 33 | 34 | DISALLOW_COPY_AND_ASSIGN(CodeSimulatorContainer); 35 | }; 36 | 37 | 38 | } // namespace whale 39 | 40 | 41 | #endif // WHALE_SIMULATOR_CODE_SIMULATOR_CONTAINER_H_ 42 | 43 | 44 | -------------------------------------------------------------------------------- /whale/src/android/art/well_known_classes.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ANDROID_ART_WELL_KNOWN_CLASSES_H_ 2 | #define WHALE_ANDROID_ART_WELL_KNOWN_CLASSES_H_ 3 | 4 | #include 5 | 6 | namespace whale { 7 | namespace art { 8 | 9 | struct WellKnownClasses { 10 | static void Load(JNIEnv *env); 11 | 12 | static jclass java_lang_Object; 13 | static jclass java_lang_reflect_Method; 14 | static jclass java_lang_Class; 15 | static jclass java_lang_ClassLoader; 16 | static jclass java_lang_reflect_AccessibleObject; 17 | static jclass java_lang_Thread; 18 | static jclass java_lang_IllegalArgumentException; 19 | 20 | static jmethodID java_lang_reflect_Method_invoke; 21 | static jmethodID java_lang_Class_getClassLoader; 22 | static jmethodID java_lang_reflect_AccessibleObject_setAccessible; 23 | static jmethodID java_lang_Thread_currentThread; 24 | 25 | static jfieldID java_lang_Thread_nativePeer; 26 | }; 27 | 28 | } // namespace art 29 | } // namespace whale 30 | 31 | #endif // WHALE_ANDROID_ART_WELL_KNOWN_CLASSES_H_ 32 | -------------------------------------------------------------------------------- /whale/src/assembler/x86_64/registers_x86_64.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ASSEMBLER_REGISTERS_X86_64_H_ 2 | #define WHALE_ASSEMBLER_REGISTERS_X86_64_H_ 3 | 4 | namespace whale { 5 | namespace x86_64 { 6 | 7 | enum Register { 8 | RAX = 0, 9 | RCX = 1, 10 | RDX = 2, 11 | RBX = 3, 12 | RSP = 4, 13 | RBP = 5, 14 | RSI = 6, 15 | RDI = 7, 16 | R8 = 8, 17 | R9 = 9, 18 | R10 = 10, 19 | R11 = 11, 20 | R12 = 12, 21 | R13 = 13, 22 | R14 = 14, 23 | R15 = 15, 24 | kLastCpuRegister = 15, 25 | kNumberOfCpuRegisters = 16, 26 | kNoRegister = -1 // Signals an illegal register. 27 | }; 28 | 29 | enum FloatRegister { 30 | XMM0 = 0, 31 | XMM1 = 1, 32 | XMM2 = 2, 33 | XMM3 = 3, 34 | XMM4 = 4, 35 | XMM5 = 5, 36 | XMM6 = 6, 37 | XMM7 = 7, 38 | XMM8 = 8, 39 | XMM9 = 9, 40 | XMM10 = 10, 41 | XMM11 = 11, 42 | XMM12 = 12, 43 | XMM13 = 13, 44 | XMM14 = 14, 45 | XMM15 = 15, 46 | kNumberOfFloatRegisters = 16 47 | }; 48 | 49 | } // namespace x86_64 50 | } // namespace whale 51 | 52 | #endif // WHALE_ASSEMBLER_REGISTERS_X86_64_H_ 53 | -------------------------------------------------------------------------------- /whale/test/test_hook.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | char *(*Origin_getenv)(const char *); 7 | 8 | char *Hooked_getenv(const char *name) { 9 | if (!strcmp(name, "lody")) { 10 | return strdup("are you ok?"); 11 | } 12 | char *(*O)(const char *) = Origin_getenv; 13 | return O(name); 14 | } 15 | 16 | int main() { 17 | #if defined(__APPLE__) 18 | void *handle = dlopen("libc.dylib", RTLD_NOW); 19 | #else 20 | void *handle = dlopen("libc.so", RTLD_NOW); 21 | #endif 22 | assert(handle != nullptr); 23 | void *symbol = dlsym(handle, "getenv"); 24 | assert(symbol != nullptr); 25 | WInlineHookFunction( 26 | symbol, 27 | reinterpret_cast(Hooked_getenv), 28 | reinterpret_cast(&Origin_getenv) 29 | ); 30 | // WImportHookFunction( 31 | // "_getenv", 32 | // reinterpret_cast(Hooked_getenv), 33 | // reinterpret_cast(&Origin_getenv) 34 | // ); 35 | 36 | const char *val = getenv("lody"); 37 | std::cout << val; 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/distorm/wstring.c: -------------------------------------------------------------------------------- 1 | /* 2 | wstring.c 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2018 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #include "wstring.h" 13 | 14 | #ifndef DISTORM_LIGHT 15 | 16 | void strclear_WS(_WString* s) 17 | { 18 | s->p[0] = '\0'; 19 | s->length = 0; 20 | } 21 | 22 | void chrcat_WS(_WString* s, uint8_t ch) 23 | { 24 | s->p[s->length] = ch; 25 | s->p[s->length + 1] = '\0'; 26 | s->length += 1; 27 | } 28 | 29 | void strcpylen_WS(_WString* s, const int8_t* buf, unsigned int len) 30 | { 31 | s->length = len; 32 | memcpy((int8_t*)s->p, buf, len + 1); 33 | } 34 | 35 | void strcatlen_WS(_WString* s, const int8_t* buf, unsigned int len) 36 | { 37 | memcpy((int8_t*)&s->p[s->length], buf, len + 1); 38 | s->length += len; 39 | } 40 | 41 | void strcat_WS(_WString* s, const _WString* s2) 42 | { 43 | memcpy((int8_t*)&s->p[s->length], s2->p, s2->length + 1); 44 | s->length += s2->length; 45 | } 46 | 47 | #endif /* DISTORM_LIGHT */ 48 | -------------------------------------------------------------------------------- /whale/src/dbi/arm/decoder_thumb.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_ARM_DECODER_THUMB_H_ 2 | #define ARCH_ARM_DECODER_THUMB_H_ 3 | 4 | #include "base/primitive_types.h" 5 | 6 | namespace whale { 7 | namespace arm { 8 | 9 | enum ThumbInsnType { 10 | kTHUMB_ADD_FROM_PC16, 11 | kTHUMB_ADDH16, 12 | kTHUMB_B16, 13 | kTHUMB_B_COND16, 14 | kTHUMB_BLX16, 15 | kTHUMB_BX16, 16 | kTHUMB_CBNZ16, 17 | kTHUMB_CBZ16, 18 | kTHUMB_CMPH16, 19 | kTHUMB_LDR_PC_16, 20 | kTHUMB_MOVH16, 21 | kTHUMB_UNHANDLED16, 22 | 23 | kTHUMB_B32, 24 | kTHUMB_BL32, 25 | kTHUMB_BL_ARM32, 26 | kTHUMB_LDRBL32, 27 | kTHUMB_LDRHL32, 28 | kTHUMB_LDRL32, 29 | kTHUMB_LDRSBL32, 30 | kTHUMB_LDRSHL32, 31 | kTHUMB_UNHANDLED32 32 | }; 33 | 34 | ThumbInsnType DecodeThumb16(u2 insn); 35 | 36 | ThumbInsnType DecodeThumb32(u4 insn); 37 | 38 | /** 39 | * Bit[15:11] in Thumb32 : 40 | * 0b11101 41 | * 0b11110 42 | * 0b11111 43 | */ 44 | static inline bool Is32BitThumbInstruction(u2 insn) { 45 | return ((insn & 0xF000) == 0xF000) || ((insn & 0xF800) == 0xE800); 46 | } 47 | 48 | } // namespace arm 49 | } // namespace whale 50 | 51 | #endif // ARCH_ARM_DECODER_THUMB_H_ 52 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/distorm/decoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | decoder.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2011 Gil Dabah 8 | 9 | This program is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see 21 | */ 22 | 23 | 24 | #ifndef DECODER_H 25 | #define DECODER_H 26 | 27 | #include "config.h" 28 | 29 | typedef unsigned int _iflags; 30 | 31 | _DecodeResult decode_internal(_CodeInfo* ci, int supportOldIntr, _DInst result[], unsigned int maxResultCount, unsigned int* usedInstructionsCount); 32 | 33 | #endif /* DECODER_H */ 34 | -------------------------------------------------------------------------------- /whale/src/platform/linux/process_map.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_PLATFORM_PROCESS_MAP_H_ 2 | #define WHALE_PLATFORM_PROCESS_MAP_H_ 3 | 4 | #include 5 | #include 6 | #include "base/primitive_types.h" 7 | 8 | namespace whale { 9 | 10 | struct MemoryRange { 11 | public: 12 | MemoryRange() : base_(0), end_(0), path_(nullptr) {} 13 | 14 | ~MemoryRange() { 15 | if (path_ != nullptr) { 16 | free((void *) path_); 17 | path_ = nullptr; 18 | } 19 | } 20 | 21 | bool IsValid() { 22 | return path_ != nullptr && base_ < end_; 23 | } 24 | 25 | bool IsInRange(uintptr_t address) { 26 | return IsValid() && base_ <= address && end_ >= address; 27 | } 28 | 29 | const char *path_; 30 | uintptr_t base_; 31 | uintptr_t end_; 32 | }; 33 | 34 | bool IsFileInMemory(const char *name); 35 | 36 | std::unique_ptr FindExecuteMemoryRange(const char *name); 37 | 38 | std::unique_ptr FindFileMemoryRange(const char *name); 39 | 40 | void ForeachMemoryRange(std::function callback); 41 | 42 | } // namespace whale 43 | 44 | #endif // WHALE_PLATFORM_PROCESS_MAP_H_ 45 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/distorm/wstring.h: -------------------------------------------------------------------------------- 1 | /* 2 | wstring.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2018 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef WSTRING_H 13 | #define WSTRING_H 14 | 15 | #include "config.h" 16 | 17 | #ifndef DISTORM_LIGHT 18 | 19 | void strclear_WS(_WString* s); 20 | void chrcat_WS(_WString* s, uint8_t ch); 21 | void strcpylen_WS(_WString* s, const int8_t* buf, unsigned int len); 22 | void strcatlen_WS(_WString* s, const int8_t* buf, unsigned int len); 23 | void strcat_WS(_WString* s, const _WString* s2); 24 | 25 | /* 26 | * Warning, this macro should be used only when the compiler knows the size of string in advance! 27 | * This macro is used in order to spare the call to strlen when the strings are known already. 28 | * Note: sizeof includes NULL terminated character. 29 | */ 30 | #define strcat_WSN(s, t) strcatlen_WS((s), ((const int8_t*)t), sizeof((t))-1) 31 | #define strcpy_WSN(s, t) strcpylen_WS((s), ((const int8_t*)t), sizeof((t))-1) 32 | 33 | #endif /* DISTORM_LIGHT */ 34 | 35 | #endif /* WSTRING_H */ 36 | -------------------------------------------------------------------------------- /whale/src/simulator/code_simulator_arm64.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_SIMULATOR_CODE_SIMULATOR_ARM64_H_ 2 | #define WHALE_SIMULATOR_CODE_SIMULATOR_ARM64_H_ 3 | 4 | #include 5 | #include "dbi/instruction_set.h" 6 | #include "base/primitive_types.h" 7 | #include "vixl/aarch64/decoder-aarch64.h" 8 | #include "vixl/aarch64/simulator-aarch64.h" 9 | #include "simulator/code_simulator.h" 10 | 11 | namespace whale { 12 | namespace arm64 { 13 | 14 | class CodeSimulatorArm64 : public CodeSimulator { 15 | public: 16 | static CodeSimulatorArm64 *CreateCodeSimulatorArm64(); 17 | 18 | ~CodeSimulatorArm64() override; 19 | 20 | void RunFrom(intptr_t code_buffer) override; 21 | 22 | bool GetCReturnBool() const override; 23 | 24 | int32_t GetCReturnInt32() const override; 25 | 26 | int64_t GetCReturnInt64() const override; 27 | 28 | private: 29 | CodeSimulatorArm64(); 30 | 31 | vixl::aarch64::Decoder *decoder_; 32 | vixl::aarch64::Simulator *simulator_; 33 | 34 | static constexpr bool kCanSimulate = (kRuntimeISA != InstructionSet::kArm64); 35 | 36 | DISALLOW_COPY_AND_ASSIGN(CodeSimulatorArm64); 37 | }; 38 | 39 | } 40 | } // namespace whale 41 | 42 | #endif // WHALE_SIMULATOR_CODE_SIMULATOR_ARM64_H_ 43 | 44 | -------------------------------------------------------------------------------- /whale/src/android/android_build.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ANDROID_ANDROID_BUILD_H_ 2 | #define WHALE_ANDROID_ANDROID_BUILD_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define ANDROID_ICE_CREAM_SANDWICH 14 9 | #define ANDROID_ICE_CREAM_SANDWICH_MR1 15 10 | #define ANDROID_JELLY_BEAN 16 11 | #define ANDROID_JELLY_BEAN_MR1 17 12 | #define ANDROID_JELLY_BEAN_MR2 18 13 | #define ANDROID_KITKAT 19 14 | #define ANDROID_KITKAT_WATCH 20 15 | #define ANDROID_LOLLIPOP 21 16 | #define ANDROID_LOLLIPOP_MR1 22 17 | #define ANDROID_M 23 18 | #define ANDROID_N 24 19 | #define ANDROID_N_MR1 25 20 | #define ANDROID_O 26 21 | #define ANDROID_O_MR1 27 22 | #define ANDROID_P 28 23 | #define ANDROID_Q 29 24 | #define ANDROID_R 30 25 | 26 | static inline int32_t GetAndroidApiLevel() { 27 | char prop_value[PROP_VALUE_MAX]; 28 | __system_property_get("ro.build.version.sdk", prop_value); 29 | return atoi(prop_value); 30 | } 31 | 32 | #endif // WHALE_ANDROID_ANDROID_BUILD_H_ 33 | -------------------------------------------------------------------------------- /whale/src/dbi/backup_code.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_BACKUP_CODE_H_ 2 | #define ARCH_BACKUP_CODE_H_ 3 | 4 | #include 5 | #include "base/primitive_types.h" 6 | #include "base/macros.h" 7 | #include "base/logging.h" 8 | 9 | 10 | namespace whale { 11 | 12 | class BackupCode { 13 | public: 14 | BackupCode(const void *address, const size_t size) : size_(size) { 15 | insns_ = malloc(size); 16 | memcpy(insns_, address, size); 17 | } 18 | 19 | ~BackupCode() { 20 | free(insns_); 21 | } 22 | 23 | size_t GetSizeInBytes() { 24 | return size_; 25 | } 26 | 27 | size_t GetCount(size_t insn_size) { 28 | return size_ / insn_size; 29 | } 30 | 31 | template 32 | size_t GetCount() { 33 | return GetCount(sizeof(T)); 34 | } 35 | 36 | template 37 | T *GetInstructions() { 38 | return reinterpret_cast(insns_); 39 | } 40 | 41 | intptr_t GetInstructions() { 42 | return reinterpret_cast(insns_); 43 | } 44 | 45 | private: 46 | void *insns_; 47 | size_t size_; 48 | 49 | private: 50 | DISALLOW_COPY_AND_ASSIGN(BackupCode); 51 | }; 52 | 53 | } // namespace whale 54 | 55 | #endif // ARCH_BACKUP_CODE_H_ 56 | 57 | -------------------------------------------------------------------------------- /whale/src/assembler/managed_register.h: -------------------------------------------------------------------------------- 1 | #ifndef MYAPPLICATION_MANAGED_REGISTER_H 2 | #define MYAPPLICATION_MANAGED_REGISTER_H 3 | 4 | #include "assembler/value_object.h" 5 | 6 | namespace whale { 7 | 8 | class ManagedRegister : public ValueObject { 9 | public: 10 | // ManagedRegister is a value class. There exists no method to change the 11 | // internal state. We therefore allow a copy constructor and an 12 | // assignment-operator. 13 | constexpr ManagedRegister(const ManagedRegister &other) = default; 14 | 15 | ManagedRegister &operator=(const ManagedRegister &other) = default; 16 | 17 | // It is valid to invoke Equals on and with a NoRegister. 18 | constexpr bool Equals(const ManagedRegister &other) const { 19 | return id_ == other.id_; 20 | } 21 | 22 | constexpr bool IsNoRegister() const { 23 | return id_ == kNoRegister; 24 | } 25 | 26 | static constexpr ManagedRegister NoRegister() { 27 | return ManagedRegister(); 28 | } 29 | 30 | constexpr int RegId() const { return id_; } 31 | 32 | explicit constexpr ManagedRegister(int reg_id) : id_(reg_id) {} 33 | 34 | protected: 35 | static const int kNoRegister = -1; 36 | 37 | constexpr ManagedRegister() : id_(kNoRegister) {} 38 | 39 | int id_; 40 | }; 41 | 42 | } // namespace whale 43 | 44 | #endif //MYAPPLICATION_MANAGED_REGISTER_H 45 | -------------------------------------------------------------------------------- /whale/src/dbi/arm/decoder_thumb.cc: -------------------------------------------------------------------------------- 1 | #include "dbi/arm/decoder_thumb.h" 2 | 3 | #define CASE(mask, val, type) \ 4 | if ((((insn) & (mask)) == val)) { \ 5 | return type; \ 6 | } 7 | 8 | namespace whale { 9 | namespace arm { 10 | 11 | 12 | ThumbInsnType DecodeThumb16(u2 insn) { 13 | CASE(0xf800, 0xa000, kTHUMB_ADD_FROM_PC16); 14 | CASE(0xff00, 0x4400, kTHUMB_ADDH16); 15 | CASE(0xf800, 0xe000, kTHUMB_B16); 16 | CASE(0xf000, 0xd000, kTHUMB_B_COND16); 17 | CASE(0xff87, 0x4780, kTHUMB_BLX16); 18 | CASE(0xff87, 0x4700, kTHUMB_BX16); 19 | CASE(0xfd00, 0xb900, kTHUMB_CBNZ16); 20 | CASE(0xfd00, 0xb100, kTHUMB_CBZ16); 21 | CASE(0xff00, 0x4500, kTHUMB_CMPH16); 22 | CASE(0xf800, 0x4800, kTHUMB_LDR_PC_16); 23 | CASE(0xff00, 0x4600, kTHUMB_MOVH16); 24 | return kTHUMB_UNHANDLED16; 25 | } 26 | 27 | ThumbInsnType DecodeThumb32(u4 insn) { 28 | CASE(0xf800d000, 0xf0009000, kTHUMB_B32); 29 | CASE(0xf800d000, 0xf000d000, kTHUMB_BL32); 30 | CASE(0xf800d000, 0xf000c000, kTHUMB_BL_ARM32); 31 | CASE(0xff7f0000, 0xf81f0000, kTHUMB_LDRBL32); 32 | CASE(0xff7f0000, 0xf83f0000, kTHUMB_LDRHL32); 33 | CASE(0xff7f0000, 0xf85f0000, kTHUMB_LDRL32); 34 | CASE(0xfff00fc0, 0xf9100000, kTHUMB_LDRSBL32); 35 | CASE(0xff7f0000, 0xf93f0000, kTHUMB_LDRSHL32); 36 | return kTHUMB_UNHANDLED32; 37 | } 38 | 39 | 40 | } // namespace arm 41 | } // namespace whale 42 | -------------------------------------------------------------------------------- /whale/src/base/cxx_helper.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_BASE_CXX_HELPER_H_ 2 | #define WHALE_BASE_CXX_HELPER_H_ 3 | 4 | #include 5 | #include "base/primitive_types.h" 6 | 7 | template 8 | U ForceCast(T *x) { 9 | return (U) (uintptr_t) x; 10 | } 11 | 12 | template 13 | U ForceCast(T &x) { 14 | return *(U *) &x; 15 | } 16 | 17 | template 18 | struct Identity { 19 | using type = T; 20 | }; 21 | 22 | template 23 | static inline R OffsetOf(uintptr_t ptr, size_t offset) { 24 | return reinterpret_cast(ptr + offset); 25 | } 26 | 27 | template 28 | static inline R OffsetOf(intptr_t ptr, size_t offset) { 29 | return reinterpret_cast(ptr + offset); 30 | } 31 | 32 | template 33 | static inline R OffsetOf(ptr_t ptr, size_t offset) { 34 | return (R) (reinterpret_cast(ptr) + offset); 35 | } 36 | 37 | template 38 | static inline T MemberOf(ptr_t ptr, size_t offset) { 39 | return *OffsetOf(ptr, offset); 40 | } 41 | 42 | static inline size_t DistanceOf(ptr_t a, ptr_t b) { 43 | return static_cast( 44 | abs(reinterpret_cast(b) - reinterpret_cast(a)) 45 | ); 46 | } 47 | 48 | template 49 | static inline void AssignOffset(ptr_t ptr, size_t offset, T member) { 50 | *OffsetOf(ptr, offset) = member; 51 | } 52 | 53 | #endif // WHALE_BASE_CXX_HELPER_H_ 54 | -------------------------------------------------------------------------------- /whale/src/dbi/hook_common.cc: -------------------------------------------------------------------------------- 1 | #include "dbi/hook_common.h" 2 | #include "hook_common.h" 3 | 4 | #if defined(linux) 5 | 6 | #include "platform/linux/process_map.h" 7 | 8 | #endif 9 | 10 | namespace whale { 11 | 12 | bool FindStdLibCallback(const char *path, bool *stop) { 13 | #if defined(linux) 14 | if (strstr(path, "system/") && strstr(path, "/libc.so")) { 15 | *stop = true; 16 | return true; 17 | } 18 | #elif defined(__APPLE__) 19 | if (strstr(path, "libc.dylib")) { 20 | *stop = true; 21 | return true; 22 | } 23 | #endif 24 | return false; 25 | } 26 | 27 | InterceptSysCallHook::InterceptSysCallHook(MemoryRangeCallback callback) 28 | : Hook() { 29 | if (callback == nullptr) { 30 | callback = FindStdLibCallback; 31 | } 32 | callback_ = callback; 33 | } 34 | 35 | void InterceptSysCallHook::StartHook() { 36 | bool stop_foreach = false; 37 | #if defined(linux) 38 | ForeachMemoryRange( 39 | [&](uintptr_t begin, uintptr_t end, uintptr_t offset, char *perm, char *mapname) -> bool { 40 | if (strstr(perm, "x") && strstr(perm, "r")) { 41 | if (callback_(mapname, &stop_foreach)) { 42 | FindSysCalls(begin, end); 43 | } 44 | } 45 | return stop_foreach; 46 | }); 47 | #endif 48 | } 49 | 50 | void InterceptSysCallHook::StopHook() { 51 | 52 | } 53 | } // namespace whale 54 | -------------------------------------------------------------------------------- /whale/src/dbi/arm/registers_arm.h: -------------------------------------------------------------------------------- 1 | #ifndef ARM64_ARM_CONVENTION_H_ 2 | #define ARM64_ARM_CONVENTION_H_ 3 | 4 | #include 5 | #include "assembler/vixl/aarch32/operands-aarch32.h" 6 | 7 | namespace whale { 8 | namespace arm { 9 | 10 | 11 | enum ArmRegister { 12 | R0 = 0, 13 | R1 = 1, 14 | R2 = 2, 15 | R3 = 3, 16 | R4 = 4, 17 | R5 = 5, 18 | R6 = 6, 19 | R7 = 7, 20 | R8 = 8, 21 | R9 = 9, 22 | R10 = 10, 23 | R11 = 11, 24 | R12 = 12, 25 | R13 = 13, 26 | R14 = 14, 27 | R15 = 15, 28 | MR = 8, 29 | TR = 9, 30 | FP = 11, 31 | IP = 12, 32 | SP = 13, 33 | LR = 14, 34 | PC = 15, 35 | kNumberOfCoreRegisters = 16, 36 | kNoRegister = -1, 37 | }; 38 | 39 | const vixl::aarch32::Register &Reg(int reg) { 40 | #define CASE(x) case R##x: \ 41 | return vixl::aarch32::r##x; 42 | 43 | switch (reg) { 44 | CASE(0) 45 | CASE(1) 46 | CASE(2) 47 | CASE(3) 48 | CASE(4) 49 | CASE(5) 50 | CASE(6) 51 | CASE(7) 52 | CASE(8) 53 | CASE(9) 54 | CASE(10) 55 | CASE(11) 56 | CASE(12) 57 | CASE(13) 58 | CASE(14) 59 | CASE(15) 60 | default: 61 | LOG(FATAL) << "Unexpected register : " << reg; 62 | UNREACHABLE(); 63 | } 64 | #undef CASE 65 | } 66 | 67 | } // namespace arm 68 | } // namespace whale 69 | 70 | 71 | #endif // ARM64_ARM_CONVENTION_H_ 72 | 73 | 74 | -------------------------------------------------------------------------------- /whale/src/dbi/darwin/macho_import_hook.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_DBI_MACHO_IMPORT_HOOK_H_ 2 | #define WHALE_DBI_MACHO_IMPORT_HOOK_H_ 3 | 4 | #include "dbi/hook_common.h" 5 | #include 6 | #include 7 | #include 8 | #include "base/cxx_helper.h" 9 | #include "base/singleton.h" 10 | 11 | #ifndef S_LAZY_DYLIB_SYMBOL_POINTERS 12 | #define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10 13 | #endif 14 | 15 | #if __LP64__ 16 | #define LC_SEGMENT_COMMAND LC_SEGMENT_64 17 | typedef mach_header_64 macho_header; 18 | typedef section_64 macho_section; 19 | typedef nlist_64 macho_nlist; 20 | typedef segment_command_64 macho_segment_command; 21 | #else 22 | #define LC_SEGMENT_COMMAND LC_SEGMENT 23 | typedef mach_header macho_header; 24 | typedef section macho_section; 25 | typedef nlist macho_nlist; 26 | typedef segment_command macho_segment_command; 27 | #endif 28 | 29 | namespace whale { 30 | namespace darwin { 31 | 32 | class MachoImportHook final : public ImportHook { 33 | public: 34 | MachoImportHook(const char *symbol_name, void *replace, void **backup) 35 | : ImportHook(symbol_name, replace, backup) {} 36 | 37 | void StartHook() override; 38 | 39 | void StopHook() override; 40 | 41 | void ImportHookOneMachO(const macho_header *mh, intptr_t slide); 42 | 43 | private: 44 | void **GetImportAddress(const macho_header *mh, intptr_t slide); 45 | }; 46 | 47 | } // namespace darwin 48 | } // namespace whale 49 | 50 | #endif // WHALE_DBI_MACHO_IMPORT_HOOK_H_ 51 | -------------------------------------------------------------------------------- /whale/src/android/art/art_symbol_resolver.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ANDROID_ART_SYMBOL_RESOLVER_H_ 2 | #define WHALE_ANDROID_ART_SYMBOL_RESOLVER_H_ 3 | 4 | #include 5 | #include "platform/linux/elf_image.h" 6 | #include "base/primitive_types.h" 7 | 8 | namespace whale { 9 | namespace art { 10 | 11 | struct ResolvedSymbols { 12 | const char *(*Art_GetMethodShorty)(JNIEnv *, jmethodID); 13 | 14 | void (*Dbg_SuspendVM)(); 15 | 16 | void (*Dbg_ResumeVM)(); 17 | 18 | void *art_quick_to_interpreter_bridge; 19 | void *artInterpreterToCompiledCodeBridge; 20 | 21 | void (*ProfileSaver_ForceProcessProfiles)(); 22 | 23 | void (*ArtMethod_CopyFrom)(jmethodID this_ptr, jmethodID from, size_t num_bytes); 24 | 25 | ptr_t (*Thread_DecodeJObject)(ptr_t thread, jobject obj); 26 | 27 | ptr_t (*Object_Clone)(ptr_t object_this, ptr_t thread); 28 | 29 | ptr_t (*Object_CloneWithClass)(ptr_t object_this, ptr_t thread, ptr_t cls); 30 | 31 | ptr_t (*Object_CloneWithSize)(ptr_t object_this, ptr_t thread, size_t num_bytes); 32 | 33 | jobject (*JniEnvExt_NewLocalRef)(JNIEnv *jnienv_ext_this, ptr_t art_object); 34 | 35 | }; 36 | 37 | class ArtSymbolResolver { 38 | public: 39 | ArtSymbolResolver() = default; 40 | 41 | bool Resolve(void *elf_image, s4 api_level); 42 | 43 | ResolvedSymbols *GetSymbols() { 44 | return &symbols_; 45 | }; 46 | 47 | private: 48 | ResolvedSymbols symbols_; 49 | }; 50 | 51 | } // namespace art 52 | } // namespace whale 53 | 54 | #endif // WHALE_ANDROID_ART_SYMBOL_RESOLVER_H_ 55 | -------------------------------------------------------------------------------- /whale/src/simulator/code_simulator_arm64.cc: -------------------------------------------------------------------------------- 1 | #include "vixl/aarch64/instructions-aarch64.h" 2 | #include "simulator/code_simulator_arm64.h" 3 | #include "base/logging.h" 4 | 5 | namespace whale { 6 | namespace arm64 { 7 | 8 | using namespace vixl::aarch64; // NOLINT(build/namespaces) 9 | 10 | CodeSimulatorArm64* CodeSimulatorArm64::CreateCodeSimulatorArm64() { 11 | if (kCanSimulate) { 12 | return new CodeSimulatorArm64(); 13 | } else { 14 | return nullptr; 15 | } 16 | } 17 | 18 | CodeSimulatorArm64::CodeSimulatorArm64() 19 | : CodeSimulator(), decoder_(nullptr), simulator_(nullptr) { 20 | CHECK(kCanSimulate); 21 | decoder_ = new Decoder(); 22 | simulator_ = new Simulator(decoder_); 23 | } 24 | 25 | CodeSimulatorArm64::~CodeSimulatorArm64() { 26 | CHECK(kCanSimulate); 27 | delete simulator_; 28 | delete decoder_; 29 | } 30 | 31 | void CodeSimulatorArm64::RunFrom(intptr_t code_buffer) { 32 | CHECK(kCanSimulate); 33 | simulator_->RunFrom(reinterpret_cast(code_buffer)); 34 | } 35 | 36 | bool CodeSimulatorArm64::GetCReturnBool() const { 37 | CHECK(kCanSimulate); 38 | return static_cast(simulator_->ReadWRegister(0)); 39 | } 40 | 41 | int32_t CodeSimulatorArm64::GetCReturnInt32() const { 42 | CHECK(kCanSimulate); 43 | return simulator_->ReadWRegister(0); 44 | } 45 | 46 | int64_t CodeSimulatorArm64::GetCReturnInt64() const { 47 | CHECK(kCanSimulate); 48 | return simulator_->ReadXRegister(0); 49 | } 50 | 51 | 52 | } // namespace arm64 53 | } // namespace whale 54 | 55 | -------------------------------------------------------------------------------- /whale/src/base/offsets.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_BASE_OFFSETS_H_ 2 | #define WHALE_BASE_OFFSETS_H_ 3 | 4 | #include 5 | #include 6 | #include "base/enums.h" 7 | 8 | namespace whale { 9 | 10 | 11 | // Allow the meaning of offsets to be strongly typed. 12 | class Offset { 13 | public: 14 | constexpr explicit Offset(size_t val) : val_(val) {} 15 | 16 | constexpr int32_t Int32Value() const { 17 | return static_cast(val_); 18 | } 19 | 20 | constexpr uint32_t Uint32Value() const { 21 | return static_cast(val_); 22 | } 23 | 24 | constexpr size_t SizeValue() const { 25 | return val_; 26 | } 27 | 28 | protected: 29 | size_t val_; 30 | }; 31 | 32 | // Offsets relative to the current frame. 33 | class FrameOffset : public Offset { 34 | public: 35 | constexpr explicit FrameOffset(size_t val) : Offset(val) {} 36 | 37 | bool operator>(FrameOffset other) const { return val_ > other.val_; } 38 | 39 | bool operator<(FrameOffset other) const { return val_ < other.val_; } 40 | }; 41 | 42 | // Offsets relative to the current running thread. 43 | template 44 | class ThreadOffset : public Offset { 45 | public: 46 | constexpr explicit ThreadOffset(size_t val) : Offset(val) {} 47 | }; 48 | 49 | using ThreadOffset32 = ThreadOffset; 50 | using ThreadOffset64 = ThreadOffset; 51 | 52 | // Offsets relative to an object. 53 | class MemberOffset : public Offset { 54 | public: 55 | constexpr explicit MemberOffset(size_t val) : Offset(val) {} 56 | }; 57 | 58 | } 59 | 60 | #endif // WHALE_BASE_OFFSETS_H_ 61 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/distorm/textdefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | textdefs.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2018 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef TEXTDEFS_H 13 | #define TEXTDEFS_H 14 | 15 | #include "config.h" 16 | #include "wstring.h" 17 | 18 | #ifndef DISTORM_LIGHT 19 | 20 | #define PLUS_DISP_CHR '+' 21 | #define MINUS_DISP_CHR '-' 22 | #define OPEN_CHR '[' 23 | #define CLOSE_CHR ']' 24 | #define SP_CHR ' ' 25 | #define SEG_OFF_CHR ':' 26 | 27 | /* 28 | Naming Convention: 29 | 30 | * get - returns a pointer to a string. 31 | * str - concatenates to string. 32 | 33 | * hex - means the function is used for hex dump (number is padded to required size) - Little Endian output. 34 | * code - means the function is used for disassembled instruction - Big Endian output. 35 | * off - means the function is used for 64bit offset - Big Endian output. 36 | 37 | * h - '0x' in front of the string. 38 | 39 | * b - byte 40 | * dw - double word (can be used for word also) 41 | * qw - quad word 42 | 43 | * all numbers are in HEX. 44 | */ 45 | 46 | void _FASTCALL_ str_hex_b(_WString* s, unsigned int x); 47 | void _FASTCALL_ str_code_hb(_WString* s, unsigned int x); 48 | void _FASTCALL_ str_code_hdw(_WString* s, uint32_t x); 49 | void _FASTCALL_ str_code_hqw(_WString* s, uint8_t src[8]); 50 | 51 | #ifdef SUPPORT_64BIT_OFFSET 52 | void _FASTCALL_ str_off64(_WString* s, OFFSET_INTEGER x); 53 | #endif 54 | 55 | #endif /* DISTORM_LIGHT */ 56 | 57 | #endif /* TEXTDEFS_H */ 58 | -------------------------------------------------------------------------------- /whale/src/base/macros.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_BASE_MACROS_H_ 2 | #define WHALE_BASE_MACROS_H_ 3 | 4 | #define DISALLOW_ALLOCATION() \ 5 | public: \ 6 | NO_RETURN ALWAYS_INLINE void operator delete(void*, size_t) { UNREACHABLE(); } \ 7 | ALWAYS_INLINE void* operator new(size_t, void* ptr) noexcept { return ptr; } \ 8 | ALWAYS_INLINE void operator delete(void*, void*) noexcept { } \ 9 | private: \ 10 | void* operator new(size_t) = delete // NOLINT 11 | 12 | #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ 13 | private: \ 14 | TypeName(); \ 15 | DISALLOW_COPY_AND_ASSIGN(TypeName) 16 | 17 | #define ALIGNED(x) __attribute__ ((__aligned__(x))) 18 | #define PACKED(x) __attribute__ ((__aligned__(x), __packed__)) 19 | 20 | #define OFFSETOF_MEMBER(t, f) offsetof(t, f) 21 | 22 | // Stringify the argument. 23 | #define QUOTE(x) #x 24 | #define STRINGIFY(x) QUOTE(x) 25 | 26 | #ifndef NDEBUG 27 | #define ALWAYS_INLINE 28 | #else 29 | #define ALWAYS_INLINE __attribute__ ((always_inline)) 30 | #endif 31 | 32 | // Define that a position within code is unreachable, for example: 33 | // int foo () { LOG(FATAL) << "Don't call me"; UNREACHABLE(); } 34 | // without the UNREACHABLE a return statement would be necessary. 35 | #define UNREACHABLE __builtin_unreachable 36 | 37 | #define LIKELY(x) __builtin_expect(!!(x), 1) 38 | #define UNLIKELY(x) __builtin_expect(!!(x), 0) 39 | 40 | #define NO_RETURN [[ noreturn ]] 41 | 42 | #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ 43 | TypeName(const TypeName&); \ 44 | void operator=(const TypeName&) 45 | 46 | #define OPTION __unused 47 | 48 | #define OPEN_API __attribute__((visibility("default"))) 49 | #define C_API extern "C" 50 | 51 | #endif // WHALE_BASE_MACROS_H_ 52 | -------------------------------------------------------------------------------- /whale/src/android/art/java_types.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ANDROID_ART_JAVA_TYPES_H_ 2 | #define WHALE_ANDROID_ART_JAVA_TYPES_H_ 3 | 4 | #include 5 | #include "android/art/art_runtime.h" 6 | 7 | 8 | namespace whale { 9 | namespace art { 10 | 11 | struct Types { 12 | #define LANG_ClASS(c) static jclass java_lang_##c; static jmethodID java_lang_##c##_init; static jmethodID java_value_##c; 13 | 14 | LANG_ClASS(Integer); 15 | LANG_ClASS(Long); 16 | LANG_ClASS(Float); 17 | LANG_ClASS(Double); 18 | LANG_ClASS(Byte); 19 | LANG_ClASS(Short); 20 | LANG_ClASS(Boolean); 21 | LANG_ClASS(Character); 22 | 23 | #undef LANG_ClASS 24 | static void Load(JNIEnv *env); 25 | 26 | 27 | #define LANG_BOX_DEF(c, t) static jobject To##c(JNIEnv *env, t v); 28 | 29 | #define LANG_UNBOX_V_DEF(k, c, t) static t From##c(JNIEnv *env, jobject j); 30 | 31 | #define LANG_UNBOX_DEF(c, t) LANG_UNBOX_V_DEF(c, c, t) 32 | 33 | LANG_BOX_DEF(Object, jobject); 34 | LANG_BOX_DEF(Integer, jint); 35 | LANG_BOX_DEF(Long, jlong); 36 | LANG_BOX_DEF(Float, jfloat); 37 | LANG_BOX_DEF(Double, jdouble); 38 | LANG_BOX_DEF(Byte, jbyte); 39 | LANG_BOX_DEF(Short, jshort); 40 | LANG_BOX_DEF(Boolean, jboolean); 41 | LANG_BOX_DEF(Character, jchar); 42 | 43 | LANG_UNBOX_V_DEF(Int, Integer, jint); 44 | LANG_UNBOX_DEF(Object, jobject); 45 | LANG_UNBOX_DEF(Long, jlong); 46 | LANG_UNBOX_DEF(Float, jfloat); 47 | LANG_UNBOX_DEF(Double, jdouble); 48 | LANG_UNBOX_DEF(Byte, jbyte); 49 | LANG_UNBOX_DEF(Short, jshort); 50 | LANG_UNBOX_DEF(Boolean, jboolean); 51 | LANG_UNBOX_V_DEF(Char, Character, jchar); 52 | 53 | #undef LANG_BOX_DEF 54 | #undef LANG_UNBOX_V_DEF 55 | #undef LANG_UNBOX_DEF 56 | }; 57 | 58 | } // namespace art 59 | } // namespace whale 60 | 61 | #endif // WHALE_ANDROID_ART_JAVA_TYPES_H_ 62 | -------------------------------------------------------------------------------- /whale/src/assembler/vixl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_CXX_STANDARD 14) 2 | 3 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -fdiagnostics-show-option -Wextra -Wredundant-decls -pedantic -Wwrite-strings -Wunused") 4 | 5 | add_definitions(-DVIXL_CODE_BUFFER_MALLOC) 6 | 7 | set(VIXL_SOURCES 8 | code-buffer-vixl.cc 9 | compiler-intrinsics-vixl.cc 10 | cpu-features.cc 11 | utils-vixl.cc) 12 | 13 | set(VIXL_AARCH32 14 | aarch32/assembler-aarch32.cc 15 | aarch32/constants-aarch32.cc 16 | aarch32/instructions-aarch32.cc 17 | aarch32/location-aarch32.cc 18 | aarch32/macro-assembler-aarch32.cc 19 | aarch32/operands-aarch32.cc 20 | ) 21 | 22 | set(VIXL_AARCH64 23 | aarch64/assembler-aarch64.cc 24 | aarch64/cpu-aarch64.cc 25 | aarch64/cpu-features-auditor-aarch64.cc 26 | aarch64/decoder-aarch64.cc 27 | aarch64/instructions-aarch64.cc 28 | aarch64/instrument-aarch64.cc 29 | aarch64/logic-aarch64.cc 30 | aarch64/macro-assembler-aarch64.cc 31 | aarch64/operands-aarch64.cc 32 | aarch64/pointer-auth-aarch64.cc 33 | aarch64/simulator-aarch64.cc 34 | ) 35 | 36 | 37 | if (ENABLE_SIMULATOR) 38 | add_definitions(-DVIXL_INCLUDE_SIMULATOR_AARCH64) 39 | set(VIXL_SOURCES ${VIXL_SOURCES} ${VIXL_AARCH32} ${VIXL_AARCH64}) 40 | endif () 41 | 42 | if (CMAKE_SYSTEM_PROCESSOR MATCHES "^arm") 43 | add_definitions("-DVIXL_INCLUDE_TARGET_A32") 44 | add_definitions("-DVIXL_INCLUDE_TARGET_T32") 45 | set(VIXL_SOURCES ${VIXL_SOURCES} ${VIXL_AARCH32}) 46 | elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64") 47 | set(VIXL_SOURCES ${VIXL_SOURCES} ${VIXL_AARCH64}) 48 | endif () 49 | 50 | if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm|aarch64)") 51 | add_library(vixl ${VIXL_SOURCES}) 52 | endif () 53 | -------------------------------------------------------------------------------- /whale/test/test_emulator.cc: -------------------------------------------------------------------------------- 1 | #include "base/logging.h" 2 | #include "dbi/arm64/inline_hook_arm64.h" 3 | #include "simulator/code_simulator_container.h" 4 | #include "simulator/code_simulator.h" 5 | #include "vixl/aarch64/macro-assembler-aarch64.h" 6 | #include "dbi/arm/decoder_arm.h" 7 | 8 | using namespace whale; //NOLINT 9 | using namespace whale::arm; //NOLINT 10 | using namespace whale::arm64; //NOLINT 11 | using namespace vixl::aarch64; //NOLINT 12 | 13 | #define __ masm-> 14 | 15 | void GenerateOriginFunction(MacroAssembler *masm) { 16 | Label label, label2; 17 | __ Mov(x1, 0); 18 | __ Cbz(x1, &label); 19 | __ Mov(x0, 111); 20 | __ B(&label2); 21 | __ Bind(&label); 22 | __ Mov(x0, 222); 23 | __ Bind(&label2); 24 | __ Ret(); 25 | masm->FinalizeCode(); 26 | } 27 | 28 | void GenerateReplaceFunction(MacroAssembler *masm) { 29 | __ Mov(x0, 999); 30 | __ Ret(); 31 | masm->FinalizeCode(); 32 | } 33 | 34 | 35 | int main() { 36 | CodeSimulatorContainer emulator(InstructionSet::kArm64); 37 | MacroAssembler masm_origin, masm_replace; 38 | GenerateOriginFunction(&masm_origin); 39 | GenerateReplaceFunction(&masm_replace); 40 | 41 | auto target = masm_origin.GetBuffer()->GetStartAddress(); 42 | auto replace = masm_replace.GetBuffer()->GetStartAddress(); 43 | emulator.Get()->RunFrom(target); 44 | LOG(INFO) << "Before Hook, result: "<< emulator.Get()->GetCReturnInt32(); 45 | intptr_t origin; 46 | Arm64InlineHook hook(target, reinterpret_cast(replace), &origin); 47 | hook.StartHook(); 48 | emulator.Get()->RunFrom(replace); 49 | LOG(INFO) << "After Hook, hooked result:"<< emulator.Get()->GetCReturnInt32(); 50 | emulator.Get()->RunFrom(origin); 51 | LOG(INFO) << "After Hook: origin result:"<< emulator.Get()->GetCReturnInt32(); 52 | } 53 | -------------------------------------------------------------------------------- /whale/src/dbi/arm64/instruction_rewriter_arm64.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_REWRITER_ARM64_H_ 2 | #define ARCH_REWRITER_ARM64_H_ 3 | 4 | #include "assembler/vixl/aarch64/macro-assembler-aarch64.h" 5 | #include "dbi/backup_code.h" 6 | #include "dbi/instruction_rewriter.h" 7 | #include "dbi/instruction_set.h" 8 | #include "base/primitive_types.h" 9 | #include "base/macros.h" 10 | 11 | namespace whale { 12 | namespace arm64 { 13 | 14 | class Arm64InstructionRewriter : public InstructionReWriter { 15 | public: 16 | Arm64InstructionRewriter(vixl::aarch64::MacroAssembler *masm, BackupCode *code, 17 | u8 origin_pc, u8 tail_pc) 18 | : masm_(masm), code_(code), cfg_pc_(origin_pc), tail_pc_(tail_pc) {} 19 | 20 | ~Arm64InstructionRewriter() = default; 21 | 22 | const InstructionSet GetISA() override { 23 | return InstructionSet::kArm64; 24 | } 25 | 26 | void Rewrite() override; 27 | 28 | ALWAYS_INLINE u4 *GetStartAddress() override { 29 | return masm_->GetBuffer()->GetStartAddress(); 30 | } 31 | 32 | ALWAYS_INLINE size_t GetCodeSize() override { 33 | return masm_->GetBuffer()->GetSizeInBytes(); 34 | } 35 | 36 | private: 37 | const u8 cfg_pc_; 38 | const u8 tail_pc_; 39 | vixl::aarch64::MacroAssembler *masm_; 40 | BackupCode *code_; 41 | 42 | ALWAYS_INLINE void EmitCode(u4 insn) { 43 | masm_->GetBuffer()->Emit32(insn); 44 | } 45 | 46 | void RewriteADR_ADRP(u8 pc, u4 insn); 47 | 48 | void RewriteB_BL(u8 pc, u4 insn); 49 | 50 | void RewriteCBZ_CBNZ(u8 pc, u4 insn); 51 | 52 | void RewriteB_COND(u8 pc, u4 insn); 53 | 54 | void RewriteTBZ_TBNZ(u8 pc, u4 insn); 55 | 56 | void RewriteLDR_LIT(u8 pc, u4 insn); 57 | }; 58 | 59 | 60 | } // namespace arm64 61 | } // namespace whale 62 | 63 | 64 | #endif // ARCH_REWRITER_ARM64_H_ 65 | 66 | 67 | -------------------------------------------------------------------------------- /whale/src/android/jni_helper.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ANDROID_ART_JNI_HELPER_H_ 2 | #define WHALE_ANDROID_ART_JNI_HELPER_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define NATIVE_METHOD(className, functionName, signature) \ 8 | { #functionName, signature, reinterpret_cast(className ## _ ## functionName) } 9 | 10 | #define NELEM(x) (sizeof(x)/sizeof((x)[0])) 11 | 12 | #define JNI_START JNIEnv *env, jclass cl 13 | 14 | static inline void JNIExceptionClear(JNIEnv *env) { 15 | if (env->ExceptionCheck()) { 16 | env->ExceptionClear(); 17 | } 18 | } 19 | 20 | static inline bool JNIExceptionCheck(JNIEnv *env) { 21 | if (env->ExceptionCheck()) { 22 | jthrowable e = env->ExceptionOccurred(); 23 | env->Throw(e); 24 | env->DeleteLocalRef(e); 25 | return true; 26 | } 27 | return false; 28 | } 29 | 30 | static inline void JNIExceptionClearAndDescribe(JNIEnv *env) { 31 | if (env->ExceptionCheck()) { 32 | env->ExceptionDescribe(); 33 | env->ExceptionClear(); 34 | } 35 | } 36 | 37 | template 38 | class ScopedLocalRef { 39 | public: 40 | ScopedLocalRef(JNIEnv *env, T localRef) : mEnv(env), mLocalRef(localRef) { 41 | } 42 | 43 | ~ScopedLocalRef() { 44 | reset(); 45 | } 46 | 47 | void reset(T ptr = nullptr) { 48 | if (ptr != mLocalRef) { 49 | if (mLocalRef != nullptr) { 50 | mEnv->DeleteLocalRef(mLocalRef); 51 | } 52 | mLocalRef = ptr; 53 | } 54 | } 55 | 56 | T release() { 57 | T localRef = mLocalRef; 58 | mLocalRef = nullptr; 59 | return localRef; 60 | } 61 | 62 | T get() const { 63 | return mLocalRef; 64 | } 65 | 66 | private: 67 | JNIEnv *const mEnv; 68 | T mLocalRef; 69 | 70 | DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef); 71 | }; 72 | 73 | #endif // WHALE_ANDROID_ART_JNI_HELPER_H_ 74 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/instruction_rewriter_x86.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_X86_REWRITER_X86_H_ 2 | #define ARCH_X86_REWRITER_X86_H_ 3 | 4 | #include 5 | #include "assembler/x86/assembler_x86.h" 6 | #include "base/primitive_types.h" 7 | #include "dbi/backup_code.h" 8 | #include "dbi/instruction_rewriter.h" 9 | #include "dbi/instruction_set.h" 10 | #include "base/macros.h" 11 | 12 | namespace whale { 13 | namespace x86 { 14 | 15 | class X86InstructionRewriter : public InstructionReWriter { 16 | public: 17 | X86InstructionRewriter(whale::x86::X86Assembler *masm, BackupCode *code, 18 | u4 origin_pc, u4 tail_pc) 19 | : masm_(masm), code_(code), cfg_pc_(origin_pc), tail_pc_(tail_pc) {} 20 | 21 | ~X86InstructionRewriter() = default; 22 | 23 | const InstructionSet GetISA() override { 24 | return InstructionSet::kX86; 25 | } 26 | 27 | void Rewrite() override; 28 | 29 | u1 *GetStartAddress() override { 30 | return masm_->GetBuffer()->contents(); 31 | } 32 | 33 | size_t GetCodeSize() override { 34 | return masm_->GetBuffer()->Size(); 35 | } 36 | 37 | void EmitCode(u1 *start, size_t size) { 38 | for (int i = 0; i < size; ++i) { 39 | AssemblerBuffer::EnsureCapacity ensured(masm_->GetBuffer()); 40 | masm_->GetBuffer()->Emit(start[i]); 41 | } 42 | } 43 | 44 | private: 45 | const u4 cfg_pc_; 46 | const u4 tail_pc_; 47 | whale::x86::X86Assembler *masm_; 48 | BackupCode *code_; 49 | 50 | void Rewrite_Call(u1 *current, u4 pc, _DInst insn); 51 | 52 | bool IsGetPCThunkToRegister(u4 address, Register *reg); 53 | 54 | void Rewrite_Jmp(u1 *current, u4 pc, _DInst insn); 55 | 56 | void Rewrite_JRCXZ(u1 *current, u4 pc, _DInst insn); 57 | }; 58 | 59 | 60 | } // namespace arm64 61 | } // namespace whale 62 | 63 | 64 | #endif // ARCH_X86_REWRITER_X86_H_ 65 | 66 | 67 | -------------------------------------------------------------------------------- /whale/src/assembler/vixl/platform-vixl.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014, VIXL authors 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // * Redistributions of source code must retain the above copyright notice, 8 | // this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, 10 | // this list of conditions and the following disclaimer in the documentation 11 | // and/or other materials provided with the distribution. 12 | // * Neither the name of ARM Limited nor the names of its contributors may be 13 | // used to endorse or promote products derived from this software without 14 | // specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | #ifndef PLATFORM_H 28 | #define PLATFORM_H 29 | 30 | // Define platform specific functionalities. 31 | extern "C" { 32 | #include 33 | } 34 | 35 | namespace vixl { 36 | inline void HostBreakpoint() { raise(SIGINT); } 37 | } // namespace vixl 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /whale/src/dbi/x86_64/instruction_rewriter_x86_64.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_X86_64_REWRITER_X86_64_H_ 2 | #define ARCH_X86_64_REWRITER_X86_64_H_ 3 | 4 | #include 5 | #include "assembler/x86_64/assembler_x86_64.h" 6 | #include "base/primitive_types.h" 7 | #include "dbi/backup_code.h" 8 | #include "dbi/instruction_rewriter.h" 9 | #include "dbi/instruction_set.h" 10 | #include "base/macros.h" 11 | 12 | namespace whale { 13 | namespace x86_64 { 14 | 15 | class X86_64InstructionRewriter : public InstructionReWriter { 16 | public: 17 | X86_64InstructionRewriter(X86_64Assembler *masm, BackupCode *code, 18 | u8 origin_pc, u8 tail_pc) 19 | : masm_(masm), code_(code), cfg_pc_(origin_pc), tail_pc_(tail_pc) {} 20 | 21 | ~X86_64InstructionRewriter() = default; 22 | 23 | const InstructionSet GetISA() override { 24 | return InstructionSet::kX86_64; 25 | } 26 | 27 | void Rewrite() override; 28 | 29 | u1 *GetStartAddress() override { 30 | return masm_->GetBuffer()->contents(); 31 | } 32 | 33 | size_t GetCodeSize() override { 34 | return masm_->GetBuffer()->Size(); 35 | } 36 | 37 | void EmitCode(u1 *start, size_t size) { 38 | for (int i = 0; i < size; ++i) { 39 | AssemblerBuffer::EnsureCapacity ensured(masm_->GetBuffer()); 40 | masm_->GetBuffer()->Emit(start[i]); 41 | } 42 | } 43 | 44 | private: 45 | const u8 cfg_pc_; 46 | const u8 tail_pc_; 47 | X86_64Assembler *masm_; 48 | BackupCode *code_; 49 | 50 | void Rewrite_Mov(u1 *current, u8 pc, _DInst insn); 51 | 52 | void Rewrite_Call(u1 *current, u8 pc, _DInst insn); 53 | 54 | void Rewrite_Jmp(u1 *current, u8 pc, _DInst insn); 55 | 56 | void Rewrite_JRCXZ(u1 *current, u8 pc, _DInst insn); 57 | }; 58 | 59 | 60 | } // namespace arm64 61 | } // namespace whale 62 | 63 | 64 | #endif // ARCH_X86_64_REWRITER_X86_64_H_ 65 | 66 | 67 | -------------------------------------------------------------------------------- /whale/src/assembler/assembler.cc: -------------------------------------------------------------------------------- 1 | #include "assembler/assembler.h" 2 | 3 | namespace whale { 4 | 5 | 6 | AssemblerBuffer::AssemblerBuffer() { 7 | static const size_t kInitialBufferCapacity = 4 * KB; 8 | contents_ = reinterpret_cast(malloc(kInitialBufferCapacity)); 9 | cursor_ = contents_; 10 | limit_ = ComputeLimit(contents_, kInitialBufferCapacity); 11 | fixup_ = nullptr; 12 | slow_path_ = nullptr; 13 | has_ensured_capacity_ = false; 14 | fixups_processed_ = false; 15 | // Verify internal state. 16 | CHECK_EQ(Capacity(), kInitialBufferCapacity); 17 | CHECK_EQ(Size(), 0U); 18 | } 19 | 20 | 21 | AssemblerBuffer::~AssemblerBuffer() { 22 | free(contents_); 23 | } 24 | 25 | 26 | void AssemblerBuffer::ProcessFixups(const MemoryRegion ®ion) { 27 | AssemblerFixup *fixup = fixup_; 28 | while (fixup != nullptr) { 29 | fixup->Process(region, fixup->position()); 30 | fixup = fixup->previous(); 31 | } 32 | } 33 | 34 | 35 | void AssemblerBuffer::FinalizeInstructions(const MemoryRegion &instructions) { 36 | // Copy the instructions from the buffer. 37 | MemoryRegion from(reinterpret_cast(contents()), Size()); 38 | instructions.CopyFrom(0, from); 39 | // Process fixups in the instructions. 40 | ProcessFixups(instructions); 41 | fixups_processed_ = true; 42 | } 43 | 44 | 45 | void AssemblerBuffer::ExtendCapacity(size_t min_capacity) { 46 | size_t old_size = Size(); 47 | size_t old_capacity = Capacity(); 48 | DCHECK_GT(min_capacity, old_capacity); 49 | size_t new_capacity = std::min(old_capacity * 2, old_capacity + 1 * MB); 50 | new_capacity = std::max(new_capacity, min_capacity); 51 | 52 | // Allocate the new data area and copy contents of the old one to it. 53 | contents_ = reinterpret_cast(realloc(contents_, new_capacity)); 54 | 55 | // Update the cursor and recompute the limit. 56 | cursor_ = contents_ + old_size; 57 | limit_ = ComputeLimit(contents_, new_capacity); 58 | 59 | // Verify internal state. 60 | CHECK_EQ(Capacity(), new_capacity); 61 | CHECK_EQ(Size(), old_size); 62 | } 63 | 64 | } // namespace whale 65 | -------------------------------------------------------------------------------- /whale/src/libffi/ffi_cfi.h: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | ffi_cfi.h - Copyright (c) 2014 Red Hat, Inc. 3 | 4 | Conditionally assemble cfi directives. Only necessary for building libffi. 5 | ----------------------------------------------------------------------- */ 6 | 7 | #ifndef FFI_CFI_H 8 | #define FFI_CFI_H 9 | 10 | #ifdef HAVE_AS_CFI_PSEUDO_OP 11 | 12 | # define cfi_startproc .cfi_startproc 13 | # define cfi_endproc .cfi_endproc 14 | # define cfi_def_cfa(reg, off) .cfi_def_cfa reg, off 15 | # define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg 16 | # define cfi_def_cfa_offset(off) .cfi_def_cfa_offset off 17 | # define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off 18 | # define cfi_offset(reg, off) .cfi_offset reg, off 19 | # define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off 20 | # define cfi_register(r1, r2) .cfi_register r1, r2 21 | # define cfi_return_column(reg) .cfi_return_column reg 22 | # define cfi_restore(reg) .cfi_restore reg 23 | # define cfi_same_value(reg) .cfi_same_value reg 24 | # define cfi_undefined(reg) .cfi_undefined reg 25 | # define cfi_remember_state .cfi_remember_state 26 | # define cfi_restore_state .cfi_restore_state 27 | # define cfi_window_save .cfi_window_save 28 | # define cfi_personality(enc, exp) .cfi_personality enc, exp 29 | # define cfi_lsda(enc, exp) .cfi_lsda enc, exp 30 | # define cfi_escape(...) .cfi_escape __VA_ARGS__ 31 | 32 | #else 33 | 34 | # define cfi_startproc 35 | # define cfi_endproc 36 | # define cfi_def_cfa(reg, off) 37 | # define cfi_def_cfa_register(reg) 38 | # define cfi_def_cfa_offset(off) 39 | # define cfi_adjust_cfa_offset(off) 40 | # define cfi_offset(reg, off) 41 | # define cfi_rel_offset(reg, off) 42 | # define cfi_register(r1, r2) 43 | # define cfi_return_column(reg) 44 | # define cfi_restore(reg) 45 | # define cfi_same_value(reg) 46 | # define cfi_undefined(reg) 47 | # define cfi_remember_state 48 | # define cfi_restore_state 49 | # define cfi_window_save 50 | # define cfi_personality(enc, exp) 51 | # define cfi_lsda(enc, exp) 52 | # define cfi_escape(...) 53 | 54 | #endif /* HAVE_AS_CFI_PSEUDO_OP */ 55 | #endif /* FFI_CFI_H */ 56 | -------------------------------------------------------------------------------- /whale/src/assembler/x86_64/managed_register_x86_64.cc: -------------------------------------------------------------------------------- 1 | #include "assembler/x86_64/managed_register_x86_64.h" 2 | 3 | namespace whale { 4 | namespace x86_64 { 5 | 6 | // Define register pairs. 7 | // This list must be kept in sync with the RegisterPair enum. 8 | #define REGISTER_PAIR_LIST(P) \ 9 | P(RAX, RDX) \ 10 | P(RAX, RCX) \ 11 | P(RAX, RBX) \ 12 | P(RAX, RDI) \ 13 | P(RDX, RCX) \ 14 | P(RDX, RBX) \ 15 | P(RDX, RDI) \ 16 | P(RCX, RBX) \ 17 | P(RCX, RDI) \ 18 | P(RBX, RDI) 19 | 20 | 21 | struct RegisterPairDescriptor { 22 | RegisterPair reg; // Used to verify that the enum is in sync. 23 | Register low; 24 | Register high; 25 | }; 26 | 27 | 28 | static const RegisterPairDescriptor kRegisterPairs[] = { 29 | #define REGISTER_PAIR_ENUMERATION(low, high) { low##_##high, low, high }, 30 | REGISTER_PAIR_LIST(REGISTER_PAIR_ENUMERATION) 31 | #undef REGISTER_PAIR_ENUMERATION 32 | }; 33 | 34 | 35 | bool X86_64ManagedRegister::Overlaps(const X86_64ManagedRegister &other) const { 36 | if (IsNoRegister() || other.IsNoRegister()) return false; 37 | if (Equals(other)) return true; 38 | if (IsRegisterPair()) { 39 | Register low = AsRegisterPairLow().AsRegister(); 40 | Register high = AsRegisterPairHigh().AsRegister(); 41 | return X86_64ManagedRegister::FromCpuRegister(low).Overlaps(other) || 42 | X86_64ManagedRegister::FromCpuRegister(high).Overlaps(other); 43 | } 44 | if (other.IsRegisterPair()) { 45 | return other.Overlaps(*this); 46 | } 47 | return false; 48 | } 49 | 50 | 51 | int X86_64ManagedRegister::AllocIdLow() const { 52 | const int r = RegId() - (kNumberOfCpuRegIds + kNumberOfXmmRegIds + 53 | kNumberOfX87RegIds); 54 | return kRegisterPairs[r].low; 55 | } 56 | 57 | 58 | int X86_64ManagedRegister::AllocIdHigh() const { 59 | const int r = RegId() - (kNumberOfCpuRegIds + kNumberOfXmmRegIds + 60 | kNumberOfX87RegIds); 61 | return kRegisterPairs[r].high; 62 | } 63 | 64 | 65 | } // namespace x86_64 66 | } // namespace whale 67 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/distorm/insts.h: -------------------------------------------------------------------------------- 1 | /* 2 | insts.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2018 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef INSTS_H 13 | #define INSTS_H 14 | 15 | #include "instructions.h" 16 | 17 | 18 | /* Flags Table */ 19 | extern _iflags FlagsTable[]; 20 | 21 | /* Root Trie DB */ 22 | extern _InstSharedInfo InstSharedInfoTable[]; 23 | extern _InstInfo InstInfos[]; 24 | extern _InstInfoEx InstInfosEx[]; 25 | extern _InstNode InstructionsTree[]; 26 | 27 | /* 3DNow! Trie DB */ 28 | extern _InstNode Table_0F_0F; 29 | /* AVX related: */ 30 | extern _InstNode Table_0F, Table_0F_38, Table_0F_3A; 31 | 32 | /* 33 | * The inst_lookup will return on of these two instructions according to the specified decoding mode. 34 | * ARPL or MOVSXD on 64 bits is one byte instruction at index 0x63. 35 | */ 36 | extern _InstInfo II_MOVSXD; 37 | 38 | /* 39 | * The NOP instruction can be prefixed by REX in 64bits, therefore we have to decide in runtime whether it's an XCHG or NOP instruction. 40 | * If 0x90 is prefixed by a usable REX it will become XCHG, otherwise it will become a NOP. 41 | * Also note that if it's prefixed by 0xf3, it becomes a Pause. 42 | */ 43 | extern _InstInfo II_NOP; 44 | extern _InstInfo II_PAUSE; 45 | 46 | /* 47 | * RDRAND and VMPTRLD share same 2.3 bytes opcode, and then alternates on the MOD bits, 48 | * RDRAND is OT_FULL_REG while VMPTRLD is OT_MEM, and there's no such mixed type. 49 | * So a hack into the inst_lookup was added for this decision, the DB isn't flexible enough. :( 50 | */ 51 | extern _InstInfo II_RDRAND; 52 | 53 | /* 54 | * Used for letting the extract operand know the type of operands without knowing the 55 | * instruction itself yet, because of the way those instructions work. 56 | * See function instructions.c!inst_lookup_3dnow. 57 | */ 58 | extern _InstInfo II_3DNOW; 59 | 60 | /* Helper tables for pseudo compare mnemonics. */ 61 | extern uint16_t CmpMnemonicOffsets[8]; /* SSE */ 62 | extern uint16_t VCmpMnemonicOffsets[32]; /* AVX */ 63 | 64 | #endif /* INSTS_H */ 65 | -------------------------------------------------------------------------------- /whale/src/assembler/x86/managed_register_x86.cc: -------------------------------------------------------------------------------- 1 | #include "assembler/x86/managed_register_x86.h" 2 | 3 | namespace whale { 4 | namespace x86 { 5 | 6 | // Define register pairs. 7 | // This list must be kept in sync with the RegisterPair enum. 8 | #define REGISTER_PAIR_LIST(P) \ 9 | P(EAX, EDX) \ 10 | P(EAX, ECX) \ 11 | P(EAX, EBX) \ 12 | P(EAX, EDI) \ 13 | P(EDX, ECX) \ 14 | P(EDX, EBX) \ 15 | P(EDX, EDI) \ 16 | P(ECX, EBX) \ 17 | P(ECX, EDI) \ 18 | P(EBX, EDI) \ 19 | P(ECX, EDX) 20 | 21 | 22 | struct RegisterPairDescriptor { 23 | RegisterPair reg; // Used to verify that the enum is in sync. 24 | Register low; 25 | Register high; 26 | }; 27 | 28 | 29 | static const RegisterPairDescriptor kRegisterPairs[] = { 30 | #define REGISTER_PAIR_ENUMERATION(low, high) { low##_##high, low, high }, 31 | REGISTER_PAIR_LIST(REGISTER_PAIR_ENUMERATION) 32 | #undef REGISTER_PAIR_ENUMERATION 33 | }; 34 | 35 | 36 | bool X86ManagedRegister::Overlaps(const X86ManagedRegister &other) const { 37 | if (IsNoRegister() || other.IsNoRegister()) return false; 38 | CHECK(IsValidManagedRegister()); 39 | CHECK(other.IsValidManagedRegister()); 40 | if (Equals(other)) return true; 41 | if (IsRegisterPair()) { 42 | Register low = AsRegisterPairLow(); 43 | Register high = AsRegisterPairHigh(); 44 | return X86ManagedRegister::FromCpuRegister(low).Overlaps(other) || 45 | X86ManagedRegister::FromCpuRegister(high).Overlaps(other); 46 | } 47 | if (other.IsRegisterPair()) { 48 | return other.Overlaps(*this); 49 | } 50 | return false; 51 | } 52 | 53 | 54 | int X86ManagedRegister::AllocIdLow() const { 55 | const int r = RegId() - (kNumberOfCpuRegIds + kNumberOfXmmRegIds + 56 | kNumberOfX87RegIds); 57 | return kRegisterPairs[r].low; 58 | } 59 | 60 | 61 | int X86ManagedRegister::AllocIdHigh() const { 62 | const int r = RegId() - (kNumberOfCpuRegIds + kNumberOfXmmRegIds + 63 | kNumberOfX87RegIds); 64 | return kRegisterPairs[r].high; 65 | } 66 | 67 | 68 | } // namespace x86 69 | } // namespace whale 70 | -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # Whale 2 | ![logo][0] 3 | 4 | ## 概述 5 | Whale是一个跨平台的Hook Framework,同时支持Android、IOS、Linux、MacOS。 6 | Whale 支持**ARM/THUMB、ARM64、X86、X86_64 (AMD64)**,这几乎覆盖了目前所有主流的设备。 7 | 8 | ## 特性 9 | #### Android 10 | * **Xposed-Style** Method Hook 11 | * 运行时修改类之间的继承关系 12 | * 修改对象所属的类 13 | * 绕过`Hidden API Policy` 14 | 15 | #### Darwin/Linux Platforms 16 | * Internal symbol resolver 17 | * Native Hook 18 | 19 | #### IOS的限制 20 | IOS的InlineHook在非越狱设备上只限在debug编译模式下开启, 21 | release编译模式下将无法正常工作。 22 | 23 | 为了解决这个问题,Whale将提供`Binary Static Inline Hook`。 24 | 25 | IOS下的`Binary Static Inline Hook`将在近期开源。 26 | 27 | 28 | ## 你可以用它做什么? 29 | * 开启App的上帝模式 30 | * 监控或篡改软件的行为 31 | * 即时生效的热修复 32 | * SandBox 33 | * 注入到系统代替Xposed 34 | 35 | ## Whale的兼容性 36 | - [x] Android 5.0.0 37 | - [x] Android 5.1.1 38 | - [x] Android 6.0 39 | - [x] Android 6.0.1 40 | - [x] Android 7.1.2 41 | - [x] Android 8.1.0 42 | - [x] Android 9.0.0 43 | - [x] IOS 11.3 44 | - [x] IOS 12.0 45 | - [x] MacOS mojave (10.14) 46 | - (不在清单内表示 `未测试` ) 47 | 48 | ## InlineHook 49 | 对于`pcrel指令`, Whale会将其转换为`pc 无关指令`, 50 | 如果在Hook过程有遇到未转换的指令,请提`issue`。 51 | 52 | ## 关于Jit 53 | Whale内置了 **Jit Engine**, 当你有更高级的Hook需求时可以通过Jit直接在内存中生成可执行的指令。 54 | 不再需要像从前那样通过工具来生成丑陋的hard code。 55 | 56 | ## 编译 57 | 我们已提前编译了Android & IOS的**二进制版本**,您可以在`built目录`找到它们。 58 | 59 | Whale使用了CMake来构建项目,所以你需要在你的系统上安装CMake。 60 | 61 | #### Android 62 | 1. 如果需要使用`Java Hook`, 请把java文件夹的代码复制到你的项目。 63 | 64 | 2. 直接使用二进制,你只需要复制 `built/Android` 下你所需的abi到你的项目的src/main/jniLibs下。 65 | 66 | 3. 如果需要编译源码,请在build.gradle中指定CMakelists.txt: 67 | ``` 68 | externalNativeBuild { 69 | cmake { 70 | path "your/whale/path/CMakeLists.txt" 71 | } 72 | } 73 | ``` 74 | 75 | #### IOS 76 | ``` 77 | cd toolchain 78 | 79 | cmake .. \ 80 | -DCMAKE_TOOLCHAIN_FILE=ios.toolchain.cmake \ 81 | -DIOS_PLATFORM=OS64 \ 82 | -DPLATFORM=IOS \ 83 | -DIOS_ARCH=arm64 \ 84 | -DENABLE_ARC=0 \ 85 | -DENABLE_BITCODE=0 \ 86 | -DENABLE_VISIBILITY=0 \ 87 | -DIOS_DEPLOYMENT_TARGET=9.3 \ 88 | -DSHARED=ON \ 89 | -DCMAKE_BUILD_TYPE=Release 90 | 91 | make -j4 92 | ``` 93 | 94 | #### Ohter platforms 95 | ``` 96 | cmake . 97 | make -j8 98 | ``` 99 | 100 | ## Technogy communication 101 | > **QQ Group: 977793836** 102 | 103 | 104 | 105 | [0]: https://github.com/asLody/whale/blob/master/LOGO.png?raw=true 106 | -------------------------------------------------------------------------------- /whale/src/libffi/ffi_cxx.cc: -------------------------------------------------------------------------------- 1 | #include "ffi_cxx.h" 2 | 3 | FFICallInterface::~FFICallInterface() { 4 | for (FFIClosure *closure : closures_) { 5 | delete closure; 6 | } 7 | delete cif_; 8 | delete types_; 9 | } 10 | 11 | 12 | void FFIDispatcher(ffi_cif *cif OPTION, void *ret, void **args, void *userdata) { 13 | FFIClosure *closure = reinterpret_cast(userdata); 14 | FFICallback callback = closure->GetCallback(); 15 | callback(closure, ret, args, closure->GetUserData()); 16 | } 17 | 18 | 19 | FFIClosure *FFICallInterface::CreateClosure(void *userdata, FFICallback callback) { 20 | std::lock_guard guard(lock_); 21 | FFIClosure *closure = new FFIClosure(this, userdata, callback); 22 | ffi_prep_closure_loc(closure->closure_, cif_, FFIDispatcher, closure, closure->code_); 23 | closures_.push_back(closure); 24 | return closure; 25 | } 26 | 27 | static ffi_type *FFIGetCType(FFIType type) { 28 | switch (type) { 29 | case FFIType::kFFITypeVoid: 30 | return &ffi_type_void; 31 | case FFIType::kFFITypeU1: 32 | return &ffi_type_uint8; 33 | case FFIType::kFFITypeU2: 34 | return &ffi_type_uint16; 35 | case FFIType::kFFITypeU4: 36 | return &ffi_type_uint32; 37 | case FFIType::kFFITypeU8: 38 | return &ffi_type_uint64; 39 | case FFIType::kFFITypeS1: 40 | return &ffi_type_sint8; 41 | case FFIType::kFFITypeS2: 42 | return &ffi_type_sint16; 43 | case FFIType::kFFITypeS4: 44 | return &ffi_type_sint32; 45 | case FFIType::kFFITypeS8: 46 | return &ffi_type_sint64; 47 | case FFIType::kFFITypePointer: 48 | return &ffi_type_pointer; 49 | case FFIType::kFFITypeFloat: 50 | return &ffi_type_float; 51 | case FFIType::kFFITypeDouble: 52 | return &ffi_type_double; 53 | } 54 | } 55 | 56 | FFICallInterface *FFICallInterface::FinalizeCif() { 57 | cif_ = new ffi_cif; 58 | types_ = new ffi_type *[parameters_.size()]; 59 | int idx = 0; 60 | for (FFIType type : parameters_) { 61 | types_[idx] = FFIGetCType(type); 62 | idx++; 63 | } 64 | ffi_prep_cif(cif_, FFI_DEFAULT_ABI, 65 | (unsigned int) parameters_.size(), FFIGetCType(return_type_), types_); 66 | return this; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /whale/src/assembler/x86/constants_x86.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ASSEMBLER_CONSTANTS_X86_H_ 2 | #define WHALE_ASSEMBLER_CONSTANTS_X86_H_ 3 | 4 | #include 5 | #include "base/macros.h" 6 | 7 | namespace whale { 8 | namespace x86 { 9 | 10 | 11 | enum ByteRegister { 12 | AL = 0, 13 | CL = 1, 14 | DL = 2, 15 | BL = 3, 16 | AH = 4, 17 | CH = 5, 18 | DH = 6, 19 | BH = 7, 20 | kNoByteRegister = -1 // Signals an illegal register. 21 | }; 22 | 23 | enum X87Register { 24 | ST0 = 0, 25 | ST1 = 1, 26 | ST2 = 2, 27 | ST3 = 3, 28 | ST4 = 4, 29 | ST5 = 5, 30 | ST6 = 6, 31 | ST7 = 7, 32 | kNumberOfX87Registers = 8, 33 | kNoX87Register = -1 // Signals an illegal register. 34 | }; 35 | 36 | enum ScaleFactor { 37 | TIMES_1 = 0, 38 | TIMES_2 = 1, 39 | TIMES_4 = 2, 40 | TIMES_8 = 3 41 | }; 42 | 43 | enum Condition { 44 | kOverflow = 0, 45 | kNoOverflow = 1, 46 | kBelow = 2, 47 | kAboveEqual = 3, 48 | kEqual = 4, 49 | kNotEqual = 5, 50 | kBelowEqual = 6, 51 | kAbove = 7, 52 | kSign = 8, 53 | kNotSign = 9, 54 | kParityEven = 10, 55 | kParityOdd = 11, 56 | kLess = 12, 57 | kGreaterEqual = 13, 58 | kLessEqual = 14, 59 | kGreater = 15, 60 | 61 | kZero = kEqual, 62 | kNotZero = kNotEqual, 63 | kNegative = kSign, 64 | kPositive = kNotSign, 65 | kCarrySet = kBelow, 66 | kCarryClear = kAboveEqual, 67 | kUnordered = kParityEven 68 | }; 69 | 70 | 71 | class Instr { 72 | public: 73 | static const uint8_t kHltInstruction = 0xF4; 74 | // We prefer not to use the int3 instruction since it conflicts with gdb. 75 | static const uint8_t kBreakPointInstruction = kHltInstruction; 76 | 77 | bool IsBreakPoint() { 78 | return (*reinterpret_cast(this)) == kBreakPointInstruction; 79 | } 80 | 81 | // Instructions are read out of a code stream. The only way to get a 82 | // reference to an instruction is to convert a pointer. There is no way 83 | // to allocate or create instances of class Instr. 84 | // Use the At(pc) function to create references to Instr. 85 | static Instr *At(uintptr_t pc) { return reinterpret_cast(pc); } 86 | 87 | private: 88 | DISALLOW_IMPLICIT_CONSTRUCTORS(Instr); 89 | }; 90 | 91 | } // namespace x86 92 | } // namespace whale 93 | 94 | #endif // WHALE_ASSEMBLER_CONSTANTS_X86_H_ 95 | -------------------------------------------------------------------------------- /whale/src/dbi/arm64/inline_hook_arm64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "platform/memory.h" 3 | #include "dbi/arm64/inline_hook_arm64.h" 4 | #include "dbi/arm64/registers_arm64.h" 5 | #include "dbi/arm64/instruction_rewriter_arm64.h" 6 | #include "assembler/vixl/aarch64/macro-assembler-aarch64.h" 7 | #include "base/align.h" 8 | #include "base/logging.h" 9 | 10 | #define __ masm. 11 | 12 | namespace whale { 13 | namespace arm64 { 14 | 15 | using namespace vixl::aarch64; // NOLINT 16 | 17 | 18 | void Arm64InlineHook::StartHook() { 19 | DCHECK(address_ != 0 && replace_ != 0); 20 | MacroAssembler masm; 21 | 22 | __ Mov(xTarget, GetReplaceAddress()); 23 | __ Br(xTarget); 24 | 25 | masm.FinalizeCode(); 26 | 27 | size_t backup_size = masm.GetSizeOfCodeGenerated(); 28 | backup_code_ = new BackupCode(GetTarget(), backup_size); 29 | 30 | if (backup_ != nullptr) { 31 | intptr_t tail = address_ + backup_size; 32 | intptr_t trampoline = BuildTrampoline(static_cast(tail)); 33 | *backup_ = trampoline; 34 | } 35 | 36 | ScopedMemoryPatch patch( 37 | GetTarget(), 38 | masm.GetBuffer()->GetStartAddress(), 39 | backup_size 40 | ); 41 | } 42 | 43 | intptr_t 44 | Arm64InlineHook::BuildTrampoline(u8 tail) { 45 | MacroAssembler masm; 46 | 47 | Arm64InstructionRewriter rewriter(&masm, backup_code_, GetTarget(), tail); 48 | rewriter.Rewrite(); 49 | 50 | __ Mov(xTarget, tail); 51 | __ Br(xTarget); 52 | 53 | masm.FinalizeCode(); 54 | 55 | size_t size = masm.GetBuffer()->GetSizeInBytes(); 56 | 57 | trampoline_addr_ = mmap(nullptr, GetPageSize(), PROT_READ | PROT_WRITE, 58 | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 59 | memcpy(trampoline_addr_, masm.GetBuffer()->GetStartAddress(), size); 60 | mprotect(trampoline_addr_, GetPageSize(), PROT_READ | PROT_EXEC); 61 | 62 | return reinterpret_cast(trampoline_addr_); 63 | } 64 | 65 | 66 | void Arm64InlineHook::StopHook() { 67 | size_t code_size = backup_code_->GetSizeInBytes(); 68 | void *insns = backup_code_->GetInstructions(); 69 | ScopedMemoryPatch patch(GetTarget(), insns, code_size); 70 | memcpy(GetTarget(), insns, code_size); 71 | if (trampoline_addr_ != nullptr) { 72 | munmap(trampoline_addr_, GetPageSize()); 73 | } 74 | } 75 | 76 | } // namespace arm64 77 | } // namespace whale 78 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/distorm/x86defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | x86defs.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2018 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef X86DEFS_H 13 | #define X86DEFS_H 14 | 15 | 16 | #define SEG_REGS_MAX (6) 17 | #define CREGS_MAX (9) 18 | #define DREGS_MAX (8) 19 | 20 | /* Maximum instruction size, including prefixes */ 21 | #define INST_MAXIMUM_SIZE (15) 22 | 23 | /* Maximum range of imm8 (comparison type) of special SSE CMP instructions. */ 24 | #define INST_CMP_MAX_RANGE (8) 25 | 26 | /* Maximum range of imm8 (comparison type) of special AVX VCMP instructions. */ 27 | #define INST_VCMP_MAX_RANGE (32) 28 | 29 | /* Wait instruction byte code. */ 30 | #define INST_WAIT_INDEX (0x9b) 31 | 32 | /* Lea instruction byte code. */ 33 | #define INST_LEA_INDEX (0x8d) 34 | 35 | /* NOP/XCHG instruction byte code. */ 36 | #define INST_NOP_INDEX (0x90) 37 | 38 | /* ARPL/MOVSXD instruction byte code. */ 39 | #define INST_ARPL_INDEX (0x63) 40 | 41 | /* 42 | * Minimal MODR/M value of divided instructions. 43 | * It's 0xc0, two MSBs set, which indicates a general purpose register is used too. 44 | */ 45 | #define INST_DIVIDED_MODRM (0xc0) 46 | 47 | /* This is the escape byte value used for 3DNow! instructions. */ 48 | #define _3DNOW_ESCAPE_BYTE (0x0f) 49 | 50 | #define PREFIX_LOCK (0xf0) 51 | #define PREFIX_REPNZ (0xf2) 52 | #define PREFIX_REP (0xf3) 53 | #define PREFIX_CS (0x2e) 54 | #define PREFIX_SS (0x36) 55 | #define PREFIX_DS (0x3e) 56 | #define PREFIX_ES (0x26) 57 | #define PREFIX_FS (0x64) 58 | #define PREFIX_GS (0x65) 59 | #define PREFIX_OP_SIZE (0x66) 60 | #define PREFIX_ADDR_SIZE (0x67) 61 | #define PREFIX_VEX2b (0xc5) 62 | #define PREFIX_VEX3b (0xc4) 63 | 64 | /* REX prefix value range, 64 bits mode decoding only. */ 65 | #define PREFIX_REX_LOW (0x40) 66 | #define PREFIX_REX_HI (0x4f) 67 | /* In order to use the extended GPR's we have to add 8 to the Modr/M info values. */ 68 | #define EX_GPR_BASE (8) 69 | 70 | /* Mask for REX and VEX features: */ 71 | /* Base */ 72 | #define PREFIX_EX_B (1) 73 | /* Index */ 74 | #define PREFIX_EX_X (2) 75 | /* Register */ 76 | #define PREFIX_EX_R (4) 77 | /* Operand Width */ 78 | #define PREFIX_EX_W (8) 79 | /* Vector Lengh */ 80 | #define PREFIX_EX_L (0x10) 81 | 82 | #endif /* X86DEFS_H */ 83 | -------------------------------------------------------------------------------- /whale/src/dbi/instruction_set.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "dbi/instruction_set.h" 4 | 5 | namespace whale { 6 | 7 | std::ostream &operator<<(std::ostream &os, const InstructionSet &rhs) { 8 | return os << GetInstructionSetString(rhs); 9 | } 10 | 11 | void InstructionSetAbort(InstructionSet isa) { 12 | switch (isa) { 13 | case InstructionSet::kArm: 14 | case InstructionSet::kThumb2: 15 | case InstructionSet::kArm64: 16 | case InstructionSet::kX86: 17 | case InstructionSet::kX86_64: 18 | case InstructionSet::kMips: 19 | case InstructionSet::kMips64: 20 | case InstructionSet::kNone: 21 | LOG(FATAL) << "Unsupported instruction set " << isa; 22 | UNREACHABLE(); 23 | } 24 | LOG(FATAL) << "Unknown ISA " << isa; 25 | UNREACHABLE(); 26 | } 27 | 28 | const char *GetInstructionSetString(InstructionSet isa) { 29 | switch (isa) { 30 | case InstructionSet::kArm: 31 | case InstructionSet::kThumb2: 32 | return "arm"; 33 | case InstructionSet::kArm64: 34 | return "arm64"; 35 | case InstructionSet::kX86: 36 | return "x86"; 37 | case InstructionSet::kX86_64: 38 | return "x86_64"; 39 | case InstructionSet::kMips: 40 | return "mips"; 41 | case InstructionSet::kMips64: 42 | return "mips64"; 43 | case InstructionSet::kNone: 44 | return "none"; 45 | } 46 | LOG(FATAL) << "Unknown ISA " << isa; 47 | UNREACHABLE(); 48 | } 49 | 50 | 51 | size_t GetInstructionSetAlignment(InstructionSet isa) { 52 | switch (isa) { 53 | case InstructionSet::kArm: 54 | // Fall-through. 55 | case InstructionSet::kThumb2: 56 | return kArmAlignment; 57 | case InstructionSet::kArm64: 58 | return kArm64Alignment; 59 | case InstructionSet::kX86: 60 | // Fall-through. 61 | case InstructionSet::kX86_64: 62 | return kX86Alignment; 63 | case InstructionSet::kMips: 64 | // Fall-through. 65 | case InstructionSet::kMips64: 66 | return kMipsAlignment; 67 | case InstructionSet::kNone: 68 | LOG(FATAL) << "ISA kNone does not have alignment."; 69 | UNREACHABLE(); 70 | } 71 | LOG(FATAL) << "Unknown ISA " << isa; 72 | UNREACHABLE(); 73 | } 74 | 75 | 76 | } // namespace whale 77 | 78 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/inline_hook_x86.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "dbi/x86/inline_hook_x86.h" 4 | #include "dbi/x86/instruction_rewriter_x86.h" 5 | #include "assembler/x86/assembler_x86.h" 6 | #include "platform/memory.h" 7 | 8 | #define __ masm. 9 | 10 | namespace whale { 11 | namespace x86 { 12 | 13 | void X86InlineHook::StartHook() { 14 | 15 | DCHECK(address_ != 0 && replace_ != 0); 16 | X86Assembler masm; 17 | __ movl(EDX, Immediate(replace_)); 18 | __ jmp(EDX); 19 | masm.FinalizeCode(); 20 | 21 | size_t backup_size = masm.GetBuffer()->Size(); 22 | size_t code_aligned_size = 0; 23 | do { 24 | u1 *code = reinterpret_cast(address_) + code_aligned_size; 25 | u1 size = Decode(code, UINT8_MAX, 0).size; 26 | code_aligned_size += size; 27 | } while (code_aligned_size < backup_size); 28 | 29 | backup_size = code_aligned_size; 30 | 31 | backup_code_ = new BackupCode(GetTarget(), backup_size); 32 | 33 | if (backup_ != nullptr) { 34 | intptr_t tail = address_ + backup_size; 35 | intptr_t trampoline = BuildTrampoline(static_cast(tail)); 36 | *backup_ = trampoline; 37 | } 38 | 39 | ScopedMemoryPatch patch(GetTarget(), masm.GetBuffer()->contents(), 40 | masm.GetBuffer()->Size()); 41 | } 42 | 43 | intptr_t X86InlineHook::BuildTrampoline(u4 tail) { 44 | X86Assembler masm; 45 | X86InstructionRewriter rewriter(&masm, backup_code_, GetTarget(), tail); 46 | rewriter.Rewrite(); 47 | 48 | __ movl(EDX, Immediate(tail)); 49 | __ jmp(EDX); 50 | masm.FinalizeCode(); 51 | size_t size = masm.GetBuffer()->Size(); 52 | 53 | trampoline_addr_ = mmap(nullptr, GetPageSize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 54 | memcpy(trampoline_addr_, masm.GetBuffer()->contents(), size); 55 | mprotect(trampoline_addr_, GetPageSize(), PROT_READ | PROT_EXEC); 56 | return reinterpret_cast(trampoline_addr_); 57 | } 58 | 59 | 60 | void X86InlineHook::StopHook() { 61 | size_t code_size = backup_code_->GetSizeInBytes(); 62 | void *insns = backup_code_->GetInstructions(); 63 | ScopedMemoryPatch patch(GetTarget(), insns, code_size); 64 | memcpy(GetTarget(), insns, code_size); 65 | if (trampoline_addr_ != nullptr) { 66 | munmap(trampoline_addr_, GetPageSize()); 67 | } 68 | } 69 | 70 | } // namespace x86 71 | } // namespace whale 72 | -------------------------------------------------------------------------------- /whale/src/dbi/x86_64/inline_hook_x86_64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "assembler/x86_64/assembler_x86_64.h" 5 | #include "dbi/x86_64/inline_hook_x86_64.h" 6 | #include "dbi/x86_64/instruction_rewriter_x86_64.h" 7 | #include "dbi/x86/distorm/distorm.h" 8 | 9 | #define __ masm. 10 | 11 | namespace whale { 12 | namespace x86_64 { 13 | 14 | 15 | void X86_64InlineHook::StartHook() { 16 | CHECK(address_ != 0 && replace_ != 0); 17 | X86_64Assembler masm; 18 | 19 | __ movq(RAX, Immediate(replace_)); 20 | __ jmp(RAX); 21 | masm.FinalizeCode(); 22 | 23 | size_t backup_size = masm.GetBuffer()->Size(); 24 | size_t code_aligned_size = 0; 25 | do { 26 | u1 *code = reinterpret_cast(address_) + code_aligned_size; 27 | u1 size = Decode(code, UINT8_MAX, 1).size; 28 | code_aligned_size += size; 29 | } while (code_aligned_size < backup_size); 30 | 31 | backup_size = code_aligned_size; 32 | backup_code_ = new BackupCode(GetTarget(), backup_size); 33 | 34 | if (backup_ != nullptr) { 35 | intptr_t tail = address_ + backup_size; 36 | intptr_t trampoline = BuildTrampoline(static_cast(tail)); 37 | *backup_ = trampoline; 38 | } 39 | 40 | ScopedMemoryPatch patch(GetTarget(), masm.GetBuffer()->contents(), 41 | masm.GetBuffer()->Size()); 42 | } 43 | 44 | intptr_t X86_64InlineHook::BuildTrampoline(u8 tail) { 45 | X86_64Assembler masm; 46 | X86_64InstructionRewriter rewriter(&masm, backup_code_, GetTarget(), tail); 47 | rewriter.Rewrite(); 48 | 49 | __ movq(R12, Immediate(tail)); 50 | __ jmp(R12); 51 | 52 | masm.FinalizeCode(); 53 | 54 | size_t size = masm.GetBuffer()->Size(); 55 | trampoline_addr_ = mmap(nullptr, GetPageSize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 56 | memcpy(trampoline_addr_, masm.GetBuffer()->contents(), size); 57 | mprotect(trampoline_addr_, GetPageSize(), PROT_READ | PROT_EXEC); 58 | return reinterpret_cast(trampoline_addr_); 59 | } 60 | 61 | 62 | void X86_64InlineHook::StopHook() { 63 | size_t code_size = backup_code_->GetSizeInBytes(); 64 | void *insns = backup_code_->GetInstructions(); 65 | ScopedMemoryPatch patch(GetTarget(), insns, code_size); 66 | memcpy(GetTarget(), insns, code_size); 67 | if (trampoline_addr_ != nullptr) { 68 | munmap(trampoline_addr_, GetPageSize()); 69 | } 70 | } 71 | 72 | } // namespace x86 73 | } // namespace whale 74 | -------------------------------------------------------------------------------- /whale/src/libffi/aarch64/internal.h: -------------------------------------------------------------------------------- 1 | #if defined(__aarch64__) || defined(__arm64__) 2 | 3 | /* 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | ``Software''), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 22 | 23 | #define AARCH64_RET_VOID 0 24 | #define AARCH64_RET_INT64 1 25 | #define AARCH64_RET_INT128 2 26 | 27 | #define AARCH64_RET_UNUSED3 3 28 | #define AARCH64_RET_UNUSED4 4 29 | #define AARCH64_RET_UNUSED5 5 30 | #define AARCH64_RET_UNUSED6 6 31 | #define AARCH64_RET_UNUSED7 7 32 | 33 | /* Note that FFI_TYPE_FLOAT == 2, _DOUBLE == 3, _LONGDOUBLE == 4, 34 | so _S4 through _Q1 are layed out as (TYPE * 4) + (4 - COUNT). */ 35 | #define AARCH64_RET_S4 8 36 | #define AARCH64_RET_S3 9 37 | #define AARCH64_RET_S2 10 38 | #define AARCH64_RET_S1 11 39 | 40 | #define AARCH64_RET_D4 12 41 | #define AARCH64_RET_D3 13 42 | #define AARCH64_RET_D2 14 43 | #define AARCH64_RET_D1 15 44 | 45 | #define AARCH64_RET_Q4 16 46 | #define AARCH64_RET_Q3 17 47 | #define AARCH64_RET_Q2 18 48 | #define AARCH64_RET_Q1 19 49 | 50 | /* Note that each of the sub-64-bit integers gets two entries. */ 51 | #define AARCH64_RET_UINT8 20 52 | #define AARCH64_RET_UINT16 22 53 | #define AARCH64_RET_UINT32 24 54 | 55 | #define AARCH64_RET_SINT8 26 56 | #define AARCH64_RET_SINT16 28 57 | #define AARCH64_RET_SINT32 30 58 | 59 | #define AARCH64_RET_MASK 31 60 | 61 | #define AARCH64_RET_IN_MEM (1 << 5) 62 | #define AARCH64_RET_NEED_COPY (1 << 6) 63 | 64 | #define AARCH64_FLAG_ARG_V_BIT 7 65 | #define AARCH64_FLAG_ARG_V (1 << AARCH64_FLAG_ARG_V_BIT) 66 | 67 | #define N_X_ARG_REG 8 68 | #define N_V_ARG_REG 8 69 | #define CALL_CONTEXT_SIZE (N_V_ARG_REG * 16 + N_X_ARG_REG * 8) 70 | 71 | 72 | #endif -------------------------------------------------------------------------------- /whale/src/libffi/debug.c: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | debug.c - Copyright (c) 1996 Red Hat, Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | ``Software''), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | ----------------------------------------------------------------------- */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | /* General debugging routines */ 31 | 32 | void ffi_stop_here(void) 33 | { 34 | /* This function is only useful for debugging purposes. 35 | Place a breakpoint on ffi_stop_here to be notified of 36 | significant events. */ 37 | } 38 | 39 | /* This function should only be called via the FFI_ASSERT() macro */ 40 | 41 | void ffi_assert(char *expr, char *file, int line) 42 | { 43 | fprintf(stderr, "ASSERTION FAILURE: %s at %s:%d\n", expr, file, line); 44 | ffi_stop_here(); 45 | abort(); 46 | } 47 | 48 | /* Perform a sanity check on an ffi_type structure */ 49 | 50 | void ffi_type_test(ffi_type *a, char *file, int line) 51 | { 52 | FFI_ASSERT_AT(a != NULL, file, line); 53 | 54 | FFI_ASSERT_AT(a->type <= FFI_TYPE_LAST, file, line); 55 | FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->size > 0, file, line); 56 | FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->alignment > 0, file, line); 57 | FFI_ASSERT_AT((a->type != FFI_TYPE_STRUCT && a->type != FFI_TYPE_COMPLEX) 58 | || a->elements != NULL, file, line); 59 | FFI_ASSERT_AT(a->type != FFI_TYPE_COMPLEX 60 | || (a->elements != NULL 61 | && a->elements[0] != NULL && a->elements[1] == NULL), 62 | file, line); 63 | 64 | } 65 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/distorm/prefix.h: -------------------------------------------------------------------------------- 1 | /* 2 | prefix.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2018 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef PREFIX_H 13 | #define PREFIX_H 14 | 15 | #include "config.h" 16 | #include "decoder.h" 17 | 18 | 19 | /* Specifies the type of the extension prefix, such as: REX, 2 bytes VEX, 3 bytes VEX. */ 20 | typedef enum {PET_NONE = 0, PET_REX, PET_VEX2BYTES, PET_VEX3BYTES} _PrefixExtType; 21 | 22 | /* Specifies an index into a table of prefixes by their type. */ 23 | typedef enum {PFXIDX_NONE = -1, PFXIDX_REX, PFXIDX_LOREP, PFXIDX_SEG, PFXIDX_OP_SIZE, PFXIDX_ADRS, PFXIDX_MAX} _PrefixIndexer; 24 | 25 | /* 26 | * This holds the prefixes state for the current instruction we decode. 27 | * decodedPrefixes includes all specific prefixes that the instruction got. 28 | * start is a pointer to the first prefix to take into account. 29 | * last is a pointer to the last byte we scanned. 30 | * Other pointers are used to keep track of prefixes positions and help us know if they appeared already and where. 31 | */ 32 | typedef struct { 33 | _iflags decodedPrefixes, usedPrefixes; 34 | const uint8_t *start, *last, *vexPos, *rexPos; 35 | _PrefixExtType prefixExtType; 36 | uint16_t unusedPrefixesMask; 37 | /* Indicates whether the operand size prefix (0x66) was used as a mandatory prefix. */ 38 | int isOpSizeMandatory; 39 | /* If VEX prefix is used, store the VEX.vvvv field. */ 40 | unsigned int vexV; 41 | /* The fields B/X/R/W/L of REX and VEX are stored together in this byte. */ 42 | unsigned int vrex; 43 | 44 | /* !! Make sure pfxIndexer is LAST! Otherwise memset won't work well with it. !! */ 45 | 46 | /* Holds the offset to the prefix byte by its type. */ 47 | int pfxIndexer[PFXIDX_MAX]; 48 | } _PrefixState; 49 | 50 | /* 51 | * Intel supports 6 types of prefixes, whereas AMD supports 5 types (lock is seperated from rep/nz). 52 | * REX is the fifth prefix type, this time I'm based on AMD64. 53 | * VEX is the 6th, though it can't be repeated. 54 | */ 55 | #define MAX_PREFIXES (5) 56 | 57 | int prefixes_is_valid(unsigned int ch, _DecodeType dt); 58 | void prefixes_ignore(_PrefixState* ps, _PrefixIndexer pi); 59 | void prefixes_ignore_all(_PrefixState* ps); 60 | uint16_t prefixes_set_unused_mask(_PrefixState* ps); 61 | void prefixes_decode(const uint8_t* code, int codeLen, _PrefixState* ps, _DecodeType dt); 62 | void prefixes_use_segment(_iflags defaultSeg, _PrefixState* ps, _DecodeType dt, _DInst* di); 63 | 64 | #endif /* PREFIX_H */ 65 | -------------------------------------------------------------------------------- /whale/src/assembler/label.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ASSEMBLER_LABEL_H_ 2 | #define WHALE_ASSEMBLER_LABEL_H_ 3 | 4 | #include 5 | #include "base/logging.h" 6 | 7 | namespace whale { 8 | 9 | class Assembler; 10 | 11 | class AssemblerBuffer; 12 | 13 | class AssemblerFixup; 14 | 15 | namespace x86 { 16 | class X86Assembler; 17 | 18 | class NearLabel; 19 | } // namespace x86 20 | namespace x86_64 { 21 | class X86_64Assembler; 22 | 23 | class NearLabel; 24 | } // namespace x86_64 25 | 26 | class ExternalLabel { 27 | public: 28 | ExternalLabel(const char *name_in, uintptr_t address_in) 29 | : name_(name_in), address_(address_in) { 30 | DCHECK(name_in != nullptr); 31 | } 32 | 33 | const char *name() const { return name_; } 34 | 35 | uintptr_t address() const { 36 | return address_; 37 | } 38 | 39 | private: 40 | const char *name_; 41 | const uintptr_t address_; 42 | }; 43 | 44 | class Label { 45 | public: 46 | Label() : position_(0) {} 47 | 48 | Label(Label &&src) 49 | : position_(src.position_) { 50 | // We must unlink/unbind the src label when moving; if not, calling the destructor on 51 | // the src label would fail. 52 | src.position_ = 0; 53 | } 54 | 55 | ~Label() { 56 | // Assert if label is being destroyed with unresolved branches pending. 57 | CHECK(!IsLinked()); 58 | } 59 | 60 | // Returns the position for bound and linked labels. Cannot be used 61 | // for unused labels. 62 | int Position() const { 63 | CHECK(!IsUnused()); 64 | return IsBound() ? -position_ - sizeof(void *) : position_ - sizeof(void *); 65 | } 66 | 67 | int LinkPosition() const { 68 | CHECK(IsLinked()); 69 | return position_ - sizeof(void *); 70 | } 71 | 72 | bool IsBound() const { return position_ < 0; } 73 | 74 | bool IsUnused() const { return position_ == 0; } 75 | 76 | bool IsLinked() const { return position_ > 0; } 77 | 78 | private: 79 | 80 | int position_; 81 | 82 | void Reinitialize() { 83 | position_ = 0; 84 | } 85 | 86 | void BindTo(int position) { 87 | position_ = -position - sizeof(void *); 88 | } 89 | 90 | void LinkTo(int position) { 91 | position_ = position + sizeof(void *); 92 | } 93 | 94 | friend class x86::X86Assembler; 95 | 96 | friend class x86::NearLabel; 97 | 98 | friend class x86_64::X86_64Assembler; 99 | 100 | friend class x86_64::NearLabel; 101 | 102 | DISALLOW_COPY_AND_ASSIGN(Label); 103 | }; 104 | 105 | 106 | } // namespace whale 107 | 108 | #endif // WHALE_ASSEMBLER_LABEL_H_ 109 | -------------------------------------------------------------------------------- /whale/src/dbi/hook_common.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ARCH_HOOK_H_ 2 | #define WHALE_ARCH_HOOK_H_ 3 | 4 | #include 5 | #include 6 | #include "dbi/instruction_set.h" 7 | 8 | namespace whale { 9 | 10 | enum class HookType { 11 | kNone, 12 | kInlineHook, 13 | kImportHook, 14 | }; 15 | 16 | class Hook { 17 | public: 18 | int id_{}; 19 | 20 | virtual ~Hook() = default; 21 | 22 | virtual InstructionSet getISA() { 23 | return InstructionSet::kNone; 24 | } 25 | 26 | virtual HookType GetType() { 27 | return HookType::kNone; 28 | } 29 | 30 | virtual void StartHook() = 0; 31 | 32 | virtual void StopHook() = 0; 33 | }; 34 | 35 | class ImportHook : public Hook { 36 | public: 37 | ImportHook(const char *symbol_name, void *replace, void **backup) 38 | : symbol_name_(symbol_name), 39 | replace_(replace), 40 | backup_(backup) {} 41 | 42 | virtual ~ImportHook() override = default; 43 | 44 | HookType GetType() override { 45 | return HookType::kImportHook; 46 | } 47 | 48 | const char *GetSymbolName() { 49 | return symbol_name_; 50 | } 51 | 52 | template 53 | ALWAYS_INLINE T GetReplaceAddress() { 54 | return (T) replace_; 55 | } 56 | 57 | protected: 58 | const char *symbol_name_; 59 | std::map address_map_; 60 | void *replace_; 61 | void **backup_; 62 | }; 63 | 64 | class InlineHook : public Hook { 65 | public: 66 | InlineHook(intptr_t address, intptr_t replace, intptr_t *backup) 67 | : address_(address), 68 | replace_(replace), 69 | backup_(backup) {} 70 | 71 | virtual ~InlineHook() override = default; 72 | 73 | template 74 | ALWAYS_INLINE T GetTarget() { 75 | return (T) address_; 76 | } 77 | 78 | template 79 | ALWAYS_INLINE T GetReplaceAddress() { 80 | return (T) replace_; 81 | } 82 | 83 | HookType GetType() override { 84 | return HookType::kInlineHook; 85 | } 86 | 87 | protected: 88 | intptr_t address_; 89 | intptr_t replace_; 90 | intptr_t *backup_; 91 | }; 92 | 93 | typedef bool (*MemoryRangeCallback)(const char *path, bool *stop); 94 | 95 | class InterceptSysCallHook : public Hook { 96 | public: 97 | InterceptSysCallHook(MemoryRangeCallback callback); 98 | 99 | void StartHook(); 100 | 101 | void StopHook(); 102 | 103 | protected: 104 | virtual void FindSysCalls(uintptr_t start, uintptr_t end) = 0; 105 | 106 | MemoryRangeCallback callback_; 107 | }; 108 | 109 | } // namespace whale 110 | 111 | #endif // WHALE_ARCH_HOOK_H_ 112 | 113 | -------------------------------------------------------------------------------- /whale/src/libffi/platform_include/ffitarget_arm64.h: -------------------------------------------------------------------------------- 1 | #ifdef __aarch64__ 2 | 3 | /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | ``Software''), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 23 | 24 | #ifndef LIBFFI_TARGET_H 25 | #define LIBFFI_TARGET_H 26 | 27 | #ifndef LIBFFI_H 28 | #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." 29 | #endif 30 | 31 | #ifndef LIBFFI_ASM 32 | #ifdef __ILP32__ 33 | #define FFI_SIZEOF_ARG 8 34 | #define FFI_SIZEOF_JAVA_RAW 4 35 | typedef unsigned long long ffi_arg; 36 | typedef signed long long ffi_sarg; 37 | #else 38 | typedef unsigned long ffi_arg; 39 | typedef signed long ffi_sarg; 40 | #endif 41 | 42 | typedef enum ffi_abi 43 | { 44 | FFI_FIRST_ABI = 0, 45 | FFI_SYSV, 46 | FFI_LAST_ABI, 47 | FFI_DEFAULT_ABI = FFI_SYSV 48 | } ffi_abi; 49 | #endif 50 | 51 | /* ---- Definitions for closures ----------------------------------------- */ 52 | 53 | #define FFI_CLOSURES 1 54 | #define FFI_NATIVE_RAW_API 0 55 | 56 | #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE 57 | 58 | #ifdef __MACH__ 59 | #define FFI_TRAMPOLINE_SIZE 16 60 | #define FFI_TRAMPOLINE_CLOSURE_OFFSET 16 61 | #else 62 | #error "No trampoline table implementation" 63 | #endif 64 | 65 | #else 66 | #define FFI_TRAMPOLINE_SIZE 24 67 | #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE 68 | #endif 69 | 70 | /* ---- Internal ---- */ 71 | 72 | #if defined (__APPLE__) 73 | #define FFI_TARGET_SPECIFIC_VARIADIC 74 | #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs 75 | #else 76 | /* iOS reserves x18 for the system. Disable Go closures until 77 | a new static chain is chosen. */ 78 | #define FFI_GO_CLOSURES 1 79 | #endif 80 | 81 | #define FFI_TARGET_HAS_COMPLEX_TYPE 82 | 83 | #endif 84 | 85 | 86 | #endif -------------------------------------------------------------------------------- /whale/src/android/art/scoped_thread_state_change.cc: -------------------------------------------------------------------------------- 1 | #include "android/jni_helper.h" 2 | #include "android/android_build.h" 3 | #include "android/art/scoped_thread_state_change.h" 4 | #include "art_runtime.h" 5 | 6 | namespace whale { 7 | namespace art { 8 | 9 | static volatile long kNoGCDaemonsGuard = 0; 10 | 11 | jclass ScopedNoGCDaemons::java_lang_Daemons; 12 | jmethodID ScopedNoGCDaemons::java_lang_Daemons_start; 13 | jmethodID ScopedNoGCDaemons::java_lang_Daemons_stop; 14 | 15 | void ScopedNoGCDaemons::Load(JNIEnv *env) { 16 | java_lang_Daemons = reinterpret_cast(env->NewGlobalRef( 17 | env->FindClass("java/lang/Daemons"))); 18 | if (java_lang_Daemons == nullptr) { 19 | JNIExceptionClear(env); 20 | LOG(WARNING) << "java/lang/Daemons API is unavailable."; 21 | return; 22 | } 23 | java_lang_Daemons_start = env->GetStaticMethodID(java_lang_Daemons, "start", "()V"); 24 | if (java_lang_Daemons_start == nullptr) { 25 | JNIExceptionClear(env); 26 | java_lang_Daemons_start = env->GetStaticMethodID(java_lang_Daemons, "startPostZygoteFork", 27 | "()V"); 28 | } 29 | if (java_lang_Daemons_start == nullptr) { 30 | LOG(WARNING) 31 | << "java/lang/Daemons API is available but no start/startPostZygoteFork method."; 32 | JNIExceptionClear(env); 33 | } 34 | java_lang_Daemons_stop = env->GetStaticMethodID(java_lang_Daemons, "stop", "()V"); 35 | JNIExceptionClear(env); 36 | } 37 | 38 | ScopedNoGCDaemons::ScopedNoGCDaemons(JNIEnv *env) : env_(env) { 39 | if (java_lang_Daemons_start != nullptr) { 40 | if (__sync_sub_and_fetch(&kNoGCDaemonsGuard, 1) <= 0) { 41 | env_->CallStaticVoidMethod(java_lang_Daemons, java_lang_Daemons_stop); 42 | JNIExceptionClear(env_); 43 | } 44 | } 45 | } 46 | 47 | 48 | ScopedNoGCDaemons::~ScopedNoGCDaemons() { 49 | if (java_lang_Daemons_stop != nullptr) { 50 | if (__sync_add_and_fetch(&kNoGCDaemonsGuard, 1) == 1) { 51 | env_->CallStaticVoidMethod(java_lang_Daemons, java_lang_Daemons_start); 52 | JNIExceptionClear(env_); 53 | } 54 | } 55 | } 56 | 57 | ScopedSuspendAll::ScopedSuspendAll() { 58 | ResolvedSymbols *symbols = art::ArtRuntime::Get()->GetSymbols(); 59 | if (symbols->Dbg_SuspendVM && symbols->Dbg_ResumeVM) { 60 | symbols->Dbg_SuspendVM(); 61 | } else { 62 | LOG(WARNING) << "Suspend VM API is unavailable."; 63 | } 64 | } 65 | 66 | ScopedSuspendAll::~ScopedSuspendAll() { 67 | ResolvedSymbols *symbols = art::ArtRuntime::Get()->GetSymbols(); 68 | if (symbols->Dbg_SuspendVM && symbols->Dbg_ResumeVM) { 69 | symbols->Dbg_ResumeVM(); 70 | } 71 | } 72 | 73 | 74 | } // namespace art 75 | } // namespace whale 76 | 77 | -------------------------------------------------------------------------------- /whale/src/libffi/platform_include/ffitarget_armv7.h: -------------------------------------------------------------------------------- 1 | #ifdef __arm__ 2 | 3 | /* -----------------------------------------------------------------*-C-*- 4 | ffitarget.h - Copyright (c) 2012 Anthony Green 5 | Copyright (c) 2010 CodeSourcery 6 | Copyright (c) 1996-2003 Red Hat, Inc. 7 | 8 | Target configuration macros for ARM. 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining 11 | a copy of this software and associated documentation files (the 12 | ``Software''), to deal in the Software without restriction, including 13 | without limitation the rights to use, copy, modify, merge, publish, 14 | distribute, sublicense, and/or sell copies of the Software, and to 15 | permit persons to whom the Software is furnished to do so, subject to 16 | the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included 19 | in all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 22 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 25 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28 | DEALINGS IN THE SOFTWARE. 29 | 30 | ----------------------------------------------------------------------- */ 31 | 32 | #ifndef LIBFFI_TARGET_H 33 | #define LIBFFI_TARGET_H 34 | 35 | #ifndef LIBFFI_H 36 | #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." 37 | #endif 38 | 39 | #ifndef LIBFFI_ASM 40 | typedef unsigned long ffi_arg; 41 | typedef signed long ffi_sarg; 42 | 43 | typedef enum ffi_abi { 44 | FFI_FIRST_ABI = 0, 45 | FFI_SYSV, 46 | FFI_VFP, 47 | FFI_LAST_ABI, 48 | #ifdef __ARM_PCS_VFP 49 | FFI_DEFAULT_ABI = FFI_VFP, 50 | #else 51 | FFI_DEFAULT_ABI = FFI_SYSV, 52 | #endif 53 | } ffi_abi; 54 | #endif 55 | 56 | #define FFI_EXTRA_CIF_FIELDS \ 57 | int vfp_used; \ 58 | unsigned short vfp_reg_free, vfp_nargs; \ 59 | signed char vfp_args[16] \ 60 | 61 | #define FFI_TARGET_SPECIFIC_VARIADIC 62 | #define FFI_TARGET_HAS_COMPLEX_TYPE 63 | 64 | /* ---- Definitions for closures ----------------------------------------- */ 65 | 66 | #define FFI_CLOSURES 1 67 | #define FFI_GO_CLOSURES 1 68 | #define FFI_NATIVE_RAW_API 0 69 | 70 | #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE 71 | 72 | #ifdef __MACH__ 73 | #define FFI_TRAMPOLINE_SIZE 12 74 | #define FFI_TRAMPOLINE_CLOSURE_OFFSET 8 75 | #else 76 | #error "No trampoline table implementation" 77 | #endif 78 | 79 | #else 80 | #define FFI_TRAMPOLINE_SIZE 12 81 | #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE 82 | #endif 83 | 84 | #endif 85 | 86 | 87 | #endif -------------------------------------------------------------------------------- /java/com/lody/whale/WhaleRuntime.java: -------------------------------------------------------------------------------- 1 | package com.lody.whale; 2 | 3 | import android.os.Build; 4 | 5 | import com.lody.whale.xposed.XposedBridge; 6 | 7 | import java.lang.reflect.InvocationTargetException; 8 | import java.lang.reflect.Member; 9 | import java.lang.reflect.Method; 10 | 11 | /** 12 | * @author Lody 13 | *

14 | * NOTICE: Do not move or rename any methods in this class. 15 | */ 16 | public class WhaleRuntime { 17 | 18 | static { 19 | System.loadLibrary("whale"); 20 | } 21 | 22 | private static String getShorty(Member member) { 23 | return VMHelper.getShorty(member); 24 | } 25 | 26 | public static long[] countInstancesOfClasses(Class[] classes, boolean assignable) { 27 | if (Build.VERSION.SDK_INT < 27) { 28 | throw new UnsupportedOperationException("Not support countInstancesOfClasses on your device yet."); 29 | } 30 | try { 31 | Class clazz = Class.forName("dalvik.system.VMDebug"); 32 | Method method = clazz.getDeclaredMethod("countInstancesOfClasses", Class[].class, boolean.class); 33 | return (long[]) method.invoke(null, classes, assignable); 34 | } catch (Throwable e) { 35 | throw new IllegalStateException(e); 36 | } 37 | } 38 | 39 | public static Object[][] getInstancesOfClasses(Class[] classes, boolean assignable) { 40 | if (Build.VERSION.SDK_INT < 28) { 41 | throw new UnsupportedOperationException("Not support getInstancesOfClasses on your device yet."); 42 | } 43 | try { 44 | Class clazz = Class.forName("dalvik.system.VMDebug"); 45 | Method method = clazz.getDeclaredMethod("getInstancesOfClasses", Class[].class, boolean.class); 46 | return (Object[][]) method.invoke(null, classes, assignable); 47 | } catch (Throwable e) { 48 | throw new IllegalStateException(e); 49 | } 50 | } 51 | 52 | public static Object handleHookedMethod(Member member, long slot, Object additionInfo, Object thisObject, Object[] args) throws Throwable { 53 | return XposedBridge.handleHookedMethod(member, slot, additionInfo, thisObject, args); 54 | } 55 | 56 | public static native Object invokeOriginalMethodNative(long slot, Object thisObject, Object[] args) 57 | throws IllegalAccessException, IllegalArgumentException, InvocationTargetException; 58 | 59 | public static native long getMethodSlot(Member member) throws IllegalArgumentException; 60 | 61 | public static native long hookMethodNative(Class declClass, Member method, Object additionInfo); 62 | 63 | public static native void setObjectClassNative(Object object, Class parent); 64 | 65 | public static native Object cloneToSubclassNative(Object object, Class subClass); 66 | 67 | public static native void removeFinalFlagNative(Class cl); 68 | 69 | public static native void enforceDisableHiddenAPIPolicy(); 70 | 71 | private static native void reserved0(); 72 | 73 | private static native void reserved1(); 74 | } 75 | -------------------------------------------------------------------------------- /whale/src/libffi/ffi_cxx.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_FFI_CXX_H_ 2 | #define WHALE_FFI_CXX_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "ffi.h" 8 | #include "base/macros.h" 9 | 10 | enum class FFIType { 11 | kFFITypeVoid, 12 | kFFITypeU1, 13 | kFFITypeU2, 14 | kFFITypeU4, 15 | kFFITypeU8, 16 | kFFITypeS1, 17 | kFFITypeS2, 18 | kFFITypeS4, 19 | kFFITypeS8, 20 | kFFITypePointer, 21 | kFFITypeFloat, 22 | kFFITypeDouble, 23 | }; 24 | 25 | class FFICallInterface; 26 | 27 | class FFIClosure; 28 | 29 | typedef void (*FFICallback)(FFIClosure *closure, void *ret, void **args, void *userdata); 30 | 31 | class FFIClosure { 32 | public: 33 | FFIClosure(FFICallInterface *cif, void *userdata, FFICallback callback) : cif_(cif), 34 | userdata_(userdata), 35 | callback_(callback) { 36 | closure_ = reinterpret_cast(ffi_closure_alloc(sizeof(ffi_closure), &code_)); 37 | } 38 | 39 | ~FFIClosure() { 40 | ffi_closure_free(closure_); 41 | } 42 | 43 | void *GetCode() { 44 | return code_; 45 | } 46 | 47 | void *GetUserData() { 48 | return userdata_; 49 | } 50 | 51 | FFICallInterface *GetCif() { 52 | return cif_; 53 | } 54 | 55 | FFICallback GetCallback() { 56 | return callback_; 57 | } 58 | 59 | private: 60 | friend class FFICallInterface; 61 | 62 | FFICallInterface *cif_; 63 | ffi_closure *closure_; 64 | FFICallback callback_; 65 | void *code_; 66 | void *userdata_; 67 | 68 | }; 69 | 70 | class FFICallInterface { 71 | public: 72 | FFICallInterface(const FFIType return_type) : return_type_(return_type) {} 73 | 74 | ~FFICallInterface(); 75 | 76 | FFICallInterface *Parameter(const FFIType parameter) { 77 | parameters_.push_back(parameter); 78 | return this; 79 | } 80 | 81 | FFICallInterface *Parameters(unsigned int count, ...) { 82 | va_list ap; 83 | va_start(ap, count); 84 | while (count-- > 0) { 85 | Parameter(va_arg(ap, FFIType)); 86 | } 87 | va_end(ap); 88 | return this; 89 | } 90 | 91 | FFICallInterface *FinalizeCif(); 92 | 93 | size_t GetParameterCount() { 94 | return parameters_.size(); 95 | } 96 | 97 | std::list GetParameters() { 98 | return parameters_; 99 | } 100 | 101 | FFIClosure *CreateClosure(void *userdata, FFICallback callback); 102 | 103 | void RemoveClosure(FFIClosure *closure) { 104 | std::lock_guard guard(lock_); 105 | closures_.remove(closure); 106 | } 107 | 108 | private: 109 | std::mutex lock_; 110 | ffi_cif *cif_; 111 | ffi_type **types_; 112 | std::list parameters_; 113 | const FFIType return_type_; 114 | std::list closures_; 115 | }; 116 | 117 | #endif //WHALE_FFI_CXX_H_ 118 | -------------------------------------------------------------------------------- /whale/src/platform/linux/process_map.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "platform/linux/process_map.h" 5 | #include "process_map.h" 6 | 7 | 8 | namespace whale { 9 | 10 | std::unique_ptr FindFileMemoryRange(const char *name) { 11 | std::unique_ptr range(new MemoryRange); 12 | range->base_ = UINTPTR_MAX; 13 | ForeachMemoryRange( 14 | [&](uintptr_t begin, uintptr_t end, uintptr_t offset, char *perm, char *mapname) -> bool { 15 | if (strstr(mapname, name)) { 16 | if (range->path_ == nullptr) { 17 | range->path_ = strdup(mapname); 18 | } 19 | if (range->base_ > begin) { 20 | range->base_ = begin; 21 | } 22 | if (range->end_ < end) { 23 | range->end_ = end; 24 | } 25 | } 26 | return true; 27 | }); 28 | return range; 29 | } 30 | 31 | std::unique_ptr FindExecuteMemoryRange(const char *name) { 32 | std::unique_ptr range(new MemoryRange); 33 | ForeachMemoryRange( 34 | [&](uintptr_t begin, uintptr_t end, uintptr_t offset, char *perm, char *mapname) -> bool { 35 | if (strncmp(mapname, "/system/fake-libs/", 18) == 0) { 36 | return true; 37 | } 38 | if (strstr(mapname, name)) { 39 | //find the correct base address 40 | if (offset == 0) { 41 | range->path_ = strdup(mapname); 42 | range->base_ = begin; 43 | range->end_ = end; 44 | } 45 | if (strstr(perm, "x")) 46 | return false; 47 | } 48 | return true; 49 | }); 50 | return range; 51 | } 52 | 53 | void 54 | ForeachMemoryRange(std::function callback) { 55 | FILE *f; 56 | if ((f = fopen("/proc/self/maps", "r"))) { 57 | char buf[PATH_MAX], perm[12] = {'\0'}, dev[12] = {'\0'}, mapname[PATH_MAX] = {'\0'}; 58 | uintptr_t begin, end, inode, foo; 59 | 60 | while (!feof(f)) { 61 | if (fgets(buf, sizeof(buf), f) == 0) 62 | break; 63 | sscanf(buf, "%lx-%lx %s %lx %s %ld %s", &begin, &end, perm, 64 | &foo, dev, &inode, mapname); 65 | if (!callback(begin, end, foo, perm, mapname)) { 66 | break; 67 | } 68 | } 69 | fclose(f); 70 | } 71 | } 72 | 73 | bool IsFileInMemory(const char *name) { 74 | bool found = false; 75 | ForeachMemoryRange( 76 | [&](uintptr_t begin, uintptr_t end, uintptr_t offset, char *perm, char *mapname) -> bool { 77 | if (strstr(mapname, name)) { 78 | found = true; 79 | return false; 80 | } 81 | return true; 82 | }); 83 | return found; 84 | } 85 | 86 | } // namespace whale 87 | -------------------------------------------------------------------------------- /whale/src/android/art/art_method.cc: -------------------------------------------------------------------------------- 1 | #include "android/art/art_method.h" 2 | #include "well_known_classes.h" 3 | 4 | namespace whale { 5 | namespace art { 6 | 7 | jobject ArtMethod::Clone(JNIEnv *env, u4 access_flags) { 8 | int32_t api_level = GetAndroidApiLevel(); 9 | jmethodID jni_clone_method = nullptr; 10 | if (api_level < ANDROID_M) { 11 | jni_clone_method = 12 | reinterpret_cast(ArtRuntime::Get()->CloneArtObject(jni_method_)); 13 | } else { 14 | jni_clone_method = reinterpret_cast(malloc(offset_->method_size_)); 15 | if (symbols_->ArtMethod_CopyFrom) { 16 | symbols_->ArtMethod_CopyFrom(jni_clone_method, jni_method_, sizeof(ptr_t)); 17 | } else { 18 | memcpy(jni_clone_method, jni_method_, offset_->method_size_); 19 | } 20 | } 21 | 22 | ArtMethod clone_method = ArtMethod(jni_clone_method); 23 | bool is_direct_method = (access_flags & kAccDirectFlags) != 0; 24 | bool is_native_method = (access_flags & kAccNative) != 0; 25 | if (!is_direct_method) { 26 | access_flags &= ~(kAccPublic | kAccProtected); 27 | access_flags |= kAccPrivate; 28 | } 29 | access_flags &= ~kAccSynchronized; 30 | if (api_level < ANDROID_O_MR1) { 31 | access_flags |= kAccCompileDontBother_N; 32 | } else { 33 | access_flags |= kAccCompileDontBother_O_MR1; 34 | access_flags |= kAccPreviouslyWarm_O_MR1; 35 | } 36 | if (!is_native_method) { 37 | access_flags |= kAccSkipAccessChecks; 38 | } 39 | if (api_level >= ANDROID_N) { 40 | clone_method.SetHotnessCount(0); 41 | if (!is_native_method) { 42 | ptr_t profiling_info = GetEntryPointFromJni(); 43 | if (profiling_info != nullptr) { 44 | offset_t end = sizeof(u4) * 4; 45 | for (offset_t offset = 0; offset != end; offset += sizeof(u4)) { 46 | if (MemberOf(profiling_info, offset) == jni_method_) { 47 | AssignOffset(profiling_info, offset, jni_clone_method); 48 | } 49 | } 50 | } 51 | } 52 | } 53 | if (!is_native_method && symbols_->art_quick_to_interpreter_bridge) { 54 | clone_method.SetEntryPointFromQuickCompiledCode( 55 | symbols_->art_quick_to_interpreter_bridge); 56 | } 57 | 58 | clone_method.SetAccessFlags(access_flags); 59 | 60 | bool is_constructor = (access_flags & kAccConstructor) != 0; 61 | bool is_static = (access_flags & kAccStatic) != 0; 62 | if (is_constructor) { 63 | clone_method.RemoveAccessFlags(kAccConstructor); 64 | } 65 | jobject java_method = env->ToReflectedMethod(WellKnownClasses::java_lang_Object, 66 | jni_clone_method, 67 | static_cast(is_static)); 68 | env->CallVoidMethod(java_method, 69 | WellKnownClasses::java_lang_reflect_AccessibleObject_setAccessible, 70 | true); 71 | if (is_constructor) { 72 | clone_method.AddAccessFlags(kAccConstructor); 73 | } 74 | return java_method; 75 | } 76 | 77 | 78 | } // namespace art 79 | } // namespace whale 80 | -------------------------------------------------------------------------------- /java/com/lody/whale/xposed/XC_MethodReplacement.java: -------------------------------------------------------------------------------- 1 | package com.lody.whale.xposed; 2 | 3 | import com.lody.whale.xposed.callbacks.XCallback; 4 | 5 | /** 6 | * A special case of {@link XC_MethodHook} which completely replaces the original method. 7 | */ 8 | @SuppressWarnings({"unused", "WeakerAccess"}) 9 | public abstract class XC_MethodReplacement extends XC_MethodHook { 10 | /** 11 | * Creates a new callback with default priority. 12 | */ 13 | public XC_MethodReplacement() { 14 | super(); 15 | } 16 | 17 | /** 18 | * Creates a new callback with a specific priority. 19 | * 20 | * @param priority See {@link XCallback#priority}. 21 | */ 22 | public XC_MethodReplacement(final int priority) { 23 | super(priority); 24 | } 25 | 26 | @Override 27 | protected final void beforeHookedMethod(final MethodHookParam param) throws Throwable { 28 | try { 29 | param.setResult(replaceHookedMethod(param)); 30 | } catch (final Throwable t) { 31 | param.setThrowable(t); 32 | } 33 | } 34 | 35 | /** 36 | * @hide 37 | */ 38 | @Override 39 | @SuppressWarnings("all") 40 | protected final void afterHookedMethod(final MethodHookParam param) throws Throwable { 41 | } 42 | 43 | /** 44 | * Shortcut for replacing a method completely. Whatever is returned/thrown here is taken 45 | * instead of the result of the original method (which will not be called). 46 | *

47 | *

Note that implementations shouldn't call {@code super(param)}, it's not necessary. 48 | * 49 | * @param param Information about the method call. 50 | * @throws Throwable Anything that is thrown by the callback will be passed on to the original caller. 51 | */ 52 | @SuppressWarnings("all") 53 | protected abstract Object replaceHookedMethod(final MethodHookParam param) throws Throwable; 54 | 55 | /** 56 | * Predefined callback that skips the method without replacements. 57 | */ 58 | public static final XC_MethodReplacement DO_NOTHING = new XC_MethodReplacement(PRIORITY_HIGHEST * 2) { 59 | @Override 60 | protected Object replaceHookedMethod(final MethodHookParam param) throws Throwable { 61 | return null; 62 | } 63 | }; 64 | 65 | /** 66 | * Creates a callback which always returns a specific value. 67 | * 68 | * @param result The value that should be returned to callers of the hooked method. 69 | */ 70 | public static XC_MethodReplacement returnConstant(final Object result) { 71 | return returnConstant(XCallback.PRIORITY_DEFAULT, result); 72 | } 73 | 74 | /** 75 | * Like {@link #returnConstant(Object)}, but allows to specify a priority for the callback. 76 | * 77 | * @param priority See {@link XCallback#priority}. 78 | * @param result The value that should be returned to callers of the hooked method. 79 | */ 80 | public static XC_MethodReplacement returnConstant(final int priority, final Object result) { 81 | return new XC_MethodReplacement(priority) { 82 | @Override 83 | protected Object replaceHookedMethod(final MethodHookParam param) throws Throwable { 84 | return result; 85 | } 86 | }; 87 | } 88 | 89 | } -------------------------------------------------------------------------------- /whale/src/android/art/java_types.cc: -------------------------------------------------------------------------------- 1 | #include "android/art/java_types.h" 2 | 3 | namespace whale { 4 | namespace art { 5 | 6 | #define EXPORT_LANG_ClASS(c) jclass Types::java_lang_##c; jmethodID Types::java_lang_##c##_init; jmethodID Types::java_value_##c; 7 | 8 | EXPORT_LANG_ClASS(Integer); 9 | EXPORT_LANG_ClASS(Long); 10 | EXPORT_LANG_ClASS(Float); 11 | EXPORT_LANG_ClASS(Double); 12 | EXPORT_LANG_ClASS(Byte); 13 | EXPORT_LANG_ClASS(Short); 14 | EXPORT_LANG_ClASS(Boolean); 15 | EXPORT_LANG_ClASS(Character); 16 | 17 | #undef EXPORT_LANG_ClASS 18 | 19 | void Types::Load(JNIEnv *env) { 20 | jclass clazz; 21 | env->PushLocalFrame(16); 22 | 23 | #define LOAD_CLASS(c, s) clazz = env->FindClass(s); c = reinterpret_cast(env->NewWeakGlobalRef(clazz)) 24 | #define LOAD_LANG_CLASS(c, s) LOAD_CLASS(java_lang_##c, "java/lang/" #c); java_lang_##c##_init = env->GetMethodID(java_lang_##c, "", s) 25 | 26 | LOAD_LANG_CLASS(Integer, "(I)V"); 27 | LOAD_LANG_CLASS(Long, "(J)V"); 28 | LOAD_LANG_CLASS(Float, "(F)V"); 29 | LOAD_LANG_CLASS(Double, "(D)V"); 30 | LOAD_LANG_CLASS(Byte, "(B)V"); 31 | LOAD_LANG_CLASS(Short, "(S)V"); 32 | LOAD_LANG_CLASS(Boolean, "(Z)V"); 33 | LOAD_LANG_CLASS(Character, "(C)V"); 34 | 35 | #undef LOAD_CLASS 36 | #undef LOAD_LANG_CLASS 37 | 38 | #define LOAD_METHOD(k, c, r, s) java_value_##c = env->GetMethodID(k, r "Value", s) 39 | #define LOAD_NUMBER(c, r, s) LOAD_METHOD(java_lang_Number, c, r, s) 40 | 41 | jclass java_lang_Number = env->FindClass("java/lang/Number"); 42 | 43 | LOAD_NUMBER(Integer, "int", "()I"); 44 | LOAD_NUMBER(Long, "long", "()J"); 45 | LOAD_NUMBER(Float, "float", "()F"); 46 | LOAD_NUMBER(Double, "double", "()D"); 47 | LOAD_NUMBER(Byte, "byte", "()B"); 48 | LOAD_NUMBER(Short, "short", "()S"); 49 | 50 | LOAD_METHOD(java_lang_Boolean, Boolean, "boolean", "()Z"); 51 | LOAD_METHOD(java_lang_Character, Character, "char", "()C"); 52 | 53 | env->PopLocalFrame(nullptr); 54 | #undef LOAD_METHOD 55 | #undef LOAD_NUMBER 56 | } 57 | 58 | 59 | #define LANG_BOX(c, t) jobject Types::To##c(JNIEnv *env, t v) { \ 60 | return env->NewObject(Types::java_lang_##c, Types::java_lang_##c##_init, v); \ 61 | } 62 | #define LANG_UNBOX_V(k, c, t) t Types::From##c(JNIEnv *env, jobject j) { \ 63 | return env->Call##k##Method(j, Types::java_value_##c); \ 64 | } 65 | #define LANG_UNBOX(c, t) LANG_UNBOX_V(c, c, t) 66 | 67 | LANG_BOX(Integer, jint); 68 | LANG_BOX(Long, jlong); 69 | LANG_BOX(Float, jfloat); 70 | LANG_BOX(Double, jdouble); 71 | LANG_BOX(Byte, jbyte); 72 | LANG_BOX(Short, jshort); 73 | LANG_BOX(Boolean, jboolean); 74 | LANG_BOX(Character, jchar); 75 | 76 | jobject Types::ToObject(JNIEnv *env, jobject obj) { 77 | return obj; 78 | } 79 | 80 | LANG_UNBOX_V(Int, Integer, jint); 81 | LANG_UNBOX(Long, jlong); 82 | LANG_UNBOX(Float, jfloat); 83 | LANG_UNBOX(Double, jdouble); 84 | LANG_UNBOX(Byte, jbyte); 85 | LANG_UNBOX(Short, jshort); 86 | LANG_UNBOX(Boolean, jboolean); 87 | LANG_UNBOX_V(Char, Character, jchar); 88 | 89 | jobject Types::FromObject(JNIEnv *env, jobject obj) { 90 | return obj; 91 | } 92 | 93 | 94 | #undef LANG_BOX 95 | #undef LANG_UNBOX_V 96 | #undef LANG_UNBOX 97 | 98 | } // namespace art 99 | } // namespace whale 100 | -------------------------------------------------------------------------------- /whale/src/assembler/x86_64/constants_x86_64.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ASSEMBLER_X86_64_CONSTANTS_X86_64_H_ 2 | #define WHALE_ASSEMBLER_X86_64_CONSTANTS_X86_64_H_ 3 | 4 | #include 5 | #include "assembler/x86_64/registers_x86_64.h" 6 | #include "base/macros.h" 7 | 8 | namespace whale { 9 | namespace x86_64 { 10 | 11 | class CpuRegister { 12 | public: 13 | explicit constexpr CpuRegister(Register r) : reg_(r) {} 14 | 15 | constexpr CpuRegister(int r) : reg_(Register(r)) {} 16 | 17 | constexpr Register AsRegister() const { 18 | return reg_; 19 | } 20 | 21 | constexpr uint8_t LowBits() const { 22 | return reg_ & 7; 23 | } 24 | 25 | constexpr bool NeedsRex() const { 26 | return reg_ > 7; 27 | } 28 | 29 | private: 30 | const Register reg_; 31 | }; 32 | 33 | class XmmRegister { 34 | public: 35 | explicit constexpr XmmRegister(FloatRegister r) : reg_(r) {} 36 | 37 | constexpr XmmRegister(int r) : reg_(FloatRegister(r)) {} 38 | 39 | constexpr FloatRegister AsFloatRegister() const { 40 | return reg_; 41 | } 42 | 43 | constexpr uint8_t LowBits() const { 44 | return reg_ & 7; 45 | } 46 | 47 | constexpr bool NeedsRex() const { 48 | return reg_ > 7; 49 | } 50 | 51 | private: 52 | const FloatRegister reg_; 53 | }; 54 | 55 | enum X87Register { 56 | ST0 = 0, 57 | ST1 = 1, 58 | ST2 = 2, 59 | ST3 = 3, 60 | ST4 = 4, 61 | ST5 = 5, 62 | ST6 = 6, 63 | ST7 = 7, 64 | kNumberOfX87Registers = 8, 65 | kNoX87Register = -1 // Signals an illegal register. 66 | }; 67 | 68 | enum ScaleFactor { 69 | TIMES_1 = 0, 70 | TIMES_2 = 1, 71 | TIMES_4 = 2, 72 | TIMES_8 = 3 73 | }; 74 | 75 | enum Condition { 76 | kOverflow = 0, 77 | kNoOverflow = 1, 78 | kBelow = 2, 79 | kAboveEqual = 3, 80 | kEqual = 4, 81 | kNotEqual = 5, 82 | kBelowEqual = 6, 83 | kAbove = 7, 84 | kSign = 8, 85 | kNotSign = 9, 86 | kParityEven = 10, 87 | kParityOdd = 11, 88 | kLess = 12, 89 | kGreaterEqual = 13, 90 | kLessEqual = 14, 91 | kGreater = 15, 92 | 93 | kZero = kEqual, 94 | kNotZero = kNotEqual, 95 | kNegative = kSign, 96 | kPositive = kNotSign, 97 | kCarrySet = kBelow, 98 | kCarryClear = kAboveEqual, 99 | kUnordered = kParityEven 100 | }; 101 | 102 | 103 | class Instr { 104 | public: 105 | static const uint8_t kHltInstruction = 0xF4; 106 | // We prefer not to use the int3 instruction since it conflicts with gdb. 107 | static const uint8_t kBreakPointInstruction = kHltInstruction; 108 | 109 | bool IsBreakPoint() { 110 | return (*reinterpret_cast(this)) == kBreakPointInstruction; 111 | } 112 | 113 | // Instructions are read out of a code stream. The only way to get a 114 | // reference to an instruction is to convert a pointer. There is no way 115 | // to allocate or create instances of class Instr. 116 | // Use the At(pc) function to create references to Instr. 117 | static Instr *At(uintptr_t pc) { return reinterpret_cast(pc); } 118 | 119 | private: 120 | DISALLOW_IMPLICIT_CONSTRUCTORS(Instr); 121 | }; 122 | 123 | } // namespace x86_64 124 | } // namespace whale 125 | 126 | #endif // WHALE_ASSEMBLER_X86_64_CONSTANTS_X86_64_H_ 127 | -------------------------------------------------------------------------------- /whale/src/android/art/modifiers.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ANDROID_ART_MODIFIERS_H_ 2 | #define WHALE_ANDROID_ART_MODIFIERS_H_ 3 | 4 | #include "base/primitive_types.h" 5 | 6 | namespace whale { 7 | namespace art { 8 | 9 | static constexpr u4 kAccPublic = 0x0001; // class, field, method, ic 10 | static constexpr u4 kAccPrivate = 0x0002; // field, method, ic 11 | static constexpr u4 kAccProtected = 0x0004; // field, method, ic 12 | static constexpr u4 kAccStatic = 0x0008; // field, method, ic 13 | static constexpr u4 kAccFinal = 0x0010; // class, field, method, ic 14 | static constexpr u4 kAccSynchronized = 0x0020; // method (only allowed on natives) 15 | static constexpr u4 kAccSuper = 0x0020; // class (not used in dex) 16 | static constexpr u4 kAccVolatile = 0x0040; // field 17 | static constexpr u4 kAccBridge = 0x0040; // method (1.5) 18 | static constexpr u4 kAccTransient = 0x0080; // field 19 | static constexpr u4 kAccVarargs = 0x0080; // method (1.5) 20 | static constexpr u4 kAccNative = 0x0100; // method 21 | static constexpr u4 kAccInterface = 0x0200; // class, ic 22 | static constexpr u4 kAccAbstract = 0x0400; // class, method, ic 23 | static constexpr u4 kAccStrict = 0x0800; // method 24 | static constexpr u4 kAccSynthetic = 0x1000; // class, field, method, ic 25 | static constexpr u4 kAccAnnotation = 0x2000; // class, ic (1.5) 26 | static constexpr u4 kAccEnum = 0x4000; // class, field, ic (1.5) 27 | 28 | static constexpr u4 kAccJavaFlagsMask = 0xffff; // bits set from Java sources (low 16) 29 | 30 | static constexpr u4 kAccConstructor = 0x00010000; // method (dex only) <(cl)init> 31 | static constexpr u4 kAccDeclaredSynchronized = 0x00020000; // method (dex only) 32 | static constexpr u4 kAccClassIsProxy = 0x00040000; // class (dex only) 33 | // Set to indicate that the ArtMethod is obsolete and has a different DexCache + DexFile from its 34 | // declaring class. This flag may only be applied to methods. 35 | static constexpr u4 kAccObsoleteMethod = 0x00040000; // method (runtime) 36 | 37 | static constexpr uint32_t kAccFastNative = 0x00080000u; // method (dex only) 38 | static constexpr uint32_t kAccPreverified = kAccFastNative; // class (runtime) 39 | static constexpr uint32_t kAccSkipAccessChecks = kAccPreverified; 40 | static constexpr uint32_t kAccCriticalNative_P = 0x00200000; // method (runtime; native only) 41 | static constexpr uint32_t kAccFastInterpreterToInterpreterInvoke = 0x40000000; 42 | // Android M only 43 | static constexpr uint32_t kAccDontInline = 0x00400000u; // method (dex only) 44 | // Android N or later. Set by the verifier for a method we do not want the compiler to compile. 45 | static constexpr uint32_t kAccCompileDontBother_N = 0x01000000u; // method (runtime) 46 | // Android O MR1 or later. Set by the verifier for a method we do not want the compiler to compile. 47 | static constexpr uint32_t kAccCompileDontBother_O_MR1 = 0x02000000; // method (runtime) 48 | // Set by the JIT when clearing profiling infos to denote that a method was previously warm. 49 | static constexpr uint32_t kAccPreviouslyWarm_O_MR1 = 0x00800000; // method (runtime) 50 | 51 | static constexpr uint32_t kAccDirectFlags = kAccStatic | kAccPrivate | kAccConstructor; 52 | 53 | static constexpr uint32_t kAccPublicApi = 0x10000000; // field, method 54 | static constexpr uint32_t kAccHiddenapiBits = 0x30000000; // field, method 55 | 56 | } // namespace art 57 | } // namespace whale 58 | 59 | #endif // WHALE_ANDROID_ART_MODIFIERS_H_ 60 | -------------------------------------------------------------------------------- /whale/src/assembler/vixl/macro-assembler-interface.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016, VIXL authors 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // * Redistributions of source code must retain the above copyright notice, 8 | // this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, 10 | // this list of conditions and the following disclaimer in the documentation 11 | // and/or other materials provided with the distribution. 12 | // * Neither the name of ARM Limited nor the names of its contributors may be 13 | // used to endorse or promote products derived from this software without 14 | // specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | #ifndef VIXL_MACRO_ASSEMBLER_INTERFACE_H 28 | #define VIXL_MACRO_ASSEMBLER_INTERFACE_H 29 | 30 | #include "assembler-base-vixl.h" 31 | 32 | namespace vixl { 33 | 34 | class MacroAssemblerInterface { 35 | public: 36 | virtual internal::AssemblerBase* AsAssemblerBase() = 0; 37 | 38 | virtual ~MacroAssemblerInterface() {} 39 | 40 | virtual bool AllowMacroInstructions() const = 0; 41 | virtual bool ArePoolsBlocked() const = 0; 42 | 43 | protected: 44 | virtual void SetAllowMacroInstructions(bool allow) = 0; 45 | 46 | virtual void BlockPools() = 0; 47 | virtual void ReleasePools() = 0; 48 | virtual void EnsureEmitPoolsFor(size_t size) = 0; 49 | 50 | // Emit the branch over a literal/veneer pool, and any necessary padding 51 | // before it. 52 | virtual void EmitPoolHeader() = 0; 53 | // When this is called, the label used for branching over the pool is bound. 54 | // This can also generate additional padding, which must correspond to the 55 | // alignment_ value passed to the PoolManager (which needs to keep track of 56 | // the exact size of the generated pool). 57 | virtual void EmitPoolFooter() = 0; 58 | 59 | // Emit n bytes of padding that does not have to be executable. 60 | virtual void EmitPaddingBytes(int n) = 0; 61 | // Emit n bytes of padding that has to be executable. Implementations must 62 | // make sure this is a multiple of the instruction size. 63 | virtual void EmitNopBytes(int n) = 0; 64 | 65 | // The following scopes need access to the above method in order to implement 66 | // pool blocking and temporarily disable the macro-assembler. 67 | friend class ExactAssemblyScope; 68 | friend class EmissionCheckScope; 69 | template 70 | friend class PoolManager; 71 | }; 72 | 73 | } // namespace vixl 74 | 75 | #endif // VIXL_MACRO_ASSEMBLER_INTERFACE_H 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Whale 2 | ![logo][0] 3 | 4 | [Chinese Version](https://github.com/asLody/whale/blob/master/README.zh-CN.md) 5 | 6 | [![license](http://img.shields.io/badge/license-Apache2.0-brightgreen.svg?style=flat)](https://github.com/alibaba/atlas/blob/master/LICENSE) 7 | ## Overview 8 | Whale is a cross-platform Hook Framework, allowed to run *Android、IOS、Linux、MacOS*. 9 | Whale support both **ARM/THUMB, ARM64, X86, X86_64 (AMD64)**, This covers almost all the major devices available today. 10 | 11 | ## Feature 12 | #### Android 13 | * **Xposed-Style** Method Hook 14 | * Modify the inheritance relationship between classes at runtime 15 | * Modifies the class to which the object belongs at runtime 16 | * bypass `Hidden API Policy` 17 | 18 | #### Darwin/Linux Platforms 19 | * Internal symbol resolver 20 | * Native Hook 21 | 22 | #### IOS Restrictions 23 | InlineHook on IOS is only usable in `debug compile mode` on non-jailbreak devices. 24 | Release compilation mode will not work properly. 25 | 26 | To solve this problem,Whale will provide a new core named `Binary Static Inline Hook`. 27 | 28 | `Binary Static Inline Hook` will open source in the near future. 29 | 30 | 31 | ## What can you do with it? 32 | * Turn on the god mode of an app 33 | * The act of monitoring or tampering with app 34 | * Instant hotfix 35 | * SandBox 36 | * Inject to system and instead of Xposed 37 | 38 | ## Compatibility 39 | - [x] Android 5.0.0 40 | - [x] Android 5.1.1 41 | - [x] Android 6.0 42 | - [x] Android 6.0.1 43 | - [x] Android 7.1.2 44 | - [x] Android 8.1.0 45 | - [x] Android 9.0.0 46 | - [x] IOS 11.3 47 | - [x] IOS 12.0 48 | - [x] MacOS mojave (10.14) 49 | - (Not in the list means `untested` ) 50 | 51 | ## InlineHook 52 | For `pcrel instruction`, Whale will convert it to `pc-independent instruction`, 53 | If the Hook procedure have not convert instructions, please feedback to ` issue `. 54 | 55 | ## About Jit 56 | Whale has a `built-in Jit Engine`, When you have more advanced Hook requirements, you can directly **generate executable instructions** in memory through the Jit. 57 | There is no longer the need to generate ugly hard code through tools as before. 58 | 59 | ## Compile 60 | We have pre-built binary versions of Android & IOS. You can find them in the built directory. 61 | 62 | Whale uses CMake to build projects, so you need to install CMake on your system. 63 | 64 | #### Android 65 | 1. If you need to use ` Java Hook ` please copy java folder to your project. 66 | 67 | 2. Direct use of binary,You just copy the files under `built/Android` to `src/main/jniLibs` in your project. 68 | 69 | 3. If you need to compile the source code, specify `CMakeLists.txt` in build.gradle: 70 | ``` 71 | externalNativeBuild { 72 | cmake { 73 | path "your/whale/path/CMakeLists.txt" 74 | } 75 | } 76 | ``` 77 | 78 | #### IOS 79 | ``` 80 | cd toolchain 81 | 82 | cmake .. \ 83 | -DCMAKE_TOOLCHAIN_FILE=ios.toolchain.cmake \ 84 | -DIOS_PLATFORM=OS64 \ 85 | -DPLATFORM=IOS \ 86 | -DIOS_ARCH=arm64 \ 87 | -DENABLE_ARC=0 \ 88 | -DENABLE_BITCODE=0 \ 89 | -DENABLE_VISIBILITY=0 \ 90 | -DIOS_DEPLOYMENT_TARGET=9.3 \ 91 | -DSHARED=ON \ 92 | -DCMAKE_BUILD_TYPE=Release 93 | 94 | make -j4 95 | ``` 96 | 97 | #### Ohter platforms 98 | ``` 99 | cmake . 100 | make -j4 101 | ``` 102 | 103 | ## Technogy communication 104 | > [GOTO => Discord](https://discord.gg/j2Cdy2g) 105 | 106 | > Email: imlody@foxmail.com 107 | 108 | 109 | [0]: https://github.com/asLody/whale/blob/master/LOGO.png?raw=true 110 | -------------------------------------------------------------------------------- /whale/src/platform/memory.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "platform/memory.h" 3 | #include "base/align.h" 4 | #include "base/cxx_helper.h" 5 | #include "base/logging.h" 6 | #include "base/macros.h" 7 | 8 | #ifdef __APPLE__ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | C_API kern_return_t mach_vm_remap(vm_map_t, mach_vm_address_t *, mach_vm_size_t, 16 | mach_vm_offset_t, int, vm_map_t, mach_vm_address_t, 17 | boolean_t, vm_prot_t *, vm_prot_t *, vm_inherit_t); 18 | 19 | #endif 20 | 21 | namespace whale { 22 | 23 | ScopedMemoryPatch::ScopedMemoryPatch(void *address, void *patch, size_t size) : address_(address), patch_(patch), 24 | size_(size) { 25 | CHECK(address != nullptr && size > 0); 26 | intptr_t page_start = PageStart(reinterpret_cast(address)); 27 | size_t page_offset = static_cast(reinterpret_cast(address) - page_start); 28 | intptr_t page_end = PageAlign(reinterpret_cast(address) + size); 29 | size_t page_size = static_cast(page_end - page_start); 30 | bool use_rwx_page = 31 | mprotect(reinterpret_cast(page_start), page_size, PROT_READ | PROT_WRITE | PROT_EXEC) == 0; 32 | if (use_rwx_page) { 33 | memcpy(address, patch, size); 34 | } else { 35 | #ifdef __APPLE__ 36 | // 37 | // Only rw- and r-x page permissions are available on IOS. 38 | // 39 | void *remap_page = mmap(nullptr, GetPageSize(), PROT_READ | PROT_WRITE, 40 | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 41 | mach_port_t task_self = mach_task_self(); 42 | vm_address_t vm_page_start = static_cast(page_start); 43 | vm_size_t region_size = 0; 44 | vm_region_submap_short_info_64 info; 45 | mach_msg_type_number_t info_count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; 46 | natural_t max_depth = UINT8_MAX; 47 | kern_return_t kr = vm_region_recurse_64(task_self, 48 | &vm_page_start, ®ion_size, &max_depth, 49 | (vm_region_recurse_info_t) &info, 50 | &info_count); 51 | if (kr != KERN_SUCCESS) { 52 | return; 53 | } 54 | vm_copy(task_self, vm_page_start, page_size, (vm_address_t) remap_page); 55 | memcpy(OffsetOf(remap_page, page_offset), patch, size); 56 | 57 | mprotect(remap_page, page_size, PROT_READ | PROT_EXEC); 58 | 59 | vm_prot_t cur_protection, max_protection; 60 | mach_vm_address_t mach_vm_page_start = static_cast(page_start); 61 | mach_vm_remap(task_self, &mach_vm_page_start, page_size, 0, VM_FLAGS_OVERWRITE, 62 | task_self, (mach_vm_address_t) remap_page, TRUE, &cur_protection, &max_protection, 63 | info.inheritance); 64 | #endif 65 | } 66 | } 67 | 68 | ScopedMemoryPatch::~ScopedMemoryPatch() { 69 | #ifdef __APPLE__ 70 | sys_icache_invalidate(reinterpret_cast(address_), size_); 71 | #else 72 | __builtin___clear_cache( 73 | reinterpret_cast(address_), 74 | reinterpret_cast(reinterpret_cast(address_) + size_) 75 | ); 76 | #endif 77 | } 78 | 79 | 80 | } // namespace whale 81 | -------------------------------------------------------------------------------- /whale/src/assembler/vixl/aarch64/cpu-aarch64.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014, VIXL authors 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // * Redistributions of source code must retain the above copyright notice, 8 | // this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, 10 | // this list of conditions and the following disclaimer in the documentation 11 | // and/or other materials provided with the distribution. 12 | // * Neither the name of ARM Limited nor the names of its contributors may be 13 | // used to endorse or promote products derived from this software without 14 | // specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | #ifndef VIXL_CPU_AARCH64_H 28 | #define VIXL_CPU_AARCH64_H 29 | 30 | #include "../globals-vixl.h" 31 | 32 | #include "instructions-aarch64.h" 33 | 34 | namespace vixl { 35 | namespace aarch64 { 36 | 37 | class CPU { 38 | public: 39 | // Initialise CPU support. 40 | static void SetUp(); 41 | 42 | // Ensures the data at a given address and with a given size is the same for 43 | // the I and D caches. I and D caches are not automatically coherent on ARM 44 | // so this operation is required before any dynamically generated code can 45 | // safely run. 46 | static void EnsureIAndDCacheCoherency(void *address, size_t length); 47 | 48 | // Handle tagged pointers. 49 | template 50 | static T SetPointerTag(T pointer, uint64_t tag) { 51 | VIXL_ASSERT(IsUintN(kAddressTagWidth, tag)); 52 | 53 | // Use C-style casts to get static_cast behaviour for integral types (T), 54 | // and reinterpret_cast behaviour for other types. 55 | 56 | uint64_t raw = (uint64_t)pointer; 57 | VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(raw)); 58 | 59 | raw = (raw & ~kAddressTagMask) | (tag << kAddressTagOffset); 60 | return (T)raw; 61 | } 62 | 63 | template 64 | static uint64_t GetPointerTag(T pointer) { 65 | // Use C-style casts to get static_cast behaviour for integral types (T), 66 | // and reinterpret_cast behaviour for other types. 67 | 68 | uint64_t raw = (uint64_t)pointer; 69 | VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(raw)); 70 | 71 | return (raw & kAddressTagMask) >> kAddressTagOffset; 72 | } 73 | 74 | private: 75 | // Return the content of the cache type register. 76 | static uint32_t GetCacheType(); 77 | 78 | // I and D cache line size in bytes. 79 | static unsigned icache_line_size_; 80 | static unsigned dcache_line_size_; 81 | }; 82 | 83 | } // namespace aarch64 84 | } // namespace vixl 85 | 86 | #endif // VIXL_CPU_AARCH64_H 87 | -------------------------------------------------------------------------------- /whale/src/dbi/x86_64/instruction_rewriter_x86_64.cc: -------------------------------------------------------------------------------- 1 | #include "dbi/x86/instruction_rewriter_x86.h" 2 | #include "instruction_rewriter_x86_64.h" 3 | #include "dbi/x86/distorm/distorm.h" 4 | #include "dbi/x86/distorm/mnemonics.h" 5 | 6 | #define __ masm_-> 7 | 8 | namespace whale { 9 | namespace x86_64 { 10 | 11 | constexpr static const unsigned kRIP_index = 74; 12 | 13 | void X86_64InstructionRewriter::Rewrite() { 14 | u1 *instructions = code_->GetInstructions(); 15 | int pos = 0; 16 | size_t count = code_->GetCount(); 17 | u8 pc = cfg_pc_; 18 | while (pos < code_->GetCount()) { 19 | u1 *current = instructions + pos; 20 | _DInst insn = Decode(current, count - pos, 1); 21 | pc += insn.size; 22 | switch (insn.opcode) { 23 | case I_MOV: 24 | Rewrite_Mov(current, pc, insn); 25 | break; 26 | case I_CALL: 27 | Rewrite_Call(current, pc, insn); 28 | break; 29 | case I_JMP: 30 | Rewrite_Jmp(current, pc, insn); 31 | break; 32 | case I_JECXZ: 33 | case I_JRCXZ: 34 | Rewrite_JRCXZ(current, pc, insn); 35 | break; 36 | default: 37 | EmitCode(current, insn.size); 38 | break; 39 | } 40 | pos += insn.size; 41 | } 42 | } 43 | 44 | void X86_64InstructionRewriter::Rewrite_Mov(u1 *current, u8 pc, _DInst insn) { 45 | _Operand op0 = insn.ops[0]; 46 | _Operand op1 = insn.ops[1]; 47 | 48 | if (op0.type == O_REG && op1.type == O_SMEM && op1.index == kRIP_index) { 49 | // mov rd, nword ptr [rip + disp] 50 | int rd = insn.ops[0].index % 16; 51 | __ movq(rd, Immediate(pc + insn.disp)); 52 | __ movl(rd, Address(rd, 0)); 53 | } else if (op0.type == O_SMEM && op1.type == O_IMM && op1.index == kRIP_index) { 54 | // mov nword ptr [rip + disp], imm 55 | __ pushq(RAX); 56 | __ movq(RAX, Immediate(pc + insn.disp)); 57 | if (op1.size <= 32) { 58 | __ movl(Address(RAX, 0), Immediate(insn.imm.dword)); 59 | } else { 60 | __ movq(Address(RAX, 0), Immediate(insn.imm.qword)); 61 | } 62 | __ popq(RAX); 63 | } else { 64 | EmitCode(current, insn.size); 65 | } 66 | } 67 | 68 | void X86_64InstructionRewriter::Rewrite_Call(u1 *current, u8 pc, _DInst insn) { 69 | _Operand op = insn.ops[0]; 70 | if (op.type == O_PC) { 71 | __ movq(R11, Immediate(pc + insn.imm.qword)); 72 | __ call(R11); 73 | } else { 74 | EmitCode(current, insn.size); 75 | } 76 | } 77 | 78 | void X86_64InstructionRewriter::Rewrite_Jmp(u1 *current, u8 pc, _DInst insn) { 79 | _Operand op = insn.ops[0]; 80 | if (op.type == O_PC) { 81 | __ movq(R11, Immediate(pc + insn.imm.qword)); 82 | __ jmp(R11); 83 | } else { 84 | EmitCode(current, insn.size); 85 | } 86 | } 87 | 88 | void X86_64InstructionRewriter::Rewrite_JRCXZ(u1 *current, u8 pc, _DInst insn) { 89 | bool rewritten = false; 90 | u8 pcrel_address = pc + insn.imm.qword; 91 | if (pcrel_address >= tail_pc_) { 92 | NearLabel true_label, false_label; 93 | 94 | __ jrcxz(&true_label); 95 | __ jmp(&false_label); 96 | 97 | __ Bind(&true_label); 98 | __ movq(R11, Immediate(pcrel_address)); 99 | __ jmp(R11); 100 | 101 | __ Bind(&false_label); 102 | rewritten = true; 103 | } 104 | if (!rewritten) { 105 | EmitCode(current, insn.size); 106 | } 107 | } 108 | 109 | 110 | } // namespace x86 111 | } // namespace whale 112 | -------------------------------------------------------------------------------- /whale/src/dbi/arm/instruction_rewriter_arm.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_REWRITER_ARM_H_ 2 | #define ARCH_REWRITER_ARM_H_ 3 | 4 | #include "assembler/vixl/aarch32/macro-assembler-aarch32.h" 5 | #include "dbi/arm/decoder_thumb.h" 6 | #include "dbi/backup_code.h" 7 | #include "dbi/instruction_rewriter.h" 8 | #include "dbi/instruction_set.h" 9 | #include "base/macros.h" 10 | #include "base/primitive_types.h" 11 | #include "decoder_arm.h" 12 | 13 | namespace whale { 14 | namespace arm { 15 | 16 | class InstructionIterator { 17 | public: 18 | explicit InstructionIterator(intptr_t insn, size_t size) : insns_(insn), index_(0), 19 | size_(size) {} 20 | 21 | ~InstructionIterator() = default; 22 | 23 | template 24 | T *GetCurrentRef() { 25 | return reinterpret_cast(insns_ + index_); 26 | } 27 | 28 | template 29 | T GetCurrent() { 30 | return *GetCurrentRef(); 31 | } 32 | 33 | bool HasNext() { 34 | return index_ < size_; 35 | } 36 | 37 | void Step(u4 step) { 38 | DCHECK_LE(index_ + step, size_); 39 | index_ += step; 40 | } 41 | 42 | u4 GetIndex() { 43 | return index_; 44 | } 45 | 46 | private: 47 | intptr_t insns_; 48 | u4 index_; 49 | size_t size_; 50 | }; 51 | 52 | class ArmInstructionRewriter : public InstructionReWriter { 53 | public: 54 | ArmInstructionRewriter(vixl::aarch32::MacroAssembler *masm, BackupCode *code, 55 | u4 origin_pc, u4 tail_pc, bool is_thumb) 56 | : masm_(masm), code_(code), cfg_pc_(origin_pc), tail_pc_(tail_pc), 57 | is_thumb_(is_thumb) {} 58 | 59 | ~ArmInstructionRewriter() { 60 | delete code_; 61 | } 62 | 63 | const InstructionSet GetISA() override { 64 | return InstructionSet::kArm; 65 | } 66 | 67 | void Rewrite() override; 68 | 69 | u4 *GetStartAddress() override { 70 | return masm_->GetBuffer()->GetStartAddress(); 71 | } 72 | 73 | size_t GetCodeSize() override { 74 | return masm_->GetBuffer()->GetSizeInBytes(); 75 | } 76 | 77 | private: 78 | bool is_thumb_; 79 | const u4 cfg_pc_; 80 | const u4 tail_pc_; 81 | vixl::aarch32::MacroAssembler *masm_; 82 | BackupCode *code_; 83 | 84 | void EmitT16(const u2 insn) { 85 | masm_->GetBuffer()->Emit16(insn); 86 | } 87 | 88 | void EmitT32(const u4 insn) { 89 | EmitT16(static_cast(insn >> 16)); 90 | EmitT16(static_cast(insn & 0xffff)); 91 | } 92 | 93 | void EmitA32(const u4 insn) { 94 | masm_->GetBuffer()->Emit32(insn); 95 | } 96 | 97 | void RewriteThumb(); 98 | 99 | void RewriteArm(); 100 | 101 | void RewriteThumb_LDR_PC16(u4 pc, u2 insn); 102 | 103 | void RewriteThumb_DataProcessing16(ThumbInsnType type, u4 cfg_pc, u2 insn); 104 | 105 | void RewriteThumb_B_COND16(u4 cfg_pc, u2 insn); 106 | 107 | void RewriteThumb_B16(u4 pc, u2 insn); 108 | 109 | void RewriteThumb_ADD_FROM_PC16(u4 pc, u2 insn); 110 | 111 | void RewriteThumb_BX16(ThumbInsnType type, u4 pc, u2 insn); 112 | 113 | void RewriteThumb_CBZ16(ThumbInsnType type, u4 pc, u2 insn); 114 | 115 | void RewriteThumb_LDRL32(ThumbInsnType type, u4 pc, u4 insn); 116 | 117 | void RewriteThumb_B32(ThumbInsnType type, u4 pc, u4 insn); 118 | 119 | void RewriteArm_LDR(ArmInsnType type, u4 pc, u4 insn); 120 | 121 | void RewriteArm_Add(ArmInsnType type, u4 pc, u4 insn); 122 | 123 | void RewriteArm_B(ArmInsnType type, u4 pc, u4 insn); 124 | }; 125 | 126 | 127 | } // namespace arm 128 | } // namespace whale 129 | 130 | 131 | #endif // ARCH_REWRITER_ARM_H_ 132 | 133 | 134 | -------------------------------------------------------------------------------- /whale/src/dbi/x86/instruction_rewriter_x86.cc: -------------------------------------------------------------------------------- 1 | #include "dbi/x86/distorm/distorm.h" 2 | #include 3 | #include "dbi/x86/instruction_rewriter_x86.h" 4 | #include "instruction_rewriter_x86.h" 5 | 6 | #define __ masm_-> 7 | 8 | namespace whale { 9 | namespace x86 { 10 | 11 | void X86InstructionRewriter::Rewrite() { 12 | __ addl(ESP, Immediate(4)); 13 | u1 *insns = code_->GetInstructions(); 14 | int pos = 0; 15 | size_t count = code_->GetCount(); 16 | u4 pc = cfg_pc_; 17 | while (pos < count) { 18 | u1 *current = insns + pos; 19 | _DInst insn = Decode(current, count - pos, 0); 20 | pc += insn.size; 21 | switch (insn.opcode) { 22 | case I_CALL: 23 | Rewrite_Call(current, pc, insn); 24 | break; 25 | case I_JMP: 26 | Rewrite_Jmp(current, pc, insn); 27 | break; 28 | case I_JECXZ: 29 | case I_JCXZ: 30 | Rewrite_JRCXZ(current, pc, insn); 31 | break; 32 | default: 33 | EmitCode(current, insn.size); 34 | break; 35 | } 36 | pos += insn.size; 37 | } 38 | } 39 | 40 | void X86InstructionRewriter::Rewrite_Call(u1 *current, u4 pc, _DInst insn) { 41 | bool rewritten = false; 42 | if (insn.ops[0].type == O_PC) { 43 | u4 pcrel_address = pc + insn.imm.dword; 44 | Register reg; 45 | if (IsGetPCThunkToRegister(pcrel_address, ®)) { 46 | __ movl(reg, Immediate(pc)); 47 | rewritten = true; 48 | } else if (pcrel_address >= tail_pc_) { 49 | __ pushl(Immediate(pc)); 50 | __ movl(EDX, Immediate(pcrel_address)); 51 | __ jmp(EDX); 52 | rewritten = true; 53 | } 54 | } 55 | if (!rewritten) { 56 | EmitCode(current, insn.size); 57 | } 58 | } 59 | 60 | void X86InstructionRewriter::Rewrite_Jmp(u1 *current, u4 pc, _DInst insn) { 61 | bool rewritten = false; 62 | if (insn.ops[0].type == O_PC) { 63 | u4 pcrel_address = pc + insn.imm.dword; 64 | if (pcrel_address >= tail_pc_) { 65 | __ movl(EDX, Immediate(pcrel_address)); 66 | __ jmp(EDX); 67 | rewritten = true; 68 | } 69 | } 70 | if (!rewritten) { 71 | EmitCode(current, insn.size); 72 | } 73 | } 74 | 75 | void X86InstructionRewriter::Rewrite_JRCXZ(u1 *current, u4 pc, _DInst insn) { 76 | bool rewritten = false; 77 | u4 pcrel_address = pc + insn.imm.dword; 78 | if (pcrel_address >= tail_pc_) { 79 | NearLabel true_label, false_label; 80 | 81 | __ jecxz(&true_label); 82 | __ jmp(&false_label); 83 | 84 | __ Bind(&true_label); 85 | __ movl(EDX, Immediate(pcrel_address)); 86 | __ jmp(EDX); 87 | 88 | __ Bind(&false_label); 89 | rewritten = true; 90 | } 91 | if (!rewritten) { 92 | EmitCode(current, insn.size); 93 | } 94 | } 95 | 96 | /** 97 | * Find the following scheme: 98 | * 99 | * _x86_get_pc_thunk_bx: 100 | * mov ebx, [esp+0] 101 | * ret 102 | * 103 | */ 104 | bool X86InstructionRewriter::IsGetPCThunkToRegister(u4 address, Register *reg) { 105 | u1 *current = reinterpret_cast(address); 106 | _DInst insn0 = Decode(current, UINT8_MAX, 0); 107 | if (insn0.opcode != I_MOV || insn0.ops[0].type != O_REG || insn0.ops[1].type != O_SMEM) { 108 | return false; 109 | } 110 | _DInst insn1 = Decode(current + insn0.size, UINT8_MAX, 0); 111 | if (insn1.opcode != I_RET) { 112 | return false; 113 | } 114 | *reg = static_cast(insn0.ops[0].index % 16); 115 | return true; 116 | } 117 | 118 | } // namespace x86 119 | } // namespace whale 120 | -------------------------------------------------------------------------------- /whale/src/dbi/instruction_set.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_ARCH_INSTRUCTION_SET_H_ 2 | #define WHALE_ARCH_INSTRUCTION_SET_H_ 3 | 4 | #include "base/macros.h" 5 | #include 6 | 7 | namespace whale { 8 | 9 | enum class InstructionSet { 10 | kNone, 11 | kArm, 12 | kArm64, 13 | kThumb2, 14 | kX86, 15 | kX86_64, 16 | kMips, 17 | kMips64, 18 | kLast = kMips64 19 | }; 20 | 21 | std::ostream &operator<<(std::ostream &os, const InstructionSet &rhs); 22 | 23 | #if defined(__arm__) 24 | static constexpr InstructionSet kRuntimeISA = InstructionSet::kArm; 25 | #elif defined(__aarch64__) || defined(__arm64__) 26 | static constexpr InstructionSet kRuntimeISA = InstructionSet::kArm64; 27 | #elif defined(__mips__) && !defined(__LP64__) 28 | static constexpr InstructionSet kRuntimeISA = InstructionSet::kMips; 29 | #elif defined(__mips__) && defined(__LP64__) 30 | static constexpr InstructionSet kRuntimeISA = InstructionSet::kMips64; 31 | #elif defined(__i386__) 32 | static constexpr InstructionSet kRuntimeISA = InstructionSet::kX86; 33 | #elif defined(__x86_64__) 34 | static constexpr InstructionSet kRuntimeISA = InstructionSet::kX86_64; 35 | #else 36 | static constexpr InstructionSet kRuntimeISA = InstructionSet::kNone; 37 | #endif 38 | 39 | static constexpr size_t kPointerSize = sizeof(void *); 40 | 41 | static constexpr size_t kArmAlignment = 8; 42 | 43 | static constexpr size_t kArm64Alignment = 16; 44 | 45 | static constexpr size_t kMipsAlignment = 8; 46 | 47 | static constexpr size_t kX86Alignment = 16; 48 | 49 | static constexpr size_t kArmInstructionAlignment = 4; 50 | static constexpr size_t kThumb2InstructionAlignment = 2; 51 | static constexpr size_t kArm64InstructionAlignment = 4; 52 | static constexpr size_t kX86InstructionAlignment = 1; 53 | static constexpr size_t kX86_64InstructionAlignment = 1; 54 | static constexpr size_t kMipsInstructionAlignment = 4; 55 | static constexpr size_t kMips64InstructionAlignment = 4; 56 | 57 | const char *GetInstructionSetString(InstructionSet isa); 58 | 59 | // Note: Returns kNone when the string cannot be parsed to a known value. 60 | InstructionSet GetInstructionSetFromString(const char *instruction_set); 61 | 62 | // Fatal logging out of line to keep the header clean of logging.h. 63 | NO_RETURN void InstructionSetAbort(InstructionSet isa); 64 | 65 | 66 | constexpr bool Is64BitInstructionSet(InstructionSet isa) { 67 | switch (isa) { 68 | case InstructionSet::kArm: 69 | case InstructionSet::kThumb2: 70 | case InstructionSet::kX86: 71 | case InstructionSet::kMips: 72 | return false; 73 | 74 | case InstructionSet::kArm64: 75 | case InstructionSet::kX86_64: 76 | case InstructionSet::kMips64: 77 | return true; 78 | 79 | case InstructionSet::kNone: 80 | break; 81 | } 82 | InstructionSetAbort(isa); 83 | } 84 | 85 | constexpr size_t GetInstructionSetInstructionAlignment(InstructionSet isa) { 86 | switch (isa) { 87 | case InstructionSet::kArm: 88 | // Fall-through. 89 | case InstructionSet::kThumb2: 90 | return kThumb2InstructionAlignment; 91 | case InstructionSet::kArm64: 92 | return kArm64InstructionAlignment; 93 | case InstructionSet::kX86: 94 | return kX86InstructionAlignment; 95 | case InstructionSet::kX86_64: 96 | return kX86_64InstructionAlignment; 97 | case InstructionSet::kMips: 98 | return kMipsInstructionAlignment; 99 | case InstructionSet::kMips64: 100 | return kMips64InstructionAlignment; 101 | 102 | case InstructionSet::kNone: 103 | break; 104 | } 105 | InstructionSetAbort(isa); 106 | } 107 | 108 | } // namespace whale 109 | 110 | #endif // WHALE_ARCH_INSTRUCTION_SET_H_ 111 | -------------------------------------------------------------------------------- /whale/src/android/art/native_on_load.cc: -------------------------------------------------------------------------------- 1 | #include "android/jni_helper.h" 2 | #include "android/art/art_runtime.h" 3 | #include "base/logging.h" 4 | 5 | #define CLASS_NAME "com/lody/whale/WhaleRuntime" 6 | 7 | #ifndef WHALE_ANDROID_AUTO_LOAD 8 | #define JNI_OnLoad Whale_OnLoad 9 | #endif 10 | 11 | 12 | extern "C" OPEN_API void WhaleRuntime_reserved0(JNI_START) {} 13 | 14 | extern "C" OPEN_API void WhaleRuntime_reserved1(JNI_START) {} 15 | 16 | static jlong 17 | WhaleRuntime_hookMethodNative(JNI_START, jclass decl_class, jobject method_obj, 18 | jobject addition_info) { 19 | auto runtime = whale::art::ArtRuntime::Get(); 20 | return runtime->HookMethod(env, decl_class, method_obj, addition_info); 21 | } 22 | 23 | static jobject 24 | WhaleRuntime_invokeOriginalMethodNative(JNI_START, jlong slot, jobject this_object, 25 | jobjectArray args) { 26 | auto runtime = whale::art::ArtRuntime::Get(); 27 | return runtime->InvokeOriginalMethod(slot, this_object, args); 28 | } 29 | 30 | static jlong 31 | WhaleRuntime_getMethodSlot(JNI_START, jclass decl_class, jobject method_obj) { 32 | auto runtime = whale::art::ArtRuntime::Get(); 33 | return runtime->GetMethodSlot(env, decl_class, method_obj); 34 | } 35 | 36 | static void 37 | WhaleRuntime_setObjectClassNative(JNI_START, jobject obj, jclass parent_class) { 38 | auto runtime = whale::art::ArtRuntime::Get(); 39 | return runtime->SetObjectClass(env, obj, parent_class); 40 | } 41 | 42 | static jobject 43 | WhaleRuntime_cloneToSubclassNative(JNI_START, jobject obj, jclass sub_class) { 44 | auto runtime = whale::art::ArtRuntime::Get(); 45 | return runtime->CloneToSubclass(env, obj, sub_class); 46 | } 47 | 48 | static void 49 | WhaleRuntime_removeFinalFlagNative(JNI_START, jclass java_class) { 50 | auto runtime = whale::art::ArtRuntime::Get(); 51 | runtime->RemoveFinalFlag(env, java_class); 52 | } 53 | 54 | void WhaleRuntime_enforceDisableHiddenAPIPolicy(JNI_START) { 55 | auto runtime = whale::art::ArtRuntime::Get(); 56 | runtime->EnforceDisableHiddenAPIPolicy(); 57 | } 58 | 59 | 60 | static JNINativeMethod gMethods[] = { 61 | NATIVE_METHOD(WhaleRuntime, hookMethodNative, 62 | "(Ljava/lang/Class;Ljava/lang/reflect/Member;Ljava/lang/Object;)J"), 63 | NATIVE_METHOD(WhaleRuntime, invokeOriginalMethodNative, 64 | "(JLjava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"), 65 | NATIVE_METHOD(WhaleRuntime, getMethodSlot, "(Ljava/lang/reflect/Member;)J"), 66 | NATIVE_METHOD(WhaleRuntime, setObjectClassNative, "(Ljava/lang/Object;Ljava/lang/Class;)V"), 67 | NATIVE_METHOD(WhaleRuntime, cloneToSubclassNative, 68 | "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;"), 69 | NATIVE_METHOD(WhaleRuntime, removeFinalFlagNative, 70 | "(Ljava/lang/Class;)V"), 71 | NATIVE_METHOD(WhaleRuntime, enforceDisableHiddenAPIPolicy, "()V"), 72 | NATIVE_METHOD(WhaleRuntime, reserved0, "()V"), 73 | NATIVE_METHOD(WhaleRuntime, reserved1, "()V") 74 | }; 75 | 76 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { 77 | JNIEnv *env = nullptr; 78 | if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_4) != JNI_OK) { 79 | return -1; 80 | } 81 | jclass cl = env->FindClass(CLASS_NAME); 82 | if (cl == nullptr) { 83 | LOG(ERROR) << "FindClass failed for " << CLASS_NAME; 84 | return JNI_ERR; 85 | } 86 | if (env->RegisterNatives(cl, gMethods, NELEM(gMethods)) < 0) { 87 | LOG(ERROR) << "RegisterNatives failed for " << CLASS_NAME; 88 | return JNI_ERR; 89 | } 90 | auto runtime = whale::art::ArtRuntime::Get(); 91 | if (!runtime->OnLoad(vm, env, cl)) { 92 | LOG(ERROR) << "Runtime setup failed"; 93 | return JNI_ERR; 94 | } 95 | return JNI_VERSION_1_4; 96 | } 97 | -------------------------------------------------------------------------------- /java/com/lody/whale/VMHelper.java: -------------------------------------------------------------------------------- 1 | package com.lody.whale; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.lang.reflect.Member; 5 | import java.lang.reflect.Method; 6 | import java.util.HashMap; 7 | 8 | /** 9 | * @author Lody 10 | */ 11 | class VMHelper { 12 | 13 | // Holds a mapping from Java type names to native type codes. 14 | private static final HashMap, String> PRIMITIVE_TO_SIGNATURE; 15 | 16 | static { 17 | PRIMITIVE_TO_SIGNATURE = new HashMap<>(9); 18 | PRIMITIVE_TO_SIGNATURE.put(byte.class, "B"); 19 | PRIMITIVE_TO_SIGNATURE.put(char.class, "C"); 20 | PRIMITIVE_TO_SIGNATURE.put(short.class, "S"); 21 | PRIMITIVE_TO_SIGNATURE.put(int.class, "I"); 22 | PRIMITIVE_TO_SIGNATURE.put(long.class, "J"); 23 | PRIMITIVE_TO_SIGNATURE.put(float.class, "F"); 24 | PRIMITIVE_TO_SIGNATURE.put(double.class, "D"); 25 | PRIMITIVE_TO_SIGNATURE.put(void.class, "V"); 26 | PRIMITIVE_TO_SIGNATURE.put(boolean.class, "Z"); 27 | } 28 | 29 | /** 30 | * Returns the internal name of {@code clazz} (also known as the 31 | * descriptor). 32 | */ 33 | private static String getSignature(final Class clazz) { 34 | final String primitiveSignature = PRIMITIVE_TO_SIGNATURE.get(clazz); 35 | if (primitiveSignature != null) { 36 | return primitiveSignature; 37 | } else if (clazz.isArray()) { 38 | return "[" + getSignature(clazz.getComponentType()); 39 | } else { 40 | return "L" + clazz.getName().replace('.', '/') + ";"; 41 | } 42 | } 43 | 44 | /** 45 | * Returns the native type codes of {@code clazz}. 46 | */ 47 | private static String getShortyType(final Class clazz) { 48 | final String primitiveSignature = PRIMITIVE_TO_SIGNATURE.get(clazz); 49 | if (primitiveSignature != null) { 50 | return primitiveSignature; 51 | } 52 | return "L"; 53 | } 54 | 55 | // @SuppressWarnings("ConstantConditions") 56 | private static String getSignature(final Class retType, 57 | final Class[] parameterTypes) { 58 | final StringBuilder result = new StringBuilder(); 59 | 60 | result.append('('); 61 | for (final Class parameterType : parameterTypes) { 62 | result.append(getSignature(parameterType)); 63 | } 64 | result.append(")"); 65 | result.append(getSignature(retType)); 66 | 67 | return result.toString(); 68 | } 69 | 70 | private static String getShorty(final Class retType, 71 | final Class[] parameterTypes) { 72 | final StringBuilder result = new StringBuilder(); 73 | 74 | result.append(getShortyType(retType)); 75 | for (final Class parameterType : parameterTypes) { 76 | result.append(getShortyType(parameterType)); 77 | } 78 | 79 | return result.toString(); 80 | } 81 | 82 | static String getSignature(final Member m) { 83 | if (m instanceof Method) { 84 | final Method md = (Method) m; 85 | return getSignature(md.getReturnType(), md.getParameterTypes()); 86 | } 87 | if (m instanceof Constructor) { 88 | final Constructor c = (Constructor) m; 89 | return getSignature(void.class, c.getParameterTypes()); 90 | } 91 | return null; 92 | } 93 | 94 | static String getShorty(final Member m) { 95 | if (m instanceof Method) { 96 | final Method md = (Method) m; 97 | return getShorty(md.getReturnType(), md.getParameterTypes()); 98 | } 99 | if (m instanceof Constructor) { 100 | final Constructor c = (Constructor) m; 101 | return getShorty(void.class, c.getParameterTypes()); 102 | } 103 | return null; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /whale/src/dbi/arm/inline_hook_arm.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "platform/memory.h" 4 | #include "assembler/vixl/aarch32/macro-assembler-aarch32.h" 5 | #include "dbi/arm/inline_hook_arm.h" 6 | #include "dbi/arm/instruction_rewriter_arm.h" 7 | #include "base/logging.h" 8 | #include "base/primitive_types.h" 9 | 10 | #ifdef WHALE_DISASM_AFTER_REWRITE 11 | #include "assembler/vixl/aarch32/disasm-aarch32.h" 12 | #endif 13 | 14 | #define __ masm. 15 | 16 | namespace whale { 17 | namespace arm { 18 | 19 | using namespace vixl::aarch32; // NOLINT 20 | 21 | #ifdef WHALE_DISASM_AFTER_REWRITE 22 | 23 | void Disassemble(MacroAssembler *masm) { 24 | whale::LogMessage log("Disassembler", static_cast(masm->GetSizeOfCodeGenerated())); 25 | vixl::aarch32::PrintDisassembler disassembler(log.stream()); 26 | disassembler.DisassembleA32Buffer(masm->GetBuffer()->GetStartAddress(), 27 | masm->GetBuffer()->GetSizeInBytes()); 28 | } 29 | 30 | #endif 31 | 32 | 33 | void ArmInlineHook::StartHook() { 34 | DCHECK(address_ != 0 && replace_ != 0); 35 | MacroAssembler masm; 36 | is_thumb_ ? masm.UseT32() : masm.UseA32(); 37 | Literal replace(static_cast(replace_)); 38 | if (is_thumb_) { 39 | if (address_ % 4 != 0) { 40 | __ Nop(); 41 | } 42 | } 43 | __ Ldr(pc, &replace); 44 | __ Place(&replace); 45 | masm.FinalizeCode(); 46 | 47 | size_t backup_size = masm.GetSizeOfCodeGenerated(); 48 | u2 *target = GetTarget(); 49 | if (is_thumb_) { 50 | if (!Is32BitThumbInstruction(target[backup_size / sizeof(u2) - 2]) 51 | && Is32BitThumbInstruction(target[backup_size / sizeof(u2) - 1])) { 52 | backup_size += sizeof(u2); 53 | } 54 | } 55 | backup_code_ = new BackupCode(GetTarget(), backup_size); 56 | 57 | if (backup_ != nullptr) { 58 | intptr_t tail = address_ + backup_size; 59 | intptr_t trampoline = BuildTrampoline(static_cast(tail)); 60 | *backup_ = trampoline; 61 | } 62 | 63 | ScopedMemoryPatch patch(GetTarget(), masm.GetBuffer()->GetStartAddress(), 64 | masm.GetBuffer()->GetSizeInBytes()); 65 | memcpy(GetTarget(), masm.GetBuffer()->GetStartAddress(), 66 | masm.GetBuffer()->GetSizeInBytes()); 67 | } 68 | 69 | intptr_t 70 | ArmInlineHook::BuildTrampoline(u4 tail) { 71 | MacroAssembler masm; 72 | is_thumb_ ? masm.UseT32() : masm.UseA32(); 73 | ArmInstructionRewriter rewriter(&masm, backup_code_, GetTarget(), tail, is_thumb_); 74 | rewriter.Rewrite(); 75 | if (is_thumb_) { 76 | tail |= 1; 77 | } 78 | Literal target(static_cast(tail)); 79 | __ Ldr(pc, &target); 80 | __ Place(&target); 81 | 82 | masm.FinalizeCode(); 83 | 84 | #ifdef WHALE_DISASM_AFTER_REWRITE 85 | Disassemble(&masm); 86 | #endif 87 | 88 | size_t size = masm.GetBuffer()->GetSizeInBytes(); 89 | trampoline_addr_ = mmap(nullptr, GetPageSize(), PROT_READ | PROT_WRITE, 90 | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 91 | memcpy(trampoline_addr_, masm.GetBuffer()->GetStartAddress(), size); 92 | mprotect(trampoline_addr_, GetPageSize(), PROT_READ | PROT_EXEC); 93 | auto trampoline_addr = reinterpret_cast(trampoline_addr_); 94 | if (is_thumb_) { 95 | trampoline_addr |= 1; 96 | } 97 | return trampoline_addr; 98 | } 99 | 100 | 101 | void ArmInlineHook::StopHook() { 102 | size_t code_size = backup_code_->GetSizeInBytes(); 103 | void *insns = backup_code_->GetInstructions(); 104 | ScopedMemoryPatch patch(GetTarget(), insns, code_size); 105 | memcpy(GetTarget(), insns, code_size); 106 | if (trampoline_addr_ != nullptr) { 107 | munmap(trampoline_addr_, GetPageSize()); 108 | } 109 | } 110 | 111 | } // namespace arm 112 | } // namespace whale 113 | -------------------------------------------------------------------------------- /whale/src/platform/linux/elf_image.h: -------------------------------------------------------------------------------- 1 | #ifndef WHALE_PLATFORM_LINUX_ELF_READER_H_ 2 | #define WHALE_PLATFORM_LINUX_ELF_READER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "base/cxx_helper.h" 13 | #include "base/primitive_types.h" 14 | #include "base/logging.h" 15 | 16 | #if defined(__LP64__) 17 | #define Elf_Ehdr Elf64_Ehdr 18 | #define Elf_Shdr Elf64_Shdr 19 | #define Elf_Phdr Elf64_Phdr 20 | #define Elf_Sym Elf64_Sym 21 | #define Elf_Word Elf64_Word 22 | #define Elf_Addr Elf64_Addr 23 | #define ElfW(what) Elf64_ ## what 24 | #define ELF_R_SYM ELF64_R_SYM 25 | #define ELF_R_TYPE ELF64_R_TYPE 26 | #else 27 | #define Elf_Ehdr Elf32_Ehdr 28 | #define Elf_Shdr Elf32_Shdr 29 | #define Elf_Phdr Elf32_Phdr 30 | #define Elf_Sym Elf32_Sym 31 | #define Elf_Word Elf32_Word 32 | #define Elf_Addr Elf32_Addr 33 | #define ElfW(what) Elf32_ ## what 34 | #define ELF_R_SYM ELF32_R_SYM 35 | #define ELF_R_TYPE ELF32_R_TYPE 36 | #endif 37 | 38 | namespace whale { 39 | 40 | class ElfParser { 41 | public: 42 | ElfParser() {} 43 | 44 | intptr_t GetLoadBias() { 45 | return load_bias_; 46 | } 47 | 48 | Elf_Sym * 49 | LinearLookup(const char *name, Elf_Sym *symtab, uintptr_t symcnt, const char *strtab); 50 | 51 | Elf_Sym *ElfLookup(const char *name); 52 | 53 | Elf_Sym *GnuLookup(const char *name); 54 | 55 | 56 | uintptr_t FindSymbolOffset(const char *name); 57 | 58 | bool Parse(uintptr_t base); 59 | 60 | private: 61 | Elf_Ehdr *ehdr_; 62 | Elf_Phdr *phdr_; 63 | Elf_Shdr *shdr_; 64 | uintptr_t load_bias_; 65 | 66 | Elf_Shdr *got_; 67 | Elf_Shdr *got_plt_; 68 | Elf_Shdr *rel_dyn_; 69 | Elf_Shdr *rel_plt_; 70 | Elf_Shdr *rela_dyn_; 71 | Elf_Shdr *rela_plt_; 72 | 73 | char *shstrtab_; 74 | char *strtab_; 75 | char *dynstr_; 76 | Elf_Sym *symtab_; 77 | uintptr_t symcnt_; 78 | Elf_Sym *dynsym_; 79 | uintptr_t dyncnt_; 80 | 81 | u4 nbucket_{}; 82 | u4 nchain_{}; 83 | u4 *bucket_{}; 84 | u4 *chain_{}; 85 | 86 | u4 gnu_nbucket_{}; 87 | u4 gnu_symndx_{}; 88 | u4 gnu_maskwords_bm_; 89 | u4 gnu_shift2_; 90 | u4 *gnu_bloom_filter_; 91 | u4 *gnu_bucket_; 92 | u4 *gnu_chain_; 93 | }; 94 | 95 | class ElfReader { 96 | public: 97 | ElfReader() : base_(nullptr), len_(0), fp_(nullptr) {} 98 | 99 | ~ElfReader() { 100 | if (fp_) { 101 | fclose(fp_); 102 | } 103 | if (base_ != nullptr && base_ != MAP_FAILED) { 104 | munmap(base_, len_); 105 | } 106 | } 107 | 108 | bool Open(const char *path); 109 | 110 | bool ReadSectionHeaders() { 111 | return parser_.Parse(reinterpret_cast(base_)); 112 | } 113 | 114 | intptr_t GetLoadBias() { 115 | return parser_.GetLoadBias(); 116 | } 117 | 118 | uintptr_t FindSymbolOffset(const char *name) { 119 | return parser_.FindSymbolOffset(name); 120 | } 121 | 122 | private: 123 | void *base_; 124 | size_t len_; 125 | FILE *fp_; 126 | ElfParser parser_; 127 | }; 128 | 129 | 130 | class ElfImage { 131 | public: 132 | ElfImage() : base_(0) {} 133 | 134 | bool Open(const char *path, uintptr_t base) { 135 | base_ = base; 136 | return reader_.Open(path) && reader_.ReadSectionHeaders(); 137 | } 138 | 139 | template 140 | T FindSymbol(const char *name) { 141 | uintptr_t offset = reader_.FindSymbolOffset(name); 142 | if (offset > 0) { 143 | uintptr_t ptr = base_ + offset; 144 | return ForceCast(reinterpret_cast(ptr)); 145 | } 146 | return (T) nullptr; 147 | } 148 | 149 | 150 | private: 151 | ElfReader reader_; 152 | uintptr_t base_; 153 | }; 154 | 155 | } // namespace whale 156 | 157 | #endif // WHALE_PLATFORM_LINUX_ELF_READER_H_ 158 | -------------------------------------------------------------------------------- /whale/src/assembler/vixl/assembler-base-vixl.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016, VIXL authors 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // * Redistributions of source code must retain the above copyright notice, 8 | // this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, 10 | // this list of conditions and the following disclaimer in the documentation 11 | // and/or other materials provided with the distribution. 12 | // * Neither the name of ARM Limited nor the names of its contributors may be 13 | // used to endorse or promote products derived from this software without 14 | // specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | #ifndef VIXL_ASSEMBLER_BASE_H 28 | #define VIXL_ASSEMBLER_BASE_H 29 | 30 | #include "code-buffer-vixl.h" 31 | 32 | namespace vixl { 33 | 34 | class CodeBufferCheckScope; 35 | 36 | namespace internal { 37 | 38 | class AssemblerBase { 39 | public: 40 | AssemblerBase() : allow_assembler_(false) {} 41 | explicit AssemblerBase(size_t capacity) 42 | : buffer_(capacity), allow_assembler_(false) {} 43 | AssemblerBase(byte* buffer, size_t capacity) 44 | : buffer_(buffer, capacity), allow_assembler_(false) {} 45 | 46 | virtual ~AssemblerBase() {} 47 | 48 | // Finalize a code buffer of generated instructions. This function must be 49 | // called before executing or copying code from the buffer. 50 | void FinalizeCode() { GetBuffer()->SetClean(); } 51 | 52 | ptrdiff_t GetCursorOffset() const { return GetBuffer().GetCursorOffset(); } 53 | 54 | // Return the address of the cursor. 55 | template 56 | T GetCursorAddress() const { 57 | VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t)); 58 | return GetBuffer().GetOffsetAddress(GetCursorOffset()); 59 | } 60 | 61 | size_t GetSizeOfCodeGenerated() const { return GetCursorOffset(); } 62 | 63 | // Accessors. 64 | CodeBuffer* GetBuffer() { return &buffer_; } 65 | const CodeBuffer& GetBuffer() const { return buffer_; } 66 | bool AllowAssembler() const { return allow_assembler_; } 67 | 68 | protected: 69 | void SetAllowAssembler(bool allow) { allow_assembler_ = allow; } 70 | 71 | // CodeBufferCheckScope must be able to temporarily allow the assembler. 72 | friend class vixl::CodeBufferCheckScope; 73 | 74 | // Buffer where the code is emitted. 75 | CodeBuffer buffer_; 76 | 77 | private: 78 | bool allow_assembler_; 79 | 80 | public: 81 | // Deprecated public interface. 82 | 83 | // Return the address of an offset in the buffer. 84 | template 85 | VIXL_DEPRECATED("GetBuffer().GetOffsetAddress(offset)", 86 | T GetOffsetAddress(ptrdiff_t offset) const) { 87 | return GetBuffer().GetOffsetAddress(offset); 88 | } 89 | 90 | // Return the address of the start of the buffer. 91 | template 92 | VIXL_DEPRECATED("GetBuffer().GetStartAddress()", 93 | T GetStartAddress() const) { 94 | return GetBuffer().GetOffsetAddress(0); 95 | } 96 | }; 97 | 98 | } // namespace internal 99 | } // namespace vixl 100 | 101 | #endif // VIXL_ASSEMBLER_BASE_H 102 | -------------------------------------------------------------------------------- /whale/src/libffi/types.c: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | types.c - Copyright (c) 1996, 1998 Red Hat, Inc. 3 | 4 | Predefined ffi_types needed by libffi. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | ``Software''), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | DEALINGS IN THE SOFTWARE. 25 | ----------------------------------------------------------------------- */ 26 | 27 | /* Hide the basic type definitions from the header file, so that we 28 | can redefine them here as "const". */ 29 | #define LIBFFI_HIDE_BASIC_TYPES 30 | 31 | #include 32 | #include 33 | 34 | /* Type definitions */ 35 | 36 | #define FFI_TYPEDEF(name, type, id, maybe_const)\ 37 | struct struct_align_##name { \ 38 | char c; \ 39 | type x; \ 40 | }; \ 41 | FFI_EXTERN \ 42 | maybe_const ffi_type ffi_type_##name = { \ 43 | sizeof(type), \ 44 | offsetof(struct struct_align_##name, x), \ 45 | id, NULL \ 46 | } 47 | 48 | #define FFI_COMPLEX_TYPEDEF(name, type, maybe_const) \ 49 | static ffi_type *ffi_elements_complex_##name [2] = { \ 50 | (ffi_type *)(&ffi_type_##name), NULL \ 51 | }; \ 52 | struct struct_align_complex_##name { \ 53 | char c; \ 54 | _Complex type x; \ 55 | }; \ 56 | FFI_EXTERN \ 57 | maybe_const ffi_type ffi_type_complex_##name = { \ 58 | sizeof(_Complex type), \ 59 | offsetof(struct struct_align_complex_##name, x), \ 60 | FFI_TYPE_COMPLEX, \ 61 | (ffi_type **)ffi_elements_complex_##name \ 62 | } 63 | 64 | /* Size and alignment are fake here. They must not be 0. */ 65 | FFI_EXTERN const ffi_type ffi_type_void = { 66 | 1, 1, FFI_TYPE_VOID, NULL 67 | }; 68 | 69 | FFI_TYPEDEF(uint8, UINT8, FFI_TYPE_UINT8, const); 70 | FFI_TYPEDEF(sint8, SINT8, FFI_TYPE_SINT8, const); 71 | FFI_TYPEDEF(uint16, UINT16, FFI_TYPE_UINT16, const); 72 | FFI_TYPEDEF(sint16, SINT16, FFI_TYPE_SINT16, const); 73 | FFI_TYPEDEF(uint32, UINT32, FFI_TYPE_UINT32, const); 74 | FFI_TYPEDEF(sint32, SINT32, FFI_TYPE_SINT32, const); 75 | FFI_TYPEDEF(uint64, UINT64, FFI_TYPE_UINT64, const); 76 | FFI_TYPEDEF(sint64, SINT64, FFI_TYPE_SINT64, const); 77 | 78 | FFI_TYPEDEF(pointer, void*, FFI_TYPE_POINTER, const); 79 | 80 | FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT, const); 81 | FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE, const); 82 | 83 | #if !defined HAVE_LONG_DOUBLE_VARIANT || defined __alpha__ 84 | #define FFI_LDBL_CONST const 85 | #else 86 | #define FFI_LDBL_CONST 87 | #endif 88 | 89 | #ifdef __alpha__ 90 | /* Even if we're not configured to default to 128-bit long double, 91 | maintain binary compatibility, as -mlong-double-128 can be used 92 | at any time. */ 93 | /* Validate the hard-coded number below. */ 94 | # if defined(__LONG_DOUBLE_128__) && FFI_TYPE_LONGDOUBLE != 4 95 | # error FFI_TYPE_LONGDOUBLE out of date 96 | # endif 97 | const ffi_type ffi_type_longdouble = { 16, 16, 4, NULL }; 98 | #elif FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE 99 | FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE, FFI_LDBL_CONST); 100 | #endif 101 | 102 | #ifdef FFI_TARGET_HAS_COMPLEX_TYPE 103 | FFI_COMPLEX_TYPEDEF(float, float, const); 104 | FFI_COMPLEX_TYPEDEF(double, double, const); 105 | #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE 106 | FFI_COMPLEX_TYPEDEF(longdouble, long double, FFI_LDBL_CONST); 107 | #endif 108 | #endif 109 | -------------------------------------------------------------------------------- /whale/src/assembler/vixl/aarch64/instrument-aarch64.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014, VIXL authors 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // 7 | // * Redistributions of source code must retain the above copyright notice, 8 | // this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright notice, 10 | // this list of conditions and the following disclaimer in the documentation 11 | // and/or other materials provided with the distribution. 12 | // * Neither the name of ARM Limited nor the names of its contributors may be 13 | // used to endorse or promote products derived from this software without 14 | // specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | #ifndef VIXL_AARCH64_INSTRUMENT_AARCH64_H_ 28 | #define VIXL_AARCH64_INSTRUMENT_AARCH64_H_ 29 | 30 | #include "../globals-vixl.h" 31 | #include "../utils-vixl.h" 32 | 33 | #include "constants-aarch64.h" 34 | #include "decoder-aarch64.h" 35 | #include "instrument-aarch64.h" 36 | 37 | namespace vixl { 38 | namespace aarch64 { 39 | 40 | const int kCounterNameMaxLength = 256; 41 | const uint64_t kDefaultInstrumentationSamplingPeriod = 1 << 22; 42 | 43 | 44 | enum InstrumentState { InstrumentStateDisable = 0, InstrumentStateEnable = 1 }; 45 | 46 | 47 | enum CounterType { 48 | Gauge = 0, // Gauge counters reset themselves after reading. 49 | Cumulative = 1 // Cumulative counters keep their value after reading. 50 | }; 51 | 52 | 53 | class Counter { 54 | public: 55 | explicit Counter(const char* name, CounterType type = Gauge); 56 | 57 | void Increment(); 58 | void Enable(); 59 | void Disable(); 60 | bool IsEnabled(); 61 | uint64_t GetCount(); 62 | VIXL_DEPRECATED("GetCount", uint64_t count()) { return GetCount(); } 63 | 64 | const char* GetName(); 65 | VIXL_DEPRECATED("GetName", const char* name()) { return GetName(); } 66 | 67 | CounterType GetType(); 68 | VIXL_DEPRECATED("GetType", CounterType type()) { return GetType(); } 69 | 70 | private: 71 | char name_[kCounterNameMaxLength]; 72 | uint64_t count_; 73 | bool enabled_; 74 | CounterType type_; 75 | }; 76 | 77 | 78 | class Instrument : public DecoderVisitor { 79 | public: 80 | explicit Instrument( 81 | const char* datafile = NULL, 82 | uint64_t sample_period = kDefaultInstrumentationSamplingPeriod); 83 | ~Instrument(); 84 | 85 | void Enable(); 86 | void Disable(); 87 | 88 | // Declare all Visitor functions. 89 | #define DECLARE(A) void Visit##A(const Instruction* instr) VIXL_OVERRIDE; 90 | VISITOR_LIST(DECLARE) 91 | #undef DECLARE 92 | 93 | private: 94 | void Update(); 95 | void DumpCounters(); 96 | void DumpCounterNames(); 97 | void DumpEventMarker(unsigned marker); 98 | void HandleInstrumentationEvent(unsigned event); 99 | Counter* GetCounter(const char* name); 100 | 101 | void InstrumentLoadStore(const Instruction* instr); 102 | void InstrumentLoadStorePair(const Instruction* instr); 103 | 104 | std::list counters_; 105 | 106 | FILE* output_stream_; 107 | 108 | // Counter information is dumped every sample_period_ instructions decoded. 109 | // For a sample_period_ = 0 a final counter value is only produced when the 110 | // Instrumentation class is destroyed. 111 | uint64_t sample_period_; 112 | }; 113 | 114 | } // namespace aarch64 115 | } // namespace vixl 116 | 117 | #endif // VIXL_AARCH64_INSTRUMENT_AARCH64_H_ 118 | -------------------------------------------------------------------------------- /whale/src/whale.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "whale.h" 3 | #include "interceptor.h" 4 | #include "dbi/instruction_set.h" 5 | 6 | #if defined(__arm__) 7 | #include "dbi/arm/inline_hook_arm.h" 8 | #elif defined(__aarch64__) 9 | 10 | #include "dbi/arm64/inline_hook_arm64.h" 11 | 12 | #elif defined(__i386__) 13 | #include "dbi/x86/inline_hook_x86.h" 14 | #elif defined(__x86_64__) 15 | 16 | #include "dbi/x86_64/inline_hook_x86_64.h" 17 | 18 | #endif 19 | 20 | #if defined(__APPLE__) 21 | 22 | #include "dbi/darwin/macho_import_hook.h" 23 | 24 | #endif 25 | 26 | #if defined(linux) 27 | 28 | #include "platform/linux/elf_image.h" 29 | #include "platform/linux/process_map.h" 30 | 31 | #endif 32 | 33 | 34 | OPEN_API void WInlineHookFunction(void *address, void *replace, void **backup) { 35 | #if defined(__arm__) 36 | std::unique_ptr hook( 37 | new whale::arm::ArmInlineHook( 38 | reinterpret_cast(address), 39 | reinterpret_cast(replace), 40 | reinterpret_cast(backup) 41 | ) 42 | ); 43 | whale::Interceptor::Instance()->AddHook(hook); 44 | #elif defined(__aarch64__) 45 | std::unique_ptr hook( 46 | new whale::arm64::Arm64InlineHook( 47 | reinterpret_cast(address), 48 | reinterpret_cast(replace), 49 | reinterpret_cast(backup) 50 | ) 51 | ); 52 | whale::Interceptor::Instance()->AddHook(hook); 53 | #elif defined(__i386__) 54 | std::unique_ptr hook( 55 | new whale::x86::X86InlineHook( 56 | reinterpret_cast(address), 57 | reinterpret_cast(replace), 58 | reinterpret_cast(backup) 59 | ) 60 | ); 61 | whale::Interceptor::Instance()->AddHook(hook); 62 | #elif defined(__x86_64__) 63 | std::unique_ptr hook( 64 | new whale::x86_64::X86_64InlineHook( 65 | reinterpret_cast(address), 66 | reinterpret_cast(replace), 67 | reinterpret_cast(backup) 68 | ) 69 | ); 70 | whale::Interceptor::Instance()->AddHook(hook); 71 | #else 72 | LOG(WARNING) << "Unsupported ISA to Hook Function: " << whale::kRuntimeISA; 73 | #endif 74 | } 75 | 76 | OPEN_API void WImportHookFunction(const char *name, const char *libname, void *replace, void **backup) { 77 | #if defined(__APPLE__) 78 | std::unique_ptr hook(new whale::darwin::MachoImportHook( 79 | name, 80 | replace, 81 | backup 82 | )); 83 | whale::Interceptor::Instance()->AddHook(hook); 84 | #endif 85 | } 86 | 87 | OPEN_API void *WDynamicLibOpen(const char *name) { 88 | #ifdef linux 89 | auto range = whale::FindExecuteMemoryRange(name); 90 | if (!range->IsValid()) { 91 | return nullptr; 92 | } 93 | whale::ElfImage *image = new whale::ElfImage(); 94 | if (!image->Open(range->path_, range->base_)) { 95 | delete image; 96 | return nullptr; 97 | } 98 | return reinterpret_cast(image); 99 | #else 100 | return dlopen(name, RTLD_NOW); 101 | #endif 102 | } 103 | 104 | OPEN_API void *WDynamicLibOpenAlias(const char *name, const char *path) { 105 | #ifdef linux 106 | auto range = whale::FindExecuteMemoryRange(name); 107 | if (!range->IsValid()) { 108 | return nullptr; 109 | } 110 | whale::ElfImage *image = new whale::ElfImage(); 111 | if (!image->Open(path, range->base_)) { 112 | delete image; 113 | return nullptr; 114 | } 115 | return reinterpret_cast(image); 116 | #else 117 | return dlopen(name, RTLD_NOW); 118 | #endif 119 | } 120 | 121 | OPEN_API void *WDynamicLibSymbol(void *handle, const char *name) { 122 | if (handle == nullptr || name == nullptr) { 123 | return nullptr; 124 | } 125 | #ifdef linux 126 | whale::ElfImage *image = reinterpret_cast(handle); 127 | return image->FindSymbol(name); 128 | #else 129 | return dlsym(handle, name); 130 | #endif 131 | } 132 | 133 | OPEN_API void WDynamicLibClose(void *handle) { 134 | #ifdef linux 135 | whale::ElfImage *image = reinterpret_cast(handle); 136 | delete image; 137 | #else 138 | dlclose(handle); 139 | #endif 140 | } 141 | -------------------------------------------------------------------------------- /whale/src/libffi/ffi_common.h: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | ffi_common.h - Copyright (C) 2011, 2012, 2013 Anthony Green 3 | Copyright (C) 2007 Free Software Foundation, Inc 4 | Copyright (c) 1996 Red Hat, Inc. 5 | 6 | Common internal definitions and macros. Only necessary for building 7 | libffi. 8 | ----------------------------------------------------------------------- */ 9 | 10 | #ifndef FFI_COMMON_H 11 | #define FFI_COMMON_H 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | #include 18 | 19 | /* Do not move this. Some versions of AIX are very picky about where 20 | this is positioned. */ 21 | #ifdef __GNUC__ 22 | # if HAVE_ALLOCA_H 23 | # include 24 | # else 25 | /* mingw64 defines this already in malloc.h. */ 26 | # ifndef alloca 27 | # define alloca __builtin_alloca 28 | # endif 29 | # endif 30 | # define MAYBE_UNUSED __attribute__((__unused__)) 31 | #else 32 | # define MAYBE_UNUSED 33 | # if HAVE_ALLOCA_H 34 | # include 35 | # else 36 | # ifdef _AIX 37 | # pragma alloca 38 | # else 39 | # ifndef alloca /* predefined by HP cc +Olibcalls */ 40 | # ifdef _MSC_VER 41 | # define alloca _alloca 42 | # else 43 | char *alloca (); 44 | # endif 45 | # endif 46 | # endif 47 | # endif 48 | #endif 49 | 50 | /* Check for the existence of memcpy. */ 51 | #if STDC_HEADERS 52 | # include 53 | #else 54 | # ifndef HAVE_MEMCPY 55 | # define memcpy(d, s, n) bcopy ((s), (d), (n)) 56 | # endif 57 | #endif 58 | 59 | #if defined(FFI_DEBUG) 60 | #include 61 | #endif 62 | 63 | #ifdef FFI_DEBUG 64 | void ffi_assert(char *expr, char *file, int line); 65 | void ffi_stop_here(void); 66 | void ffi_type_test(ffi_type *a, char *file, int line); 67 | 68 | #define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) 69 | #define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) 70 | #define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) 71 | #else 72 | #define FFI_ASSERT(x) 73 | #define FFI_ASSERT_AT(x, f, l) 74 | #define FFI_ASSERT_VALID_TYPE(x) 75 | #endif 76 | 77 | /* v cast to size_t and aligned up to a multiple of a */ 78 | #define FFI_ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) 79 | /* v cast to size_t and aligned down to a multiple of a */ 80 | #define FFI_ALIGN_DOWN(v, a) (((size_t) (v)) & -a) 81 | 82 | /* Perform machine dependent cif processing */ 83 | ffi_status ffi_prep_cif_machdep(ffi_cif *cif); 84 | ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, 85 | unsigned int nfixedargs, unsigned int ntotalargs); 86 | 87 | 88 | #if HAVE_LONG_DOUBLE_VARIANT 89 | /* Used to adjust size/alignment of ffi types. */ 90 | void ffi_prep_types (ffi_abi abi); 91 | #endif 92 | 93 | /* Used internally, but overridden by some architectures */ 94 | ffi_status ffi_prep_cif_core(ffi_cif *cif, 95 | ffi_abi abi, 96 | unsigned int isvariadic, 97 | unsigned int nfixedargs, 98 | unsigned int ntotalargs, 99 | ffi_type *rtype, 100 | ffi_type **atypes); 101 | 102 | /* Extended cif, used in callback from assembly routine */ 103 | typedef struct 104 | { 105 | ffi_cif *cif; 106 | void *rvalue; 107 | void **avalue; 108 | } extended_cif; 109 | 110 | /* Terse sized type definitions. */ 111 | #if defined(_MSC_VER) || defined(__sgi) || defined(__SUNPRO_C) 112 | typedef unsigned char UINT8; 113 | typedef signed char SINT8; 114 | typedef unsigned short UINT16; 115 | typedef signed short SINT16; 116 | typedef unsigned int UINT32; 117 | typedef signed int SINT32; 118 | # ifdef _MSC_VER 119 | typedef unsigned __int64 UINT64; 120 | typedef signed __int64 SINT64; 121 | # else 122 | # include 123 | typedef uint64_t UINT64; 124 | typedef int64_t SINT64; 125 | # endif 126 | #else 127 | typedef unsigned int UINT8 __attribute__((__mode__(__QI__))); 128 | typedef signed int SINT8 __attribute__((__mode__(__QI__))); 129 | typedef unsigned int UINT16 __attribute__((__mode__(__HI__))); 130 | typedef signed int SINT16 __attribute__((__mode__(__HI__))); 131 | typedef unsigned int UINT32 __attribute__((__mode__(__SI__))); 132 | typedef signed int SINT32 __attribute__((__mode__(__SI__))); 133 | typedef unsigned int UINT64 __attribute__((__mode__(__DI__))); 134 | typedef signed int SINT64 __attribute__((__mode__(__DI__))); 135 | #endif 136 | 137 | typedef float FLOAT32; 138 | 139 | #ifndef __GNUC__ 140 | #define __builtin_expect(x, expected_value) (x) 141 | #endif 142 | #define LIKELY(x) __builtin_expect(!!(x),1) 143 | #define UNLIKELY(x) __builtin_expect((x)!=0,0) 144 | 145 | #ifdef __cplusplus 146 | } 147 | #endif 148 | 149 | #endif 150 | --------------------------------------------------------------------------------