import
idautils
import
idc
import
idaapi
import
ida_ua
from
keystone
import
*
g_reg
=
[
0
]
*
40
reg_base
=
129
g_cond_info
=
list
()
ldr_reg
=
-
1
add_reg
=
-
1
ks
=
keystone.Ks(keystone.KS_ARCH_ARM64, keystone.KS_MODE_LITTLE_ENDIAN)
def
get_opcode(ea):
opcode
=
None
disasm
=
idc.GetDisasm(ea)
if
disasm.find(
'LT'
) !
=
-
1
:
opcode
=
'blt'
elif
disasm.find(
'EQ'
) !
=
-
1
:
opcode
=
'beq'
elif
disasm.find(
'CC'
) !
=
-
1
:
opcode
=
'bcc'
elif
disasm.find(
'GT'
) !
=
-
1
:
opcode
=
'bgt'
elif
disasm.find(
'NE'
) !
=
-
1
:
opcode
=
'bne'
elif
disasm.find(
'GE'
) !
=
-
1
:
opcode
=
'bge'
elif
disasm.find(
'HI'
) !
=
-
1
:
opcode
=
'bhi'
return
opcode
def
do_patch(patch_1, patch_2, opcode, cond_jmp_addr, uncond_jmp_addr):
print
(
"patch_1=0x%x patch_1=0x%x opcode=%s cond_jmp_addr=0x%x uncond_jmp_addr=0x%x"
%
(patch_1, patch_2, opcode, cond_jmp_addr, uncond_jmp_addr))
jump_offset
=
" ({:d})"
.
format
(cond_jmp_addr
-
patch_1)
repair_opcode
=
opcode
+
jump_offset
encoding, count
=
ks.asm(repair_opcode)
idaapi.patch_byte(patch_1, encoding[
0
])
idaapi.patch_byte(patch_1
+
1
, encoding[
1
])
idaapi.patch_byte(patch_1
+
2
, encoding[
2
])
idaapi.patch_byte(patch_1
+
3
, encoding[
3
])
jump_offset
=
" ({:d})"
.
format
(uncond_jmp_addr
-
patch_2)
repair_opcode
=
'b'
+
jump_offset
encoding, count
=
ks.asm(repair_opcode)
idaapi.patch_byte(patch_2, encoding[
0
])
idaapi.patch_byte(patch_2
+
1
, encoding[
1
])
idaapi.patch_byte(patch_2
+
2
, encoding[
2
])
idaapi.patch_byte(patch_2
+
3
, encoding[
3
])
def
do_deobf(ea):
opcode
=
get_opcode(ea)
if
opcode
is
None
:
print
(
"opcode:unknown opcode 0x%x"
%
ea)
return
ea
cond_reg
=
-
1
uncond_reg
=
-
1
cond_data
=
-
1
uncond_data
=
-
1
mnem
=
idc.ida_ua.ua_mnem(ea)
if
mnem
=
=
'CSEL'
:
cond_reg
=
idc.get_operand_value(ea,
1
)
uncond_reg
=
idc.get_operand_value(ea,
2
)
elif
mnem
=
=
'CSET'
:
cond_data
=
1
uncond_data
=
0
ea
=
idc.next_head(ea)
ldr_reg
=
-
1
lsl_value
=
-
1
mnem
=
idc.ida_ua.ua_mnem(ea)
if
mnem
=
=
'LSL'
:
lsl_value
=
idc.get_operand_value(ea,
2
)
ea
=
idc.next_head(ea)
mnem
=
idc.ida_ua.ua_mnem(ea)
if
mnem !
=
'LDR'
:
print
(
"LDR:0x%x -> %s"
%
(ea, mnem))
return
ea
operand_type
=
idc.get_operand_type(ea,
1
)
if
operand_type
=
=
idc.o_phrase:
insn
=
ida_ua.insn_t()
ida_ua.decode_insn(insn, ea)
ldr_reg
=
insn.Op2.reg
if
lsl_value
=
=
-
1
:
lsl_value
=
insn.Op2.value
else
:
return
ea
ea
=
idc.next_head(ea)
mnem
=
idc.ida_ua.ua_mnem(ea)
if
mnem
=
=
'MOV'
:
ea
=
idc.next_head(ea)
mnem
=
idc.ida_ua.ua_mnem(ea)
if
mnem !
=
'ADD'
:
print
(
"ADD:0x%x -> %s"
%
(ea, mnem))
return
ea
op_3
=
idc.print_operand(ea,
2
)
op_3
=
op_3[
1
:]
ea
=
idc.next_head(ea)
mnem
=
idc.ida_ua.ua_mnem(ea)
if
mnem !
=
'BR'
:
print
(
"BR:0x%x -> %s"
%
(ea, mnem))
return
ea
if
cond_data !
=
-
1
and
uncond_data !
=
-
1
:
print
(lsl_value)
cond_jmp_addr
=
(idc.get_qword(g_reg[ldr_reg
-
reg_base]
+
(cond_data << lsl_value))
+
g_reg[
int
(op_3)]) &
0xffffffffffffffff
uncond_jmp_addr
=
(idc.get_qword(g_reg[ldr_reg
-
reg_base]
+
(uncond_data << lsl_value))
+
g_reg[
int
(op_3)]) &
0xffffffffffffffff
else
:
cond_jmp_addr
=
(idc.get_qword(g_reg[ldr_reg
-
reg_base]
+
(g_reg[cond_reg
-
reg_base] << lsl_value))
+
g_reg[
int
(op_3)]) &
0xffffffffffffffff
uncond_jmp_addr
=
(idc.get_qword(g_reg[ldr_reg
-
reg_base]
+
(g_reg[uncond_reg
-
reg_base] << lsl_value))
+
g_reg[
int
(op_3)]) &
0xffffffffffffffff
do_patch(idc.prev_head(ea), ea, opcode, cond_jmp_addr, uncond_jmp_addr)
return
ea
def
deobf(ea):
off_reg
=
-
1
off_data
=
-
1
while
True
:
mnem
=
idc.ida_ua.ua_mnem(ea)
if
mnem
=
=
'RET'
:
break
elif
mnem
=
=
'MOV'
:
op_1_type
=
idc.get_operand_type(ea,
0
)
op_2_type
=
idc.get_operand_type(ea,
1
)
if
(op_1_type
=
=
idc.o_reg)
and
(op_2_type
=
=
idc.o_imm):
op_1
=
idc.get_operand_value(ea,
0
)
op_2
=
idc.get_operand_value(ea,
1
)
g_reg[op_1
-
reg_base]
=
op_2
elif
mnem
=
=
'MOVK'
:
op_1_type
=
idc.get_operand_type(ea,
0
)
op_2_type
=
idc.get_operand_type(ea,
1
)
op_3_type
=
idc.get_operand_type(ea,
2
)
if
(op_1_type
=
=
idc.o_reg)
and
(op_2_type
=
=
idc.o_imm):
op_1
=
idc.get_operand_value(ea,
0
)
op_2
=
idc.get_operand_value(ea,
1
)
g_reg[op_1
-
reg_base]
=
(op_2 <<
16
) | (g_reg[op_1
-
reg_base] &
0xffff
)
elif
mnem
=
=
'ADRP'
:
op_1
=
idc.get_operand_value(ea,
0
)
op_2
=
idc.get_operand_value(ea,
1
)
off_reg
=
op_1
off_data
=
op_2
elif
mnem
=
=
'ADD'
:
op_1
=
idc.get_operand_value(ea,
0
)
op_2
=
idc.get_operand_value(ea,
1
)
op_3
=
idc.get_operand_value(ea,
2
)
op_3_type
=
idc.get_operand_type(ea,
2
)
if
(op_1
=
=
off_reg)
and
(op_2
=
=
off_reg)
and
(op_3_type
=
=
idc.o_imm):
off_data
=
off_data
+
op_3
ldr_reg
=
off_reg
-
reg_base
g_reg[ldr_reg]
=
off_data
elif
(mnem
=
=
'CSEL'
)
or
(mnem
=
=
'CSINC'
)
or
(mnem
=
=
'CSET'
)
or
(mnem
=
=
'CINC'
):
ea
=
do_deobf(ea)
continue
ea
=
idc.next_head(ea)
def
test():
for
i
in
range
(
len
(g_reg)):
print
(
"%d:0x%x"
%
(i, g_reg[i]))
def
main():
ea
=
idc.get_screen_ea()
func
=
idaapi.get_func(ea)
ea
=
func.start_ea
print
(
"start deobf fun:0x%x"
%
(ea))
deobf(ea)
print
(
"deobf ok!"
)
pass
if
__name__
=
=
"__main__"
:
main()