首页
社区
课程
招聘
[原创]静态InlineHook的脚本实现
发表于: 2021-9-30 18:42 30419

[原创]静态InlineHook的脚本实现

2021-9-30 18:42
30419

Use lief, keystone and capstone to manually inline hook elf(libil2cpp.so) file

前文说到使用基于LIEF的InlineHook实现 ,在这里我们再借助 keystonecapstone 来完善一下这个想法,解决一些比较枯燥且容易出错的事,比如 地址偏移的计算,指令备份还原 ...

小提示

记录下用到的五个起始位置

原来的样子
这里在+-32MB范围内建议直接用bl会比较简洁一些
脚本中提供了三种方式的 hook:ldr(3)/b(1)/bl(1)
原来的样子

hook之后使用三条指令跳转到 trampolines
hook之后

进入到trampolines
做一次中转,保存上下文同时跳转到hook代码
进入到trampolines

进入到textCodes
真实的hook代码位置,使用的每一个小功能代码连续且独立成块,用一条b跳过相对寻址占用的位置
进入到textCodes

GLOBAL_TABLE
GLOBAL_TABLE

STR_TABLE
STR_TABLE

(目前有一个已知的问题是对CallStaticVoidMethod参数的构建,具体JValueArray的内存实现大概是猜对了,基本数据类型是没啥问题,主要是引用数据类型不能正确读取)
具体实现如下:

relocationGot

继承关系
AsmPatch -> AndroidPatch -> UnityPatch

然后就得到了这种 arm32 hook

https://github.com/axhlzy/PyAsmPatch

[手动狗头].png

 
 
 
 
 
 
 
def fixGot(self, log):
    self.mprotect(mPtr=functionsMap.get("GOT_TABLE"), size=1024 * 8, log=log)
    self.loadBaseToReg(reg="R9", log=True)
    self.relocationGot(reg="R9")
    self.endHook()
def fixGot(self, log):
    self.mprotect(mPtr=functionsMap.get("GOT_TABLE"), size=1024 * 8, log=log)
    self.loadBaseToReg(reg="R9", log=True)
    self.relocationGot(reg="R9")
    self.endHook()
# 使用 mprotect 修改内存区域的读写权限
def mprotect(self, mPtr=None, size=4096, prot=7, log=False):
    if mPtr is None:
        self.patchASM("MOV R2,PC")
    else:
        self.loadToReg(self.addPtr(mPtr), reg="R2")
    self.prepareStack(3)
    self.patchASM("MOV R1,R2,LSR#12")
    self.patchASM("MOV R0,R1,LSL#12")
    self.saveRegToStack(reg="R0", index=0)
    self.patchASM("MOV R1,#{}".format(size))
    self.saveRegToStack(reg="R1", index=1)
    self.patchASM("MOV R2,#{}".format(prot))
    self.saveRegToStack(reg="R2", index=2)
    self.jumpTo(self.getRelocation("mprotect"), jmpType="REL", reg="R3", resetPC=False)
    self.patchASM("MOV R3,R0")
    if log:
        self.android_log_print_reg(formart="mprotect ret = %d  args : %p %p %p")
    self.restoreStack(3)
 
# 获取 il2cpp 基地址
# 代码执行到这里的时候我们知道当前的pc值以及当前代码静态的地址,所以我们相减即可得到当前的so基地址
def loadBaseToReg(self, reg="R4", log=False):
    self.loadToReg(self.addPtr(self.currentPC + 7 * self._pSize), reg="R1", fix=1)
    self.patchASM("LDR R2,[R1]")
    self.patchASM("SUB R0,PC,R2")
    self.patchASM("MOV {},R0".format(reg))
    if log:
        self.patchASM("MOV R3,R0")
        self.android_log_print_reg(formart="soAddr -> %p")
 
# 直接理解为用汇编实现的一下代码即可
# while(GOT_TABLE[index]!=0x0){
#       GOT_TABLE[index] += soAddr
# }
def relocationGot(self, reg="R9"):
    self.prepareStack(2)
    self.loadToReg(functionsMap.get("GOT_TABLE"), reg="R5", fix=1)
    self.patchASM("MOV R7,#0")
    self.patchASM("MOV R10,#0")
    # R5:存放指针 R6:存放具体值 R7:存放偏移 R8:CurrentPtr
    self.patchASM("ADD R8,R5,R7")
    self.patchASM("LDR R6,[R8]")
    self.patchASM("CMP R6,#0")
    # 标识结束,直接跳转到 endHook
    self.jumpTo(self.currentPC + self._pSize * 24, jmpType="BEQ", resetPC=False)
    self.patchASM("MOV R3,R8")
    self.patchASM("ADD R10,#1")
    self.saveRegToStack(reg="R6", index=0)
    self.patchASM("ADD R6,R6,{}".format(reg))
    self.saveRegToStack(reg="R6", index=1)
    self.android_log_print_reg(formart="GOT relocation %p ---> %p ---> %p")
    self.patchASM("STR R6,[R8]")
    self.patchASM("ADD R7,R7,#4")
    self.jumpTo(self.currentPC - self._pSize * 26, jmpType="B", resetPC=False)
    self.patchASM("MOV R3,R10")
    self.android_log_print_reg(formart="Finished GOT relocation all:%d")
    self.restoreStack(2)
# 使用 mprotect 修改内存区域的读写权限
def mprotect(self, mPtr=None, size=4096, prot=7, log=False):
    if mPtr is None:
        self.patchASM("MOV R2,PC")
    else:
        self.loadToReg(self.addPtr(mPtr), reg="R2")
    self.prepareStack(3)
    self.patchASM("MOV R1,R2,LSR#12")
    self.patchASM("MOV R0,R1,LSL#12")
    self.saveRegToStack(reg="R0", index=0)
    self.patchASM("MOV R1,#{}".format(size))
    self.saveRegToStack(reg="R1", index=1)
    self.patchASM("MOV R2,#{}".format(prot))
    self.saveRegToStack(reg="R2", index=2)
    self.jumpTo(self.getRelocation("mprotect"), jmpType="REL", reg="R3", resetPC=False)
    self.patchASM("MOV R3,R0")
    if log:
        self.android_log_print_reg(formart="mprotect ret = %d  args : %p %p %p")
    self.restoreStack(3)
 
# 获取 il2cpp 基地址
# 代码执行到这里的时候我们知道当前的pc值以及当前代码静态的地址,所以我们相减即可得到当前的so基地址
def loadBaseToReg(self, reg="R4", log=False):
    self.loadToReg(self.addPtr(self.currentPC + 7 * self._pSize), reg="R1", fix=1)
    self.patchASM("LDR R2,[R1]")
    self.patchASM("SUB R0,PC,R2")
    self.patchASM("MOV {},R0".format(reg))
    if log:
        self.patchASM("MOV R3,R0")
        self.android_log_print_reg(formart="soAddr -> %p")
 
# 直接理解为用汇编实现的一下代码即可
# while(GOT_TABLE[index]!=0x0){
#       GOT_TABLE[index] += soAddr
# }
def relocationGot(self, reg="R9"):
    self.prepareStack(2)
    self.loadToReg(functionsMap.get("GOT_TABLE"), reg="R5", fix=1)
    self.patchASM("MOV R7,#0")
    self.patchASM("MOV R10,#0")
    # R5:存放指针 R6:存放具体值 R7:存放偏移 R8:CurrentPtr
    self.patchASM("ADD R8,R5,R7")
    self.patchASM("LDR R6,[R8]")
    self.patchASM("CMP R6,#0")
    # 标识结束,直接跳转到 endHook
    self.jumpTo(self.currentPC + self._pSize * 24, jmpType="BEQ", resetPC=False)
    self.patchASM("MOV R3,R8")
    self.patchASM("ADD R10,#1")
    self.saveRegToStack(reg="R6", index=0)

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2021-10-27 14:33 被唱过阡陌编辑 ,原因:
收藏
免费 6
支持
分享
最新回复 (1)
雪    币: 223
活跃值: (141)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
大佬 可否 给个联系方式!有事相求
2022-12-3 20:33
0
游客
登录 | 注册 方可回帖
返回
//