import
idaapi
import
idc
import
idautils
import
ida_dbg
import
ida_funcs
import
datetime
class
MyDbgHook(ida_dbg.DBG_Hooks):
is_tracing
=
False
was_at_end_addr
=
False
def
__init__(
self
, start_addr, end_addr):
super
().__init__()
self
.start_addr
=
start_addr
self
.end_addr
=
end_addr
self
.rva
=
start_addr &
0x00000FFF
now
=
datetime.datetime.now()
timestr
=
now.strftime(
"%Y%m%d_%H%M%S"
)
self
.f
=
open
(
'i:\\crack\\2025spring\\06\\tracevmlog4_'
+
timestr
+
'.txt'
,
'w'
)
self
.rawdata
=
0
self
.opdata
=
0
self
.opcode
=
0
self
.opaddr
=
0
self
.sp
=
0x800c
def
get_byte(
int
a):
b
=
a&
0xff
if
b&
0x80
:
return
b
-
256
else
:
return
b
def
dbg_bpt(
self
, tid, ea):
current_addr
=
idc.get_reg_value(
"pc"
)
if
current_addr
=
=
self
.start_addr:
self
.enable_tracing()
r0
=
idc.get_reg_value(
"r0"
)
print
(f
"Start trace vm at {hex(self.start_addr)}, a1={hex(r0)},flag={hex(r0+0x1000)},opcode={hex(r0+0x10000)},stack={hex(r0+0xC000)}\n"
,
file
=
self
.f)
self
.step_and_trace(
self
.start_addr,
self
.end_addr)
elif
current_addr
=
=
self
.end_addr:
print
(f
"Exit trace vm at {hex(current_addr)}\n"
,
file
=
self
.f)
self
.disable_tracing()
idaapi.continue_process()
else
:
rva
=
current_addr &
0x00000FFF
if
rva
=
=
0x8AC
:
r0
=
idc.get_reg_value(
"r0"
)
r2
=
idc.get_reg_value(
"r2"
)
self
.opdata
=
r0
self
.opcode
=
r2
print
(f
"****Case {hex(r2)}: SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} {hex(self.rawdata)} OPDATA={hex(self.opdata)}\n"
,
file
=
self
.f)
elif
rva
=
=
0x888
:
r1
=
idc.get_reg_value(
"r1"
)
r6
=
idc.get_reg_value(
"r6"
)
self
.opaddr
=
r6
self
.rawdata
=
r1
elif
rva
=
=
0x9D8
:
r0
=
idc.get_reg_value(
"r0"
)
r1
=
idc.get_reg_value(
"r1"
)
print
(f
" [0] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} xor [sp-4], [sp]; sp-=4 // v7=*(a1+SP-4)^*(a1+*SP) [SP={hex(r0)}] ; *(a1+*SP-4) = v7; *SP=*SP-4\n"
,
file
=
self
.f)
self
.sp
=
self
.sp
-
4
elif
rva
=
=
0x992
:
r0
=
idc.get_reg_value(
"r0"
)
r1
=
idc.get_reg_value(
"r1"
)
print
(f
" [1] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} neg [sp] //*(a1+*SP)= -*(a1+*SP) [SP={hex(r0)},val={hex(r1)}]\n"
,
file
=
self
.f)
elif
rva
=
=
0x980
:
r0
=
idc.get_reg_value(
"r0"
)
r1
=
idc.get_reg_value(
"r1"
)
rr
=
(r1
-
r0)
/
/
4
print
(f
" [2] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} sub [sp], [sp]-4*v7 //*SP=*SP-4*v7 [SP={hex(r1)},v7={hex(rr)}]\n"
,
file
=
self
.f)
elif
rva
=
=
0x8F2
:
r0
=
idc.get_reg_value(
"r0"
)
print
(f
" [4] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} or [sp-4], [sp]; sp-=4 //v7 = *(a1+*SP-4) | *(a1+*SP); [SP={hex(r0)}] *(a1+*SP-4) = v7; *SP=*SP-4\n"
,
file
=
self
.f)
self
.sp
=
self
.sp
-
4
elif
rva
=
=
0x99C
:
r0
=
idc.get_reg_value(
"r0"
)
r1
=
idc.get_reg_value(
"r1"
)
print
(f
" [5] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} mov [sp-4-4*v7], [sp]; sp = sp-4-4*v7; jmp [sp-4] //v3 = *(a1+*SP-4); *(a1+*SP-4-4*v7) = *(a1+*SP) ; *SP = *SP-4-4*v7 [SP={hex(r1)},v7={hex(r0)}]\n"
,
file
=
self
.f)
elif
rva
=
=
0xA6C
:
r0
=
idc.get_reg_value(
"r0"
)
print
(f
" [6] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} setne [sp-4], [sp]; sp-=4 //v7= ( *(a1+*SP) != *(a1+*SP-4) ) ; [SP={hex(r0)}] *(a1+*SP-4) = v7; *SP=*SP-4\n"
,
file
=
self
.f)
self
.sp
=
self
.sp
-
4
elif
rva
=
=
0xA00
:
r0
=
idc.get_reg_value(
"r0"
)
r1
=
idc.get_reg_value(
"r1"
)
r2
=
idc.get_reg_value(
"r2"
)
r3
=
idc.get_reg_value(
"r3"
)
print
(f
" [7] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} xchg [sp-4*v7], [sp] //*(a1+*SP-4*v7) = *(a1+*SP) ; *(a1+*SP) = *(a1+*SP-4*v7) [SWAP:a1+SP-4*v7({hex(r0)})={hex(r3)},a1+SP({hex(r1)})={hex(r2)}]\n"
,
file
=
self
.f)
elif
rva
=
=
0xA9A
:
r1
=
idc.get_reg_value(
"r1"
)
print
(f
" [8] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} and [sp-4], [sp]; sp-=4 //v7 = *(a1+*SP-4) & *(a1+*SP); [SP={hex(r1+4)}] *(a1+*SP-4) = v7; *SP=*SP-4\n"
,
file
=
self
.f)
self
.sp
=
self
.sp
-
4
elif
rva
=
=
0x9C4
:
r0
=
idc.get_reg_value(
"r0"
)
r1
=
idc.get_reg_value(
"r1"
)
print
(f
" [9] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} shl [sp], v7 //*(a1+*SP) = *(a1+*SP) << v7 [SP={hex(r1)},v7={hex(r0)}]\n"
,
file
=
self
.f)
elif
rva
=
=
0xA5A
:
r0
=
idc.get_reg_value(
"r0"
)
print
(f
" [A] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} not [sp] //*(a1+*SP) = ~ *(a1+*SP) [SP={hex(r0)}]\n"
,
file
=
self
.f)
elif
rva
=
=
0xAA8
:
r0
=
idc.get_reg_value(
"r0"
)
print
(f
" [C] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} add [sp-4], [sp]; sp-=4 //v7 = *(a1+*SP-4) + *(a1+*SP); [SP={hex(r0)}] *(a1+*SP-4) = v7; *SP=*SP-4\n"
,
file
=
self
.f)
self
.sp
=
self
.sp
-
4
elif
rva
=
=
0x9EA
:
r0
=
idc.get_reg_value(
"r0"
)
r6
=
idc.get_reg_value(
"r6"
)
print
(f
" [E] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} jmp {hex(self.opaddr)}+{hex(r0)} //OPADDR_v3[{hex(r6)}] += v7[{hex(r0)}]\n"
,
file
=
self
.f)
elif
rva
=
=
0xAF2
:
print
(f
" [F] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} exit //!!!!EXIT HERE\n"
,
file
=
self
.f)
elif
rva
=
=
0x968
:
r0
=
idc.get_reg_value(
"r0"
)
r1
=
idc.get_reg_value(
"r1"
)
print
(f
" [11] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} shr [sp], v7 //*(a1+*SP) = *(a1+*SP)>>v7 [SP={hex(r1)},v7={hex(r0)}]\n"
,
file
=
self
.f)
elif
rva
=
=
0x93E
:
r0
=
idc.get_reg_value(
"r0"
)
print
(f
" [12] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} ???? //if [*(a1+*SP-4)==0] goto LABEL34; *SP=*SP-4; [SP={hex(r0)}] call sub_518(*(a1+*SP-8)) "
,
file
=
self
.f)
elif
rva
=
=
0x538
:
r0
=
idc.get_reg_value(
"r0"
)
r1
=
idc.get_reg_value(
"r1"
)
r2
=
idc.get_reg_value(
"r2"
)
r3
=
idc.get_reg_value(
"r3"
)
print
(f
" [12*] sub_534 [p1={hex(r0)},p2={hex(r1)},p3={hex(r2)},p4={hex(r3)}] "
,
file
=
self
.f)
elif
rva
=
=
0x550
:
r3
=
idc.get_reg_value(
"r3"
)
r12
=
idc.get_reg_value(
"r12"
)
print
(f
" [12**] sub_534 [_clz1={hex(r12)},_clz2={hex(r3)},final-funcaddr=6DC-{hex(12*(r3-r12))}] "
,
file
=
self
.f)
elif
rva
=
=
0xA10
:
r0
=
idc.get_reg_value(
"r0"
)
r1
=
idc.get_reg_value(
"r1"
)
print
(f
" [14] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} mov [sp], byte ptr [sp] //*(a1+*SP)= byte*(a1+*SP) [SP={hex(r0)},val={hex(r1)}]\n"
,
file
=
self
.f)
elif
rva
=
=
0xAC0
:
r0
=
idc.get_reg_value(
"r0"
)
print
(f
" [15] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} multi [sp-4], [sp]; sp-=4 //v7 = *(a1+*SP-4) * *(a1+*SP); [SP={hex(r0)}] *(a1+*SP-4) = v7; *SP=*SP-4\n"
,
file
=
self
.f)
self
.sp
=
self
.sp
-
4
elif
rva
=
=
0xA44
:
r0
=
idc.get_reg_value(
"r0"
)
r1
=
idc.get_reg_value(
"r1"
)
print
(f
" [16] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} call func_{hex(self.opaddr)}+{hex(r0)}+2 //*SP=*SP+4 ; *(a1+*SP+4)=old_OPADDR_v3 ; OPADDR_v3+=v7 [SP={hex(r1)},v7={hex(r0)}]\n"
,
file
=
self
.f)
self
.sp
=
self
.sp
+
4
elif
rva
=
=
0x90C
:
r0
=
idc.get_reg_value(
"r0"
)
r2
=
idc.get_reg_value(
"r2"
)
print
(f
" [{hex(self.opcode)}] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} cmp [sp], [sp-4]; sp-=8; je {hex(self.opaddr)}+{hex(r0)} //*SP = *SP-8 ; [SP={hex(r2)},v7={hex(r0)}] if [v9==0x18 && (*(a1+*SP) != *(a1+*SP-4))] OPADDR += v7\n"
,
file
=
self
.f)
self
.sp
=
self
.sp
-
8
elif
rva
=
=
0xA28
:
r0
=
idc.get_reg_value(
"r0"
)
print
(f
" [1A] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} mov [sp-4], [sp+word([sp-4]+[sp])]; sp-=4 //v7=*(a1+word*(a1+*SP-4)+word*(a1+*SP)) ; [SP={hex(r0)}] *(a1+*SP-4) = v7; *SP=*SP-4\n"
,
file
=
self
.f)
self
.sp
=
self
.sp
-
4
elif
rva
=
=
0xA1C
:
r0
=
idc.get_reg_value(
"r0"
)
r1
=
idc.get_reg_value(
"r1"
)
r2
=
idc.get_reg_value(
"r2"
)
print
(f
" [1B] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} push [sp-4*v7] //v7=*(a1+*SP-4*v7) ; [SP={hex(r1)},v7={hex(r0)},addr={hex(r2)}] *(a1+*SP+4) = v7; *SP=*SP+4\n"
,
file
=
self
.f)
self
.sp
=
self
.sp
+
4
elif
rva
=
=
0xA88
:
r1
=
idc.get_reg_value(
"r1"
)
r0
=
idc.get_reg_value(
"r0"
)
print
(f
" [1D] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} push {hex(r0)} //*(a1+*SP+4) = v7; *SP=*SP+4 [push v7. SP={hex(r1)},v7={hex(r0)}]\n"
,
file
=
self
.f)
self
.sp
=
self
.sp
+
4
elif
rva
=
=
0xAE2
:
r0
=
idc.get_reg_value(
"r0"
)
print
(f
" [1E] SP:{hex(self.sp)} ADDR:{hex(self.opaddr)} OPCODE:{hex(self.opcode)} sub [sp], 1 //*(a1+*SP) = *(a1+*SP) - 1 [SP={hex(r0)}]\n"
,
file
=
self
.f)
idaapi.continue_process()
return
0
def
dbg_step_into(
self
)
-
>
bool
:
self
.step_and_trace(
self
.start_addr,
self
.end_addr)
return
True
def
dbg_step_over(
self
):
self
.step_and_trace(
self
.start_addr,
self
.end_addr)
return
True
def
enable_tracing(
self
):
if
not
self
.is_tracing:
self
.is_tracing
=
True
ida_dbg.clear_trace()
ida_dbg.enable_insn_trace()
print
(
"清除所有 tracing 数据,开启指令跟踪,挂起其他线程"
)
def
disable_tracing(
self
):
self
.is_tracing
=
False
ida_dbg.disable_insn_trace()
print
(
"关闭指令跟踪"
)
idaapi.del_bpt(
self
.start_addr)
idaapi.del_bpt(
self
.end_addr)
print
(f
"移除断点: {hex(self.start_addr)}, {hex(self.end_addr)}"
)
self
.f.close()
self
.unhook()
print
(
"解除hook"
)
def
step_and_trace(
self
, start_addr, end_addr):
if
self
.is_tracing:
current_addr
=
idc.get_reg_value(
"pc"
)
off
=
current_addr
-
self
.start_addr
if
current_addr
=
=
end_addr:
print
(f
"[{hex(start_addr)}] 已到达结束地址,执行结束指令"
)
ida_dbg.request_step_over()
self
.was_at_end_addr
=
True
return
if
current_addr !
=
end_addr
and
self
.was_at_end_addr:
print
(f
"[{hex(start_addr)}] 已执行完结束地址指令,关闭 tracing"
)
self
.disable_tracing()
idaapi.continue_process()
return
print
(f
"[{hex(current_addr)}] step over"
)
ida_dbg.request_step_over()
def
get_module_by_addr(addr):
for
seg
in
idautils.Segments():
if
seg <
=
addr < idc.get_segm_end(seg):
return
seg
return
None
def
is_in_current_module(addr, start_addr):
start_module
=
get_module_by_addr(start_addr)
current_module
=
get_module_by_addr(addr)
if
start_module
=
=
current_module:
return
True
return
False
def
is_call_instruction(ea):
mnem
=
idc.print_insn_mnem(ea)
return
mnem
in
[
"BL"
,
"BLR"
,
"BR"
]
def
get_call_target(ea):
if
is_call_instruction(ea):
mnem
=
idc.print_insn_mnem(ea)
if
mnem
in
[
"BL"
,
"BLR"
]:
return
idc.get_operand_value(ea,
0
)
if
mnem
=
=
"BR"
:
reg_name
=
idc.print_operand(ea,
0
)
reg_val
=
idc.get_reg_value(reg_name)
return
reg_val
return
None
def
set_breakpoints(start_addr, end_addr):
idaapi.add_bpt(start_addr)
print
(f
"在 {hex(start_addr)} 设置断点"
)
idaapi.add_bpt(end_addr)
print
(f
"在 {hex(end_addr)} 设置断点"
)
def
suspend_other_threads():
current_tid
=
ida_dbg.get_current_thread()
thread_qty
=
ida_dbg.get_thread_qty()
for
i
in
range
(thread_qty):
tid
=
ida_dbg.getn_thread(i)
if
tid !
=
current_tid:
success
=
ida_dbg.suspend_thread(tid)
if
success:
print
(f
"Suspended thread {tid}"
)
else
:
print
(f
"Failed to suspend thread {tid}"
)
print
(f
"Current thread {current_tid} remains active."
)
def
resume_all_threads():
thread_qty
=
ida_dbg.get_thread_qty()
for
i
in
range
(thread_qty):
tid
=
ida_dbg.getn_thread(i)
success
=
ida_dbg.resume_thread(tid)
if
success:
print
(f
"Resumed thread {tid}"
)
print
(
"All threads resumed."
)
if
__name__
=
=
"__main__"
:
start_addr
=
0xCB422860
end_addr
=
start_addr
+
0x2AE
print
(f
"ida trace start[{hex(start_addr)}] end[{hex(end_addr)}]"
)
set_breakpoints(start_addr, end_addr)
hook
=
MyDbgHook(start_addr, end_addr)
hook.hook()