class
BranchInstruction:
def
__init__(
self
, address, branch_type, compare_address
=
None
, condition
=
None
, function_index
=
None
):
self
.address
=
address
self
.branch_type
=
branch_type
self
.compare_address
=
compare_address
self
.condition
=
condition
self
.taken_branch_address
=
None
self
.not_taken_branch_address
=
None
self
.function_index
=
function_index
branch_info
=
dict
()
branch_data
=
[
{
"branch_address"
:
0x27b9c
,
"compare_address"
:
0x27b70
,
"condition"
:
"EQ"
,
"branch_type"
:
"jcc"
},
{
"branch_address"
:
0x27be4
,
"branch_type"
:
"jmp"
},
]
breakpoint_addresses_branch
=
[]
breakpoint_addresses_compare
=
[]
all_conditions
=
set
()
compare_address_lookup
=
dict
()
function_ranges
=
[(
162512
,
164428
), (
182320
,
185084
), (
220224
,
220252
), (
294424
,
294440
), (
300112
,
300140
),
(
308092
,
309132
), (
368928
,
368976
), ..., (
0
,
0
)]
def
set_condition_flags(uc, condition, condition_hit
=
True
):
nzcv
=
uc.reg_read(arm64_const.UC_ARM64_REG_NZCV)
def
set_bit(value, bit):
return
value | (
1
<< bit)
def
clear_bit(value, bit):
return
value & ~(
1
<< bit)
N_BIT
=
31
Z_BIT
=
30
C_BIT
=
29
V_BIT
=
28
if
condition
=
=
"EQ"
:
if
condition_hit:
nzcv
=
set_bit(nzcv, Z_BIT)
else
:
nzcv
=
clear_bit(nzcv, Z_BIT)
elif
condition
=
=
"NE"
:
if
condition_hit:
nzcv
=
clear_bit(nzcv, Z_BIT)
else
:
nzcv
=
set_bit(nzcv, Z_BIT)
elif
condition
=
=
"GT"
:
if
condition_hit:
nzcv
=
clear_bit(nzcv, Z_BIT)
nzcv
=
set_bit(nzcv, N_BIT)
if
(nzcv >> V_BIT) &
1
else
clear_bit(nzcv, N_BIT)
else
:
nzcv
=
set_bit(nzcv, Z_BIT)
elif
condition
=
=
"LT"
:
if
condition_hit:
nzcv
=
set_bit(nzcv, N_BIT)
if
not
(nzcv >> V_BIT) &
1
else
clear_bit(nzcv, N_BIT)
else
:
nzcv
=
set_bit(nzcv, N_BIT)
if
(nzcv >> V_BIT) &
1
else
clear_bit(nzcv, N_BIT)
elif
condition
=
=
"HI"
:
if
condition_hit:
nzcv
=
set_bit(nzcv, C_BIT)
nzcv
=
clear_bit(nzcv, Z_BIT)
else
:
nzcv
=
clear_bit(nzcv, C_BIT)
nzcv
=
set_bit(nzcv, Z_BIT)
elif
condition
=
=
"CC"
:
if
condition_hit:
nzcv
=
clear_bit(nzcv, C_BIT)
else
:
nzcv
=
set_bit(nzcv, C_BIT)
else
:
raise
ValueError(f
"Unsupported condition: {condition}"
)
uc.reg_write(arm64_const.UC_ARM64_REG_NZCV, nzcv)
def
is_condition_met(uc, condition):
nzcv
=
uc.reg_read(arm64_const.UC_ARM64_REG_NZCV)
def
is_bit_set(value, bit):
return
(value >> bit) &
1
N_BIT
=
31
Z_BIT
=
30
C_BIT
=
29
V_BIT
=
28
if
condition
=
=
"EQ"
:
return
is_bit_set(nzcv, Z_BIT)
elif
condition
=
=
"NE"
:
return
not
is_bit_set(nzcv, Z_BIT)
elif
condition
=
=
"GT"
:
return
not
is_bit_set(nzcv, Z_BIT)
and
(is_bit_set(nzcv, N_BIT)
=
=
is_bit_set(nzcv, V_BIT))
elif
condition
=
=
"LT"
:
return
is_bit_set(nzcv, N_BIT) !
=
is_bit_set(nzcv, V_BIT)
elif
condition
=
=
"HI"
:
return
is_bit_set(nzcv, C_BIT)
and
not
is_bit_set(nzcv, Z_BIT)
elif
condition
=
=
"CC"
:
return
not
is_bit_set(nzcv, C_BIT)
else
:
raise
ValueError(f
"Unsupported condition: {condition}"
)
def
is_valid_address(addr, segment_name
=
".text"
):
seg
=
get_segm_by_name(segment_name)
return
addr >
=
seg.start_ea
and
addr <
=
seg.end_ea
def
instruction_hook(uc, address, size, userData):
print
(
">>> Tracing instruction at 0x%x"
%
(address))
eh: flare_emu.EmuHelper
=
userData[
"EmuHelper"
]
uc: unicorn.Uc
if
address
=
=
0xB9624
:
print
(
"memcpy api hook"
)
eh._handleApiHooks(address, eh.getArgv(),
"memcpy"
, userData)
uc.reg_write(arm64_const.UC_ARM64_REG_PC, address
+
size)
return
if
address
=
=
0xB96A4
or
address
=
=
0xBB18C
or
address
in
range
(
0xBA2E8
,
0x0BA338
):
print
(
"Consts Decrypt func execute"
)
return
if
not
is_valid_address(address):
print
(
"Error: Invalid address detected. Stopping emulation."
)
print
(traceback.print_stack())
uc.emu_stop()
return
if
idc.print_insn_mnem(address)
in
[
"BL"
,
"BLR"
,
"BLX"
]:
print
(
"Info: Skipping function call."
)
uc.reg_write(arm64_const.UC_ARM64_REG_X0,
1
)
uc.reg_write(arm64_const.UC_ARM64_REG_PC, address
+
size)
if
idc.print_insn_mnem(address)
=
=
"RET"
:
print
(
"Info: Function returned. Stopping emulation."
)
uc.emu_stop()
return
if
idc.print_insn_mnem(address)[:
2
]
=
=
"B."
and
address
not
in
compare_visited:
print
(f
"Info: Conditional branch detected at 0x{address:x}"
)
compare_visited.append(address)
current_state: unicorn.UcContext
=
uc.context_save()
instruction
=
idaapi.insn_t()
idaapi.decode_insn(instruction, address)
current_emu_helper
=
flare_emu.EmuHelper(verbose
=
1
, emuHelper
=
emu_helper)
print
(f
" Emulating branch condition: taken (0x{instruction.Op1.addr:x})"
)
current_emu_helper.emulateRange(instruction.Op1.addr, user_data[
"endAddr"
], instructionHook
=
instruction_hook, count
=
100
,
uc_context
=
current_state)
current_emu_helper
=
flare_emu.EmuHelper(verbose
=
1
, emuHelper
=
emu_helper)
print
(f
" Emulating branch condition: not taken (0x{address + 4:x})"
)
current_emu_helper.emulateRange(address
+
4
, user_data[
"endAddr"
], instructionHook
=
instruction_hook, count
=
100
,
uc_context
=
current_state)
emu_helper.stopEmulation(user_data)
return
if
address
in
breakpoint_addresses_compare:
branch_address
=
compare_address_lookup[address]
condition
=
branch_info[branch_address].condition
print
(f
"Info: Compare instruction at 0x{address:x}, Condition: {condition}"
)
breakpoint_addresses_compare.remove(address)
start_pc
=
address
+
4
current_state: unicorn.UcContext
=
uc.context_save()
if
branch_info[branch_address].taken_branch_address
is
None
:
print
(f
"Info: Starting emulation with condition taken at 0x{start_pc:x}"
)
current_emu_helper
=
flare_emu.EmuHelper(verbose
=
1
, emuHelper
=
emu_helper)
set_condition_flags(current_state, condition,
True
)
current_emu_helper.emulateRange(start_pc, user_data[
"endAddr"
], instructionHook
=
instruction_hook, count
=
100
,
uc_context
=
current_state)
if
branch_info[branch_address].not_taken_branch_address
is
None
:
print
(f
"Info: Starting emulation with condition not taken at 0x{start_pc:x}"
)
current_emu_helper
=
flare_emu.EmuHelper(verbose
=
1
, emuHelper
=
emu_helper)
set_condition_flags(current_state, condition,
False
)
current_emu_helper.emulateRange(start_pc, user_data[
"endAddr"
], instructionHook
=
instruction_hook, count
=
100
,
uc_context
=
current_state)
emu_helper.stopEmulation(user_data)
return
elif
address
in
breakpoint_addresses_branch:
instruction
=
idaapi.insn_t()
idaapi.decode_insn(instruction, address)
register_name
=
regid_2_name[instruction.Op1.reg]
register_value
=
uc.reg_read(unicorn_reg_map[register_name])
print
(f
"Info: Executing branch instruction at 0x{address:x}, {register_name} = 0x{register_value:x}"
)
if
branch_info[address].branch_type
=
=
"jcc"
:
if
is_condition_met(uc, branch_info[address].condition)
and
branch_info[address].taken_branch_address
is
None
:
if
register_value
in
range
(function_ranges[branch_info[address].function_index][
0
],
function_ranges[branch_info[address].function_index][
1
]):
print
(f
"Info: Conditional jump (JCC) condition taken at 0x{address:x}, {register_name} = 0x{register_value:x}"
)
branch_info[address].taken_branch_address
=
register_value
elif
not
is_condition_met(uc, branch_info[address].condition)
and
branch_info[address].not_taken_branch_address
is
None
:
if
register_value
in
range
(function_ranges[branch_info[address].function_index][
0
],
function_ranges[branch_info[address].function_index][
1
]):
print
(f
"Info: Conditional jump (JCC) condition not taken at 0x{address:x}, {register_name} = 0x{register_value:x}"
)
branch_info[address].not_taken_branch_address
=
register_value
if
branch_info[address].taken_branch_address
is
not
None
and
branch_info[address].not_taken_branch_address
is
not
None
:
print
(
f
"Info: All conditional jump (JCC) paths processed at 0x{address:x}. "
f
"Taken path: 0x{branch_info[address].taken_branch_address:x}, "
f
"Not taken path: 0x{branch_info[address].not_taken_branch_address:x}"
)
breakpoint_addresses_branch.remove(address)
elif
branch_info[address].branch_type
=
=
"jmp"
and
branch_info[address].taken_branch_address
is
None
:
if
register_value
in
range
(function_ranges[branch_info[address].function_index][
0
],
function_ranges[branch_info[address].function_index][
1
]):
branch_info[address].taken_branch_address
=
register_value
print
(f
"Info: Unconditional jump (JMP) executed at 0x{address:x}, {register_name} = 0x{register_value:x}"
)
breakpoint_addresses_branch.remove(address)
for
(function_start, function_end)
in
function_ranges[:
-
1
]:
print
(f
"Info: Emulating function from 0x{function_start:x} to 0x{function_end:x}"
)
emu_helper
=
flare_emu.EmuHelper(verbose
=
1
)
try
:
emu_helper.emulateRange(function_start, function_end
-
4
, instructionHook
=
instruction_hook, count
=
100
)
print
(
"Info: Function emulation completed successfully."
)
except
Exception as e:
print
(f
"Error: Exception occurred during emulation: {e}"
)