diff --git a/.gitignore b/.gitignore index 8850692..a5e0706 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ __handlers__ *.sqlite .DS_Store diaphora_batch* -data \ No newline at end of file +data +.venv \ No newline at end of file diff --git a/function.md b/function.md index 459860a..4ebbffc 100644 --- a/function.md +++ b/function.md @@ -1,15 +1,26 @@ + + + +装填数据,发到jobqueue是他们的目地,我感觉重点是在这里 +sub_1032003B0 -> sub_1024803E4 -> sub_1024C6354 可能是统一入口 +sub_10237997C image_handler.cc +sub_1023E73E8 text_handler.cc +sub_102363BB0 file_handler.cc +sub_100400950 装填消息 + + +键盘事件触发 +sub_10064DD2C 里面有铭文的数据,看看怎么把这个数据传输到下层,估计是 +sub_100662CC4 处理消息的关键函数 +sub_100662CC4 -> sub_100668580 -> sub_10064DD2C +sub_100662CC4 -> sub_10063F318 -> sub_1006DDDBC 处理发送消息结构体 +sub_1006DDDBC 消息体在这个函数 + +真正的发送阶段 +sub_10250D878 是整体的发消息入口有多个阶段来自这里 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 装填消息 +sub_1024C7FB4 sendMessage 入口 \ No newline at end of file diff --git a/idapro/analysis_x.py b/idapro/analysis_x.py index 0182bf8..92f2ff0 100644 --- a/idapro/analysis_x.py +++ b/idapro/analysis_x.py @@ -7,16 +7,13 @@ 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: + print(f"不可打印字符: {chr(byte)}") return False, "" return True, result @@ -29,8 +26,7 @@ def dereference_recursive(traceMap, addr, struct_size, depth=0, max_depth=5): :param depth: 当前递归深度 :param max_depth: 最大递归深度 """ - mapAddr = f"0x{addr:016X}" - print(f"mapAddr: {mapAddr}") + mapAddr = f"0x{addr:X}" traceMap[mapAddr] = {} if depth >= max_depth: print(" " * depth + f"[达到最大递归深度 {max_depth}]") @@ -58,7 +54,7 @@ def dereference_recursive(traceMap, addr, struct_size, depth=0, max_depth=5): is_str, str_val = is_printable_string(data) if is_str and len(str_val) > 0: - data[addr][str_val] = {} + traceMap[mapAddr][str_val] = {} print(f"{indent}字符串: \"{str_val}\"") return except: @@ -71,20 +67,23 @@ def dereference_recursive(traceMap, addr, struct_size, depth=0, max_depth=5): 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}") + # 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}") + # 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 @@ -99,12 +98,9 @@ def dereference_recursive(traceMap, addr, struct_size, depth=0, max_depth=5): 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}") + 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) @@ -139,6 +135,7 @@ def print_register_struct(reg_name, struct_size=64, max_depth=3): except Exception as e: print(f"错误: {e}") + print(f"{reg_name}递归分析结果:") print(json.dumps(traceMap, indent=4)) @@ -198,4 +195,4 @@ analyze_all_args() example_usage() """ -print_register_struct("X0", 64, 3) \ No newline at end of file +print_register_struct("X27", 64, 5) \ No newline at end of file diff --git a/idapro/memory_check.py b/idapro/memory_check.py index 9f7f58c..4b0fd55 100644 --- a/idapro/memory_check.py +++ b/idapro/memory_check.py @@ -1,68 +1,56 @@ -# IDAPython Breakpoint Action Script - import idc import ida_dbg import idautils +import ida_idd +import ida_name -# ---------------------------------------------------- -# 步骤 1: 定义获取和打印堆栈的函数 -# ---------------------------------------------------- -def print_call_stack(): - """获取当前的调用堆栈地址,并将其打印到 IDA 消息窗口。""" +def dbg_get_call_stack() -> list[dict[str, str]]: + """Get the current call stack.""" + callstack = [] + try: + tid = ida_dbg.get_current_thread() + trace = ida_idd.call_stack_t() - # 获取当前线程 ID,通常是获取堆栈的第一步 - tid = idc.get_current_thread() - if tid == -1: - print("[!] 脚本错误: 无法获取当前线程 ID。") - return + if not ida_dbg.collect_stack_trace(tid, trace): + return [] + for frame in trace: + frame_info = { + "address": hex(frame.callea), + } + try: + module_info = ida_idd.modinfo_t() + if ida_dbg.get_module_info(frame.callea, module_info): + frame_info["module"] = os.path.basename(module_info.name) + else: + frame_info["module"] = "" - print("=" * 40) - print(f"✅ 断点触发于地址: 0x{idc.get_screen_ea():X}") - print(f"➡️ **调用堆栈 (Call Stack) 地址:**") + name = ( + ida_name.get_nice_colored_name( + frame.callea, + ida_name.GNCN_NOCOLOR + | ida_name.GNCN_NOLABEL + | ida_name.GNCN_NOSEG + | ida_name.GNCN_PREFDBG, + ) + or "" + ) + frame_info["symbol"] = name - # idautils.get_current_caller_frame() 可获取调用堆栈信息 - # 它返回一个列表,其中每个元素都是一个 (返回地址, 帧指针/栈指针) 的元组。 + except Exception as e: + frame_info["module"] = "" + frame_info["symbol"] = str(e) - # 遍历堆栈帧并打印返回地址 - frame_count = 0 + callstack.append(frame_info) - # 注意: 在 64 位 ARM (AArch64) 上,栈操作可能与 x86 不同 - # 我们使用 idautils.get_call_stack 尝试获取更标准的堆栈信息。 - # idautils.get_call_stack() 可能会返回一系列的 (地址, 描述) 元组 - stack_info = ida_dbg.collect_stack_trace() + except Exception as e: + pass + return callstack - 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) +def dbg_print_call_stack(callstack: list[dict[str, str]]): + print("Call Stack:----------------------------------------") + for i, frame in enumerate(reversed(callstack)): + print(f"{i}: {frame['module']}.{frame['symbol']} @ {frame['address']}") -# ---------------------------------------------------- -# 步骤 2: 调用主函数 -# ---------------------------------------------------- -# 在断点被命中时,执行堆栈打印 -print_call_stack() -# ---------------------------------------------------- -# 步骤 3: 控制程序流 (重要!) -# ---------------------------------------------------- -# 要让程序在打印堆栈后继续执行,必须返回 0 或不返回 (即让 IDA 默认继续)。 -# 但是,如果希望程序在打印后暂停 (即执行普通断点的动作),则返回 1 (但这不是本脚本的目的)。 -# 如果你想继续执行(Trace Breakpoint),请确保 Action 下一步是 Resume -return 0 \ No newline at end of file +dbg_print_call_stack(dbg_get_call_stack()) \ No newline at end of file diff --git a/idapro/modify_send.py b/idapro/modify_send.py new file mode 100644 index 0000000..214086f --- /dev/null +++ b/idapro/modify_send.py @@ -0,0 +1,30 @@ +import ida_dbg +import ida_idaapi +import ida_bytes + +def dbg_bpt(ea): + # 获取X22寄存器的值(指向的内存地址) + x22_value = ida_dbg.get_reg_val("X22") + + if x22_value != ida_idaapi.BADADDR: + # 要写入的数据:'1','2','3' 的ASCII码 + patch_data = [ord('1'), ord('2'), ord('3')] + + # 修改内存 + for i, byte_val in enumerate(patch_data): + ida_bytes.patch_byte(x22_value + i, byte_val) + + print(f"[断点 0x{ea:X}] 已将 X22(0x{x22_value:X}) 的前3字节修改为 '123'") + + # 可选:显示修改前后的内容对比 + original = [] + for i in range(3): + original.append(ida_bytes.get_byte(x22_value + i)) + + print(f" 修改前: {[hex(b) for b in original]}") + print(f" 修改后: {[hex(b) for b in patch_data]}") + + # 返回0继续执行 + return 0 + +dbg_bpt(0x1006DDE30) \ No newline at end of file