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よりも多くの記号を検索できます
    suspendVMBackup = reinterpret_cast<void (*)()>(SandInlineHookSym("/system/lib/libart.so", "_ZN3art3Dbg9SuspendVMEv",                                                                 reinterpret_cast<void *>(SuspendVMReplace)));
    
  • Hookを除く
  • コンパイラや解析器を使って他のことをすることもできます.もちろん、より多くのコマンドをサポートするのに便利です.
    コード#コード#
    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は现在テストが多くありません.テストと一绪に改善することを歓迎します.