SandHook 之 Native Inline Hook

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

内容简介:在 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

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


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

查看所有标签

猜你喜欢:

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

谁说菜鸟不会数据分析

谁说菜鸟不会数据分析

张文霖、刘夏璐、狄松 编著 / 电子工业出版社 / 2011-7 / 59.00元

《谁说菜鸟不会数据分析(全彩)》内容简介:很多人看到数据分析就望而却步,担心门槛高,无法迈入数据分析的门槛。《谁说菜鸟不会数据分析(全彩)》在降低学习难度方面做了大量的尝试:基于通用的Excel工具,加上必知必会的数据分析概念,并且采用通俗易懂的讲解方式。《谁说菜鸟不会数据分析(全彩)》努力将数据分析写成像小说一样通俗易懂,使读者可以在无形之中学会数据分析。《谁说菜鸟不会数据分析(全彩)》按照数据......一起来看看 《谁说菜鸟不会数据分析》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

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

在线压缩/解压 CSS 代码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器