10.5.40.26392 去花
直接查看jni_onload,反彙編都不行
.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這時反彙編不正常
.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做了什麼
.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線性反彙編算不出來這個要跳轉的地址。
使用腳本去花
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: # PUSH {R0,R1,LR}
ea1 = ea + 2
if idc.get_wide_word(ea) == 0xbf00: # NOP
ea1 += 2
# ⽬的寄存器是通⽤寄存器 and ⽬的寄存器是r0 and 源寄存器是⽴即數
if idc.get_operand_type(ea1, 0) == 1 and idc.get_operand_value(ea1, 0) == 0 and idc.get_operand_type(ea1,1) == 2:
# get_operand_type 獲取寄存器的類型
index = idc.get_wide_dword(idc.get_operand_value(ea1, 1))
print("index =", hex(index))
ea1 += 2
table = None
# get_operand_type獲取操作數的值
# https://www.hex-rays.com/products/ida/support/idadoc/276.shtml
if idc.get_operand_type(ea1, 0) == 7:
print(222)
# BL loc_53754
# 獲取tabel表
table = idc.get_operand_value(ea1, 0) + 4
# elif idc.get_operand_type(ea1, 1) == 2:
# table = idc.get_operand_value(ea1, 1) + 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)
# 0x2f150`
def getAddrRange():
start = ida_ida.inf_get_min_ea()
size = ida_ida.inf_get_max_ea() - start
# 將地址範圍限定於text節
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__':
# so中.text段的起始與結束位置
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中