Commit 935457ea authored by swift_gan's avatar swift_gan Committed by swift_gan

add SingleInstBreakPoint

parent d714cd48
...@@ -233,7 +233,7 @@ return is backup method ...@@ -233,7 +233,7 @@ return is backup method
you can insert a break point in body of method(not only start of method), so you can read/write registers in break point. you can insert a break point in body of method(not only start of method), so you can read/write registers in break point.
bool SandBreakpoint(void* origin, void (*callback)(REG[])); bool SandBreakPoint(void* origin, void (*callback)(REG[]));
## short method ## short method
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <log.h> #include <log.h>
#include <cstdlib> #include <cstdlib>
#include <cassert>
#include "code_relocate_arm32.h" #include "code_relocate_arm32.h"
#include "hook_arm32.h" #include "hook_arm32.h"
#include "code_buffer.h" #include "code_buffer.h"
...@@ -75,6 +76,8 @@ IMPORT_SHELLCODE(BP_SHELLCODE) ...@@ -75,6 +76,8 @@ IMPORT_SHELLCODE(BP_SHELLCODE)
IMPORT_LABEL(callback_addr_s, Addr) IMPORT_LABEL(callback_addr_s, Addr)
IMPORT_LABEL(origin_addr_s, Addr) IMPORT_LABEL(origin_addr_s, Addr)
bool InlineHookArm32Android::BreakPoint(void *origin, void (*callback)(REG *)) { bool InlineHookArm32Android::BreakPoint(void *origin, void (*callback)(REG *)) {
if (origin == nullptr || callback == nullptr)
return false;
AutoLock lock(hook_lock); AutoLock lock(hook_lock);
void* origin_code; void* origin_code;
...@@ -129,6 +132,8 @@ bool InlineHookArm32Android::BreakPoint(void *origin, void (*callback)(REG *)) { ...@@ -129,6 +132,8 @@ bool InlineHookArm32Android::BreakPoint(void *origin, void (*callback)(REG *)) {
} }
void *InlineHookArm32Android::SingleInstHook(void *origin, void *replace) { void *InlineHookArm32Android::SingleInstHook(void *origin, void *replace) {
if (origin == nullptr || replace == nullptr)
return nullptr;
if (!InitForSingleInstHook()) { if (!InitForSingleInstHook()) {
return nullptr; return nullptr;
} }
...@@ -166,22 +171,76 @@ void *InlineHookArm32Android::SingleInstHook(void *origin, void *replace) { ...@@ -166,22 +171,76 @@ void *InlineHookArm32Android::SingleInstHook(void *origin, void *replace) {
__ Finish(); __ Finish();
#undef __ #undef __
hook_infos.push_back({origin, replace, GetThumbPC(backup)}); hook_infos.push_back({false, nullptr, origin, replace, GetThumbPC(backup)});
//commit inline trampoline //commit inline trampoline
assembler_inline.Finish(); assembler_inline.Finish();
return GetThumbPC(backup); return GetThumbPC(backup);
} }
bool InlineHookArm32Android::SingleBreakPoint(void *point, BreakCallback callback, void *data) {
if (point == nullptr || callback == nullptr)
return false;
if (!InitForSingleInstHook())
return false;
AutoLock lock(hook_lock);
void* origin_code;
if (IsThumbCode((Addr) point)) {
origin_code = GetThumbCodeAddress(point);
} else {
LOGE("hook %d error!, only support thumb2 now!", point);
return nullptr;
}
void* backup = nullptr;
AssemblerA32 assembler_backup(backup_buffer);
StaticCodeBuffer inline_buffer = StaticCodeBuffer(reinterpret_cast<Addr>(origin_code));
AssemblerA32 assembler_inline(&inline_buffer);
CodeContainer* code_container_inline = &assembler_inline.code_container;
//build inline trampoline
#define __ assembler_inline.
__ Hvc(static_cast<U16>(hook_infos.size()));
#undef __
//build backup method
CodeRelocateA32 relocate = CodeRelocateA32(assembler_backup);
backup = relocate.Relocate(point, code_container_inline->Size(), nullptr);
#define __ assembler_backup.
Label* origin_addr_label = new Label();
ALIGN_FOR_LDR
__ Ldr(PC, origin_addr_label);
__ Emit(origin_addr_label);
__ Emit((Addr) GetThumbPC(reinterpret_cast<void *>(reinterpret_cast<Addr>(origin_code) + relocate.cur_offset)));
__ Finish();
#undef __
hook_infos.push_back({true, data, point, (void*)callback, GetThumbPC(backup)});
//commit inline trampoline
assembler_inline.Finish();
return true;
}
void InlineHookArm32Android::ExceptionHandler(int num, sigcontext *context) { void InlineHookArm32Android::ExceptionHandler(int num, sigcontext *context) {
assert(num == SIGILL);
InstT32 *code = reinterpret_cast<InstT32*>(context->arm_pc); InstT32 *code = reinterpret_cast<InstT32*>(context->arm_pc);
if (!IS_OPCODE_T32(*code, HVC)) { assert(IS_OPCODE_T32(*code, HVC));
abort();
}
INST_T32(HVC) hvc(code); INST_T32(HVC) hvc(code);
hvc.Disassemble(); hvc.Disassemble();
if (hvc.imme >= hook_infos.size()) if (hvc.imme >= hook_infos.size())
return; return;
HookInfo &hook_info = hook_infos[hvc.imme]; HookInfo &hook_info = hook_infos[hvc.imme];
context->arm_pc = reinterpret_cast<U32>(hook_info.replace); if (!hook_info.is_break_point) {
context->arm_pc = reinterpret_cast<U32>(hook_info.replace);
} else {
BreakCallback callback = reinterpret_cast<BreakCallback>(hook_info.replace);
if (callback(context, hook_info.user_data)) {
context->arm_pc = reinterpret_cast<U32>(hook_info.replace);
} else {
context->arm_pc += 4;
}
}
} }
...@@ -16,6 +16,8 @@ namespace SandHook { ...@@ -16,6 +16,8 @@ namespace SandHook {
bool BreakPoint(void *point, void (*callback)(REG *)) override; bool BreakPoint(void *point, void (*callback)(REG *)) override;
bool SingleBreakPoint(void *point, BreakCallback callback, void *data) override;
void *SingleInstHook(void *origin, void *replace) override; void *SingleInstHook(void *origin, void *replace) override;
void ExceptionHandler(int num, sigcontext *context) override; void ExceptionHandler(int num, sigcontext *context) override;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// //
#include <cstdlib> #include <cstdlib>
#include <cassert>
#include "hook_arm64.h" #include "hook_arm64.h"
#include "code_buffer.h" #include "code_buffer.h"
#include "lock.h" #include "lock.h"
...@@ -53,6 +54,8 @@ void *InlineHookArm64Android::Hook(void *origin, void *replace) { ...@@ -53,6 +54,8 @@ void *InlineHookArm64Android::Hook(void *origin, void *replace) {
} }
bool InlineHookArm64Android::BreakPoint(void *point, void (*callback)(REG regs[])) { bool InlineHookArm64Android::BreakPoint(void *point, void (*callback)(REG regs[])) {
if (point == nullptr || callback == nullptr)
return false;
AutoLock lock(hook_lock); AutoLock lock(hook_lock);
void* backup = nullptr; void* backup = nullptr;
...@@ -135,9 +138,10 @@ bool InlineHookArm64Android::BreakPoint(void *point, void (*callback)(REG regs[] ...@@ -135,9 +138,10 @@ bool InlineHookArm64Android::BreakPoint(void *point, void (*callback)(REG regs[]
void *InlineHookArm64Android::SingleInstHook(void *origin, void *replace) { void *InlineHookArm64Android::SingleInstHook(void *origin, void *replace) {
if (!InitForSingleInstHook()) { if (origin == nullptr || replace == nullptr)
return nullptr;
if (!InitForSingleInstHook())
return nullptr; return nullptr;
}
AutoLock lock(hook_lock); AutoLock lock(hook_lock);
void* backup = nullptr; void* backup = nullptr;
AssemblerA64 assembler_backup(backup_buffer); AssemblerA64 assembler_backup(backup_buffer);
...@@ -163,22 +167,67 @@ void *InlineHookArm64Android::SingleInstHook(void *origin, void *replace) { ...@@ -163,22 +167,67 @@ void *InlineHookArm64Android::SingleInstHook(void *origin, void *replace) {
__ Finish(); __ Finish();
#undef __ #undef __
hook_infos.push_back({origin, replace, backup}); hook_infos.push_back({false, nullptr, origin, replace, backup});
//commit inline trampoline //commit inline trampoline
assembler_inline.Finish(); assembler_inline.Finish();
return backup; return backup;
} }
bool InlineHookArm64Android::SingleBreakPoint(void *point, BreakCallback callback, void *data) {
if (point == nullptr || callback == nullptr)
return false;
if (!InitForSingleInstHook())
return false;
AutoLock lock(hook_lock);
void* backup = nullptr;
AssemblerA64 assembler_backup(backup_buffer);
StaticCodeBuffer inline_buffer = StaticCodeBuffer(reinterpret_cast<Addr>(point));
AssemblerA64 assembler_inline(&inline_buffer);
CodeContainer* code_container_inline = &assembler_inline.code_container;
//build inline trampoline
#define __ assembler_inline.
__ Hvc(static_cast<U16>(hook_infos.size()));
#undef __
//build backup method
CodeRelocateA64 relocate = CodeRelocateA64(assembler_backup);
backup = relocate.Relocate(point, code_container_inline->Size(), nullptr);
#define __ assembler_backup.
Label* origin_addr_label = new Label();
__ Ldr(IP1, origin_addr_label);
__ Br(IP1);
__ Emit(origin_addr_label);
__ Emit((Addr) point + code_container_inline->Size());
__ Finish();
#undef __
hook_infos.push_back({true, data, point, (void*)callback, backup});
//commit inline trampoline
assembler_inline.Finish();
return true;
}
void InlineHookArm64Android::ExceptionHandler(int num, sigcontext *context) { void InlineHookArm64Android::ExceptionHandler(int num, sigcontext *context) {
assert(num == SIGILL);
InstA64 *code = reinterpret_cast<InstA64*>(context->pc); InstA64 *code = reinterpret_cast<InstA64*>(context->pc);
if (!IS_OPCODE_A64(*code, EXCEPTION_GEN)) { assert(IS_OPCODE_A64(*code, EXCEPTION_GEN));
abort();
}
INST_A64(EXCEPTION_GEN) hvc(code); INST_A64(EXCEPTION_GEN) hvc(code);
hvc.Disassemble(); hvc.Disassemble();
if (hvc.imme >= hook_infos.size()) if (hvc.imme >= hook_infos.size())
return; return;
HookInfo &hook_info = hook_infos[hvc.imme]; HookInfo &hook_info = hook_infos[hvc.imme];
context->pc = reinterpret_cast<U64>(hook_info.replace); if (!hook_info.is_break_point) {
context->pc = reinterpret_cast<U64>(hook_info.replace);
} else {
BreakCallback callback = reinterpret_cast<BreakCallback>(hook_info.replace);
if (callback(context, hook_info.user_data)) {
context->pc = reinterpret_cast<U64>(hook_info.replace);
} else {
context->pc += 4;
}
}
} }
...@@ -12,8 +12,11 @@ namespace SandHook { ...@@ -12,8 +12,11 @@ namespace SandHook {
class InlineHookArm64Android : public InlineHook { class InlineHookArm64Android : public InlineHook {
public: public:
void *Hook(void *origin, void *replace) override; void *Hook(void *origin, void *replace) override;
bool BreakPoint(void *point, void (*callback)(REG[])) override; bool BreakPoint(void *point, void (*callback)(REG[])) override;
bool SingleBreakPoint(void *point, BreakCallback callback, void *data) override;
void *SingleInstHook(void *origin, void *replace) override; void *SingleInstHook(void *origin, void *replace) override;
void ExceptionHandler(int num, sigcontext *context) override; void ExceptionHandler(int num, sigcontext *context) override;
......
...@@ -18,11 +18,15 @@ namespace SandHook { ...@@ -18,11 +18,15 @@ namespace SandHook {
namespace Hook { namespace Hook {
struct HookInfo { struct HookInfo {
bool is_break_point;
void *user_data;
void *origin; void *origin;
void *replace; void *replace;
void *backup; void *backup;
}; };
using BreakCallback = bool (*)(sigcontext*, void*);
class InlineHook { class InlineHook {
public: public:
//return == backup method //return == backup method
...@@ -30,6 +34,9 @@ namespace SandHook { ...@@ -30,6 +34,9 @@ namespace SandHook {
virtual bool BreakPoint(void *point, void (*callback)(REG[])) { virtual bool BreakPoint(void *point, void (*callback)(REG[])) {
return false; return false;
}; };
virtual bool SingleBreakPoint(void *point, BreakCallback callback, void *data = nullptr) {
return false;
};
virtual void *SingleInstHook(void *origin, void *replace) { virtual void *SingleInstHook(void *origin, void *replace) {
return nullptr; return nullptr;
}; };
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
// //
#include <jni.h> #include <jni.h>
#include <cassert>
#include <cstdlib>
#include "sandhook_native.h" #include "sandhook_native.h"
#include "hook.h" #include "hook.h"
#include "elf.h" #include "elf.h"
...@@ -10,6 +12,11 @@ ...@@ -10,6 +12,11 @@
using namespace SandHook::Hook; using namespace SandHook::Hook;
using namespace SandHook::Elf; using namespace SandHook::Elf;
extern "C"
EXPORT void* SandGetModuleBase(const char* so) {
return ElfImg::GetModuleBase(so);
}
extern "C" extern "C"
EXPORT void* SandGetSym(const char* so, const char* symb) { EXPORT void* SandGetSym(const char* so, const char* symb) {
ElfImg elfImg(so); ElfImg elfImg(so);
...@@ -47,6 +54,33 @@ EXPORT void* SandSingleInstHookSym(const char* so, const char* symb, void* repla ...@@ -47,6 +54,33 @@ EXPORT void* SandSingleInstHookSym(const char* so, const char* symb, void* repla
} }
extern "C" extern "C"
EXPORT bool SandBreakpoint(void* origin, void (*callback)(REG[])) { EXPORT bool SandBreakPoint(void *origin, void (*callback)(REG[])) {
return InlineHook::instance->BreakPoint(origin, callback); return InlineHook::instance->BreakPoint(origin, callback);
} }
\ No newline at end of file
extern "C"
EXPORT bool SandSingleInstBreakPoint(void *origin, BreakCallback(callback)) {
return InlineHook::instance->SingleBreakPoint(origin, callback);
}
#if defined(__aarch64__)
fpsimd_context* GetSimdContext(sigcontext *mcontext) {
size_t size = 0;
do {
fpsimd_context *fp = reinterpret_cast<fpsimd_context *>(&mcontext->__reserved[size]);
if (fp->head.magic == FPSIMD_MAGIC) {
assert(fp->head.size >= sizeof(fpsimd_context));
assert(size + fp->head.size <= sizeof(mcontext->__reserved));
return fp;
}
if (fp->head.size == 0) {
break;
}
size += fp->head.size;
} while (size + sizeof(fpsimd_context) <= sizeof(mcontext->__reserved));
abort();
return nullptr;
}
#endif
\ No newline at end of file
...@@ -4,10 +4,17 @@ ...@@ -4,10 +4,17 @@
#pragma once #pragma once
#include <signal.h>
typedef size_t REG; typedef size_t REG;
#define EXPORT __attribute__ ((visibility ("default"))) #define EXPORT __attribute__ ((visibility ("default")))
#define BreakCallback(callback) bool(*callback)(sigcontext*, void*)
extern "C"
EXPORT void* SandGetModuleBase(const char* so);
extern "C" extern "C"
EXPORT void* SandGetSym(const char* so, const char* sym); EXPORT void* SandGetSym(const char* so, const char* sym);
...@@ -24,4 +31,15 @@ extern "C" ...@@ -24,4 +31,15 @@ extern "C"
EXPORT void* SandSingleInstHookSym(const char* so, const char* symb, void* replace); EXPORT void* SandSingleInstHookSym(const char* so, const char* symb, void* replace);
extern "C" extern "C"
EXPORT bool SandBreakpoint(void* origin, void (*callback)(REG[])); EXPORT bool SandBreakPoint(void *origin, void (*callback)(REG[]));
\ No newline at end of file
extern "C"
EXPORT bool SandSingleInstBreakPoint(void *origin, BreakCallback(callback));
#if defined(__aarch64__)
#include <asm/sigcontext.h>
extern "C"
EXPORT fpsimd_context* GetSimdContext(sigcontext *mcontext);
#endif
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment