add idapro

This commit is contained in:
yincong
2025-12-11 16:27:56 +08:00
parent c25130c4e7
commit 0a5e4d16be
8 changed files with 372 additions and 181 deletions
+1
View File
@@ -3,3 +3,4 @@ __handlers__
*.sqlite
.DS_Store
diaphora_batch*
data
+15
View File
@@ -0,0 +1,15 @@
StartSendMessageSerial sub_1024C4CB4
CoSendMessageWithUploadInfo sub_1023E8108
CoAddSendMessageToDb sub_1023C09D0
CoPrepareShowSendMessage sub_1023BC4E0
sub_1024C7FB4 -> sub_102481CA0 -> sub_105268848
sub_1024C7FB4 sendMessage 入口
sub_10237997C image_handler.cc
sub_1023E73E8 text_handler.cc
sub_102363BB0 file_handler.cc
sub_1024C6354 可能是统一入口
sub_100400950 装填消息
-8
View File
@@ -86,7 +86,6 @@ function sendMessageWechat() {
Interceptor.attach(targetAddress, {
onEnter: function (args) {
console.log(`[ENTER] sendMsg called with a1 = ${args[0]}`);
// 检查传入的结构
const a1 = args[0]
console.log(` a1: ${a1.readPointer()}`);
@@ -94,13 +93,6 @@ Interceptor.attach(targetAddress, {
console.log(` a1+16: ${a1.add(0x10).readPointer()}`);
console.log(` a1+24: ${a1.add(0x18).readPointer()}`);
console.log(` a1+32: ${a1.add(0x20).readPointer()}`);
if (resent) {
resent = false;
arg0 = a1;
// resend()
Thread.sleep(100);
}
console.log(`[ENTER] sendMsg called with a1 = ${args[0]}`);
},
onLeave: function (retval) {
View File
+201
View File
@@ -0,0 +1,201 @@
import ida_dbg
import ida_bytes
import json
def is_printable_string(data):
"""检查是否是可打印字符串"""
if not data:
return False, ""
# 检查是否以null结尾
if data[-1] != 0:
return False, ""
# 检查所有字符是否可打印
result = ""
for byte in data[:-1]: # 排除结尾的null
if 32 <= byte <= 126: # 可打印ASCII
result += chr(byte)
else:
return False, ""
return True, result
def dereference_recursive(traceMap, addr, struct_size, depth=0, max_depth=5):
"""
递归解引用指针并打印内容
:param addr: 地址值
:param struct_size: 结构体大小(字节)
:param depth: 当前递归深度
:param max_depth: 最大递归深度
"""
mapAddr = f"0x{addr:016X}"
print(f"mapAddr: {mapAddr}")
traceMap[mapAddr] = {}
if depth >= max_depth:
print(" " * depth + f"[达到最大递归深度 {max_depth}]")
return
if addr == 0:
print(" " * depth + f"[NULL 指针]")
return
indent = " " * depth
ptr_size = 8
print(f"{indent}层级 {depth}: 地址 0x{addr:X}")
# 尝试读取字符串
try:
# 尝试读取最多256字节
max_read = min(256, struct_size)
data = bytearray()
for i in range(max_read):
byte = ida_bytes.get_byte(addr + i)
data.append(byte)
if byte == 0: # 遇到null终止符
break
is_str, str_val = is_printable_string(data)
if is_str and len(str_val) > 0:
data[addr][str_val] = {}
print(f"{indent}字符串: \"{str_val}\"")
return
except:
pass
# 打印原始内存内容(前64字节)
try:
bytes_to_show = min(64, struct_size)
print(f"{indent}内存内容 ({bytes_to_show} 字节):")
hex_line = indent + " "
ascii_line = indent + " "
for i in range(bytes_to_show):
if i > 0 and i % 16 == 0:
print(f"{hex_line} {ascii_line}")
hex_line = indent + " "
ascii_line = indent + " "
byte = ida_bytes.get_byte(addr + i)
hex_line += f"{byte:02X} "
ascii_line += chr(byte) if 32 <= byte <= 126 else "."
# 打印最后一行
if hex_line.strip():
print(f"{hex_line:50} {ascii_line}")
except Exception as e:
print(f"{indent}读取内存失败: {e}")
return
print(f"ptr_size {ptr_size} struct_size {struct_size}")
# 检查是否可能是指针数组
if struct_size >= ptr_size:
# 如果 ptr_size < struct_size,则连续读取多个 QWORD
ptr_count = struct_size // ptr_size # 能读取多少个 qword
for i in range(ptr_count):
cur_addr = addr + i * ptr_size
try:
ptr_value = ida_bytes.get_qword(cur_addr)
print(f"{indent}指针[{i}] @ 0x{cur_addr:X} -> 0x{ptr_value:X}")
if ptr_value != 0 and ptr_value != cur_addr:
print(f"{indent}可能是指针,指向: 0x{ptr_value:X}")
nextAddr = f"0x{ptr_value:016X}"
print(f"nextAddr: {nextAddr}")
traceMap[mapAddr][nextAddr] = {}
dereference_recursive(traceMap[mapAddr], ptr_value, struct_size, depth + 1, max_depth)
except Exception as e:
print(f"{indent}读取失败: 0x{cur_addr:X}, err={e}")
continue
def print_register_struct(reg_name, struct_size=64, max_depth=3):
"""
打印寄存器内容(递归解引用)
:param reg_name: 寄存器名称(如 "X0", "RAX"
:param struct_size: 假设的结构体大小
:param max_depth: 最大递归深度
"""
print(f"\n{'='*60}")
print(f"分析寄存器: {reg_name}")
print(f"结构体大小: {struct_size} 字节")
print(f"{'='*60}")
traceMap = {}
try:
# 获取寄存器值
reg_value = ida_dbg.get_reg_val(reg_name)
print(f"寄存器 {reg_name} = 0x{reg_value:X} ({reg_value})")
if reg_value == 0:
print("寄存器值为0 (NULL)")
return
# 递归分析
dereference_recursive(traceMap, reg_value, struct_size, 0, max_depth)
except Exception as e:
print(f"错误: {e}")
print(json.dumps(traceMap, indent=4))
# =========== 使用示例函数 ===========
# def example_usage():
# """使用示例 - 在断点处调用这些函数"""
# 示例1: 分析X0寄存器(ARM64
# print_register_struct("X0", 64, 3)
# 示例2: 分析RCX寄存器(x64)
# print_register_struct("RCX", 32, 2)
# 示例3: 分析特定大小的结构
# print_register_struct("X1", 128, 4)
# =========== 常用快捷函数 ===========
# def analyze_args_arm64():
# """分析ARM64的前4个参数寄存器"""
# print("\n分析ARM64函数参数:")
# for i, reg in enumerate(["X0", "X1", "X2", "X3"]):
# print(f"\n--- 参数 {i+1} ({reg}) ---")
# print_register_struct(reg, 64, 2)
#
#
# def analyze_all_args(struct_size=64, max_depth=2):
# """根据架构分析所有参数寄存器"""
# regs = ["X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7"]
#
# print(f"\n分析函数参数 ({inf.procname}):")
# for reg in regs:
# try:
# value = ida_dbg.get_reg_val(reg)
# if value != 0:
# print(f"\n--- 寄存器 {reg} (0x{value:X}) ---")
# print_register_struct(reg, struct_size, max_depth)
# except:
# pass
# =========== 如何在断点中使用 ===========
"""
使用方法:
1. 在IDA中设置断点
2. 断点触发时,打开Python控制台
3. 调用以下任一函数:
# 分析单个寄存器
# print_register_struct("X0", 64, 3)
# 或分析所有参数
analyze_all_args()
# 或直接运行示例
example_usage()
"""
print_register_struct("X0", 64, 3)
+64 -173
View File
File diff suppressed because one or more lines are too long
+23
View File
@@ -0,0 +1,23 @@
import idc
# -----------------
# 步骤 1: 确定你要读取的 ARM64 寄存器名称
# -----------------
# 注意: 寄存器名称必须是大写字符串,例如 'X0', 'X19', 'PC', 'SP' 等
register_name = 'X0' # X0 通常用于存放函数返回值或第一个参数
# -----------------
# 步骤 2: 在脚本中调用函数获取值
# -----------------
try:
# idc.get_reg_value() 只在动态调试且程序暂停时有效
reg_value = idc.get_reg_value(register_name)
print(f"程序暂停在断点处。")
print(f"ARM64 寄存器 **{register_name}** 的当前值为:")
print(f"十进制: {reg_value}")
print(f"十六进制: 0x{reg_value:X}")
except Exception as e:
print("错误:无法读取寄存器值。")
print("请确保你已:1. 配置并启动了调试器 (Debugger)。2. 程序已运行并暂停在某个断点上。")
+68
View File
@@ -0,0 +1,68 @@
# IDAPython Breakpoint Action Script
import idc
import ida_dbg
import idautils
# ----------------------------------------------------
# 步骤 1: 定义获取和打印堆栈的函数
# ----------------------------------------------------
def print_call_stack():
"""获取当前的调用堆栈地址,并将其打印到 IDA 消息窗口。"""
# 获取当前线程 ID,通常是获取堆栈的第一步
tid = idc.get_current_thread()
if tid == -1:
print("[!] 脚本错误: 无法获取当前线程 ID。")
return
print("=" * 40)
print(f"✅ 断点触发于地址: 0x{idc.get_screen_ea():X}")
print(f"➡️ **调用堆栈 (Call Stack) 地址:**")
# idautils.get_current_caller_frame() 可获取调用堆栈信息
# 它返回一个列表,其中每个元素都是一个 (返回地址, 帧指针/栈指针) 的元组。
# 遍历堆栈帧并打印返回地址
frame_count = 0
# 注意: 在 64 位 ARM (AArch64) 上,栈操作可能与 x86 不同
# 我们使用 idautils.get_call_stack 尝试获取更标准的堆栈信息。
# idautils.get_call_stack() 可能会返回一系列的 (地址, 描述) 元组
stack_info = ida_dbg.collect_stack_trace()
if stack_info:
for frame_count, (return_address, _) in enumerate(stack_info):
# 获取函数名(如果有的话)
func_name = idc.get_func_name(return_address)
# 如果函数名获取失败或地址在外部库,则使用原始地址
if not func_name or func_name.startswith("loc_"):
name = ""
else:
name = f" <{func_name}>"
print(f" [{frame_count:02d}] 0x{return_address:X}{name}")
else:
# 如果 idautils.get_call_stack 失败,尝试使用更底层的方法(不推荐,但作为备选)
# 实际调试中,推荐依赖 IDA 调试器自动提供的堆栈视图。
print(" [!] 警告: 自动堆栈追踪失败,请检查 IDA Stack View.")
print(f" --- 堆栈深度: {frame_count + 1} 层 ---")
print("=" * 40)
# ----------------------------------------------------
# 步骤 2: 调用主函数
# ----------------------------------------------------
# 在断点被命中时,执行堆栈打印
print_call_stack()
# ----------------------------------------------------
# 步骤 3: 控制程序流 (重要!)
# ----------------------------------------------------
# 要让程序在打印堆栈后继续执行,必须返回 0 或不返回 (即让 IDA 默认继续)。
# 但是,如果希望程序在打印后暂停 (即执行普通断点的动作),则返回 1 (但这不是本脚本的目的)。
# 如果你想继续执行(Trace Breakpoint),请确保 Action 下一步是 Resume
return 0