10.5.40.26392 去花
直接查看jni_onload,反汇编都不行
1 2 3
| .text:00053744 03 B5 PUSH {R0,R1,LR} .text:00053746 01 48 LDR R0, =6 .text:00053748 00 F0 04 F8 BL loc_53754
|
到这儿一直正常,ida在进行反汇编的时候依然能正常的识别出来二进制代码所走的流程,当走到下方的代码的时候ida这时反汇编不正常
1 2 3 4 5 6 7
| .text:00053754 B9 F7 A4 EB BLX sub_CEA0 .text:00053758 AC 01 LSLS R4, R5, #6 .text:0005375A 00 00 MOVS R0, R0 .text:0005375C C4 01 LSLS R4, R0, #7 .text:0005375E 00 00 MOVS R0, R0 .text:00053760 DC 01 LSLS R4, R3, #7 .text:00053762 00 00 MOVS R0, R0
|
那么我们看下sub_CEA0做了什么
1 2 3 4 5 6 7 8 9 10 11 12
| .text:0000CEA0 sub_CEA0 ; CODE XREF: .text:loc_7918↑p .text:0000CEA0 ; .text:loc_A8C0↑p ... .text:0000CEA0 .text:0000CEA0 arg_8 = 8 .text:0000CEA0 .text:0000CEA0 ; __unwind { .text:0000CEA0 01 10 CE E3 BIC R1, LR, #1 .text:0000CEA4 00 11 91 E7 LDR R1, [R1,R0,LSL#2] .text:0000CEA8 0E 10 81 E0 ADD R1, R1, LR .text:0000CEAC 08 E0 9D E5 LDR LR, [SP,#arg_8] .text:0000CEB0 08 10 8D E5 STR R1, [SP,#arg_8] .text:0000CEB4 03 80 BD E8 POP {R0,R1,PC}
|
BIC R1, LR, #1;R1 = LR and not #1
;把下一条指令的最低位,置为0,现在也就是说R1的值就是执行完CEA0函数后执行的地址值
LDR R1, [R1,R0,LSL#2];R1 = R1+R04
;RO在上方赋值过了,R1又增加了0x104
ADD R1, R1, LR
;可以翻译为R1 = LR + LR(最低位置为0)+ R0*4
LDR LR, [SP,#arg_8]
;先从堆栈中保存LR寄存器的值
STR R1, [SP,#arg_8]
;然后用算出的R1覆盖掉堆栈的LR
POP {R0,R1,PC}
;恢复堆栈,但是现在PC已经被刚才计算出的R1覆盖了,下一条被执行的指令将要跳转到一个更远的地方
对上面代码的综上叙述,也就是根据在跳出CEA0这个函数的时候会根据R0的值,和LR的值,根据码表计算后赋值给PC寄存器从而跳转到一个地址,但是ida线性反汇编算不出来这个要跳转的地址。
使用脚本去花
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| import idc from ida_bytes import patch_word
def put_unconditional_branch(source, destination): offset = (destination - source - 4) >> 1 if offset > 2097151 or offset < -2097152: raise RuntimeError("Invalid offset") if offset > 1023 or offset < -1024: instruction1 = 0xf000 | ((offset >> 11) & 0x7ff) instruction2 = 0xb800 | (offset & 0x7ff) patch_word(source, instruction1) patch_word(source + 2, instruction2) patch_word(source + 4, 0xbf00) patch_word(source + 6, 0xbf00) else: instruction = 0xe000 | (offset & 0x7ff) patch_word(source, instruction) patch_word(source + 2, 0xbf00) patch_word(source + 4, 0xbf00)
def patch(ea): if idc.get_wide_word(ea) == 0xb503: ea1 = ea + 2 if idc.get_wide_word(ea) == 0xbf00: ea1 += 2 if idc.get_operand_type(ea1, 0) == 1 and idc.get_operand_value(ea1, 0) == 0 and idc.get_operand_type(ea1,1) == 2: index = idc.get_wide_dword(idc.get_operand_value(ea1, 1)) print("index =", hex(index)) ea1 += 2 table = None if idc.get_operand_type(ea1, 0) == 7: print(222) table = idc.get_operand_value(ea1, 0) + 4 if table is None: print("Unable to find table") else: print("table =", hex(table)) offset = idc.get_wide_dword(table + (index << 2)) print("offset =", hex(offset)) put_unconditional_branch(ea, table + offset)
def getAddrRange(): start = ida_ida.inf_get_min_ea() size = ida_ida.inf_get_max_ea() - start for seg in idautils.Segments(): seg = idaapi.getseg(seg) segName = ida_segment.get_segm_name(seg) if segName == ".text": start = seg.start_ea size = seg.size() return start, size
if __name__ == '__main__': start, size = getAddrRange() print("start: ", hex(start)) print("size: ", hex(size)) print("end: " ,hex(start + size))
for i in range(0x7698, 0x662dc): patch(i) print("finish")
|
10.8.20.27623 去花
两个版本跨度有点大,直接从armv7整到armv8,花指令的内容也变了
能够反编译了,但是反编译后是这样:
使用keypatch 去花
patch选择第一行
填入B 0x4AC0CLL
全部选中后nop掉
patch到so中
参考