SandHookのNative Inline Hook
概要
SandHook ART Hookが安定した後、暇を見つけてNative Inline Hookを実現した.車輪を繰り返す疑いがあるが、確かに本人が1行1行コードで出てきたもので、基本的なものはすべて自分で実現したものだ.
Github: https://github.com/ganyao114/SandHook
サポート
現在のサポート ARM32 ARM64
実はX 86はとてもよく実现して、しかし考えてやはり后で少し、ARMが安定したことを待って更に言います
特長純手書きの逆アセンブリとアセンブリ vixlや他のライブラリを使っていないし、bit操作が読みにくいものではなく、読みやすさが強い.もちろん私も一部の一般的な命令を実現しただけです.命令修復より多くのCase を考慮
例えば、同じ関数を何度も繰り返した場合、SandHookはよりよくサポートできます.純手書きELF解析 dlysmよりも多くの記号を検索できます Hookを除く コンパイラや解析器を使って他のことをすることもできます.もちろん、より多くのコマンドをサポートするのに便利です.
コード#コード#
Hookセクション
命令解析とアセンブリ
まず命令のbit構造を記述し,基本的にARMマニュアルと照合できる.
命令の解析とアセンブリ
アセンブリ:基本的には、各命令パッケージの呼び出しです.
解析:
コマンドリペア
の最後の部分
実はNative Inline HookはART Hookとは大きく异なっています.それ自体に深さはありません.マニュアルをたくさん见てください.もちろんnative hookは现在テストが多くありません.テストと一绪に改善することを歓迎します.
SandHook ART Hookが安定した後、暇を見つけてNative Inline Hookを実現した.車輪を繰り返す疑いがあるが、確かに本人が1行1行コードで出てきたもので、基本的なものはすべて自分で実現したものだ.
Github: https://github.com/ganyao114/SandHook
サポート
現在のサポート
実はX 86はとてもよく実现して、しかし考えてやはり后で少し、ARMが安定したことを待って更に言います
特長
例えば、同じ関数を何度も繰り返した場合、SandHookはよりよくサポートできます.
suspendVMBackup = reinterpret_cast<void (*)()>(SandInlineHookSym("/system/lib/libart.so", "_ZN3art3Dbg9SuspendVMEv", reinterpret_cast<void *>(SuspendVMReplace)));
コード#コード#
Hookセクション
#include "hook_arm64.h"
#include "code_buffer.h"
#include "lock.h"
using namespace SandHook::Hook;
using namespace SandHook::Decoder;
using namespace SandHook::Asm;
using namespace SandHook::Assembler;
using namespace SandHook::Utils;
#include "assembler_arm64.h"
#include "code_relocate_arm64.h"
using namespace SandHook::RegistersA64;
void *InlineHookArm64Android::inlineHook(void *origin, void *replace) {
AutoLock lock(hookLock);
void* backup = nullptr;
AssemblerA64 assemblerBackup(backupBuffer);
StaticCodeBuffer inlineBuffer = StaticCodeBuffer(reinterpret_cast<Addr>(origin));
AssemblerA64 assemblerInline(&inlineBuffer);
CodeContainer* codeContainerInline = &assemblerInline.codeContainer;
//build inline trampoline
#define __ assemblerInline.
Label* target_addr_label = new Label();
__ Ldr(IP1, target_addr_label);
__ Br(IP1);
__ Emit(target_addr_label);
__ Emit((Addr) replace);
#undef __
//build backup method
CodeRelocateA64 relocate = CodeRelocateA64(assemblerBackup);
backup = relocate.relocate(origin, codeContainerInline->size(), nullptr);
#define __ assemblerBackup.
Label* origin_addr_label = new Label();
__ Ldr(IP1, origin_addr_label);
__ Br(IP1);
__ Emit(origin_addr_label);
__ Emit((Addr) origin + codeContainerInline->size());
__ finish();
#undef __
//commit inline trampoline
assemblerInline.finish();
return backup;
}
命令解析とアセンブリ
まず命令のbit構造を記述し,基本的にARMマニュアルと照合できる.
DEFINE_OPCODE_T32(LDR_LIT, 0b1111100)
DEFINE_STRUCT_T32(LDR_LIT) {
InstT32 op:7;
InstT32 U:1;
InstT32 S:1;
InstT32 opcode:7;
InstT32 imm12:12;
InstT32 rt:T32_REG_WIDE;
};
命令の解析とアセンブリ
void T32_LDR_LIT::decode(T32_STRUCT_LDR_LIT *inst) {
DECODE_OP;
DECODE_RT(Reg);
s = S(inst->S);
offset = getImmPCOffset();
}
void T32_LDR_LIT::assembler() {
SET_OPCODE(LDR_LIT);
ENCODE_OP;
ENCODE_RT;
get()->S = s;
if (offset >= 0) {
get()->U = add;
get()->imm12 = static_cast<InstT32>(offset);
} else {
get()->U = cmp;
get()->imm12 = static_cast<InstT32>(-offset);
}
}
アセンブリ:基本的には、各命令パッケージの呼び出しです.
void AssemblerA32::Mov(RegisterA32 &rd, U16 imm16) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(MOV_MOVT_IMM)(INST_T32(MOV_MOVT_IMM)::MOV, rd, imm16)));
}
void AssemblerA32::Movt(RegisterA32 &rd, U16 imm16) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(MOV_MOVT_IMM)(INST_T32(MOV_MOVT_IMM)::MOVT, rd, imm16)));
}
void AssemblerA32::Mov(RegisterA32 &rd, U32 imm32) {
U16 immL = BITS16L(imm32);
U16 immH = BITS16H(imm32);
Mov(rd, immL);
Movt(rd, immH);
}
解析:
void Arm64Decoder::decode(void *codeStart, Addr codeLen, InstVisitor &visitor, bool onlyPcRelInst) {
InstA64 *pc = reinterpret_cast<InstA64 *>(codeStart);
Addr endAddr = (Addr) codeStart + codeLen;
Unit<Base>* unit = nullptr;
while((Addr) pc < endAddr) {
// pc relate insts
CASE(B_BL)
CASE(B_COND)
CASE(CBZ_CBNZ)
CASE(TBZ_TBNZ)
CASE(LDR_LIT)
CASE(ADR_ADRP)
if (onlyPcRelInst)
goto label_matched;
CASE(MOV_WIDE)
CASE(MOV_REG)
CASE(LDR_IMM)
CASE(LDR_UIMM)
CASE(LDRSW_IMM)
CASE(LDRSW_UIMM)
CASE(STR_UIMM)
CASE(STR_IMM)
CASE(BR_BLR_RET)
CASE(SUB_EXT_REG)
CASE(SVC)
CASE(EXCEPTION_GEN)
label_matched:
if (unit == nullptr) {
unit = reinterpret_cast<Unit<Base> *>(new INST_A64(UNKNOW)(*reinterpret_cast<STRUCT_A64(UNKNOW) *>(pc)));
}
if (!visitor.visit(unit, pc)) {
break;
}
pc = reinterpret_cast<InstA64 *>((Addr)pc + unit->size());
unit = nullptr;
}
}
コマンドリペア
void* CodeRelocateA64::relocate(Instruction<Base> *instruction, void *toPc) throw(ErrorCodeException) {
void* curPc = __ getPC();
//insert later bind labels
__ Emit(getLaterBindLabel(curOffset));
if (!instruction->pcRelate()) {
__ Emit(instruction);
instruction->ref();
return curPc;
}
switch (instruction->instCode()) {
CASE(B_BL)
CASE(B_COND)
CASE(TBZ_TBNZ)
CASE(CBZ_CBNZ)
CASE(LDR_LIT)
CASE(ADR_ADRP)
default:
__ Emit(instruction);
instruction->ref();
}
return curPc;
}
IMPL_RELOCATE(B_BL) {
if (inRelocateRange(inst->offset, sizeof(InstA64))) {
inst->ref();
inst->bindLabel(*getLaterBindLabel(inst->offset + curOffset));
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
return;
}
Addr targetAddr = inst->getImmPCOffsetTarget();
if (inst->op == inst->BL) {
Addr lr = reinterpret_cast<Addr>(toPc);
lr += 4 * 4; // MovWide * 4;
lr += 4 * 4; // MovWide * 4;
lr += 4; // Br
__ Mov(LR, lr);
}
__ Mov(IP1, targetAddr);
__ Br(IP1);
}
の最後の部分
実はNative Inline HookはART Hookとは大きく异なっています.それ自体に深さはありません.マニュアルをたくさん见てください.もちろんnative hookは现在テストが多くありません.テストと一绪に改善することを歓迎します.