BinSentry 自研二进制哨兵调用Python SDK库
BinSentry 二进制哨兵,由 LYSHARK 独立自研,是一款运行于 Windows 平台的二进制动态调试引擎。该调试引擎从零手写开发,C++ 代码 3.5 万(主框架)+ AI Agent 专家协同框架(开发中)余行,实现 300 + 调试方法;原生采用 CMD 命令行 HTTP 服务器架构,专为 AI Agent 打造。配合配套 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 < timeout:
st = self.session_status()
if not st["sessionActive"]:
return False
if st["stopped"]:
return True
time.sleep(0.2)
return False
def ensure_stopped(self, timeout: int = 60) -> 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 < timeout:
st = self.session_status()
if st["sessionActive"]:
return st
time.sleep(0.2)
raise RuntimeError("Restart 后未等到新会话")
def force_stop(self, timeout: int = 60) -> 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"] <= self._int(addr) < m["base"] + m["size"]:
return m
return None
def module_summary(self) -> 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:<12} {m['name']:<24} {m.get('path') or ''}")
return "\n".join(lines)
def module_sections(self, module: str) -> 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 < size:
n = min(chunk, size - off)
raw = self.custom_post({"interface": "Memory", "params": {"address": hex(base + off), "size": n}})
res = self._parse_ok(raw, f"Memory(0x{base + off:X})")
hexdata = self._find(res, "hex", "data", "bytes", "content", "buffer")
if hexdata is None:
raise RuntimeError(f"Memory 响应缺少字节数据: {str(res)[:200]}")
if isinstance(hexdata, list):
out += bytes(int(b) for b in hexdata)
else:
out += bytes.fromhex(re.sub(r"[^0-9a-fA-F]", "", str(hexdata)))
off += n
return bytes(out)
def read_hex(self, addr, size: int) -> 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 < len(data):
n = min(self._CHUNK, len(data) - off)
self._parse_ok(self.write_memory(hex(base + off), data[off:off + n].hex()),
f"WriteMemory(0x{base + off:X})")
off += n
return len(data)
def read_cstring(self, addr, max_len: int = 256) -> 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:
batch = self.disasm(cur, 8)
if not batch:
break
for insn in batch:
out.append(insn)
if self._is_ret(insn) or (insn.get("mnemonic") or "").lower() == "jmp" or \
(insn.get("mnemonic") or "").lower().startswith("j"):
return out
if 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}
文章出处:https://www.cnblogs.com/LyShark/p/23118968
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

浙公网安备 33010602011771号