mirror of
https://github.com/yincongcyincong/wechat_chatter.git
synced 2026-07-15 10:26:52 +08:00
196 lines
5.9 KiB
Python
196 lines
5.9 KiB
Python
import ida_dbg
|
||
import ida_bytes
|
||
import json
|
||
|
||
def is_printable_string(data):
|
||
"""检查是否是可打印字符串"""
|
||
if not data:
|
||
return False, ""
|
||
|
||
# 检查所有字符是否可打印
|
||
result = ""
|
||
for byte in data[:-1]: # 排除结尾的null
|
||
if 32 <= byte <= 126: # 可打印ASCII
|
||
result += chr(byte)
|
||
else:
|
||
print(f"不可打印字符: {chr(byte)}")
|
||
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:X}"
|
||
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:
|
||
traceMap[mapAddr][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 + " "
|
||
all_ascii_line = ""
|
||
|
||
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 "."
|
||
all_ascii_line += chr(byte) if 32 <= byte <= 126 else "."
|
||
|
||
# 打印最后一行
|
||
# if hex_line.strip():
|
||
# print(f"{hex_line:50} {ascii_line}")
|
||
print(f"地址 0x{addr:X} ascii {all_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)
|
||
if 0X00000001019013F4 < ptr_value < 0x7FFFFFFFFFFFFFFF and ptr_value != cur_addr:
|
||
print(f"{indent}指针[{i}] @ 0x{cur_addr:X} -> 0x{ptr_value:X}")
|
||
nextAddr = f"0x{ptr_value:X}"
|
||
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} 结构体大小: {struct_size} 字节")
|
||
|
||
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(f"{reg_name}递归分析结果:")
|
||
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", 128, 4) |