BinSentry 自研二进制哨兵调用Python SDK库
BinSentry 二进制哨兵,由 LYSHARK 独立自研,是一款运行于 Windows 平台的二进制动态调试引擎。该调试引擎从零手写开发,C++ 代码 3 万余行,实现 300 + 调试方法;原生采用 CMD 命令行 HTTP 服务器架构,专为 AI Agent 打造。配合配套 AI 智能体,能够对二进制文件、木马等恶意样本进行深层次分析,是二进制样本研究的实用工具。 **哨兵可以部署到任意的虚拟机沙盒之中,并可以搭载目前流行的jev等大模型产品,AI驱动速度有质的提升,是Windows平台下AI动态调试的优质项目。** 执行命令安装哨兵客户端: ``` Microsoft Windows [版本] (c) 2018 Microsoft Corporation。保留所有权利。 C:\Users\Admin>pip install BinSentry==1.0.0 ``` 哨兵运行后会在后台,并默认侦听6891端口,且可以设置开机自启动。   结论:**186 项接口调用,184 项 PASS,0 项 FAIL/ERROR,2 项 SKIP(谨慎跳过)**,所有接口均正常。 ## 测试概况 - **服务端**:127.0.0.1:6891(在线);**测试目标**:`E:\win32.exe` - **覆盖范围**:11 个 API 类别全部接口 ——SystemApi、LogConfigApi、SymbolVarApi、BreakPointApi、DebugSessionApi、RegisterThreadApi、ModulePeApi、MemoryApi、DisasmXrefApi、StackTraceApi、ExecutionControlApi - **流程**:基础状态 → 系统 → 变量 / 日志 → 启动调试 `E:\win32.exe` → 模块 / PE → 内存 → 寄存器 / 线程 → 断点 → 反汇编 → 栈 / 追踪 → 执行控制 → 会话管理 → 数据库,含写类操作(内存写、补丁、断点、寄存器)均做了 "写入→验证→还原",不污染目标进程 ## 各类别结果 |API 类|总数|PASS|说明| | --- | --- | --- | --- | |BreakPointApi|35|35|软 / 硬 / 内存 / API / 异常 / DLL 断点全套| |ExecutionControlApi|28|28|单步、trace、animate、run/pause 等| |MemoryApi|26|26|读写、搜索、页权限、补丁、分配| |ModulePeApi|21|21|模块 / PE / 导入导出 / 符号| |DebugSessionApi|15|15|debug/detach/restart/stop/dump/minidump| |其余 6 类|61|61|全部通过| ## 2 项 SKIP(谨慎跳过,非故障) - `set_jit`:`get_jit` 未返回有效 JIT 路径,为避免写注册表而跳过 - `set_command_line`:`get_command_line` 未返回可用值,为避免覆盖配置而跳过 ### 完整开源接口 ``` import json import socket from urllib.parse import urlparse from typing import List, Dict, Union, Optional, Callable from functools import wraps def check_server_available(func: Callable) -> Callable: """装饰器:检测服务是否可用,不可用直接返回error json""" @wraps(func) def wrapper(self, *args, **kwargs): if not self.config.is_server_available(): return json.dumps({ "status": "error", "message": "Server unavailable" }, ensure_ascii=False) return func(self, *args, **kwargs) return wrapper def validate_hex_address(address: Union[int, str]) -> Optional[str]: """校验并格式化十六进制地址,返回 0xxxxx 格式字符串,非法返回None""" if isinstance(address, int): return hex(address) addr_str = str(address).strip() if not addr_str: return None if addr_str.startswith(('0x', '0X')): try: int(addr_str, 16) return addr_str except ValueError: return None try: int(addr_str, 10) return addr_str except ValueError: return None class Config: def __init__(self, address: str = "127.0.0.1", port: int = 6891): self.address = address self.port = port self.server_addr = f"http://{address}:{port}" self.timeout = 5 def is_server_available(self, timeout: Optional[int] = None) -> bool: """检测端口是否开放""" timeout = timeout or self.timeout try: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.settimeout(timeout) result = sock.connect_ex((self.address, self.port)) return result == 0 except socket.error as e: print(f"WARNING: Server check failed: {str(e)}") return False class BaseHttpClient: def __init__(self, config: Optional[Config] = None): self.config = config or Config() parsed_url = urlparse(self.config.server_addr) self.address = parsed_url.hostname self.port = parsed_url.port self.scheme = parsed_url.scheme self.path = parsed_url.path or '/' self.verify_ssl = True def custom_post(self, payload: Optional[Dict] = None, timeout: Optional[int] = None) -> str: """发送POST请求,payload对应BinSentry接口 {interface, params}""" import http.client headers = {"Content-Type": "application/json"} body = json.dumps(payload).encode("utf-8") if payload else None timeout = timeout or self.config.timeout try: if self.scheme == "https": import ssl context = ssl._create_unverified_context() if not self.verify_ssl else None conn = http.client.HTTPSConnection(self.address, self.port, timeout=timeout, context=context) else: conn = http.client.HTTPConnection(self.address, self.port, timeout=timeout) conn.request("POST", self.path, body=body, headers=headers) response = conn.getresponse() response_text = response.read().decode("utf-8", errors="ignore") conn.close() return response_text except socket.timeout: return json.dumps({"status": "error", "message": "Request timed out"}, ensure_ascii=False) except ConnectionRefusedError: return json.dumps({"status": "error", "message": "Connection refused by server"}, ensure_ascii=False) except Exception as e: return json.dumps({"status": "error", "message": f"Request failed: {str(e)}"}, ensure_ascii=False) class SystemApi(BaseHttpClient): """系统与进程相关接口""" @check_server_available def system_info(self) -> str: return self.custom_post({"interface": "SystemInfo", "params": {}}) @check_server_available def process_list(self) -> str: return self.custom_post({"interface": "ProcessList", "params": {}}) @check_server_available def enum_windows(self, pid: int) -> str: return self.custom_post({"interface": "EnumWindows", "params": {"pid": pid}}) @check_server_available def is_process_elevated(self) -> str: return self.custom_post({"interface": "IsProcessElevated", "params": {}}) @check_server_available def enum_error_codes(self) -> str: return self.custom_post({"interface": "EnumErrorCodes", "params": {}}) @check_server_available def enum_exceptions(self) -> str: return self.custom_post({"interface": "EnumExceptions", "params": {}}) @check_server_available def help(self) -> str: return self.custom_post({"interface": "Help", "params": {}}) @check_server_available def get_jit(self) -> str: return self.custom_post({"interface": "GetJIT", "params": {}}) @check_server_available def set_jit(self, path: str) -> str: return self.custom_post({"interface": "SetJIT", "params": {"path": path}}) @check_server_available def get_command_line(self) -> str: return self.custom_post({"interface": "GetCommandLine", "params": {}}) @check_server_available def set_command_line(self, args: str) -> str: return self.custom_post({"interface": "SetCommandLine", "params": {"args": args}}) class LogConfigApi(BaseHttpClient): """日志与配置数据库""" @check_server_available def clear_log(self) -> str: return self.custom_post({"interface": "ClearLog", "params": {}}) @check_server_available def logs(self) -> str: return self.custom_post({"interface": "Logs", "params": {}}) @check_server_available def save_log(self, path: str) -> str: return self.custom_post({"interface": "SaveLog", "params": {"path": path}}) @check_server_available def load_database(self, path: str) -> str: return self.custom_post({"interface": "LoadDatabase", "params": {"path": path}}) @check_server_available def save_database(self, path: str) -> str: return self.custom_post({"interface": "SaveDatabase", "params": {"path": path}}) @check_server_available def load_config(self, module: str) -> str: return self.custom_post({"interface": "LoadConfig", "params": {"module": module}}) class SymbolVarApi(BaseHttpClient): """变量、参数、注释、标签、函数""" @check_server_available def set_var(self, name: str, value: str) -> str: return self.custom_post({"interface": "SetVar", "params": {"name": name, "value": value}}) @check_server_available def del_var(self, name: str) -> str: return self.custom_post({"interface": "DelVar", "params": {"name": name}}) @check_server_available def get_vars(self) -> str: return self.custom_post({"interface": "GetVars", "params": {}}) @check_server_available def add_argument(self, start: Union[int, str], end: Union[int, str] = "", name: str = "") -> str: start_addr = validate_hex_address(start) payload: Dict = {"start": start_addr} if end: payload["end"] = validate_hex_address(end) if name: payload["name"] = name return self.custom_post({"interface": "AddArgument", "params": payload}) @check_server_available def del_argument(self, start: Union[int, str]) -> str: s = validate_hex_address(start) return self.custom_post({"interface": "DelArgument", "params": {"start": s}}) @check_server_available def get_arguments(self) -> str: return self.custom_post({"interface": "GetArguments", "params": {}}) @check_server_available def get_comments(self) -> str: return self.custom_post({"interface": "GetComments", "params": {}}) @check_server_available def get_labels(self) -> str: return self.custom_post({"interface": "GetLabels", "params": {}}) @check_server_available def get_bookmarks(self) -> str: return self.custom_post({"interface": "GetBookMarks", "params": {}}) @check_server_available def functions(self) -> str: return self.custom_post({"interface": "Functions", "params": {}}) class BreakPointApi(BaseHttpClient): """断点:软件/硬件/内存/api/异常/dll断点""" @check_server_available def show_breakpoint(self) -> str: return self.custom_post({"interface": "ShowBreakPoint", "params": {}}) @check_server_available def show_hbreakpoint(self) -> str: return self.custom_post({"interface": "ShowHbreakPoint", "params": {}}) @check_server_available def show_mem_breakpoint(self) -> str: return self.custom_post({"interface": "ShowMemBreakPoint", "params": {}}) @check_server_available def show_api_breakpoint(self) -> str: return self.custom_post({"interface": "ShowApiBreakPoint", "params": {}}) @check_server_available def set_bpx_options(self, option: str, enable: int) -> str: return self.custom_post({"interface": "SetBPXOptions", "params": {"option": option, "enable": enable}}) @check_server_available def set_exception_bpx(self, code: str) -> str: return self.custom_post({"interface": "SetExceptionBPX", "params": {"code": code}}) @check_server_available def del_exception_bpx(self, code: str) -> str: return self.custom_post({"interface": "DelExceptionBPX", "params": {"code": code}}) @check_server_available def get_exception_bpx_list(self) -> str: return self.custom_post({"interface": "GetExceptionBPXList", "params": {}}) @check_server_available def set_dll_breakpoint(self, dll: str) -> str: return self.custom_post({"interface": "SetDllBreakPoint", "params": {"dll": dll}}) @check_server_available def del_dll_breakpoint(self, dll: str) -> str: return self.custom_post({"interface": "DelDllBreakPoint", "params": {"dll": dll}}) @check_server_available def get_dll_breakpoints(self) -> str: return self.custom_post({"interface": "GetDllBreakPoints", "params": {}}) @check_server_available def set_breakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakPoint", "params": {"address": addr}}) @check_server_available def del_breakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DelBreakPoint", "params": {"address": addr}}) @check_server_available def get_breakpoint_info(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetBreakpointInfo", "params": {"address": addr}}) @check_server_available def get_breakpoint_type(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetBreakpointType", "params": {"address": addr}}) @check_server_available def set_breakpoint_name(self, address: Union[int, str], name: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointName", "params": {"address": addr, "name": name}}) @check_server_available def set_breakpoint_singleshoot(self, address: Union[int, str], enable: int = 0) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointSingleshoot", "params": {"address": addr, "enable": enable}}) @check_server_available def set_breakpoint_fast_resume(self, address: Union[int, str], enable: int = 0) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointFastResume", "params": {"address": addr, "enable": enable}}) @check_server_available def set_breakpoint_silent(self, address: Union[int, str], enable: int = 0) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointSilent", "params": {"address": addr, "enable": enable}}) @check_server_available def set_breakpoint_log(self, address: Union[int, str], text: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointLog", "params": {"address": addr, "text": text}}) @check_server_available def set_breakpoint_log_file(self, address: Union[int, str], file: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointLogFile", "params": {"address": addr, "file": file}}) @check_server_available def set_breakpoint_hit_count(self, address: Union[int, str], count: int) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointHitCount", "params": {"address": addr, "count": count}}) @check_server_available def get_breakpoint_hit_count(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetBreakpointHitCount", "params": {"address": addr}}) @check_server_available def reset_breakpoint_hit_count(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "ResetBreakpointHitCount", "params": {"address": addr}}) @check_server_available def set_cond_breakpoint(self, address: Union[int, str], cond: str, thread: int = 0) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetCondBreakPoint", "params": {"address": addr, "cond": cond, "thread": thread}}) @check_server_available def del_cond_breakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DelCondBreakPoint", "params": {"address": addr}}) @check_server_available def set_hbreakpoint(self, address: Union[int, str], len_: str = "1", flag: str = "e") -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetHbreakPoint", "params": {"address": addr, "len": len_, "flag": flag}}) @check_server_available def del_hbreakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DelHbreakPoint", "params": {"address": addr}}) @check_server_available def set_mem_breakpoint(self, address: Union[int, str], flag: str = "e") -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetMemBreakPoint", "params": {"address": addr, "flag": flag}}) @check_server_available def del_mem_breakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DelMemBreakPoint", "params": {"address": addr}}) @check_server_available def set_api_breakpoint(self, dll: str, api: str) -> str: return self.custom_post({"interface": "SetApiBreakPoint", "params": {"dll": dll, "api": api}}) @check_server_available def del_api_breakpoint(self, dll: str, api: str) -> str: return self.custom_post({"interface": "DelApiBreakPoint", "params": {"dll": dll, "api": api}}) @check_server_available def disable_breakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DisableBreakpoint", "params": {"address": addr}}) @check_server_available def enable_breakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "EnableBreakpoint", "params": {"address": addr}}) @check_server_available def breakpoint_command(self, address: Union[int, str], command: str = "") -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "BreakpointCommand", "params": {"address": addr, "command": command}}) class DebugSessionApi(BaseHttpClient): """会话管理:启动调试、停止、分离、dump""" @check_server_available def debug(self, path: str, args: str = "", cwd: str = "") -> str: return self.custom_post({"interface": "Debug", "params": {"path": path, "args": args, "cwd": cwd}}) @check_server_available def set_debug(self, command: str = "Logs") -> str: return self.custom_post({"interface": "SetDebug", "params": command}) @check_server_available def stop(self) -> str: return self.custom_post({"interface": "Stop", "params": {}}) @check_server_available def detach(self) -> str: return self.custom_post({"interface": "Detach", "params": {}}) @check_server_available def restart(self) -> str: return self.custom_post({"interface": "Restart", "params": {}}) @check_server_available def dump_process(self, path: str, base: Union[int, str], size: int) -> str: base_addr = validate_hex_address(base) return self.custom_post({"interface": "DumpProcess", "params": {"path": path, "base": base_addr, "size": size}}) @check_server_available def minidump(self, path: str) -> str: return self.custom_post({"interface": "minidump", "params": {"path": path}}) @check_server_available def status(self) -> str: return self.custom_post({"interface": "Status", "params": {}}) class RegisterThreadApi(BaseHttpClient): """寄存器、线程操作""" @check_server_available def register(self) -> str: return self.custom_post({"interface": "Register", "params": {}}) @check_server_available def set_register(self, reg: str, value: str) -> str: return self.custom_post({"interface": "SetRegister", "params": {"reg": reg, "value": value}}) @check_server_available def threads(self) -> str: return self.custom_post({"interface": "Threads", "params": {}}) @check_server_available def thread_info(self, tid: int) -> str: return self.custom_post({"interface": "ThreadInfo", "params": {"tid": tid}}) @check_server_available def get_active_thread(self) -> str: return self.custom_post({"interface": "GetActiveThread", "params": {}}) @check_server_available def set_active_thread(self, tid: int) -> str: return self.custom_post({"interface": "SetActiveThread", "params": {"tid": tid}}) @check_server_available def get_thread_last_error(self, tid: int) -> str: return self.custom_post({"interface": "GetThreadLastError", "params": {"tid": tid}}) @check_server_available def get_thread_priority(self, tid: int) -> str: return self.custom_post({"interface": "GetThreadPriority", "params": {"tid": tid}}) @check_server_available def set_thread_priority(self, tid: int, priority: str = "NORMAL") -> str: return self.custom_post({"interface": "SetThreadPriority", "params": {"tid": tid, "priority": priority}}) @check_server_available def set_thread_name(self, tid: int, name: str) -> str: return self.custom_post({"interface": "SetThreadName", "params": {"tid": tid, "name": name}}) @check_server_available def set_flag(self, flag: str, value: int) -> str: return self.custom_post({"interface": "SetFlag", "params": {"flag": flag, "value": value}}) class ModulePeApi(BaseHttpClient): """模块、PE、导入导出、符号""" @check_server_available def modules(self) -> str: return self.custom_post({"interface": "Modules", "params": {}}) @check_server_available def module_info(self, module: str) -> str: return self.custom_post({"interface": "ModuleInfo", "params": {"module": module}}) @check_server_available def sections(self, module: str) -> str: return self.custom_post({"interface": "Sections", "params": {"module": module}}) @check_server_available def pe_info(self, path: str) -> str: return self.custom_post({"interface": "PEInfo", "params": {"path": path}}) @check_server_available def rich_header(self, module: str) -> str: return self.custom_post({"interface": "RichHeader", "params": {"module": module}}) @check_server_available def tls_callbacks(self, module: str) -> str: return self.custom_post({"interface": "TLSCallbacks", "params": {"module": module}}) @check_server_available def relocation_list(self, module: str) -> str: return self.custom_post({"interface": "RelocationList", "params": {"module": module}}) @check_server_available def debug_directory(self, module: str) -> str: return self.custom_post({"interface": "DebugDirectory", "params": {"module": module}}) @check_server_available def import_list(self, module: str) -> str: return self.custom_post({"interface": "ImportList", "params": {"module": module}}) @check_server_available def export_list(self, module: str) -> str: return self.custom_post({"interface": "ExportList", "params": {"module": module}}) @check_server_available def get_import_address(self, module: str, name: str) -> str: return self.custom_post({"interface": "GetImportAddress", "params": {"module": module, "name": name}}) @check_server_available def get_export_address(self, module: str, name: str) -> str: return self.custom_post({"interface": "GetExportAddress", "params": {"module": module, "name": name}}) @check_server_available def gpa(self, dll: str, api: str) -> str: return self.custom_post({"interface": "gpa", "params": {"dll": dll, "api": api}}) @check_server_available def addr_to_module(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "AddrToModule", "params": {"address": addr}}) @check_server_available def get_section_data(self, module: str, name: str) -> str: return self.custom_post({"interface": "GetSectionData", "params": {"module": module, "name": name}}) @check_server_available def get_section_info(self, module: str, name: str) -> str: return self.custom_post({"interface": "GetSectionInfo", "params": {"module": module, "name": name}}) @check_server_available def symbol(self, expr: str) -> str: return self.custom_post({"interface": "Symbol", "params": {"expr": expr}}) @check_server_available def get_symbol_info(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetSymbolInfo", "params": {"address": addr}}) @check_server_available def get_function_size(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetFunctionSize", "params": {"address": addr}}) @check_server_available def heaps(self) -> str: return self.custom_post({"interface": "Heaps", "params": {}}) @check_server_available def handles(self, max_num: int = 20) -> str: return self.custom_post({"interface": "Handles", "params": {"max": max_num}}) @check_server_available def seh_list(self) -> str: return self.custom_post({"interface": "SEHList", "params": {}}) class MemoryApi(BaseHttpClient): """内存读写、搜索、补丁、内存分配""" @check_server_available def memory_info(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "MemoryInfo", "params": {"address": addr}}) @check_server_available def regions(self) -> str: return self.custom_post({"interface": "Regions", "params": {}}) @check_server_available def memory(self, address: Union[int, str], size: int = 16) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "Memory", "params": {"address": addr, "size": size}}) @check_server_available def read_memory_value(self, address: Union[int, str], size: int = 4) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "ReadMemoryValue", "params": {"address": addr, "size": size}}) @check_server_available def write_memory(self, address: Union[int, str], hex_: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "WriteMemory", "params": {"address": addr, "hex": hex_}}) @check_server_available def get_page_rights(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetPageRights", "params": {"address": addr}}) @check_server_available def set_page_rights(self, address: Union[int, str], protect: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetPageRights", "params": {"address": addr, "protect": protect}}) @check_server_available def set_page_memory(self, address: Union[int, str], protect: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetPageMemory", "params": {"address": addr, "protect": protect}}) @check_server_available def allocate_memory(self, size: int) -> str: return self.custom_post({"interface": "AllocateMemory", "params": {"size": size}}) @check_server_available def free_memory(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "FreeMemory", "params": {"address": addr}}) @check_server_available def set_memory(self, address: Union[int, str], hex_: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetMemory", "params": {"address": addr, "hex": hex_}}) @check_server_available def fill_memory(self, address: Union[int, str], size: int, value: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "FillMemory", "params": {"address": addr, "size": size, "value": value}}) @check_server_available def memcpy(self, src: Union[int, str], dst: Union[int, str], size: int) -> str: src_a = validate_hex_address(src) dst_a = validate_hex_address(dst) return self.custom_post({"interface": "Memcpy", "params": {"src": src_a, "dst": dst_a, "size": size}}) @check_server_available def va_to_file_offset(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "VaToFileOffset", "params": {"address": addr}}) @check_server_available def file_offset_to_va(self, offset: str) -> str: return self.custom_post({"interface": "FileOffsetToVa", "params": {"offset": offset}}) @check_server_available def get_string(self, address: Union[int, str], max_num: int = 64, type_: str = "ascii") -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetString", "params": {"address": addr, "max": max_num, "type": type_}}) @check_server_available def search_memory(self, pattern: str, start: Union[int, str], size: int) -> str: s = validate_hex_address(start) return self.custom_post({"interface": "SearchMemory", "params": {"pattern": pattern, "start": s, "size": size}}) @check_server_available def search_all_memory(self, pattern: str, max_num: int = 5) -> str: return self.custom_post({"interface": "SearchAllMemory", "params": {"pattern": pattern, "max": max_num}}) @check_server_available def search_strings(self, address: Union[int, str], size: int) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SearchStrings", "params": {"address": addr, "size": size}}) @check_server_available def match_pattern(self, address: Union[int, str], pattern: str, size: int) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "MatchPattern", "params": {"address": addr, "pattern": pattern, "size": size}}) @check_server_available def hash_memory(self, address: Union[int, str], size: int, algo: str = "md5") -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "HashMemory", "params": {"address": addr, "size": size, "algo": algo}}) @check_server_available def patch_memory(self, address: Union[int, str], hex_: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "PatchMemory", "params": {"address": addr, "hex": hex_}}) @check_server_available def patches(self) -> str: return self.custom_post({"interface": "Patches", "params": {}}) @check_server_available def revert_patch(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "RevertPatch", "params": {"address": addr}}) @check_server_available def delete_patch(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DeletePatch", "params": {"address": addr}}) class DisasmXrefApi(BaseHttpClient): """反汇编、汇编、交叉引用""" @check_server_available def disassemble_at(self, address: Union[int, str], count: int = 5) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DisassembleAt", "params": {"address": addr, "count": count}}) @check_server_available def dissasembler(self, address: Union[int, str], count: int = 5) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "Dissasembler", "params": {"address": addr, "count": count}}) @check_server_available def get_opcode_size(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetOpcodeSize", "params": {"address": addr}}) @check_server_available def mnemonicbrief(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "mnemonicbrief", "params": {"address": addr}}) @check_server_available def get_branch_target(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetBranchTarget", "params": {"address": addr}}) @check_server_available def assemble(self, instr: str, cip: Union[int, str]) -> str: c = validate_hex_address(cip) return self.custom_post({"interface": "Assemble", "params": {"instr": instr, "cip": c}}) @check_server_available def assemble_at(self, address: Union[int, str], instr: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "AssembleAt", "params": {"address": addr, "instr": instr}}) @check_server_available def xrefs(self, address: Union[int, str], max_num: int = 5) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "xrefs", "params": {"address": addr, "max": max_num}}) @check_server_available def find_ref(self, address: Union[int, str], max_num: int = 5) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "FindRef", "params": {"address": addr, "max": max_num}}) class StackTraceApi(BaseHttpClient): """栈、调用栈、追踪记录""" @check_server_available def call_stack(self, max_num: int = 16) -> str: return self.custom_post({"interface": "CallStack", "params": {"max": max_num}}) @check_server_available def stack(self, count: int = 8) -> str: return self.custom_post({"interface": "Stack", "params": {"count": count}}) @check_server_available def stack_push(self, value: str) -> str: return self.custom_post({"interface": "StackPush", "params": {"value": value}}) @check_server_available def stack_pop(self) -> str: return self.custom_post({"interface": "StackPop", "params": {}}) @check_server_available def stack_peek(self, offset: int = 0) -> str: return self.custom_post({"interface": "StackPeek", "params": {"offset": offset}}) @check_server_available def start_trace_record(self) -> str: return self.custom_post({"interface": "StartTraceRecord", "params": {}}) @check_server_available def get_trace_record(self, count: int = 5) -> str: return self.custom_post({"interface": "GetTraceRecord", "params": {"count": count}}) @check_server_available def stop_trace_record(self) -> str: return self.custom_post({"interface": "StopTraceRecord", "params": {}}) @check_server_available def jmp_history(self) -> str: return self.custom_post({"interface": "JmpHistory", "params": {}}) @check_server_available def last_exception(self) -> str: return self.custom_post({"interface": "LastException", "params": {}}) @check_server_available def eval_expr(self, expr: str) -> str: return self.custom_post({"interface": "Eval", "params": {"expr": expr}}) @check_server_available def show_debugger(self) -> str: return self.custom_post({"interface": "ShowDebugger", "params": {}}) @check_server_available def hide_debugger(self) -> str: return self.custom_post({"interface": "HideDebugger", "params": {}}) class ExecutionControlApi(BaseHttpClient): """执行控制:运行、单步、暂停、run_to""" @check_server_available def run(self) -> str: return self.custom_post({"interface": "Run", "params": {}}) @check_server_available def pause(self) -> str: return self.custom_post({"interface": "Pause", "params": {}}) @check_server_available def e_run(self) -> str: return self.custom_post({"interface": "ERun", "params": {}}) @check_server_available def se_run(self) -> str: return self.custom_post({"interface": "SERun", "params": {}}) @check_server_available def step_in(self) -> str: return self.custom_post({"interface": "StepIn", "params": {}}) @check_server_available def step_over(self) -> str: return self.custom_post({"interface": "StepOver", "params": {}}) @check_server_available def step_out(self) -> str: return self.custom_post({"interface": "StepOut", "params": {}}) @check_server_available def e_step_into(self) -> str: return self.custom_post({"interface": "EStepInto", "params": {}}) @check_server_available def e_step_over(self) -> str: return self.custom_post({"interface": "EStepOver", "params": {}}) @check_server_available def e_step_out(self) -> str: return self.custom_post({"interface": "EStepOut", "params": {}}) @check_server_available def step_user(self) -> str: return self.custom_post({"interface": "StepUser", "params": {}}) @check_server_available def step_system(self) -> str: return self.custom_post({"interface": "StepSystem", "params": {}}) @check_server_available def skip(self, count: int = 1) -> str: return self.custom_post({"interface": "Skip", "params": {"count": count}}) @check_server_available def instr_undo(self) -> str: return self.custom_post({"interface": "InstrUndo", "params": {}}) @check_server_available def execute_command(self, command: str) -> str: return self.custom_post({"interface": "ExecuteCommand", "params": command}) @check_server_available def trace_into(self, count: int = 3) -> str: return self.custom_post({"interface": "TraceInto", "params": {"count": count}}) @check_server_available def trace_over(self, count: int = 3) -> str: return self.custom_post({"interface": "TraceOver", "params": {"count": count}}) @check_server_available def trace_line(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "TraceLine", "params": {"address": addr}}) @check_server_available def run_to(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "RunTo", "params": {"address": addr}}) @check_server_available def run_to_user_code(self) -> str: return self.custom_post({"interface": "RunToUserCode", "params": {}}) @check_server_available def debug_continue(self, status: int = 0) -> str: return self.custom_post({"interface": "DebugContinue", "params": {"status": status}}) @check_server_available def pause_all_threads(self) -> str: return self.custom_post({"interface": "PauseAllThreads", "params": {}}) @check_server_available def resume_all_threads(self) -> str: return self.custom_post({"interface": "ResumeAllThreads", "params": {}}) @check_server_available def thread_pause(self, tid: int) -> str: return self.custom_post({"interface": "ThreadPause", "params": {"tid": tid}}) @check_server_available def thread_resume(self, tid: int) -> str: return self.custom_post({"interface": "ThreadResume", "params": {"tid": tid}}) @check_server_available def animate_into(self, count: int = 3) -> str: return self.custom_post({"interface": "AnimateInto", "params": {"count": count}}) @check_server_available def animate_over(self, count: int = 3) -> str: return self.custom_post({"interface": "AnimateOver", "params": {"count": count}}) @check_server_available def animate_stop(self) -> str: return self.custom_post({"interface": "AnimateStop", "params": {}}) # 统一入口类 把所有API聚合在一起 class BinSentryClient( SystemApi, LogConfigApi, SymbolVarApi, BreakPointApi, DebugSessionApi, RegisterThreadApi, ModulePeApi, MemoryApi, DisasmXrefApi, StackTraceApi, ExecutionControlApi ): def __init__(self, config: Optional[Config] = None): super().__init__(config) ``` 调用接口测试 ``` from binsentry import BinSentryClient, Config if __name__ == "__main__": cfg = Config(address="127.0.0.1", port=6891) client = BinSentryClient(cfg) # 获取状态 resp = client.status() print(resp) # 设置断点,支持数字int或者字符串地址 resp = client.set_breakpoint(0x401000) print(resp) ``` 输出内容: ``` {"status":"success","result":{"sessionActive":false,"mode":"None","pid":0,"tid":0,"stopped":false,"firstRun":true,"softBreakpoints":0,"memoryBreakpoints":0," hardwareBreakpoints":0,"apiBreakpoints":0,"labels":0,"comments":0,"logCount":0,"watches":0,"bookmarks":0,"variables":0,"traceActive":false,"traceIntoActive": false,"traceResult":"","interfaces":[{"interface":"Debug","usage":"启动调试会话: params.path = 进程路径"},{"interface":"Attach","usage":"附加进程: params.pid = 进程ID"},{"interface":"Detach","usage":"分离调试会话"},{"interface":"Stop","usage":"终止被调试进程"},{"interface":"Status","usage":"查询调试器状态(含接口 列表)"},{"interface":"WaitStop","usage":"等待调试器停止: params.timeout = 超时秒数(默认60)"},{"interface":"Run","usage":"继续运行程序"},{"interface":"StepIn" ,"usage":"单步步入"},{"interface":"StepOver","usage":"单步步过"},{"interface":"StepOut","usage":"单步步出"},{"interface":"SetBreakPoint","usage":"设置软件断 点: address, thread(可选), temp(可选)"},{"interface":"DelBreakPoint","usage":"删除软件断点: address"},{"interface":"ShowBreakPoint","usage":"显示软件断点列表 "},{"interface":"SetMemBreakPoint","usage":"设置内存断点: address, flag(r/w/e)"},{"interface":"DelMemBreakPoint","usage":"删除内存断点: address"},{"interface ":"ShowMemBreakPoint","usage":"显示内存断点列表"},{"interface":"SetHbreakPoint","usage":"设置硬件断点: address, len(1/2/4), flag(r/w/e)"},{"interface":"DelHb reakPoint","usage":"删除硬件断点: dr(可选, 默认全部)"},{"interface":"ShowHbreakPoint","usage":"显示硬件断点列表"},{"interface":"SetApiBreakPoint","usage":"设 置API断点: dll, api(可选--end为函数返回处)"},{"interface":"DelApiBreakPoint","usage":"删除API断点: dll, api(可选--end)"},{"interface":"ShowApiBreakPoint","us age":"显示API断点列表"},{"interface":"SearchMemory","usage":"搜索内存: pattern(hex, ?=通配), start(可选), size(可选)"},{"interface":"PatchMemory","usage":"内 存补丁: address, hex(字节串), nop(可选)"},{"interface":"DumpProcess","usage":"转储进程(脱壳): path, entry(可选)"},{"interface":"HideDebugger","usage":"隐藏调 试器(CheckRemoteDebuggerPresent等)"},{"interface":"ShowDebugger","usage":"恢复调试器可见"},{"interface":"ThreadPause","usage":"暂停线程: tid"},{"interface":" ThreadResume","usage":"恢复线程: tid"},{"interface":"PauseAllThreads","usage":"暂停所有线程"},{"interface":"ResumeAllThreads","usage":"恢复所有线程"},{"inter face":"PEInfo","usage":"PE文件信息: path"},{"interface":"Register","usage":"显示寄存器"},{"interface":"SetRegister","usage":"修改寄存器: reg(eax/ebx/...), va lue"},{"interface":"Stack","usage":"显示栈: count(可选)"},{"interface":"Memory","usage":"显示内存: address, size(可选)"},{"interface":"SetMemory","usage":"修 改内存: address, value"},{"interface":"Dissasembler","usage":"反汇编: address(可选, 默认EIP), size(可选)"},{"interface":"Modules","usage":"显示模块列表"},{"i nterface":"Threads","usage":"显示线程列表"},{"interface":"SetDebug","usage":"执行调试命令字符串: params = \"命令行\" 或 {command: \"命令行\"}"},{"interface": "ProcessList","usage":"进程列表: filter(可选, 名称模糊过滤)"},{"interface":"Regions","usage":"内存区域列表(VirtualQueryEx)"},{"interface":"CallStack","usage" :"调用栈: count(可选, 默认32, StackWalk64+符号)"},{"interface":"SearchStrings","usage":"搜索进程字符串: max(可选, 默认100, ASCII+Unicode)"},{"interface":"Fil lMemory","usage":"内存填充: address, size, value (FillEx)"},{"interface":"SetCondBreakPoint","usage":"设置条件断点: address, cond(表达式, 如 \"eax == 0x5\"), thread(可选)"},{"interface":"DelCondBreakPoint","usage":"清除断点条件: address (转为普通断点)"},{"interface":"SetLabel","usage":"设置标签: address, name"},{ "interface":"DelLabel","usage":"删除标签: address"},{"interface":"GetLabels","usage":"显示标签列表"},{"interface":"SetComment","usage":"设置注释: address, te xt"},{"interface":"DelComment","usage":"删除注释: address"},{"interface":"GetComments","usage":"显示注释列表"},{"interface":"Logs","usage":"查询调试日志: cou nt(可选, 默认50)"},{"interface":"Eval","usage":"表达式求值: expr(寄存器/0x十六进制/十进制/运算, 需停止态)"},{"interface":"SetFlag","usage":"设置标志位: flag( CF PF AF ZF SF TF IF DF OF), value(0/1)"},{"interface":"GetBranchTarget","usage":"分支指令目标地址: address (GetJumpDestinationEx)"},{"interface":"GetArgumen ts","usage":"参数标记列表"},{"interface":"AddArgument","usage":"添加参数标记: start, end(可选), name(可选)"},{"interface":"DelArgument","usage":"删除参数标记 : start"},{"interface":"RevertPatch","usage":"还原补丁: address(恢复原字节并移除记录)"},{"interface":"DeletePatch","usage":"删除补丁记录: address(不写内存)"} ,{"interface":"ReadMemoryValue","usage":"读数值: address, size(1/2/4/8)"},{"interface":"GetThreadPriority","usage":"读线程优先级: tid"},{"interface":"SystemI nfo","usage":"系统信息(架构/页大小/CPU/内存/OS版本)"},{"interface":"GetSectionInfo","usage":"指定节详情: module, name"},{"interface":"GetBreakpointInfo","usa ge":"指定地址断点详情: address (软/内存/硬件)"},{"interface":"InjectDll","usage":"远程注入DLL: path (LoadLibraryA+CreateRemoteThread)"},{"interface":"HashMem ory","usage":"内存哈希: address, size, algo(可选 md5/sha1/crc32)"},{"interface":"AddrToModule","usage":"地址归属模块: address (模块名+基址+RVA)"},{"interface ":"RunTo","usage":"运行到目标地址: address (临时断点, 命中自动移除)"},{"interface":"SetExceptionIgnore","usage":"设置异常忽略: code, ignore(0/1; 断点/单步不 可忽略)"},{"interface":"GetExceptionSettings","usage":"异常忽略列表"},{"interface":"StartTraceRecord","usage":"开始执行足迹记录(每次停止记录EIP, 上限4096)"}, {"interface":"StopTraceRecord","usage":"停止执行足迹记录"},{"interface":"GetTraceRecord","usage":"执行足迹列表"},{"interface":"GetImportAddress","usage":"导 入函数IAT地址: module, name (或 #序号)"},{"interface":"GetSectionData","usage":"节内容转储: module, name (hex, 限4KB)"},{"interface":"TraceOver","usage":"步 过跟踪: count(步数,可选), condition(表达式,可选); call 自动跳过"},{"interface":"LoadLibrary","usage":"目标进程远程加载DLL: path (返回 moduleHandle)"},{"inter face":"FreeLibrary","usage":"目标进程远程卸载DLL: handle (LoadLibrary 返回值)"},{"interface":"gpa","usage":"远程API地址解析: dll, api 或 expr(模块:函数)"},{" interface":"VaToFileOffset","usage":"虚拟地址->文件偏移: address"},{"interface":"FileOffsetToVa","usage":"文件偏移->虚拟地址: offset, module(可选,默认主模块) "},{"interface":"GetPageRights","usage":"页权限查询: address (返回 rights 如 RX/RWX)"},{"interface":"SetPageRights","usage":"页权限修改: address, protect(hex 或RWX串)"},{"interface":"minidump","usage":"生成目标进程转储: path (.dmp, 含全内存)"},{"interface":"xrefs","usage":"代码引用查找: address, max(可选)"},{"inte rface":"mnemonicbrief","usage":"指令助记符简介: address(可选,默认EIP)"},{"interface":"EnumWindows","usage":"枚举目标进程窗口: pid(可选,默认会话进程)"},{"inte rface":"IsProcessElevated","usage":"进程提权检查: pid(可选,默认本进程)"},{"interface":"ClearLog","usage":"清空调试日志缓冲区"},{"interface":"SaveLog","usage" :"保存日志到文件: path"},{"interface":"EnumErrorCodes","usage":"常见Win32错误码表: code(可选过滤)"},{"interface":"EnumExceptions","usage":"常见异常码表: code (可选过滤)"},{"interface":"GetFunctionSize","usage":"函数边界: address (函数表优先, 反汇编扫描兜底)"},{"interface":"BreakpointCommand","usage":"断点命令: add ress, command (命中时自动入队执行; 空清除)"},{"interface":"JmpHistory","usage":"跳转历史(恢复运行前记录分支指令)"},{"interface":"GetSymbolInfo","usage":"符号 详情: address (dbghelp: 名称/模块/偏移/行号)"},{"interface":"TCPConnections","usage":"目标进程 TCP 连接列表"},{"interface":"StackPush","usage":"栈压入: value (ESP-4 写入)"},{"interface":"StackPop","usage":"栈弹出(读栈顶+ESP+4)"},{"interface":"StackPeek","usage":"栈窥视: offset (ESP+offset*4)"},{"interface":"SetTh readName","usage":"线程命名: tid, name (SetThreadDescription)"},{"interface":"Restart","usage":"重启目标进程(分离旧会话并重新创建)"},{"interface":"SetJIT","u sage":"设置系统JIT调试器: path (HKLM AeDebug, 需管理员)"},{"interface":"GetJIT","usage":"查询当前JIT调试器"},{"interface":"TraceLine","usage":"单步跟踪到目标 地址: address, timeout(可选, 秒)"},{"interface":"Handles","usage":"句柄列表: max(可选, NtQuerySystemInformation+对象名)"},{"interface":"FindRef","usage":"查 找引用: address(目标地址), max(可选, 反汇编扫描代码区)"},{"interface":"SearchAllMemory","usage":"全内存搜索: pattern(hex, ?=通配), max(可选)"},{"interface":" ExportList","usage":"模块导出表: module(模块名)"},{"interface":"SetWatch","usage":"添加/更新监视: name, expr(表达式, 含 $变量)"},{"interface":"DelWatch","usa ge":"删除监视: id 或 name"},{"interface":"GetWatches","usage":"查询监视(实时求值, 需停止态)"},{"interface":"SetVar","usage":"设置用户变量: name, value (表达 式 $name 引用)"},{"interface":"DelVar","usage":"删除用户变量: name"},{"interface":"GetVars","usage":"查询用户变量列表"},{"interface":"SetBookMark","usage":" 添加书签: address"},{"interface":"DelBookMark","usage":"删除书签: address"},{"interface":"GetBookMarks","usage":"查询书签列表"},{"interface":"Assemble","usag e":"汇编指令为字节码(XEDParse): instr, cip(可选)"},{"interface":"AssembleAt","usage":"汇编并写入目标进程: address, instr, fillnop(可选)"},{"interface":"Enabl eBreakpoint","usage":"启用软断点: address"},{"interface":"DisableBreakpoint","usage":"禁用软断点: address"},{"interface":"SetThreadPriority","usage":"设置线 程优先级: tid, priority(数值或名称)"},{"interface":"Memcpy","usage":"进程内内存复制: src, dst, size"},{"interface":"AllocateMemory","usage":"目标进程分配内存 : size, protect(可选)"},{"interface":"FreeMemory","usage":"释放目标进程内存: address"},{"interface":"Symbol","usage":"符号解析(模块名+偏移 或 表达式): expr"} ,{"interface":"MemoryInfo","usage":"地址内存信息(区域/保护/模块归属): address"},{"interface":"IsValidPointer","usage":"地址是否可读: address"},{"interface":" LastException","usage":"最近一次异常信息"},{"interface":"Pause","usage":"暂停运行中的程序(DebugBreakProcess)"},{"interface":"CreateRemoteThread","usage":"目 标进程创建远程线程: start 或 hex(shellcode), param(可选)"},{"interface":"TerminateThread","usage":"结束线程: tid"},{"interface":"GetThreadLastError","usage": "读取线程 TEB.LastErrorValue: tid"},{"interface":"WriteMemory","usage":"按 hex 字节串写内存: address, hex"},{"interface":"GetString","usage":"读取内存字符串: address, max(可选), type(ascii/unicode)"},{"interface":"GetOpcodeSize","usage":"指令长度: address (LengthDisassembleEx)"},{"interface":"Functions","usage":" 函数标记列表"},{"interface":"AddFunction","usage":"添加函数标记: start, end(可选), name(可选)"},{"interface":"DelFunction","usage":"删除函数标记: start"},{"i nterface":"ProcessInfo","usage":"进程详细信息: pid(可选, 默认会话进程)"},{"interface":"GetExportAddress","usage":"模块导出函数地址: module, name 或 ordinal"} ,{"interface":"Help","usage":"显示帮助"}]},"timestamp":4107265} ``` 改进 ``` import json import re import socket import time from urllib.parse import urlparse from typing import List, Dict, Union, Optional, Callable from functools import wraps def check_server_available(func: Callable) -> Callable: """装饰器:检测服务是否可用,不可用直接返回error json""" @wraps(func) def wrapper(self, *args, **kwargs): if not self.config.is_server_available(): return json.dumps({ "status": "error", "message": "Server unavailable" }, ensure_ascii=False) return func(self, *args, **kwargs) return wrapper def validate_hex_address(address: Union[int, str]) -> Optional[str]: """校验并格式化十六进制地址,返回 0xxxxx 格式字符串,非法返回None""" if isinstance(address, int): return hex(address) addr_str = str(address).strip() if not addr_str: return None if addr_str.startswith(('0x', '0X')): try: int(addr_str, 16) return addr_str except ValueError: return None try: int(addr_str, 10) return addr_str except ValueError: return None class Config: def __init__(self, address: str = "127.0.0.1", port: int = 6891): self.address = address self.port = port self.server_addr = f"http://{address}:{port}" self.timeout = 5 def is_server_available(self, timeout: Optional[int] = None) -> bool: """检测端口是否开放""" timeout = timeout or self.timeout try: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.settimeout(timeout) result = sock.connect_ex((self.address, self.port)) return result == 0 except socket.error as e: print(f"WARNING: Server check failed: {str(e)}") return False class BaseHttpClient: def __init__(self, config: Optional[Config] = None): self.config = config or Config() parsed_url = urlparse(self.config.server_addr) self.address = parsed_url.hostname self.port = parsed_url.port self.scheme = parsed_url.scheme self.path = parsed_url.path or '/' self.verify_ssl = True def custom_post(self, payload: Optional[Dict] = None, timeout: Optional[int] = None) -> str: """发送POST请求,payload对应BinSentry接口 {interface, params}""" import http.client headers = {"Content-Type": "application/json"} body = json.dumps(payload).encode("utf-8") if payload else None timeout = timeout or self.config.timeout try: if self.scheme == "https": import ssl context = ssl._create_unverified_context() if not self.verify_ssl else None conn = http.client.HTTPSConnection(self.address, self.port, timeout=timeout, context=context) else: conn = http.client.HTTPConnection(self.address, self.port, timeout=timeout) conn.request("POST", self.path, body=body, headers=headers) response = conn.getresponse() response_text = response.read().decode("utf-8", errors="ignore") conn.close() return response_text except socket.timeout: return json.dumps({"status": "error", "message": "Request timed out"}, ensure_ascii=False) except ConnectionRefusedError: return json.dumps({"status": "error", "message": "Connection refused by server"}, ensure_ascii=False) except Exception as e: return json.dumps({"status": "error", "message": f"Request failed: {str(e)}"}, ensure_ascii=False) class SystemApi(BaseHttpClient): """系统与进程相关接口""" @check_server_available def system_info(self) -> str: return self.custom_post({"interface": "SystemInfo", "params": {}}) @check_server_available def process_list(self) -> str: return self.custom_post({"interface": "ProcessList", "params": {}}) @check_server_available def enum_windows(self, pid: int) -> str: return self.custom_post({"interface": "EnumWindows", "params": {"pid": pid}}) @check_server_available def is_process_elevated(self) -> str: return self.custom_post({"interface": "IsProcessElevated", "params": {}}) @check_server_available def enum_error_codes(self) -> str: return self.custom_post({"interface": "EnumErrorCodes", "params": {}}) @check_server_available def enum_exceptions(self) -> str: return self.custom_post({"interface": "EnumExceptions", "params": {}}) @check_server_available def help(self) -> str: return self.custom_post({"interface": "Help", "params": {}}) @check_server_available def get_jit(self) -> str: return self.custom_post({"interface": "GetJIT", "params": {}}) @check_server_available def set_jit(self, path: str) -> str: return self.custom_post({"interface": "SetJIT", "params": {"path": path}}) @check_server_available def get_command_line(self) -> str: return self.custom_post({"interface": "GetCommandLine", "params": {}}) @check_server_available def set_command_line(self, args: str) -> str: return self.custom_post({"interface": "SetCommandLine", "params": {"args": args}}) class LogConfigApi(BaseHttpClient): """日志与配置数据库""" @check_server_available def clear_log(self) -> str: return self.custom_post({"interface": "ClearLog", "params": {}}) @check_server_available def logs(self) -> str: return self.custom_post({"interface": "Logs", "params": {}}) @check_server_available def save_log(self, path: str) -> str: return self.custom_post({"interface": "SaveLog", "params": {"path": path}}) @check_server_available def load_database(self, path: str) -> str: return self.custom_post({"interface": "LoadDatabase", "params": {"path": path}}) @check_server_available def save_database(self, path: str) -> str: return self.custom_post({"interface": "SaveDatabase", "params": {"path": path}}) @check_server_available def load_config(self, module: str) -> str: return self.custom_post({"interface": "LoadConfig", "params": {"module": module}}) class SymbolVarApi(BaseHttpClient): """变量、参数、注释、标签、函数""" @check_server_available def set_var(self, name: str, value: str) -> str: return self.custom_post({"interface": "SetVar", "params": {"name": name, "value": value}}) @check_server_available def del_var(self, name: str) -> str: return self.custom_post({"interface": "DelVar", "params": {"name": name}}) @check_server_available def get_vars(self) -> str: return self.custom_post({"interface": "GetVars", "params": {}}) @check_server_available def add_argument(self, start: Union[int, str], end: Union[int, str] = "", name: str = "") -> str: start_addr = validate_hex_address(start) payload: Dict = {"start": start_addr} if end: payload["end"] = validate_hex_address(end) if name: payload["name"] = name return self.custom_post({"interface": "AddArgument", "params": payload}) @check_server_available def del_argument(self, start: Union[int, str]) -> str: s = validate_hex_address(start) return self.custom_post({"interface": "DelArgument", "params": {"start": s}}) @check_server_available def get_arguments(self) -> str: return self.custom_post({"interface": "GetArguments", "params": {}}) @check_server_available def get_comments(self) -> str: return self.custom_post({"interface": "GetComments", "params": {}}) @check_server_available def get_labels(self) -> str: return self.custom_post({"interface": "GetLabels", "params": {}}) @check_server_available def get_bookmarks(self) -> str: return self.custom_post({"interface": "GetBookMarks", "params": {}}) @check_server_available def functions(self) -> str: return self.custom_post({"interface": "Functions", "params": {}}) class BreakPointApi(BaseHttpClient): """断点:软件/硬件/内存/api/异常/dll断点""" @check_server_available def show_breakpoint(self) -> str: return self.custom_post({"interface": "ShowBreakPoint", "params": {}}) @check_server_available def show_hbreakpoint(self) -> str: return self.custom_post({"interface": "ShowHbreakPoint", "params": {}}) @check_server_available def show_mem_breakpoint(self) -> str: return self.custom_post({"interface": "ShowMemBreakPoint", "params": {}}) @check_server_available def show_api_breakpoint(self) -> str: return self.custom_post({"interface": "ShowApiBreakPoint", "params": {}}) @check_server_available def set_bpx_options(self, option: str, enable: int) -> str: return self.custom_post({"interface": "SetBPXOptions", "params": {"option": option, "enable": enable}}) @check_server_available def set_exception_bpx(self, code: str) -> str: return self.custom_post({"interface": "SetExceptionBPX", "params": {"code": code}}) @check_server_available def del_exception_bpx(self, code: str) -> str: return self.custom_post({"interface": "DelExceptionBPX", "params": {"code": code}}) @check_server_available def get_exception_bpx_list(self) -> str: return self.custom_post({"interface": "GetExceptionBPXList", "params": {}}) @check_server_available def set_dll_breakpoint(self, dll: str) -> str: return self.custom_post({"interface": "SetDllBreakPoint", "params": {"dll": dll}}) @check_server_available def del_dll_breakpoint(self, dll: str) -> str: return self.custom_post({"interface": "DelDllBreakPoint", "params": {"dll": dll}}) @check_server_available def get_dll_breakpoints(self) -> str: return self.custom_post({"interface": "GetDllBreakPoints", "params": {}}) @check_server_available def set_breakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakPoint", "params": {"address": addr}}) @check_server_available def del_breakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DelBreakPoint", "params": {"address": addr}}) @check_server_available def get_breakpoint_info(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetBreakpointInfo", "params": {"address": addr}}) @check_server_available def get_breakpoint_type(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetBreakpointType", "params": {"address": addr}}) @check_server_available def set_breakpoint_name(self, address: Union[int, str], name: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointName", "params": {"address": addr, "name": name}}) @check_server_available def set_breakpoint_singleshoot(self, address: Union[int, str], enable: int = 0) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointSingleshoot", "params": {"address": addr, "enable": enable}}) @check_server_available def set_breakpoint_fast_resume(self, address: Union[int, str], enable: int = 0) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointFastResume", "params": {"address": addr, "enable": enable}}) @check_server_available def set_breakpoint_silent(self, address: Union[int, str], enable: int = 0) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointSilent", "params": {"address": addr, "enable": enable}}) @check_server_available def set_breakpoint_log(self, address: Union[int, str], text: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointLog", "params": {"address": addr, "text": text}}) @check_server_available def set_breakpoint_log_file(self, address: Union[int, str], file: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointLogFile", "params": {"address": addr, "file": file}}) @check_server_available def set_breakpoint_hit_count(self, address: Union[int, str], count: int) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetBreakpointHitCount", "params": {"address": addr, "count": count}}) @check_server_available def get_breakpoint_hit_count(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetBreakpointHitCount", "params": {"address": addr}}) @check_server_available def reset_breakpoint_hit_count(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "ResetBreakpointHitCount", "params": {"address": addr}}) @check_server_available def set_cond_breakpoint(self, address: Union[int, str], cond: str, thread: int = 0) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetCondBreakPoint", "params": {"address": addr, "cond": cond, "thread": thread}}) @check_server_available def del_cond_breakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DelCondBreakPoint", "params": {"address": addr}}) @check_server_available def set_hbreakpoint(self, address: Union[int, str], len_: str = "1", flag: str = "e") -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetHbreakPoint", "params": {"address": addr, "len": len_, "flag": flag}}) @check_server_available def del_hbreakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DelHbreakPoint", "params": {"address": addr}}) @check_server_available def set_mem_breakpoint(self, address: Union[int, str], flag: str = "e") -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetMemBreakPoint", "params": {"address": addr, "flag": flag}}) @check_server_available def del_mem_breakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DelMemBreakPoint", "params": {"address": addr}}) @check_server_available def set_api_breakpoint(self, dll: str, api: str) -> str: return self.custom_post({"interface": "SetApiBreakPoint", "params": {"dll": dll, "api": api}}) @check_server_available def del_api_breakpoint(self, dll: str, api: str) -> str: return self.custom_post({"interface": "DelApiBreakPoint", "params": {"dll": dll, "api": api}}) @check_server_available def disable_breakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DisableBreakpoint", "params": {"address": addr}}) @check_server_available def enable_breakpoint(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "EnableBreakpoint", "params": {"address": addr}}) @check_server_available def breakpoint_command(self, address: Union[int, str], command: str = "") -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "BreakpointCommand", "params": {"address": addr, "command": command}}) class DebugSessionApi(BaseHttpClient): """会话管理:启动调试、停止、分离、dump""" @check_server_available def debug(self, path: str, args: str = "", cwd: str = "") -> str: return self.custom_post({"interface": "Debug", "params": {"path": path, "args": args, "cwd": cwd}}) @check_server_available def set_debug(self, command: str = "Logs") -> str: return self.custom_post({"interface": "SetDebug", "params": command}) @check_server_available def stop(self) -> str: return self.custom_post({"interface": "Stop", "params": {}}) @check_server_available def detach(self) -> str: return self.custom_post({"interface": "Detach", "params": {}}) @check_server_available def restart(self) -> str: return self.custom_post({"interface": "Restart", "params": {}}) @check_server_available def dump_process(self, path: str, base: Union[int, str], size: int) -> str: base_addr = validate_hex_address(base) return self.custom_post({"interface": "DumpProcess", "params": {"path": path, "base": base_addr, "size": size}}) @check_server_available def minidump(self, path: str) -> str: return self.custom_post({"interface": "minidump", "params": {"path": path}}) @check_server_available def status(self) -> str: return self.custom_post({"interface": "Status", "params": {}}) class RegisterThreadApi(BaseHttpClient): """寄存器、线程操作""" @check_server_available def register(self) -> str: return self.custom_post({"interface": "Register", "params": {}}) @check_server_available def set_register(self, reg: str, value: str) -> str: return self.custom_post({"interface": "SetRegister", "params": {"reg": reg, "value": value}}) @check_server_available def threads(self) -> str: return self.custom_post({"interface": "Threads", "params": {}}) @check_server_available def thread_info(self, tid: int) -> str: return self.custom_post({"interface": "ThreadInfo", "params": {"tid": tid}}) @check_server_available def get_active_thread(self) -> str: return self.custom_post({"interface": "GetActiveThread", "params": {}}) @check_server_available def set_active_thread(self, tid: int) -> str: return self.custom_post({"interface": "SetActiveThread", "params": {"tid": tid}}) @check_server_available def get_thread_last_error(self, tid: int) -> str: return self.custom_post({"interface": "GetThreadLastError", "params": {"tid": tid}}) @check_server_available def get_thread_priority(self, tid: int) -> str: return self.custom_post({"interface": "GetThreadPriority", "params": {"tid": tid}}) @check_server_available def set_thread_priority(self, tid: int, priority: str = "NORMAL") -> str: return self.custom_post({"interface": "SetThreadPriority", "params": {"tid": tid, "priority": priority}}) @check_server_available def set_thread_name(self, tid: int, name: str) -> str: return self.custom_post({"interface": "SetThreadName", "params": {"tid": tid, "name": name}}) @check_server_available def set_flag(self, flag: str, value: int) -> str: return self.custom_post({"interface": "SetFlag", "params": {"flag": flag, "value": value}}) class ModulePeApi(BaseHttpClient): """模块、PE、导入导出、符号""" @check_server_available def modules(self) -> str: return self.custom_post({"interface": "Modules", "params": {}}) @check_server_available def module_info(self, module: str) -> str: return self.custom_post({"interface": "ModuleInfo", "params": {"module": module}}) @check_server_available def sections(self, module: str) -> str: return self.custom_post({"interface": "Sections", "params": {"module": module}}) @check_server_available def pe_info(self, path: str) -> str: return self.custom_post({"interface": "PEInfo", "params": {"path": path}}) @check_server_available def rich_header(self, module: str) -> str: return self.custom_post({"interface": "RichHeader", "params": {"module": module}}) @check_server_available def tls_callbacks(self, module: str) -> str: return self.custom_post({"interface": "TLSCallbacks", "params": {"module": module}}) @check_server_available def relocation_list(self, module: str) -> str: return self.custom_post({"interface": "RelocationList", "params": {"module": module}}) @check_server_available def debug_directory(self, module: str) -> str: return self.custom_post({"interface": "DebugDirectory", "params": {"module": module}}) @check_server_available def import_list(self, module: str) -> str: return self.custom_post({"interface": "ImportList", "params": {"module": module}}) @check_server_available def export_list(self, module: str) -> str: return self.custom_post({"interface": "ExportList", "params": {"module": module}}) @check_server_available def get_import_address(self, module: str, name: str) -> str: return self.custom_post({"interface": "GetImportAddress", "params": {"module": module, "name": name}}) @check_server_available def get_export_address(self, module: str, name: str) -> str: return self.custom_post({"interface": "GetExportAddress", "params": {"module": module, "name": name}}) @check_server_available def gpa(self, dll: str, api: str) -> str: return self.custom_post({"interface": "gpa", "params": {"dll": dll, "api": api}}) @check_server_available def addr_to_module(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "AddrToModule", "params": {"address": addr}}) @check_server_available def get_section_data(self, module: str, name: str) -> str: return self.custom_post({"interface": "GetSectionData", "params": {"module": module, "name": name}}) @check_server_available def get_section_info(self, module: str, name: str) -> str: return self.custom_post({"interface": "GetSectionInfo", "params": {"module": module, "name": name}}) @check_server_available def symbol(self, expr: str) -> str: return self.custom_post({"interface": "Symbol", "params": {"expr": expr}}) @check_server_available def get_symbol_info(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetSymbolInfo", "params": {"address": addr}}) @check_server_available def get_function_size(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetFunctionSize", "params": {"address": addr}}) @check_server_available def heaps(self) -> str: return self.custom_post({"interface": "Heaps", "params": {}}) @check_server_available def handles(self, max_num: int = 20) -> str: return self.custom_post({"interface": "Handles", "params": {"max": max_num}}) @check_server_available def seh_list(self) -> str: return self.custom_post({"interface": "SEHList", "params": {}}) class MemoryApi(BaseHttpClient): """内存读写、搜索、补丁、内存分配""" @check_server_available def memory_info(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "MemoryInfo", "params": {"address": addr}}) @check_server_available def regions(self) -> str: return self.custom_post({"interface": "Regions", "params": {}}) @check_server_available def memory(self, address: Union[int, str], size: int = 16) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "Memory", "params": {"address": addr, "size": size}}) @check_server_available def read_memory_value(self, address: Union[int, str], size: int = 4) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "ReadMemoryValue", "params": {"address": addr, "size": size}}) @check_server_available def write_memory(self, address: Union[int, str], hex_: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "WriteMemory", "params": {"address": addr, "hex": hex_}}) @check_server_available def get_page_rights(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetPageRights", "params": {"address": addr}}) @check_server_available def set_page_rights(self, address: Union[int, str], protect: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetPageRights", "params": {"address": addr, "protect": protect}}) @check_server_available def set_page_memory(self, address: Union[int, str], protect: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetPageMemory", "params": {"address": addr, "protect": protect}}) @check_server_available def allocate_memory(self, size: int) -> str: return self.custom_post({"interface": "AllocateMemory", "params": {"size": size}}) @check_server_available def free_memory(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "FreeMemory", "params": {"address": addr}}) @check_server_available def set_memory(self, address: Union[int, str], hex_: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SetMemory", "params": {"address": addr, "hex": hex_}}) @check_server_available def fill_memory(self, address: Union[int, str], size: int, value: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "FillMemory", "params": {"address": addr, "size": size, "value": value}}) @check_server_available def memcpy(self, src: Union[int, str], dst: Union[int, str], size: int) -> str: src_a = validate_hex_address(src) dst_a = validate_hex_address(dst) return self.custom_post({"interface": "Memcpy", "params": {"src": src_a, "dst": dst_a, "size": size}}) @check_server_available def va_to_file_offset(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "VaToFileOffset", "params": {"address": addr}}) @check_server_available def file_offset_to_va(self, offset: str) -> str: return self.custom_post({"interface": "FileOffsetToVa", "params": {"offset": offset}}) @check_server_available def get_string(self, address: Union[int, str], max_num: int = 64, type_: str = "ascii") -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetString", "params": {"address": addr, "max": max_num, "type": type_}}) @check_server_available def search_memory(self, pattern: str, start: Union[int, str], size: int) -> str: s = validate_hex_address(start) return self.custom_post({"interface": "SearchMemory", "params": {"pattern": pattern, "start": s, "size": size}}) @check_server_available def search_all_memory(self, pattern: str, max_num: int = 5) -> str: return self.custom_post({"interface": "SearchAllMemory", "params": {"pattern": pattern, "max": max_num}}) @check_server_available def search_strings(self, address: Union[int, str], size: int) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "SearchStrings", "params": {"address": addr, "size": size}}) @check_server_available def match_pattern(self, address: Union[int, str], pattern: str, size: int) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "MatchPattern", "params": {"address": addr, "pattern": pattern, "size": size}}) @check_server_available def hash_memory(self, address: Union[int, str], size: int, algo: str = "md5") -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "HashMemory", "params": {"address": addr, "size": size, "algo": algo}}) @check_server_available def patch_memory(self, address: Union[int, str], hex_: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "PatchMemory", "params": {"address": addr, "hex": hex_}}) @check_server_available def patches(self) -> str: return self.custom_post({"interface": "Patches", "params": {}}) @check_server_available def revert_patch(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "RevertPatch", "params": {"address": addr}}) @check_server_available def delete_patch(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DeletePatch", "params": {"address": addr}}) class DisasmXrefApi(BaseHttpClient): """反汇编、汇编、交叉引用""" @check_server_available def disassemble_at(self, address: Union[int, str], count: int = 5) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "DisassembleAt", "params": {"address": addr, "count": count}}) @check_server_available def dissasembler(self, address: Union[int, str], count: int = 5) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "Dissasembler", "params": {"address": addr, "count": count}}) @check_server_available def get_opcode_size(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetOpcodeSize", "params": {"address": addr}}) @check_server_available def mnemonicbrief(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "mnemonicbrief", "params": {"address": addr}}) @check_server_available def get_branch_target(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "GetBranchTarget", "params": {"address": addr}}) @check_server_available def assemble(self, instr: str, cip: Union[int, str]) -> str: c = validate_hex_address(cip) return self.custom_post({"interface": "Assemble", "params": {"instr": instr, "cip": c}}) @check_server_available def assemble_at(self, address: Union[int, str], instr: str) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "AssembleAt", "params": {"address": addr, "instr": instr}}) @check_server_available def xrefs(self, address: Union[int, str], max_num: int = 5) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "xrefs", "params": {"address": addr, "max": max_num}}) @check_server_available def find_ref(self, address: Union[int, str], max_num: int = 5) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "FindRef", "params": {"address": addr, "max": max_num}}) class StackTraceApi(BaseHttpClient): """栈、调用栈、追踪记录""" @check_server_available def call_stack(self, max_num: int = 16) -> str: return self.custom_post({"interface": "CallStack", "params": {"max": max_num}}) @check_server_available def stack(self, count: int = 8) -> str: return self.custom_post({"interface": "Stack", "params": {"count": count}}) @check_server_available def stack_push(self, value: str) -> str: return self.custom_post({"interface": "StackPush", "params": {"value": value}}) @check_server_available def stack_pop(self) -> str: return self.custom_post({"interface": "StackPop", "params": {}}) @check_server_available def stack_peek(self, offset: int = 0) -> str: return self.custom_post({"interface": "StackPeek", "params": {"offset": offset}}) @check_server_available def start_trace_record(self) -> str: return self.custom_post({"interface": "StartTraceRecord", "params": {}}) @check_server_available def get_trace_record(self, count: int = 5) -> str: return self.custom_post({"interface": "GetTraceRecord", "params": {"count": count}}) @check_server_available def stop_trace_record(self) -> str: return self.custom_post({"interface": "StopTraceRecord", "params": {}}) @check_server_available def jmp_history(self) -> str: return self.custom_post({"interface": "JmpHistory", "params": {}}) @check_server_available def last_exception(self) -> str: return self.custom_post({"interface": "LastException", "params": {}}) @check_server_available def eval_expr(self, expr: str) -> str: return self.custom_post({"interface": "Eval", "params": {"expr": expr}}) @check_server_available def show_debugger(self) -> str: return self.custom_post({"interface": "ShowDebugger", "params": {}}) @check_server_available def hide_debugger(self) -> str: return self.custom_post({"interface": "HideDebugger", "params": {}}) class ExecutionControlApi(BaseHttpClient): """执行控制:运行、单步、暂停、run_to""" @check_server_available def run(self) -> str: return self.custom_post({"interface": "Run", "params": {}}) @check_server_available def pause(self) -> str: return self.custom_post({"interface": "Pause", "params": {}}) @check_server_available def e_run(self) -> str: return self.custom_post({"interface": "ERun", "params": {}}) @check_server_available def se_run(self) -> str: return self.custom_post({"interface": "SERun", "params": {}}) @check_server_available def step_in(self) -> str: return self.custom_post({"interface": "StepIn", "params": {}}) @check_server_available def step_over(self) -> str: return self.custom_post({"interface": "StepOver", "params": {}}) @check_server_available def step_out(self) -> str: return self.custom_post({"interface": "StepOut", "params": {}}) @check_server_available def e_step_into(self) -> str: return self.custom_post({"interface": "EStepInto", "params": {}}) @check_server_available def e_step_over(self) -> str: return self.custom_post({"interface": "EStepOver", "params": {}}) @check_server_available def e_step_out(self) -> str: return self.custom_post({"interface": "EStepOut", "params": {}}) @check_server_available def step_user(self) -> str: return self.custom_post({"interface": "StepUser", "params": {}}) @check_server_available def step_system(self) -> str: return self.custom_post({"interface": "StepSystem", "params": {}}) @check_server_available def skip(self, count: int = 1) -> str: return self.custom_post({"interface": "Skip", "params": {"count": count}}) @check_server_available def instr_undo(self) -> str: return self.custom_post({"interface": "InstrUndo", "params": {}}) @check_server_available def execute_command(self, command: str) -> str: return self.custom_post({"interface": "ExecuteCommand", "params": command}) @check_server_available def trace_into(self, count: int = 3) -> str: return self.custom_post({"interface": "TraceInto", "params": {"count": count}}) @check_server_available def trace_over(self, count: int = 3) -> str: return self.custom_post({"interface": "TraceOver", "params": {"count": count}}) @check_server_available def trace_line(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "TraceLine", "params": {"address": addr}}) @check_server_available def run_to(self, address: Union[int, str]) -> str: addr = validate_hex_address(address) return self.custom_post({"interface": "RunTo", "params": {"address": addr}}) @check_server_available def run_to_user_code(self) -> str: return self.custom_post({"interface": "RunToUserCode", "params": {}}) @check_server_available def debug_continue(self, status: int = 0) -> str: return self.custom_post({"interface": "DebugContinue", "params": {"status": status}}) @check_server_available def pause_all_threads(self) -> str: return self.custom_post({"interface": "PauseAllThreads", "params": {}}) @check_server_available def resume_all_threads(self) -> str: return self.custom_post({"interface": "ResumeAllThreads", "params": {}}) @check_server_available def thread_pause(self, tid: int) -> str: return self.custom_post({"interface": "ThreadPause", "params": {"tid": tid}}) @check_server_available def thread_resume(self, tid: int) -> str: return self.custom_post({"interface": "ThreadResume", "params": {"tid": tid}}) @check_server_available def animate_into(self, count: int = 3) -> str: return self.custom_post({"interface": "AnimateInto", "params": {"count": count}}) @check_server_available def animate_over(self, count: int = 3) -> str: return self.custom_post({"interface": "AnimateOver", "params": {"count": count}}) @check_server_available def animate_stop(self) -> str: return self.custom_post({"interface": "AnimateStop", "params": {}}) # 统一入口类 把所有API聚合在一起 class BinSentryClient( SystemApi, LogConfigApi, SymbolVarApi, BreakPointApi, DebugSessionApi, RegisterThreadApi, ModulePeApi, MemoryApi, DisasmXrefApi, StackTraceApi, ExecutionControlApi ): def __init__(self, config: Optional[Config] = None): super().__init__(config) # ====================================================================== # 扩展功能区:以下方法全部由上方 11 个 API 类的现有接口组合而成, # 不改变、不遮蔽任何原始接口,仅新增面向逆向分析/漏洞挖掘的实用封装。 # 说明:扩展方法一律直发 HTTP(不套 check_server_available 装饰器), # 服务端离线时快速抛 RuntimeError(Connection refused),而非每次 5s 探测。 # ====================================================================== # ---------------- 解析辅助 ---------------- def _parse_ok(self, raw: str, what: str) -> dict: """解析 JSON 并校验 status=success,返回 result dict;失败抛 RuntimeError""" try: obj = json.loads(raw) except Exception as e: raise RuntimeError(f"{what} 响应不是合法 JSON: {str(raw)[:160]}") from e if obj.get("status") != "success": res = obj.get("result") msg = res.get("message") if isinstance(res, dict) else (res if isinstance(res, str) else None) msg = msg or obj.get("message") or "未知错误" raise RuntimeError(f"{what} 失败: {msg}") return obj.get("result") or {} def _find(self, obj, *keys): """递归查找第一个命中的键值,容忍服务端字段名差异""" if isinstance(obj, dict): for k in keys: if k in obj and obj[k] is not None: return obj[k] for v in obj.values(): r = self._find(v, *keys) if r is not None: return r elif isinstance(obj, list): for v in obj: r = self._find(v, *keys) if r is not None: return r return None def _int(self, v): """宽容转 int:支持 int / '0x..' / 十进制字符串""" if v is None: return None if isinstance(v, int): return v s = str(v).strip() if not s: return None try: return int(s, 16) if s.lower().startswith("0x") else int(s) except ValueError: return None def _hex(self, v): iv = self._int(v) return hex(iv) if iv is not None else None def _collect_addresses(self, res) -> list: """从响应中收集所有地址(搜索/引用/匹配结果通用)""" out = [] def walk(o): if isinstance(o, dict): for k, v in o.items(): if k.lower() in ("address", "addr", "base", "target", "found") and self._int(v) is not None: out.append(self._int(v)) else: walk(v) elif isinstance(o, list): for v in o: walk(v) walk(res) return sorted(set(out)) @staticmethod def _region_is_exec(r) -> bool: rt = str(r.get("rights") or "").upper() if any(x in rt for x in ("X", "E")): return True p = r.get("protect") return isinstance(p, int) and bool(p & 0x10) # PAGE_EXECUTE 系列 @staticmethod def _region_is_writable(r) -> bool: rt = str(r.get("rights") or "").upper() if "W" in rt: return True p = r.get("protect") return isinstance(p, int) and bool(p & 0x04) # PAGE_READWRITE/WRITECOPY 系列 # ---------------- 会话管理 ---------------- def session_status(self) -> dict: """结构化 Status:会话激活、模式、pid/tid、停止态、断点计数""" res = self._parse_ok(self.custom_post({"interface": "Status", "params": {}}), "Status") return { "sessionActive": bool(res.get("sessionActive")), "mode": res.get("mode"), "pid": self._int(res.get("pid")), "tid": self._int(res.get("tid")), "stopped": bool(res.get("stopped")), "firstRun": bool(res.get("firstRun")), "traceActive": bool(res.get("traceActive")), "breakpoints": { "soft": res.get("softBreakpoints"), "mem": res.get("memoryBreakpoints"), "hw": res.get("hardwareBreakpoints"), "api": res.get("apiBreakpoints"), }, } def wait_stopped(self, timeout: int = 60) -> bool: """轮询等待调试器进入停止态;超时返回 False""" t0 = time.time() while time.time() - t0 bool: """运行中则 Pause,等待停止态""" st = self.session_status() if not st["sessionActive"]: raise RuntimeError("没有活动的调试会话") if st["stopped"]: return True self.custom_post({"interface": "Pause", "params": {}}) return self.wait_stopped(timeout) def restart_and_wait(self, timeout: int = 10) -> dict: """Restart 后轮询等待新会话出现(restart 是异步的,约 0.5s 后新会话才可见)""" self._parse_ok(self.custom_post({"interface": "Restart", "params": {}}), "Restart") t0 = time.time() while time.time() - t0 dict: """从异常运行态安全停下:animate_stop → Pause → Detach → 重新 Debug 重建会话""" self.custom_post({"interface": "AnimateStop", "params": {}}) self.custom_post({"interface": "Pause", "params": {}}) try: self.wait_stopped(timeout) except RuntimeError: pass self.custom_post({"interface": "Detach", "params": {}}) time.sleep(0.5) return self.session_status() # ---------------- 进程 ---------------- def processes(self) -> list: """结构化进程列表:[{pid, name, path}]""" res = self._parse_ok(self.process_list(), "ProcessList") procs = self._find(res, "processes", "list", "items") out = [] if isinstance(procs, list): for p in procs: if isinstance(p, dict) and p.get("pid") is not None: out.append({"pid": self._int(p.get("pid")), "name": p.get("name"), "path": p.get("path")}) return out def attach(self, pid: int) -> int: """附加指定 PID(服务端 Attach 接口,原文件未封装,此处补上)""" self._parse_ok(self.custom_post({"interface": "Attach", "params": {"pid": pid}}), f"Attach({pid})") return pid def attach_by_name(self, name: str) -> dict: """按进程名子串匹配附加;返回 {attached, candidates}""" cands = [p for p in self.processes() if name.lower() in str(p.get("name", "")).lower()] if not cands: raise RuntimeError(f"进程列表中没有匹配 '{name}' 的进程") self.attach(cands[0]["pid"]) return {"attached": cands[0]["pid"], "candidates": cands} def windows_of(self, pid: int): """进程窗口列表(枚举窗口接口)""" res = self._parse_ok(self.enum_windows(pid), f"EnumWindows({pid})") return self._find(res, "windows", "list", "items") or res def is_elevated(self) -> bool: """当前调试进程是否以管理员权限运行""" res = self._parse_ok(self.is_process_elevated(), "IsProcessElevated") return bool(self._find(res, "elevated", "isElevated", "result", "ok")) # ---------------- 模块 / PE ---------------- def get_modules(self) -> list: """模块列表:[{name, base, size, path}]""" res = self._parse_ok(self.modules(), "Modules") mods = self._find(res, "modules", "list", "items") out = [] if isinstance(mods, list): for m in mods: if isinstance(m, dict) and m.get("name"): out.append({ "name": m.get("name"), "base": self._int(m.get("baseAddressHex") or m.get("baseAddress") or m.get("base")), "size": self._int(m.get("size") or m.get("imageSize")), "path": m.get("path"), }) return out def find_module(self, name: str = None, addr=None) -> dict: """按名称(子串/精确)或地址定位模块;未找到返回 None""" for m in self.get_modules(): if name and (m["name"].lower() == name.lower() or name.lower() in m["name"].lower()): return m if addr is not None and m["base"] is not None and m["size"] is not None: if m["base"] str: """全模块摘要文本(基址/大小/名称/路径,按基址排序)""" lines = [] for m in sorted(self.get_modules(), key=lambda x: x["base"] or 0): base = f"0x{m['base']:08X}" if m["base"] else "?" size = f"0x{m['size']:X}" if m["size"] else "?" lines.append(f"{base} {size: list: """节表:[{name, va, vsize, raw, rsize, flags}]""" res = self._parse_ok(self.sections(module), f"Sections({module})") secs = self._find(res, "sections", "list", "items") out = [] if isinstance(secs, list): for s in secs: if isinstance(s, dict) and s.get("name"): out.append({ "name": s.get("name"), "va": self._int(s.get("virtualAddress") or s.get("va") or s.get("address")), "vsize": self._int(s.get("virtualSize") or s.get("vsize") or s.get("size")), "raw": self._int(s.get("rawOffset") or s.get("pointerToRawData")), "rsize": self._int(s.get("rawSize") or s.get("sizeOfRawData")), "flags": s.get("flags"), }) return out def module_headers(self, module: str) -> dict: """PE 头摘要(入口点/机器/节数量等),path 由模块信息自动解析; entry 为 RVA,entry_va 为加基址后的虚拟地址(可直接用于反汇编/设断点)""" m = self.find_module(module) path = (m or {}).get("path") or module base = (m or {}).get("base") res = self._parse_ok(self.pe_info(path), f"PEInfo({path})") entry = self._int(self._find(res, "entry", "entryPoint", "addressOfEntryPoint")) return { "entry": entry, "entry_va": (base + entry) if (base is not None and entry is not None) else None, "machine": self._find(res, "machine", "machineType"), "characteristics": self._find(res, "characteristics", "imageCharacteristics"), "sections": self._find(res, "sectionCount", "numberOfSections"), "magic": self._find(res, "magic", "optionalMagic"), } def module_detail(self, module: str) -> dict: """ModuleInfo 原样结构化(入口/基址/大小等)""" res = self._parse_ok(self.module_info(module), f"ModuleInfo({module})") return res def imports_of(self, module: str) -> list: """导入表(展开 DLL 下的函数级条目):[{name, dll, hint, iat}]""" res = self._parse_ok(self.import_list(module), f"ImportList({module})") lst = self._find(res, "imports", "list", "items", "functions") out = [] if isinstance(lst, list): for d in lst: if not isinstance(d, dict): continue dll = d.get("dll") or d.get("module") funcs = d.get("funcs") or d.get("functions") or [] if isinstance(funcs, list) and funcs: for f in funcs: if isinstance(f, dict): out.append({ "name": f.get("name"), "dll": dll, "hint": f.get("hint") or f.get("ordinal"), "iat": self._int(f.get("iat") or f.get("address") or f.get("thunk")), }) else: out.append({ "name": d.get("name"), "dll": dll, "hint": d.get("hint") or d.get("ordinal"), "iat": self._int(d.get("iat") or d.get("address") or d.get("thunk")), }) return [x for x in out if x["name"] or x["dll"]] def exports_of(self, module: str) -> list: """导出表:[{name, ordinal, address}]""" res = self._parse_ok(self.export_list(module), f"ExportList({module})") lst = self._find(res, "exports", "list", "items", "functions") out = [] if isinstance(lst, list): for i in lst: if isinstance(i, dict): out.append({ "name": i.get("name"), "ordinal": self._int(i.get("ordinal")), "address": self._int(i.get("address") or i.get("va")), }) return out def imports_by_name(self, module: str, keyword: str) -> list: """按关键字过滤导入函数(含 DLL 名匹配)""" kw = keyword.lower() return [i for i in self.imports_of(module) if kw in (i["name"] or "").lower() or kw in (i["dll"] or "").lower()] def exports_by_name(self, module: str, keyword: str) -> list: """按关键字过滤导出函数(返回含地址,便于下 API 断点)""" kw = keyword.lower() return [e for e in self.exports_of(module) if kw in (e["name"] or "").lower()] def import_address(self, module: str, name: str) -> int: """导入函数 IAT 地址""" res = self._parse_ok(self.get_import_address(module, name), f"GetImportAddress({module}!{name})") return self._int(self._find(res, "address", "va", "iat", "value")) def export_address(self, module: str, name: str) -> int: """导出函数 VA""" res = self._parse_ok(self.get_export_address(module, name), f"GetExportAddress({module}!{name})") return self._int(self._find(res, "address", "va", "value")) def gpa_resolve(self, dll: str, api: str) -> int: """GetProcAddress 式解析:dll!api → 地址""" res = self._parse_ok(self.gpa(dll, api), f"gpa({dll}!{api})") return self._int(self._find(res, "address", "va", "value", "result")) def symbol_at(self, addr) -> dict: """地址 → 符号信息(模块/名称/偏移)""" res = self._parse_ok(self.get_symbol_info(self._hex(addr)), f"GetSymbolInfo(0x{self._int(addr):X})") return { "module": self._find(res, "module", "mod"), "name": self._find(res, "name", "symbol", "label"), "offset": self._int(self._find(res, "offset", "delta")), } def symbol_lookup(self, expr: str): """表达式 → 符号/地址信息""" res = self._parse_ok(self.symbol(expr), f"Symbol({expr})") return res def addr_to_module_name(self, addr) -> str: """地址所属模块名""" res = self._parse_ok(self.addr_to_module(self._hex(addr)), f"AddrToModule(0x{self._int(addr):X})") return self._find(res, "module", "name", "mod") or "" def function_size(self, addr) -> int: """函数大小(服务端按签名/下个函数推断)""" res = self._parse_ok(self.get_function_size(self._hex(addr)), f"GetFunctionSize(0x{self._int(addr):X})") return self._int(self._find(res, "size", "length", "count")) def section_data(self, module: str, name: str) -> bytes: """节原始数据 → bytes""" res = self._parse_ok(self.get_section_data(module, name), f"GetSectionData({module}!{name})") hexdata = self._find(res, "hex", "data", "bytes", "content") if isinstance(hexdata, list): return bytes(int(b) for b in hexdata) return bytes.fromhex(re.sub(r"[^0-9a-fA-F]", "", str(hexdata or ""))) def section_info(self, module: str, name: str) -> dict: """节信息详情""" res = self._parse_ok(self.get_section_info(module, name), f"GetSectionInfo({module}!{name})") return res def rich_header(self, module: str) -> dict: res = self._parse_ok(self.rich_header(module), f"RichHeader({module})") return res def tls_callbacks_list(self, module: str) -> list: """TLS 回调地址列表(反调试/初始化代码分析)""" res = self._parse_ok(self.tls_callbacks(module), f"TLSCallbacks({module})") return self._collect_addresses(res) def relocations(self, module: str) -> list: """重定位表(基址随机化分析)""" res = self._parse_ok(self.relocation_list(module), f"RelocationList({module})") return self._collect_addresses(res) def debug_directory(self, module: str) -> dict: """调试目录(PDB/源码信息)""" res = self._parse_ok(self.debug_directory(module), f"DebugDirectory({module})") return res # ---------------- 内存读写 ---------------- _CHUNK = 0x400 # 单次读写分块大小(保守值) def read_bytes(self, addr, size: int, chunk: int = None) -> bytes: """分块读取原始字节 → bytes""" chunk = chunk or self._CHUNK base = self._int(addr) if base is None: raise RuntimeError(f"非法地址: {addr}") out = bytearray() off = 0 while off str: """读取内存 → hex 字符串""" return self.read_bytes(addr, size).hex() def read_mem_value(self, addr, size: int = 4) -> int: """ReadMemoryValue:任意宽度整数读取""" res = self._parse_ok(self.read_memory_value(self._hex(addr), size), f"ReadMemoryValue(0x{self._int(addr):X},{size})") v = self._find(res, "value", "val", "result", "number") if v is None: raise RuntimeError(f"ReadMemoryValue 响应缺少值: {str(res)[:200]}") return self._int(v) def read_u8(self, addr) -> int: return self.read_mem_value(addr, 1) def read_u16(self, addr) -> int: return self.read_mem_value(addr, 2) def read_u32(self, addr) -> int: return self.read_mem_value(addr, 4) def read_u64(self, addr) -> int: return self.read_mem_value(addr, 8) def write_bytes(self, addr, data) -> int: """写内存(bytes 或 hex 字符串),分块;返回写入字节数""" if isinstance(data, str): data = bytes.fromhex(re.sub(r"[^0-9a-fA-F]", "", data)) base = self._int(addr) off = 0 while off str: return self.read_string(addr, "ascii", max_len) def read_wstring(self, addr, max_len: int = 256) -> str: return self.read_string(addr, "unicode", max_len) def read_string(self, addr, type_: str = "ascii", max_len: int = 256) -> str: """GetString:按类型(ascii/unicode)读取字符串""" res = self._parse_ok(self.get_string(self._hex(addr), max_len, type_), f"GetString(0x{self._int(addr):X},{type_})") s = self._find(res, "string", "value", "text", "content") if s is None: return "" if isinstance(s, (list, dict)): s = self._find(s, "string", "value", "text") return str(s) def memory_region(self, addr) -> dict: """地址所在内存区域(基址/大小/权限/类型)""" res = self._parse_ok(self.memory_info(self._hex(addr)), f"MemoryInfo(0x{self._int(addr):X})") return { "base": self._int(self._find(res, "base", "baseAddress", "regionBase")), "size": self._int(self._find(res, "size", "regionSize")), "rights": self._find(res, "rights", "protect", "protection"), "type": self._find(res, "type", "state"), "module": self._find(res, "module", "moduleName"), } def memory_map(self) -> list: """内存区域表:[{base, size, rights, protect, type}]""" res = self._parse_ok(self.regions(), "Regions") regs = self._find(res, "regions", "list", "items") out = [] if isinstance(regs, list): for r in regs: if isinstance(r, dict) and (r.get("base") is not None or r.get("address") is not None): rights = self._find(r, "rights", "protect", "protection", "flags") out.append({ "base": self._int(r.get("base") or r.get("address") or r.get("baseAddress")), "size": self._int(r.get("size") or r.get("regionSize")), "rights": rights, "protect": self._int(r.get("protect") or r.get("protection")), "type": r.get("type") or r.get("state"), }) return out def executable_regions(self) -> list: """可执行区域(代码扫描/设断点)""" return [r for r in self.memory_map() if self._region_is_exec(r)] def writable_regions(self) -> list: """可写区域(数据区/堆分析)""" return [r for r in self.memory_map() if self._region_is_writable(r)] def page_rights(self, addr) -> dict: """页面权限详情""" res = self._parse_ok(self.get_page_rights(self._hex(addr)), f"GetPageRights(0x{self._int(addr):X})") return res def set_protect(self, addr, protect: str) -> dict: """修改页面保护属性(如 'rwx'),用于可写可执行改造实验""" res = self._parse_ok(self.set_page_rights(self._hex(addr), protect), f"SetPageRights(0x{self._int(addr):X},{protect})") return res def alloc(self, size: int = 0x1000) -> int: """分配内存,返回地址""" res = self._parse_ok(self.allocate_memory(size), f"AllocateMemory({size})") addr = self._int(res.get("addressHex") or res.get("address")) if addr is None: raise RuntimeError(f"AllocateMemory 响应缺少地址: {str(res)[:200]}") return addr def free(self, addr) -> bool: """释放分配的内存""" self._parse_ok(self.free_memory(self._hex(addr)), f"FreeMemory(0x{self._int(addr):X})") return True def fill(self, addr, size: int, value: str) -> bool: """填充内存(value 为字节值)""" self._parse_ok(self.fill_memory(self._hex(addr), size, value), f"FillMemory(0x{self._int(addr):X})") return True def mem_copy(self, src, dst, size: int) -> bool: """进程内 memcpy""" self._parse_ok(self.memcpy(self._hex(src), self._hex(dst), size), f"Memcpy(0x{self._int(src):X}->0x{self._int(dst):X})") return True def va_to_offset(self, addr) -> int: """虚拟地址 → 文件偏移(PE 静态分析)""" res = self._parse_ok(self.va_to_file_offset(self._hex(addr)), f"VaToFileOffset(0x{self._int(addr):X})") return self._int(self._find(res, "offset", "fileOffset", "value")) def offset_to_va(self, offset) -> int: """文件偏移 → 虚拟地址(注意:offset 传 0 会被服务端判非法,需传非零值)""" res = self._parse_ok(self.file_offset_to_va(str(offset)), f"FileOffsetToVa({offset})") return self._int(self._find(res, "va", "address", "value")) def snapshot(self, addr, size: int) -> str: """内存快照 → hex(配合 restore 做 fuzz 回滚/补丁备份)""" return self.read_hex(addr, size) def restore(self, addr, hexdata: str) -> int: """按快照还原内存""" return self.write_bytes(addr, hexdata) def hash_region(self, addr, size: int, algo: str = "md5") -> str: """区域哈希(校验完整性/样本去重)""" res = self._parse_ok(self.hash_memory(self._hex(addr), size, algo), f"HashMemory({algo})") return self._find(res, "hash", "digest", "value") or "" # ---------------- 搜索 ---------------- def search_in_module(self, module: str, pattern: str, max_num: int = 5) -> list: """模块映射范围内搜索字节模式(pattern 支持 '?' 通配,如 'E8 ? ? ? ?')""" m = self.find_module(module) if not m or m["base"] is None or m["size"] is None: raise RuntimeError(f"无法定位模块 {module}") res = self._parse_ok(self.search_memory(pattern, hex(m["base"]), m["size"]), f"SearchMemory({pattern} in {module})") return self._collect_addresses(res)[:max_num] def search_all(self, pattern: str, max_num: int = 10) -> list: """全内存搜索""" res = self._parse_ok(self.search_all_memory(pattern, max_num), f"SearchAllMemory({pattern})") return self._collect_addresses(res)[:max_num] def pattern_match(self, addr, pattern: str, size: int) -> bool: """检查 addr 处是否匹配模式('?' 通配)""" res = self._parse_ok(self.match_pattern(self._hex(addr), pattern, size), f"MatchPattern(0x{self._int(addr):X})") return bool(self._find(res, "match", "matched", "found", "ok")) def strings_in_module(self, module: str, max_num: int = 200) -> list: """模块内字符串提取:[{address, string}]""" m = self.find_module(module) if not m or m["base"] is None: raise RuntimeError(f"无法定位模块 {module}") size = m["size"] or 0x100000 res = self._parse_ok(self.search_strings(hex(m["base"]), size), f"SearchStrings({module})") lst = self._find(res, "strings", "list", "items", "results") out = [] if isinstance(lst, list): for it in lst: if isinstance(it, dict): s = it.get("string") or it.get("text") or it.get("value") if s: out.append({"address": self._int(it.get("address") or it.get("addr")), "string": str(s)}) return out[:max_num] def read_pointer_chain(self, addr, depth: int = 8, mask: int = None) -> list: """解引用链:addr → *addr → **addr ...(对象/链表遍历)""" chain = [] cur = self._int(addr) seen = set() width = 8 # 默认按 x64;win32 等 x86 目标由调用方按需传参或用 system_info 判断 try: si = self._parse_ok(self.system_info(), "SystemInfo") arch = str(si.get("arch") or si.get("processorArchitecture") or "").lower() if "86" in arch or "x86" in arch or arch == "x32": width = 4 except RuntimeError: pass for _ in range(depth): if cur is None or cur in seen: break seen.add(cur) chain.append(cur) try: val = self.read_u64(cur) if width == 8 else self.read_u32(cur) except RuntimeError: break if val is None or val == 0: break if mask: val &= mask cur = val return chain # ---------------- 反汇编 / 静态分析 ---------------- def disasm(self, addr, count: int = 10) -> list: """反汇编 count 条:[{addr, mnemonic, text, size}];text 优先取 titan 完整指令""" res = self._parse_ok(self.disassemble_at(self._hex(addr), count), f"DisassembleAt(0x{self._int(addr):X})") insns = self._find(res, "instructions", "lines", "list", "disasm") out = [] if isinstance(insns, list): for i in insns: if isinstance(i, dict): mn = (i.get("mnemonic") or "").strip() op = (i.get("opStr") or "").strip() text = (i.get("titan") or i.get("text") or i.get("disasm") or i.get("instruction") or "").strip() if not text and op: text = f"{mn} {op}".strip() size = self._int(i.get("size") or i.get("length")) if size is None and i.get("bytes"): size = len(str(i["bytes"]).replace(" ", "")) // 2 out.append({"addr": self._int(i.get("address") or i.get("addr")), "mnemonic": mn, "text": text, "size": size}) return out @staticmethod def _is_ret(insn) -> bool: return (insn.get("mnemonic") or "").lower().startswith("ret") @staticmethod def _is_branch(insn) -> bool: mn = (insn.get("mnemonic") or "").lower() return mn.startswith(("j", "call", "loop")) or BinSentryClient._is_ret(insn) def basic_block(self, addr, max_insns: int = 64) -> list: """顺序反汇编到分支/返回(不含 call 也保留),返回指令列表""" out = [] cur = self._int(addr) while len(out) = max_insns: return out cur = (out[-1]["addr"] or cur) + (out[-1]["size"] or 1) return out def function_prologue(self, addr) -> tuple: """识别函数序言:返回 (模式名, 匹配指令数, 前若干条指令)""" insns = self.disasm(addr, 12) if not insns: return None, 0, [] mns = [(i.get("mnemonic") or "").lower() for i in insns] txts = [(i.get("text") or "").lower() for i in insns] if mns[:2] == ["push", "mov"] and "ebp" in txts[1]: return "push ebp; mov ebp,esp", 2, insns[:6] if mns and mns[0] == "push" and "esp" in txts[0]: return "push regs prologue", 1, insns[:6] if mns[:2] == ["mov", "push"] and "esp" in txts[1]: return "mov; push regs prologue", 2, insns[:6] if mns[:2] == ["push", "mov"] and "rsp" in txts[1]: return "push rbp; mov rbp,rsp (x64)", 2, insns[:6] if mns and mns[0] == "endbr64": return "endbr64 (CET)", 1, insns[:6] if mns and mns[0] == "sub" and "rsp" in txts[0]: return "sub rsp, imm (x64 leaf)", 1, insns[:6] return "未知序言", 0, insns[:6] def analyze_function(self, addr) -> dict: """函数分析:序言 + 函数大小 + 前 6 条指令""" prologue, n, insns = self.function_prologue(addr) size = None try: size = self.function_size(addr) except RuntimeError: pass return {"entry": self._int(addr), "prologue": prologue, "prologue_insns": n, "size": size, "instructions": insns} _GADGET_PATTERNS = { "ret": "C3", "jmp esp": "FF E4", "jmp eax": "FF E0", "jmp ecx": "FF E1", "call esp": "FF D4", "pop eax; ret": "58 C3", "pop ebx; ret": "5B C3", "pop ecx; ret": "59 C3", "pop edx; ret": "5A C3", "pop esi; ret": "5E C3", "pop edi; ret": "5F C3", "pop ebp; ret": "5D C3", "leave; ret": "C9 C3", "jmp [esp]": "FF 24 24", "int3": "CC", } def find_gadgets(self, module: str, patterns: dict = None, max_per_gadget: int = 20) -> dict: """ROP gadget 扫描:在模块可执行范围搜常见字节模式(启发式)""" patterns = patterns or self._GADGET_PATTERNS m = self.find_module(module) if not m or m["base"] is None or m["size"] is None: raise RuntimeError(f"无法定位模块 {module}") found = {} for name, pat in patterns.items(): try: res = self._parse_ok(self.search_memory(pat, hex(m["base"]), m["size"]), f"gadget {name}") addrs = self._collect_addresses(res)[:max_per_gadget] if addrs: found[name] = addrs except RuntimeError: continue return found def xrefs_to(self, addr, max_num: int = 10) -> list: """交叉引用(谁引用了该地址)""" res = self._parse_ok(self.xrefs(self._hex(addr), max_num), f"xrefs(0x{self._int(addr):X})") return self._collect_addresses(res)[:max_num] def find_refs(self, addr, max_num: int = 10) -> list: """反汇编扫描引用""" res = self._parse_ok(self.find_ref(self._hex(addr), max_num), f"FindRef(0x{self._int(addr):X})") return self._collect_addresses(res)[:max_num] def opcode_size_at(self, addr) -> int: """指令长度""" res = self._parse_ok(self.get_opcode_size(self._hex(addr)), f"GetOpcodeSize(0x{self._int(addr):X})") return self._int(self._find(res, "size", "length", "count")) def branch_target(self, addr) -> int: """分支指令的目标地址""" res = self._parse_ok(self.get_branch_target(self._hex(addr)), f"GetBranchTarget(0x{self._int(addr):X})") return self._int(self._find(res, "target", "address", "dest")) def mnemonic_at(self, addr) -> str: """指令助记符简述""" res = self._parse_ok(self.mnemonicbrief(self._hex(addr)), f"mnemonicbrief(0x{self._int(addr):X})") return self._find(res, "mnemonic", "brief", "description", "text") or "" def asm(self, instr: str, cip=None) -> str: """汇编一条指令为字节 hex;cip 缺省取当前 eip""" if cip is None: try: cip = self.reg("eip") or self.reg("rip") except RuntimeError: cip = 0 res = self._parse_ok(self.assemble(instr, self._hex(cip)), f"Assemble({instr})") return self._find(res, "hex", "bytes", "opcode", "code") or "" def asm_at(self, addr, instr: str) -> int: """汇编并写入目标进程(就地补丁/改指令)""" self._parse_ok(self.assemble_at(self._hex(addr), instr), f"AssembleAt({instr})") return self._int(addr) # ---------------- 断点 / 运行监控 ---------------- def set_bp(self, addr, name: str = None, log: str = None, cond: str = None, singleshoot: bool = False) -> int: """组合式设软断点:地址 + 可选名称/日志/条件/单次命中""" self._parse_ok(self.set_breakpoint(self._hex(addr)), f"SetBreakPoint(0x{self._int(addr):X})") if name: self._parse_ok(self.set_breakpoint_name(self._hex(addr), name), "SetBreakpointName") if log: self._parse_ok(self.set_breakpoint_log(self._hex(addr), log), "SetBreakpointLog") if cond: self._parse_ok(self.set_cond_breakpoint(self._hex(addr), cond, 0), "SetCondBreakPoint") if singleshoot: self._parse_ok(self.set_breakpoint_singleshoot(self._hex(addr), 1), "SetBreakpointSingleshoot") return self._int(addr) def del_bp(self, addr) -> int: self._parse_ok(self.del_breakpoint(self._hex(addr)), f"DelBreakPoint(0x{self._int(addr):X})") return self._int(addr) def bp_list(self) -> list: """软件断点列表:[{id, address, temporary, threadId, condition}]""" res = self._parse_ok(self.show_breakpoint(), "ShowBreakPoint") lst = self._find(res, "breakpoints", "list", "items", "bpx") out = [] if isinstance(lst, list): for it in lst: if isinstance(it, dict): out.append({ "id": it.get("id"), "address": self._int(it.get("addressHex") or it.get("address") or it.get("addr")), "temporary": it.get("temporary"), "threadId": self._int(it.get("threadId")), "condition": it.get("condition"), }) return out def bp_info(self, addr) -> dict: """断点详情(类型/状态/命中数)""" res = self._parse_ok(self.get_breakpoint_info(self._hex(addr)), f"GetBreakpointInfo(0x{self._int(addr):X})") return {"address": self._int(self._find(res, "address", "addr")), "type": self._find(res, "type", "kind"), "enabled": self._find(res, "enabled", "active"), "hits": self._int(self._find(res, "hitCount", "count", "hits"))} def bp_type(self, addr) -> str: """断点类型(软/硬/内存/api)""" res = self._parse_ok(self.get_breakpoint_type(self._hex(addr)), f"GetBreakpointType(0x{self._int(addr):X})") return self._find(res, "type", "kind") or "" def bp_hit_count(self, addr) -> int: """断点命中数""" res = self._parse_ok(self.get_breakpoint_hit_count(self._hex(addr)), f"GetBreakpointHitCount(0x{self._int(addr):X})") return self._int(self._find(res, "count", "hitCount", "hits")) def set_bp_hits(self, addr, count: int) -> bool: """设置断点命中阈值""" self._parse_ok(self.set_breakpoint_hit_count(self._hex(addr), count), "SetBreakpointHitCount") return True def reset_bp_hits(self, addr) -> bool: self._parse_ok(self.reset_breakpoint_hit_count(self._hex(addr)), "ResetBreakpointHitCount") return True def enable_bp(self, addr) -> bool: self._parse_ok(self.enable_breakpoint(self._hex(addr)), f"EnableBreakpoint(0x{self._int(addr):X})") return True def disable_bp(self, addr) -> bool: self._parse_ok(self.disable_breakpoint(self._hex(addr)), f"DisableBreakpoint(0x{self._int(addr):X})") return True def bp_command(self, addr, command: str = "") -> bool: """断点命中时执行命令(脚本化调试)""" self._parse_ok(self.breakpoint_command(self._hex(addr), command), "BreakpointCommand") return True def bp_fast_resume(self, addr, enable: int = 1) -> bool: self._parse_ok(self.set_breakpoint_fast_resume(self._hex(addr), enable), "SetBreakpointFastResume") return True def bp_silent(self, addr, enable: int = 1) -> bool: self._parse_ok(self.set_breakpoint_silent(self._hex(addr), enable), "SetBreakpointSilent") return True def bp_log_file(self, addr, file: str) -> bool: self._parse_ok(self.set_breakpoint_log_file(self._hex(addr), file), "SetBreakpointLogFile") return True def del_cond_bp(self, addr) -> bool: self._parse_ok(self.del_cond_breakpoint(self._hex(addr)), "DelCondBreakPoint") return True def set_hw_bp(self, addr, len_: str = "1", flag: str = "e") -> int: """硬件断点(可能回退软件断点)""" self._parse_ok(self.set_hbreakpoint(self._hex(addr), len_, flag), f"SetHbreakPoint(0x{self._int(addr):X})") return self._int(addr) def del_hw_bp(self, addr) -> bool: self._parse_ok(self.del_hbreakpoint(self._hex(addr)), f"DelHbreakPoint(0x{self._int(addr):X})") return True def hw_bp_list(self) -> list: res = self._parse_ok(self.show_hbreakpoint(), "ShowHbreakPoint") lst = self._find(res, "hbreakpoints", "list", "items", "bpx") return lst if isinstance(lst, list) else [] def set_mem_bp(self, addr, flag: str = "r") -> int: """内存访问断点(r/w/x 访问监控)""" self._parse_ok(self.set_mem_breakpoint(self._hex(addr), flag), f"SetMemBreakPoint(0x{self._int(addr):X},{flag})") return self._int(addr) def del_mem_bp(self, addr) -> bool: self._parse_ok(self.del_mem_breakpoint(self._hex(addr)), f"DelMemBreakPoint(0x{self._int(addr):X})") return True def mem_bp_list(self) -> list: res = self._parse_ok(self.show_mem_breakpoint(), "ShowMemBreakPoint") lst = self._find(res, "membreakpoints", "list", "items", "bpx") return lst if isinstance(lst, list) else [] def set_api_bp(self, dll: str, api: str) -> str: """API 断点:dll!api""" self._parse_ok(self.set_api_breakpoint(dll, api), f"SetApiBreakPoint({dll}!{api})") return f"{dll}!{api}" def del_api_bp(self, dll: str, api: str) -> str: self._parse_ok(self.del_api_breakpoint(dll, api), f"DelApiBreakPoint({dll}!{api})") return f"{dll}!{api}" def api_bp_list(self) -> list: res = self._parse_ok(self.show_api_breakpoint(), "ShowApiBreakPoint") lst = self._find(res, "apibreakpoints", "list", "items", "bpx") return lst if isinstance(lst, list) else [] def set_exception_bp(self, code: str) -> str: """异常断点(如 'C0000005' 访问违例)""" self._parse_ok(self.set_exception_bpx(code), f"SetExceptionBPX({code})") return code def del_exception_bp(self, code: str) -> str: self._parse_ok(self.del_exception_bpx(code), f"DelExceptionBPX({code})") return code def exception_bp_list(self) -> list: res = self._parse_ok(self.get_exception_bpx_list(), "GetExceptionBPXList") lst = self._find(res, "exceptions", "list", "items", "bpx") return lst if isinstance(lst, list) else [] def set_dll_bp(self, dll: str) -> str: """DLL 加载断点""" self._parse_ok(self.set_dll_breakpoint(dll), f"SetDllBreakPoint({dll})") return dll def del_dll_bp(self, dll: str) -> str: self._parse_ok(self.del_dll_breakpoint(dll), f"DelDllBreakPoint({dll})") return dll def dll_bp_list(self) -> list: res = self._parse_ok(self.get_dll_breakpoints(), "GetDllBreakPoints") lst = self._find(res, "dlls", "list", "items", "breakpoints") return lst if isinstance(lst, list) else [] def bpx_options(self, option: str, enable: int) -> bool: """断点全局选项(如 single_shot 等)""" self._parse_ok(self.set_bpx_options(option, enable), f"SetBPXOptions({option},{enable})") return True def run_to_bp(self, addr, timeout: int = 60) -> dict: """设临时断点 → Run → 等待命中;返回 {hit, info, registers}""" self.set_bp(addr) self.custom_post({"interface": "Run", "params": {}}) hit = self.wait_stopped(timeout) info = self.bp_info(addr) if hit else None regs = self.registers() if hit else None return {"hit": hit, "info": info, "registers": regs} def trace_to(self, addr, timeout: int = 30) -> dict: """TraceLine 运行到目标地址(TF 单步跟踪)""" self._parse_ok(self.trace_line(self._hex(addr)), f"TraceLine(0x{self._int(addr):X})") hit = self.wait_stopped(timeout) return {"hit": hit, "registers": self.registers() if hit else None} # ---------------- 寄存器 / 线程 / 栈 ---------------- def registers(self) -> dict: """全部寄存器 dict""" res = self._parse_ok(self.register(), "Register") regs = self._find(res, "registers", "regs") if not isinstance(regs, dict): raise RuntimeError(f"Register 响应缺少寄存器表: {str(res)[:200]}") return dict(regs) def reg(self, name: str) -> int: """读取单个寄存器(eax/eip/eflags...)""" v = self.registers().get(name) return self._int(v) def set_reg(self, name: str, value) -> bool: self._parse_ok(self.set_register(name, str(value)), f"SetRegister({name})") return True def expr_eval(self, expr: str) -> int: """表达式求值(需停止态):'eax' / '0x401000+0x20' / '[esp]' 等""" res = self._parse_ok(self.eval_expr(expr), f"Eval({expr})") return self._int(self._find(res, "value", "result", "val")) def context(self) -> dict: """调试上下文:寄存器 + EIP 指令 + 栈顶""" regs = self.registers() eip = self._int(regs.get("eip") or regs.get("rip")) ctx = {"registers": regs} if eip: try: ctx["eip"] = eip ctx["mnemonic"] = self.mnemonic_at(eip) ctx["instructions"] = self.disasm(eip, 3) except RuntimeError: pass try: ctx["stack_top"] = self.stack_dump(8) except RuntimeError: pass return ctx def stack_dump(self, count: int = 16) -> list: """栈转储:[{address, value, ascii}]""" res = self._parse_ok(self.stack(count), f"Stack({count})") lst = self._find(res, "stack", "items", "list", "entries") out = [] if isinstance(lst, list): for it in lst: if isinstance(it, dict): out.append({ "address": self._int(it.get("address") or it.get("addr")), "value": self._int(it.get("value") or it.get("data")), "ascii": it.get("ascii") or it.get("text"), }) return out def stack_frames(self, max_num: int = 16) -> list: """调用栈帧:[{frame, address, sp, module, name}](name 含符号+偏移)""" res = self._parse_ok(self.call_stack(max_num), f"CallStack({max_num})") lst = self._find(res, "frames", "stack", "callstack", "list", "items") out = [] if isinstance(lst, list): for it in lst: if isinstance(it, dict): out.append({ "frame": self._int(it.get("frame") or it.get("index")), "address": self._int(it.get("pcHex") or it.get("pc") or it.get("address") or it.get("addr")), "sp": self._int(it.get("spHex") or it.get("sp")), "frame_addr": self._int(it.get("frameHex") or it.get("frameAddr")), "module": it.get("module") or it.get("mod"), "name": it.get("symbol") or it.get("name"), }) return out def threads_info(self) -> list: """线程列表:[{tid, teb, status, name}]""" res = self._parse_ok(self.threads(), "Threads") lst = self._find(res, "threads", "list", "items") out = [] if isinstance(lst, list): for it in lst: if isinstance(it, dict): out.append({ "tid": self._int(it.get("threadId") or it.get("tid")), "teb": it.get("tebBaseHex") or it.get("teb"), "status": it.get("status"), "name": it.get("name"), }) return out def thread_detail(self, tid: int) -> dict: """单线程详情""" res = self._parse_ok(self.thread_info(tid), f"ThreadInfo({tid})") return res def active_thread_id(self) -> int: """活动线程 TID""" res = self._parse_ok(self.get_active_thread(), "GetActiveThread") return self._int(self._find(res, "activeThread", "tid", "thread")) def set_active_thread_id(self, tid: int) -> bool: self._parse_ok(self.set_active_thread(tid), f"SetActiveThread({tid})") return True def thread_last_error(self, tid: int) -> int: """线程最近错误码""" res = self._parse_ok(self.get_thread_last_error(tid), f"GetThreadLastError({tid})") return self._int(self._find(res, "error", "code", "lastError", "value")) def thread_priority(self, tid: int) -> str: """线程优先级""" res = self._parse_ok(self.get_thread_priority(tid), f"GetThreadPriority({tid})") return self._find(res, "priority", "value", "level") or "" def thread_set_priority(self, tid: int, priority: str = "NORMAL") -> bool: """设置线程优先级(HIGHEST/ABOVE_NORMAL/NORMAL/BELOW_NORMAL/LOWEST)""" self._parse_ok(self.set_thread_priority(tid, priority), f"SetThreadPriority({tid},{priority})") return True def thread_set_name(self, tid: int, name: str) -> bool: self._parse_ok(self.set_thread_name(tid, name), f"SetThreadName({tid})") return True def flag_get(self, name: str) -> int: """读取标志位(CF/PF/AF/ZF/SF/TF/IF/DF/OF)""" regs = self.registers() ef = self._int(regs.get("eflags") or regs.get("flags")) if ef is None: raise RuntimeError("寄存器中无 eflags") bits = {"CF": 0, "PF": 2, "AF": 4, "ZF": 6, "SF": 7, "TF": 8, "IF": 9, "DF": 10, "OF": 11} name = name.upper() if name not in bits: raise RuntimeError(f"未知标志位: {name}") return (ef >> bits[name]) & 1 def flag_set(self, name: str, value: int) -> bool: self._parse_ok(self.set_flag(name.upper(), int(value)), f"SetFlag({name})") return True def trace_record_start(self) -> bool: self._parse_ok(self.start_trace_record(), "StartTraceRecord") return True def trace_record_get(self, count: int = 5) -> list: """最近执行轨迹记录""" res = self._parse_ok(self.get_trace_record(count), f"GetTraceRecord({count})") lst = self._find(res, "records", "trace", "list", "items") return lst if isinstance(lst, list) else [] def trace_record_stop(self) -> bool: self._parse_ok(self.stop_trace_record(), "StopTraceRecord") return True def jmp_history_list(self) -> list: """跳转历史""" res = self._parse_ok(self.jmp_history(), "JmpHistory") lst = self._find(res, "history", "jumps", "list", "items") return lst if isinstance(lst, list) else [] def last_exception_info(self) -> dict: """最近一次异常信息""" res = self._parse_ok(self.last_exception(), "LastException") return {"code": self._find(res, "code", "exceptionCode"), "address": self._int(self._find(res, "address", "exceptionAddress")), "flags": self._find(res, "flags", "exceptionFlags")} # ---------------- 执行控制包装(自动等待停止态) ---------------- def run_and_wait(self, timeout: int = 60) -> bool: self.custom_post({"interface": "Run", "params": {}}) return self.wait_stopped(timeout) def step_into_wait(self, timeout: int = 60) -> bool: self.custom_post({"interface": "StepIn", "params": {}}) return self.wait_stopped(timeout) def step_over_wait(self, timeout: int = 60) -> bool: self.custom_post({"interface": "StepOver", "params": {}}) return self.wait_stopped(timeout) def step_out_wait(self, timeout: int = 60) -> bool: self.custom_post({"interface": "StepOut", "params": {}}) return self.wait_stopped(timeout) def skip_wait(self, count: int = 1, timeout: int = 60) -> bool: self.custom_post({"interface": "Skip", "params": {"count": count}}) return self.wait_stopped(timeout) def run_to_and_wait(self, addr, timeout: int = 60) -> bool: self._parse_ok(self.run_to(self._hex(addr)), f"RunTo(0x{self._int(addr):X})") return self.wait_stopped(timeout) def run_to_user_wait(self, timeout: int = 60) -> bool: self.custom_post({"interface": "RunToUserCode", "params": {}}) return self.wait_stopped(timeout) def trace_into_wait(self, count: int = 3, timeout: int = 60) -> bool: self.custom_post({"interface": "TraceInto", "params": {"count": count}}) return self.wait_stopped(timeout) def trace_over_wait(self, count: int = 3, timeout: int = 60) -> bool: self.custom_post({"interface": "TraceOver", "params": {"count": count}}) return self.wait_stopped(timeout) def animate_into_wait(self, count: int = 3, timeout: int = 60) -> bool: self.custom_post({"interface": "AnimateInto", "params": {"count": count}}) return self.wait_stopped(timeout) def animate_over_wait(self, count: int = 3, timeout: int = 60) -> bool: self.custom_post({"interface": "AnimateOver", "params": {"count": count}}) return self.wait_stopped(timeout) def animate_stop_now(self) -> bool: self._parse_ok(self.custom_post({"interface": "AnimateStop", "params": {}}), "AnimateStop") return True def pause_all(self) -> bool: self.custom_post({"interface": "PauseAllThreads", "params": {}}) return True def resume_all(self) -> bool: self.custom_post({"interface": "ResumeAllThreads", "params": {}}) return True def thread_pause_by_id(self, tid: int) -> bool: self.custom_post({"interface": "ThreadPause", "params": {"tid": tid}}) return True def thread_resume_by_id(self, tid: int) -> bool: self.custom_post({"interface": "ThreadResume", "params": {"tid": tid}}) return True def debug_continue_wait(self, status: int = 0, timeout: int = 60) -> bool: """处理完异常/事件后继续执行""" self.custom_post({"interface": "DebugContinue", "params": {"status": status}}) return self.wait_stopped(timeout) def exec_cmd(self, command: str) -> str: """执行调试器命令(如 'Help'、'SetDebug' 等命令串)""" res = self._parse_ok(self.execute_command(command), f"ExecuteCommand({command})") return json.dumps(res, ensure_ascii=False) # ---------------- 漏洞挖掘 / 深度取证 ---------------- def exception_chain(self) -> list: """SEH 异常处理链:[{address, handler, next}](栈溢出利用分析)""" res = self._parse_ok(self.seh_list(), "SEHList") lst = self._find(res, "seh", "chain", "list", "items", "entries") out = [] if isinstance(lst, list): for it in lst: if isinstance(it, dict): out.append({ "address": self._int(it.get("address") or it.get("addr")), "handler": self._int(it.get("handler") or it.get("handlerAddress")), "next": self._int(it.get("next") or it.get("nextAddress")), }) return out def heap_layout(self) -> list: """堆布局:[{base, size, flags}](堆喷/堆溢出分析)""" res = self._parse_ok(self.heaps(), "Heaps") lst = self._find(res, "heaps", "list", "items") out = [] if isinstance(lst, list): for it in lst: if isinstance(it, dict): out.append({ "base": self._int(it.get("base") or it.get("address") or it.get("baseAddress")), "size": self._int(it.get("size") or it.get("regionSize")), "flags": it.get("flags") or it.get("type"), }) return out def handles_of(self, max_num: int = 50) -> list: """句柄列表:[{handle, type, name}]""" res = self._parse_ok(self.handles(max_num), f"Handles({max_num})") lst = self._find(res, "handles", "list", "items") out = [] if isinstance(lst, list): for it in lst: if isinstance(it, dict): out.append({ "handle": self._int(it.get("handle") or it.get("value")), "type": it.get("type") or it.get("objectType"), "name": it.get("name"), }) return out def patch(self, addr, hexstr: str) -> int: """打补丁(写字节)并返回字节数""" self._parse_ok(self.patch_memory(self._hex(addr), hexstr), f"PatchMemory(0x{self._int(addr):X})") return len(re.sub(r"[^0-9a-fA-F]", "", hexstr)) // 2 def patch_list(self) -> list: """已打补丁列表""" res = self._parse_ok(self.patches(), "Patches") lst = self._find(res, "patches", "list", "items") return lst if isinstance(lst, list) else [] def del_patch(self, addr) -> bool: self._parse_ok(self.delete_patch(self._hex(addr)), f"DeletePatch(0x{self._int(addr):X})") return True def verify_patch(self, addr, hexstr: str) -> tuple: """校验补丁生效(读回对比),返回 (是否一致, 实际字节 hex)""" want = bytes.fromhex(re.sub(r"[^0-9a-fA-F]", "", hexstr)) got = self.read_bytes(addr, len(want)) return got == want, got.hex() def minidump_to(self, path: str) -> str: """生成 minidump(崩溃现场取证)""" self._parse_ok(self.minidump(path), f"minidump({path})") return path def dump_to(self, path: str, addr, size: int) -> str: """按区域 dump 进程内存到文件""" self._parse_ok(self.dump_process(path, self._hex(addr), size), f"DumpProcess({path})") return path _DANGEROUS_PATTERNS = [ (r"%[0-9]*[n]", "格式串 %n(任意写原语)"), (r"%[0-9]*\$[a-zA-Z]", "位置参数格式串"), (r"system\s*\(", "system() 调用"), (r"(/bin/)?sh\b", "shell 命令"), (r"cmd\.exe", "cmd.exe"), (r"http[s]?://", "URL"), (r"password|passwd", "口令字段"), (r"secret|token|apikey|api[_-]?key", "密钥字段"), (r"SELECT\s|INSERT\s|DELETE\s|DROP\s|UPDATE\s", "SQL 语句"), (r"\.\./|\.\.\\", "路径穿越"), (r"GetProcAddress|LoadLibrary|VirtualAlloc|WriteProcessMemory|CreateRemoteThread", "危险 API 名"), (r"flag\{|ctf\{", "CTF flag"), ] def string_scan_report(self, module: str, max_strings: int = 2000) -> dict: """危险字符串扫描:提取模块字符串并标记漏洞相关模式(格式串/SQL/口令/危险API等)""" strs = self.strings_in_module(module, max_strings) hits = [] for item in strs: s = item["string"] for pat, desc in self._DANGEROUS_PATTERNS: if re.search(pat, s, re.IGNORECASE): hits.append({"address": item["address"], "string": s[:120], "pattern": desc}) return {"total_strings": len(strs), "dangerous_hits": hits} ```