SandHook 之 Native Inline Hook

栏目: 编程语言 · 发布时间: 5年前

内容简介:在 SandHook ART Hook 稳定之后,抽空把 Native Inline Hook 实现了,虽然有重复造轮子的嫌疑,但确实是本人一行一行码出来的,基本所有的东西都是自己实现的。Github: https://github.com/ganyao114/SandHook

简介

在 SandHook ART Hook 稳定之后,抽空把 Native Inline Hook 实现了,虽然有重复造轮子的嫌疑,但确实是本人一行一行码出来的,基本所有的东西都是自己实现的。

Github: https://github.com/ganyao114/SandHook

支持

目前支持  ARM32、 ARM64

其实 X86 非常好实现,但是想了一下还是往后稍稍吧,等 ARM 稳定了再说。

特点

1、纯手写的反汇编器和汇编器

没有用 vixl 或者其他库,也不是那种一堆 bit 操作难以阅读那种,可读性很强。当然我也仅仅实现了部分常见指令。

2、指令修复考虑到了更多的 Case

比如当你重复多次 Hook 同一个函数时,SandHook 可以比较好的支持。

3、纯手写的 ELF 解析

你可以搜索到比 dlysm 更多的符号,你可以直接这样 hook

suspendVMBackup = reinterpret_cast<void (*)()>(SandInlineHookSym("/system/lib/libart.so", "_ZN3art3Dbg9SuspendVMEv", reinterpret_cast<void *>(SuspendVMReplace)));

4、除了 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 目前测试的不多,欢迎测试一起完善。

- End -

SandHook 之 Native Inline Hook

看雪ID:坑大      

https://bbs.pediy.com/user-675677.htm   

本文由看雪论坛  坑大     原创

转载请注明来自看雪社区

热门图书推荐

SandHook 之 Native Inline Hook   立即购买!

:warning: 注意

2019 看雪安全开发者峰会门票正在热售中!

长按识别下方 二维码 即可享受  2.5折  优惠!

SandHook 之 Native Inline Hook

SandHook 之 Native Inline Hook

公众号ID:ikanxue

官方微博:看雪安全

商务合作:wsc@kanxue.com

点击下方“阅读原文”,查看更多干货


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

架构整洁之道

架构整洁之道

【美】Robert C. Martin(罗伯特 C. 马丁) / 电子工业出版社 / 2018-9 / 99.00元

《架构整洁之道》是创造“Clean神话”的Bob大叔在架构领域的登峰之作,围绕“架构整洁”这一重要导向,系统地剖析其缘起、内涵及应用场景,涵盖软件研发完整过程及所有核心架构模式。《架构整洁之道》分为6部分,第1部分纲领性地提出软件架构设计的终极目标,描述软件架构设计的重点与模式;第2~4部分从软件开发中三个基础编程范式的定义和特征出发,进一步描述函数、组件、服务设计与实现的定律,以及它们是如何有效......一起来看看 《架构整洁之道》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

在线进制转换器
在线进制转换器

各进制数互转换器