简介API Monitor 是一款面向 Windows 平台的 API 监视与调试工具适合软件开发者和系统管理员用于跟踪应用程序与系统接口之间的交互。它通过 DLL 注入技术实时捕获 API 调用可查看函数名、参数值、返回值、调用堆栈及调用时间并支持过滤搜索、日志导出与模拟调用帮助快速定位问题、理解程序行为。资源包共 1406 个文件以 1397 个 xml 规则文件为主另含 apimonitor-x86/x64 可执行程序、驱动 sys 文件、dll 组件及 ini 配置、txt 说明文档压缩包约 7.25MB覆盖 32 位与 64 位环境。目前已有 940 人学习下载。借助其中的规则库与说明文档读者可快速上手 API 监视、参数修改与调用堆栈分析掌握从调用记录到日志导出的完整排错思路提升调试与性能优化效率。1. API Monitor 到底在监视什么从一次线上 502 说起去年冬天某公司后端团队遇到一个诡异问题订单服务每隔几小时就报一批 502重启后恢复几小时后又复发。日志里没有任何异常堆栈CPU 和内存曲线也平稳得像一条直线。后来用 API Monitor 抓了两小时流量才发现是一个内部服务在特定条件下会向另一个服务发送超大 JSON 体触发了网关的请求体限制而网关的报错日志被采样策略丢掉了。问题定位只花了十分钟但找到“该看哪里”花了两天。这就是 API Monitor 类工具的核心价值它不替代日志系统也不替代 APM它解决的是“请求和响应在传输层到底长什么样”这个黑匣子问题。具体来说它能让你看到完整的 HTTP 请求头、请求体、响应头、响应体、状态码、耗时、TLS 握手细节甚至能对比两次请求的差异。适合谁用后端开发排查接口联调问题、测试工程师验证接口契约、SRE 定位网关层异常、安全人员检查敏感数据泄露都用得上。但“API Monitor”这个词本身有歧义。有人指的是 Windows 平台下那个经典的 API Monitor监视 Win32 API 调用有人指的是 HTTP 层面的抓包工具还有人指的是 APM 里的接口监控模块。这篇笔记锁定的是 HTTP/HTTPS API 的请求响应监视不涉及系统调用级别的 API Hook。选型逻辑、部署方式、参数配置、踩坑记录都围绕这个范围展开。2. 选型先看三层能力抓包、解析、回放2.1 抓包层流量怎么进来决定了一切API Monitor 工具的第一层能力是流量捕获。常见做法有三种代理模式、网卡嗅探模式、Agent 嵌入模式。代理模式最通用工具启动一个 HTTP 代理客户端把请求指向代理端口即可。网卡嗅探模式需要抓包驱动能捕获本机所有流量但解不了 HTTPS。Agent 嵌入模式是在应用进程内注入拦截逻辑能拿到最完整的上下文但侵入性最强。我一般会优先选代理模式因为它的边界最清晰你明确知道哪些流量被监视了哪些没有。代理模式的一个关键参数是监听地址和端口。以常见的 mitmproxy 为例默认监听 8080 端口只接受本机连接。如果要让局域网内其他设备把流量送过来需要显式指定--listen-host 0.0.0.0。这个参数一改安全边界就变了后面会细说。# 启动 mitmproxy监听所有网卡的 8080 端口 # --listen-host 0.0.0.0 表示接受来自局域网的连接 # --set block_globalfalse 允许非本机流量进入 mitmproxy --listen-host 0.0.0.0 --listen-port 8080 --set block_globalfalse逻辑说明--listen-host控制绑定地址默认是127.0.0.1改成0.0.0.0后局域网内任何设备都能连。block_global默认是true会拒绝非本机来源的连接必须同时关掉。参数说明端口选 8080 是因为它通常不被占用如果冲突可以换 8888 或 9090。注意开放到局域网后任何能访问该端口的人都能看到明文流量所以只在受控网络里这么做。2.2 解析层HTTPS 解密是分水岭HTTP 流量直接可读HTTPS 流量默认是加密的。API Monitor 工具要能解密 HTTPS核心机制是中间人证书。工具生成一个自签名根证书客户端信任这个根证书后工具就能用动态生成的域名证书与客户端握手再用真实证书与服务端握手从而拿到明文。以 mitmproxy 为例首次启动后会在~/.mitmproxy/目录下生成mitmproxy-ca-cert.pem等文件。客户端需要安装并信任这个证书。不同平台的安装方式不同macOS 用钥匙串访问导入并设为始终信任Windows 用 certmgr.msc 导入到“受信任的根证书颁发机构”Linux 把证书复制到/usr/local/share/ca-certificates/后执行update-ca-certificates。# 查看 mitmproxy 生成的证书文件 ls -la ~/.mitmproxy/ # 输出通常包含 # mitmproxy-ca-cert.pem PEM 格式用于 Linux/Android # mitmproxy-ca-cert.p12 PKCS12 格式用于 Windows/macOS # mitmproxy-ca-cert.cer DER 格式用于部分 Java 应用逻辑说明不同客户端对证书格式要求不同。PEM 是文本格式Linux 和 Android 常用。PKCS12 是二进制容器Windows 和 macOS 双击即可导入。CER 是 DER 编码Java 的 keytool 需要这种格式。参数说明如果客户端是 Java 应用还需要用 keytool 把证书导入到 JVM 的 truststore否则 Java 不认系统证书。2.3 回放层改包重发才是排查利器抓到包只是第一步能改包重发才能验证假设。比如你怀疑某个接口在特定参数下会返回 500就可以在 API Monitor 里拦截请求修改参数后重发观察响应变化。mitmproxy 的intercept功能可以按规则拦截请求或响应进入交互式编辑界面。# 启动 mitmproxy 后按 i 键设置拦截规则 # 例如拦截所有发往 /api/order 的请求 # 在交互界面中可以修改请求方法、路径、头、体 # 修改完成后按 a 放行按 A 放行所有按 r 重发逻辑说明拦截规则支持正则表达式~u /api/order表示匹配 URL 中包含/api/order的请求。进入编辑界面后用方向键选择要修改的字段回车进入编辑Esc 退出编辑。参数说明修改请求体时注意 Content-Length 会自动更新但如果你手动改了头里的 Content-Length可能造成请求截断。重发时工具会新建一个连接不会复用原连接。3. 用 mitmproxy 搭一套可复现的监视环境3.1 安装与最小验证mitmproxy 支持 macOS、Linux、Windows安装方式有 pip、brew、apt、二进制包。我一般用 pip 装因为版本更新快而且能指定 Python 版本。# 用 pip 安装 mitmproxy pip install mitmproxy # 验证安装 mitmproxy --version # 输出示例Mitmproxy: 10.1.5 # Python: 3.11.4 # OpenSSL: OpenSSL 3.0.10逻辑说明pip 安装会自动处理依赖包括 cryptography、h2、kaitaistruct 等。参数说明如果系统里有多个 Python 版本建议用python3 -m pip install mitmproxy明确指定。安装完成后mitmproxy是交互式界面mitmdump是无界面命令行版mitmweb是 Web 界面版。排查问题时我常用mitmweb因为可以直观地看到请求列表和详情。3.2 客户端接入三种典型场景场景一本机浏览器。启动 mitmproxy 后浏览器设置 HTTP 代理为127.0.0.1:8080安装并信任 mitmproxy 根证书即可。场景二移动端 App。手机 Wi-Fi 设置代理指向电脑 IP 和 8080 端口下载证书后在系统设置里安装并信任。Android 7 以上需要把证书放到系统证书目录或者用 App 的网络安全配置允许用户证书。场景三服务端间调用。在调用方的 HTTP 客户端里设置代理或者用环境变量HTTP_PROXY和HTTPS_PROXY。# 在 Linux 服务端设置环境变量让 curl 走代理 export HTTP_PROXYhttp://127.0.0.1:8080 export HTTPS_PROXYhttp://127.0.0.1:8080 # 验证 curl -s https://httpbin.org/get | head -20逻辑说明环境变量方式对 curl、wget、python requests 等大多数工具生效。参数说明如果服务端调用的是内部 HTTPS 服务且证书是自签的还需要把 mitmproxy 根证书加到系统的 CA 信任链否则会报证书验证失败。另一种做法是在客户端代码里设置verifyFalse但这会引入安全风险只建议在测试环境用。3.3 过滤与保存别让无关流量淹没你默认情况下mitmproxy 会捕获所有经过代理的流量。如果客户端同时访问了几十个域名界面会很快被刷屏。用过滤表达式可以只显示关心的流量。# 只显示发往 api.example.com 的请求 # 在 mitmproxy 交互界面按 f 键输入过滤表达式 # 表达式~d api.example.com # 或者启动时直接指定 mitmweb --set view_filter~d api.example.com逻辑说明~d表示匹配域名~u表示匹配 URL~m表示匹配方法~c表示匹配状态码。多个条件可以用组合比如~d api.example.com ~m POST。参数说明view_filter只影响显示不影响捕获。如果要真正丢弃某些流量用--ignore-hosts参数支持正则表达式。保存流量到文件也很重要方便事后分析或分享给同事。# 把流量保存为 mitmproxy 自有格式 mitmdump -w traffic.mitm # 把流量导出为 HAR 格式可以用 Chrome DevTools 打开 mitmdump -w traffic.har --set hardumptraffic.har逻辑说明.mitm格式是 mitmproxy 私有的只能用 mitmproxy 读取但保存了最完整的信息。HAR 是通用格式Chrome DevTools、Fiddler 都能打开但会丢失一些 mitmproxy 特有的元数据。参数说明hardump是 mitmproxy 的一个插件选项需要确认版本支持。如果不支持可以用mitmdump -s export_har.py自定义脚本导出。4. 避坑API Monitor 部署中最容易翻车的五个点4.1 证书信任了但 HTTPS 还是解不开现象客户端已经安装了 mitmproxy 根证书但抓到的 HTTPS 请求显示为Client TLS handshake failed或直接显示加密流量。原因客户端使用了证书固定Certificate Pinning只信任特定证书或公钥不信任系统证书链。解决如果是自己开发的应用在测试包里关掉 Pinning如果是第三方应用考虑用 Frida 等工具绕过但这涉及合规问题只在授权测试中使用。另一个常见原因是 Android 7 以上把用户证书和系统证书分开App 默认只信任系统证书需要把 mitmproxy 证书放到系统证书目录或修改 App 的网络安全配置。4.2 代理开了但部分请求不经过代理现象浏览器流量能抓到但某个命令行工具或服务端程序的请求抓不到。原因这些工具不读系统代理设置需要显式配置。比如 Java 应用需要设置-Dhttp.proxyHost和-Dhttps.proxyHostGo 程序需要设置HTTP_PROXY环境变量Node.js 的 axios 需要设置proxy配置。解决先确认工具是否支持代理再按对应方式配置。如果工具完全不支持代理只能改用网卡嗅探模式或 Agent 嵌入模式。4.3 大响应体导致界面卡死现象mitmproxy 界面在收到一个几 MB 的 JSON 响应后无响应内存飙升。原因mitmproxy 默认会把完整响应体加载到内存并显示大文件会拖垮界面。解决用--set stream_large_bodies1m让超过 1MB 的响应体流式处理不加载到内存。或者在过滤规则里排除大文件接口。另一个做法是用mitmdump而不是mitmproxy因为命令行版不渲染界面内存占用低很多。4.4 修改请求后服务端返回 400现象拦截请求修改了 JSON 体放行后服务端返回 400 Bad Request。原因修改后的请求体长度变了但 Content-Length 头没有自动更新或者修改了签名相关的字段导致签名校验失败。解决mitmproxy 通常会自动更新 Content-Length但如果你手动改了头里的值就会不一致。检查方法是看请求头里的 Content-Length 是否等于实际体长度。如果是签名问题需要同时修改签名或关掉服务端的签名校验仅测试环境。4.5 代理端口被占用或防火墙拦截现象启动 mitmproxy 时报Address already in use或者局域网设备连不上代理。原因8080 端口被其他程序占用或者系统防火墙阻止了入站连接。解决换一个端口比如--listen-port 8888。防火墙问题在 Linux 上用iptables -L或ufw status检查在 Windows 上用“高级安全 Windows Defender 防火墙”检查入站规则。如果只是本机使用不需要开放防火墙监听127.0.0.1即可。5. 进阶用脚本把 API Monitor 变成自动化检查工具5.1 写一个 mitmproxy 插件拦截敏感字段mitmproxy 支持用 Python 写插件在请求或响应经过时执行自定义逻辑。一个典型场景是检查响应里是否包含手机号、身份证号等敏感信息如果发现就告警或阻断。# save as check_sensitive.py # 用法mitmdump -s check_sensitive.py import re from mitmproxy import http # 定义敏感信息正则 PATTERNS { phone: re.compile(r1[3-9]\d{9}), id_card: re.compile(r\d{17}[\dXx]), } def response(flow: http.HTTPFlow) - None: # 只检查 JSON 响应 content_type flow.response.headers.get(content-type, ) if application/json not in content_type: return body flow.response.get_text() if not body: return for name, pattern in PATTERNS.items(): matches pattern.findall(body) if matches: # 打印告警包含 URL 和匹配到的内容 print(f[ALERT] {name} found in {flow.request.url}) print(f matches: {matches[:3]}) # 只打印前3个逻辑说明response函数会在每个响应到达时被调用。flow.response.get_text()拿到响应体文本如果响应是压缩的mitmproxy 会自动解压。PATTERNS字典定义了要检查的敏感信息类型和对应正则。参数说明手机号正则1[3-9]\d{9}匹配中国大陆手机号身份证正则\d{17}[\dXx]匹配 18 位身份证。实际使用时可以根据业务调整正则比如加上银行卡号、邮箱等。注意这个脚本只告警不阻断如果要阻断可以把flow.response替换为一个自定义响应。5.2 用 mitmdump 做批量回归验证如果你有一组固定的 API 请求可以用 mitmdump 录制后回放对比响应差异。做法是先用mitmdump -w baseline.mitm录制基线流量修改代码后再录一次candidate.mitm然后用脚本对比两个文件里的响应。# save as diff_flows.py # 用法python diff_flows.py baseline.mitm candidate.mitm import sys from mitmproxy import io from mitmproxy.exceptions import FlowReadException def load_flows(path): flows {} with open(path, rb) as f: reader io.FlowReader(f) try: for flow in reader.stream(): if flow.request and flow.response: key f{flow.request.method} {flow.request.path} flows[key] flow.response.get_text() except FlowReadException as e: print(fError reading {path}: {e}) return flows def main(): baseline load_flows(sys.argv[1]) candidate load_flows(sys.argv[2]) all_keys set(baseline.keys()) | set(candidate.keys()) for key in sorted(all_keys): b baseline.get(key) c candidate.get(key) if b ! c: print(f[DIFF] {key}) if b is None: print( baseline: missing) if c is None: print( candidate: missing) if b and c: print(f baseline length: {len(b)}) print(f candidate length: {len(c)}) if __name__ __main__: main()逻辑说明FlowReader读取.mitm文件stream()逐条返回 flow 对象。用请求方法和路径作为 key响应体作为 value。对比时找出 key 相同但响应体不同的条目。参数说明这个脚本假设请求路径里不包含查询参数如果包含需要把flow.request.path换成flow.request.pretty_url。另外如果响应体是二进制或压缩的get_text()可能返回 None需要先判断。5.3 把监视数据接入现有可观测性平台mitmproxy 插件可以把关键指标推送到 Prometheus、OpenTelemetry 等平台。比如统计每个接口的响应时间、状态码分布、请求体大小然后暴露为 Prometheus 指标。# save as metrics.py # 用法mitmdump -s metrics.py from mitmproxy import http from prometheus_client import Counter, Histogram, start_http_server # 定义指标 REQUEST_COUNT Counter( api_requests_total, Total API requests, [method, path, status] ) REQUEST_DURATION Histogram( api_request_duration_seconds, API request duration, [method, path] ) def response(flow: http.HTTPFlow) - None: method flow.request.method path flow.request.path.split(?)[0] # 去掉查询参数 status str(flow.response.status_code) REQUEST_COUNT.labels(methodmethod, pathpath, statusstatus).inc() if flow.response.timestamp_end and flow.request.timestamp_start: duration flow.response.timestamp_end - flow.request.timestamp_start REQUEST_DURATION.labels(methodmethod, pathpath).observe(duration) # 启动 Prometheus 指标端点 start_http_server(9091)逻辑说明Counter和Histogram是 Prometheus 的两种指标类型。Counter只增不减适合统计请求数。Histogram记录数值分布适合统计耗时。start_http_server(9091)在 9091 端口暴露/metrics端点Prometheus 可以抓取。参数说明path去掉了查询参数避免指标基数爆炸。如果接口路径里有动态 ID比如/api/order/123还需要进一步归一化否则每个 ID 都会生成一个指标。可以用正则替换数字为{id}。5.4 一个我常犯的错误早期我用 mitmproxy 时习惯把所有流量都录下来觉得“数据越多越好”。结果一次排查中.mitm文件涨到 2GB打开时 mitmproxy 直接 OOM。后来我改成按需录制先用过滤规则只录关心的域名再用--set stream_large_bodies1m限制大文件最后定期清理旧文件。另一个教训是不要在生产环境长期开着代理模式抓包因为代理本身会成为单点故障而且明文流量落盘有合规风险。测试环境用完就关生产环境用采样或 Agent 模式。希望帮到你。本文还有配套的精品资源点击获取