diff --git a/.gitignore b/.gitignore index 83b34e9..8850692 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ __handlers__ *.sqlite .DS_Store diaphora_batch* +data \ No newline at end of file diff --git a/function.md b/function.md new file mode 100644 index 0000000..459860a --- /dev/null +++ b/function.md @@ -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 装填消息 diff --git a/hook/hook.js b/hook/hook.js index 35f7ab9..46f123e 100644 --- a/hook/hook.js +++ b/hook/hook.js @@ -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) { diff --git a/hook/log_decrypt.js b/hook/log_decrypt.js new file mode 100644 index 0000000..e69de29 diff --git a/idapro/analysis_x.py b/idapro/analysis_x.py new file mode 100644 index 0000000..0182bf8 --- /dev/null +++ b/idapro/analysis_x.py @@ -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) \ No newline at end of file diff --git a/idapro/decrypt.py b/idapro/decrypt.py index c49a1cb..14e1b16 100644 --- a/idapro/decrypt.py +++ b/idapro/decrypt.py @@ -1,183 +1,74 @@ -import struct +import idc -def decode_from_bytes(byte_data_hex): - """ - 根据提供的字节数据解码UTF-8字符串 +# ==================================================================== +# 【请务必修改以下参数】 +# ==================================================================== - Args: - byte_data_hex: 十六进制字符串,如 "835594A658483F62EAA226D522BC97" - 或者字节列表/字节数组 +# 1. 你想开始执行的代码段的起始地址 +# 示例:假设你想从函数 sub_1000 开始执行 +START_ADDRESS = 0x1024C6614 - Returns: - 解码后的UTF-8字符串 - """ - # 处理输入数据 - if isinstance(byte_data_hex, str): - # 如果是字符串,去除空格 - byte_data_hex = byte_data_hex.replace(" ", "") - # 将十六进制字符串转换为字节数组 - try: - if len(byte_data_hex) % 2 != 0: - byte_data_hex = "0" + byte_data_hex - data_bytes = bytes.fromhex(byte_data_hex) - except ValueError: - # 如果不是有效的十六进制,假设是原始字节 - data_bytes = byte_data_hex.encode('latin-1') - elif isinstance(byte_data_hex, (bytes, bytearray)): - data_bytes = bytes(byte_data_hex) +# 2. 你想执行的步数(单步执行的次数) +# 例如:执行 5 条指令 +STEPS_TO_EXECUTE = 5 + +# ==================================================================== + +def execute_code_snippet(start_addr, num_steps): + # 1. 获取当前线程 ID + tid = idc.get_current_thread() + if tid == -1: + print("[!] 错误:无法获取当前线程 ID。") + return + + # 2. 设置指令指针 (PC/RIP/EIP) 到起始地址 + # 寄存器名称取决于架构 (ARM64用'PC', x64用'RIP', x86用'EIP') + architecture = idc.get_inf_attr(idc.INF_PROCNAME) + + if "arm" in architecture.lower(): + pc_reg = "PC" + elif "x64" in architecture.lower(): + pc_reg = "RIP" + else: # 默认为 x86 + pc_reg = "EIP" + + print(f"--- 准备执行代码片段 ({architecture}, PC={pc_reg}) ---") + + # 获取当前 PC/RIP/EIP 的值(用于后续打印) + original_pc = idc.get_reg_value(pc_reg) + + # 设置新的 PC/RIP/EIP 值 + if idc.set_reg_value(start_addr, pc_reg): + print(f"✅ PC/RIP/EIP 成功设置为起始地址: 0x{start_addr:X}") else: - raise ValueError("输入必须是十六进制字符串或字节数据") + print(f"[!] 警告:无法设置 PC/RIP/EIP 到 0x{start_addr:X}。请检查地址有效性。") + return - # 确保数据足够长 - if len(data_bytes) < 0x60: - # 如果数据不够长,填充0 - data_bytes = data_bytes.ljust(0x60, b'\x00') + # 3. 单步执行指定的步数 + print(f"🚀 开始单步执行 {num_steps} 条指令...") - # 初始化常量 - x9 = 0 # 索引/计数器 - x10 = 0xCCCCCCCCCCCCCCCD # 乘法常量 - x11 = 0xFFFFFFFFFFFFFFEC # -20的补码 + for i in range(num_steps): + # 使用 Step Over (跨过函数调用) + # 如果需要进入函数,请使用 idc.step_into() + if not idc.step_over(): + print(f"[!] 警告:第 {i+1} 步执行失败或遇到程序结束。") + break - # 初始化向量寄存器V0(包含0x8A) - v0 = bytes([0x8A, 0x8A, 0x8A, 0x8A]) # 4个字节,每个0x8A + current_pc = idc.get_reg_value(pc_reg) + disasm = idc.generate_disasm_line(current_pc, 0) - # 解码输出缓冲区(大小至少0x60字节) - result_size = 0x60 - decoded_bytes = bytearray(result_size) + # 打印当前执行的指令和新的 PC 地址 + print(f" [Step {i+1}/{num_steps}] -> 0x{current_pc:X}: {disasm}") - # 假设数据在内存中的起始地址(我们不需要实际地址,只需要数据) - # 我们用data_bytes作为内存数据源 - - # 解码循环 - while x9 < result_size: # 循环直到处理完0x60个字节 - # UMULH X14, X9, X10 (无符号高位乘法) - # Python中模拟64位无符号乘法的高位 - product = (x9 * x10) & 0xFFFFFFFFFFFFFFFF - x14 = (product >> 64) & 0xFFFFFFFFFFFFFFFF if product.bit_length() > 64 else 0 - - # LSR X14, X14, #4 (逻辑右移4位) - x14 = (x14 >> 4) & 0xFFFFFFFFFFFFFFFF - - # X12是数据起始地址,但在Python中我们使用数据偏移 - # 实际上x12 + x9就是数据偏移量x9 - - # ADD X15, X12, X9 -> x15 = x12 + x9 = x9 (偏移量) - # 在Python中,我们直接使用x9作为偏移 - x15_offset = x9 - - # MADD X14, X14, X11, X15 - # X14 = X14 * X11 + X15 - x14 = ((x14 * x11) + x15_offset) & 0xFFFFFFFFFFFFFFFF - - # ADD X15, X15, #0xCDA - x15_with_cda = (x15_offset + 0xCDA) & 0xFFFFFFFFFFFFFFFF - - # ADD X14, X14, #0xCC6 - x14_with_cc6 = (x14 + 0xCC6) & 0xFFFFFFFFFFFFFFFF - - # 从数据中读取(模拟内存读取) - # 注意:在实际汇编中,这些地址可能是绝对地址 - # 但在我们的模拟中,我们将它们视为数据内的偏移 - - # LDR S1, [X15] - 从地址X15读取4个字节 - # 我们使用data_bytes作为数据源,但需要确保索引有效 - s1_bytes = bytearray(4) - for i in range(4): - # 将地址转换为数据偏移(取模或边界检查) - # 简化:使用地址的低16位作为偏移 - offset = (x15_with_cda + i) & 0xFFFF - if offset < len(data_bytes): - s1_bytes[i] = data_bytes[offset] - else: - s1_bytes[i] = 0 - - # UADDW V1.8H, V0.8H, V1.8B - # 将v0(8个16位)与s1(4个8位零扩展为16位)相加 - v1_words = [] - for i in range(4): - v0_byte = v0[i % len(v0)] - s1_byte = s1_bytes[i % len(s1_bytes)] - # 8位零扩展为16位然后相加 - result = (v0_byte & 0xFF) + (s1_byte & 0xFF) - v1_words.append(result & 0xFFFF) - - # LDR S2, [X14] - 从地址X14读取4个字节 - s2_bytes = bytearray(4) - for i in range(4): - # 将地址转换为数据偏移 - offset = (x14_with_cc6 + i) & 0xFFFF - if offset < len(data_bytes): - s2_bytes[i] = data_bytes[offset] - else: - s2_bytes[i] = 0 - print(f"中间结果s2_bytes: {s2_bytes.decode('utf-8', errors='ignore')}") - # USHLL V2.8H, V2.8B, #0 - # 8位零扩展为16位 - v2_words = [] - for i in range(4): - v2_words.append(s2_bytes[i % len(s2_bytes)] & 0xFF) - - # EOR V1.8B, V1.8B, V2.8B - # 逐字节异或(只处理低8位) - xor_bytes = bytearray(4) - for i in range(4): - v1_low_byte = v1_words[i] & 0xFF - v2_low_byte = v2_words[i] & 0xFF - xor_bytes[i] = v1_low_byte ^ v2_low_byte - - # UZP1 V1.8B, V1.8B, V0.8B - # 交错取V1和V0的低字节,这里简化处理:取异或后的结果 - final_bytes = xor_bytes[:4] - print(f"中间结果: {final_bytes.decode('utf-8', errors='ignore')}") - - # 存储结果到解码缓冲区 - if x9 + 4 <= result_size: - decoded_bytes[x9:x9+4] = final_bytes - - - # ADD X9, X9, #4 - x9 += 4 - - # 最后在特定位置添加'h'字符(0x68) - # 在汇编中:STRH W10, [X9] 其中 W10 = 0x68, X9 = word_1086E320A - # 这里我们简单地在结果中添加这个字符 - if result_size > 0: - # 在适当位置添加(根据原始代码逻辑) - # 注意:实际位置可能需要调整 - pass # 先注释掉,根据实际需要添加 - - # 转换为UTF-8字符串 - try: - # 查找第一个null字节 - null_pos = -1 - for i in range(len(decoded_bytes)): - if decoded_bytes[i] == 0: - null_pos = i - break - - if null_pos != -1: - result_str = decoded_bytes[:null_pos].decode('utf-8', errors='ignore') - else: - result_str = decoded_bytes.decode('utf-8', errors='ignore') - except UnicodeDecodeError: - # 如果UTF-8解码失败,返回hex表示 - result_str = "解码失败,原始数据: " + decoded_bytes.hex() - - return result_str, decoded_bytes.hex() - -# 使用示例 -if __name__ == "__main__": - # 测试用示例数据 - test_data = [ - "83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 66 A6 5D 4B A7 9D C7 B3 0F 4C BF 1D B9 51 68 13 D0 8B 8F D1 23 AC 6D 1C F7 C7 76 1D 89 7B 1A 6F 26 53 72 11 BF B7 40 6A 1C 19 68 C2 4B 3F C8 0F 94 D1 0D 9A 0C CD 98 F9 6D 6F C5 B0 F1 02 9E 46 4A 1C 0D 87 7E D0 46 53 E0 B8 51 9A 99 D9 2B 32 BB 27 4D 01 B9 10 7E E0 1B A4 66 32 8C D4 71 E9 FC AA 58 5B D4 49 3E 01 87 7E D0 46 53 E0 B8 51 9A 99 D9 2B 32 BB 27 4D 01 B9 10 7E A8 2B A3 23 21 93 97 29 ED FC BA 43 53 CF 08 2C 66 DC 7E 0A A8 09 BF 34 38 93 C8 30 F9 FC F6 53 45 DE 44 25 60 CD 4F 13 E6 1D 8F 74 63 D2 8D 05 AF B6 B2 4E 40 D5 42 21 2E DA 7F 0C E2 51 BD 27 3D 81 DF 34 E8 B6 AA 4E 41 C8 4E 22 6F 96 63 1B F4 0D B9 29 3D BF CB 25 F5 EB B8 4C 57 E4 4E 20 71 D5 3E 1D E4 7E F7 C7 76 1D 89 7B 1A 6F 26 53 72 11 BF B7 40 6A 1C 19 68 C2 4B 3F CE 10 84 CB FF D1 ED CE AA FC 71 7B BC B0 06 07 9E 43 3A 3F C9 F6 20 87 7E D0 46 53 E0 B8 51 9A 99 D9 2B 32 BB 27 4D 01 B9 10 7E E6 1A B4 66 3C 92 98 24 EA FD B8 5F 57 9B 54 28 72 CA 79 11 E9 44 F5 19 53 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 36 B0 4B 38 B2 7D C3 AD 10 3C BD 17 BD 65 68 27 B6 87 7C CF 4A B2 56 44 83 9C C3 7D 01 3C E5 31 B7 5E 6E FC E7 EE 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 58 A7 66 FC AD B0 95 8D 10 3C BD 17 BD 12 5A 1D B6 81 76 CE 63 E5 27 6F EE B3 C7 86 05 39 B8 6B C1 48 6A 26 CC 8B 82 CF 6D E5 27 6F CE F7 C7 76 1D 89 7B 1A 6F 26 53 72 11 BF B7 40 6A 1C 19 68 C2 4B 3F CE 10 84 CB FF D1 ED CE AA FC 71 7B BC B0 06 07 9E 43 37 45 99 0C 73 AC FF A1 DE CE D6 0B 63 5B B8 A4 10 01 D3 44 4A 1C 0D 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 58 A7 66 FC AD B0 95 8D 10 3C BD 17 BD 12 5A 1D B6 81 76 CE 63 E5 27 6F EE B3 C7 86 05 39 B8 6B C1 48 6A 26 CC 8B 82 CF 6D E5 27 6F EA DE C0 82 0E 3D BD 27 78 47 68 27 B6 8F 84 C8 66 EB 6D 3F A3 9C C1 CE 45 73 9C 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 36 B0 37 4C B2 9F C1 7D 2F 3D CB 1C C1 49 6F FC B7 8F 85 B9 4D B0 46 5A CE 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 6C 9B 66 3D A2 A3 95 87 05 47 CB 32 C3 48 23 5D E2 CE 83 BB 58 A9 56 12 F3 8D 95 87 FB 46 C8 00 CC 4B 70 1D B6 82 7E D0 69 E5 27 6F CE 87 7E D0 46 53 E0 B8 51 9A 99 D9 2B 32 BB 27 4D 01 B9 10 7E C4 11 85 36 37 81 CC 34 C9 FC AA 58 5B D4 49 1E 6E CB 64 2A EE 13 B5 35 27 81 D5 21 CE F6 9D 69 32 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 6C 9B 66 3D A2 A3 95 87 05 47 CB 32 C3 48 23 5D E2 CE 90 CE 67 97 41 48 A7 9B D0 87 14 39 C1 1B 8E 0F 3E 38 F7 C7 76 1D 89 7B 1A 6F 26 53 72 11 BF B7 40 6A 1C 19 68 C2 4B 3F BA 04 84 B1 05 A1 0C CD 98 F9 6D 6F C5 B9 0C 14 A3 3E 30 2B 99 13 94 A5 00 D2 E0 AE C7 A8 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 6C 9B 66 3D A2 A3 95 87 05 47 CB 32 C3 48 23 5D E2 CE 76 BA 52 B3 73 38 B2 A3 C7 CE 45 73 9C F7 C7 76 1D 89 7B 1A 6F 26 53 72 11 BF B7 40 6A 1C 19 68 C2 4B 3F BA 04 84 B1 05 A1 0C CD 98 F9 6D 6F C5 C3 14 07 9B 3E 2A 2B 99 13 94 A5 00 D2 E0 AE C7 A8 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 6C 9B 66 3D A2 A3 95 87 05 47 CB 32 C3 48 23 5D E2 CE 76 BA 52 A9 6B 45 AA A3 D1 CE 45 73 9C 87 7E D0 46 53 E0 B8 51 9A 99 D9 2B 32 BB 27 4D 01 B9 10 7E C4 11 85 36 37 81 CC 34 C9 FC AA 58 5B D4 49 02 6F F5 71 0D F3 2D B5 28 37 85 CA 18 F4 FF B6 7F 5D FF 65 4D 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 6C 9B 66 3D A2 A3 95 87 05 47 CB 32 C3 48 23 5D E2 CE 90 C8 63 A7 67 4A 7D 97 C7 7A FB 0E 79 00 98 87 7E D0 46 53 E0 B8 51 9A 99 D9 2B 32 BB 27 4D 01 B9 10 7E C4 11 85 36 37 81 CC 34 C9 FC AA 58 5B D4 49 18 6F CB 75 1F E3 29 B9 32 3B A4 DD 3D FF ED BC 4F 7F DE 54 3E 60 DE 75 2A E8 3A 92 46 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 6C 9B 66 3D A2 A3 95 87 05 47 CB 32 C3 48 23 5D E2 CE 90 C8 67 99 67 4A 7D 97 D1 CE 45 73 7C 17 C1 47 68 27 BD 8F 7A BD 2F E6 41 1C 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 36 B0 37 4C B2 9F C1 7D 2F 3D CB 1C C1 49 6F 0C B7 8F 7D BA 5B A6 5C 6B A2 9F C1 8D 0F 6C BF 07 B6 32 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 6C 9B 66 3D A2 A3 95 87 05 47 CB 32 C3 48 23 5D E2 CE 93 BB 58 B1 5D 36 B3 B0 D6 87 14 39 C8 16 C7 FC 28 13 A9 87 7E D0 46 53 E0 B8 51 9A 99 D9 2B 32 BB 27 4D 01 B9 10 7E C4 11 95 22 3A 94 EB 34 E9 EA B0 44 5C EE 49 3F 64 D8 74 2D F1 0C 99 22 07 8F FC 13 9A 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 36 B0 47 38 A7 B2 E2 7D 0F 47 C5 30 C2 5F 6F 26 CC 8F 83 DA 6B 9D 53 38 82 9D F1 96 40 4D CB 26 C6 48 6C 25 CC BB C2 DE 25 B0 6E 38 7D B1 BF 86 2B 41 B8 5E 7D 59 31 22 CC 85 AC BA 6B 9D 41 45 B2 EB 90 B3 60 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 36 B0 4D 40 B3 9F C3 A7 05 47 CB 32 C3 48 38 22 B7 93 7E C9 36 B0 57 3E A2 92 C6 9C 1E 18 83 55 94 A6 58 48 3F 62 EA A2 26 D5 22 BC 97 C2 33 78 69 37 56 AF 67 3D A0 DE C2 7D 0F 47 C5 30 C2 12 58 22 B7 93 7E C9 2F E6 41 FC B1 9A D0 79 0E 73 C9 31 C6 4F 6C 1C E2 82 76 D0 5C E5 27 6F EE A1 C9 7D 01 46 EF 2E B9 44 72 13 BC 8C 91 C8 58 A7 24 F9 7D BE F7 C7 76 1D 89 7B 1A 6F 26 53 72 11 BF B7 40 6A 1C 19 68 C2 4B 3F BC FB 7E AF E0 A1 EC B7 B2 15 68 79 C5 AF 10 0F A3 18 2F 49 AF 00 74 AB F5 C4 BD 83 55" - ] - - for i, data in enumerate(test_data): - print(f"\n测试数据 {i+1}: {data}") - try: - result, hex_result = decode_from_bytes(data) - print(f"解码结果: {result}") - print(f"Hex表示: {hex_result}") - except Exception as e: - print(f"解码出错: {e}") + # 4. 执行完毕后的状态 + final_pc = idc.get_reg_value(pc_reg) + print("----------------------------------------") + print(f"执行完毕。") + print(f"起始 PC/RIP/EIP (设置前): 0x{original_pc:X}") + print(f"当前 PC/RIP/EIP (执行后): 0x{final_pc:X}") + print(f"📢 **程序处于暂停状态,请手动恢复 (F9) 或检查状态。**") +# ---------------------------------------------------- +# 执行主函数 +# ---------------------------------------------------- +execute_code_snippet(START_ADDRESS, STEPS_TO_EXECUTE) \ No newline at end of file diff --git a/idapro/get_x_value.py b/idapro/get_x_value.py new file mode 100644 index 0000000..cf31196 --- /dev/null +++ b/idapro/get_x_value.py @@ -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. 程序已运行并暂停在某个断点上。") \ No newline at end of file diff --git a/idapro/memory_check.py b/idapro/memory_check.py new file mode 100644 index 0000000..9f7f58c --- /dev/null +++ b/idapro/memory_check.py @@ -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 \ No newline at end of file