EA破解揭秘:关于MT4/5EA的限制教学

| 发表于 昨天 17:23 | 显示全部楼层 |复制链接
本文为技术研究性质的科普文章,仅供安全研究人员了解 MetaTrader 平台的编译与加载机制。不提供任何可编译的完整工具源码,仅讨论方法论。


一、一个被误解的事实

大多数交易者以为 .ex4/.ex5 文件只是一层简单的 XOR。实际上,从 Build 600 开始,MetaQuotes 引入了两级密钥派生机制。

首次加载时,terminal.exe 会在 kernel32!VirtualAlloc 返回的堆内存中构造一个 64 字节的 MQLCipherContext。这个结构体我曾在 x64dbg 里追过:

0x00245220  E8 12 00 00 00        call  terminal.00245237
0x00245225  48 8B 4F 18           mov   rcx, [rdi+0x18]
0x00245229  48 8D 15 D8 3F 6C 01  lea   rdx, [terminal.01909208]

[rdi+0x18] 指向解密后的 Section Table。0x01909208 这个 RVA 在不同 Build 之间会漂移,所以不能直接写死一个绝对地址去 patch。

真正有趣的发生在 0x016CDB3C 附近。如果在这个位置下硬件断点,会发现每次 call rdx 之前,rcx 指向的结构体里已经有了解密后的 EA 字节码。换句话说,MT5 的 VM 在执行前一刻才完成解密,执行完立刻重新加密。

这就是为什么"在磁盘上改 EX5"这条路不通——你改的是密文,而 runtime 解密后立刻执行,根本没有窗口去 patch 明文。


二、内存驻留补丁的原理

绕过上面那套机制的核心思路,不是去破解加密算法本身。而是在解密完成、VM 执行之前的那几微秒里,把已经解密的数据替换掉。

说得再直白一点:

terminal.exe
  ├─ 解密 EX5 → 明文字节码(仅存在于寄存器+栈,小于 50ms)
  │      │
  │      └─ 在这个窗口期,外部进程通过 OpenProcess(0x1F3FFF)
  │         写入 E9 xx xx xx xx 90 90 90
  │         把 VM dispatch 的入口劫持到自己的 stub page
  │
  └─ VM 继续执行 → 但已经走的是劫持后的逻辑了

这个过程中有几个关键的结构体偏移需要处理。比如 stub 的元数据布局:

  +0x78  被 patch 的 VA(8 bytes)
  +0x88  模板函数指针(8 bytes)  ← 这个指回 EXE 自身 .rdata 段的常量表
  +0xA8  原始 8 字节备份

+0x88 的函数指针根据不同的 EA 品牌会指向不同的模板:福袋系指向 0x0040AAA0,金龙系指向 0x0040D7E7。这就是为什么市面上看起来差不多的辅助工具,有的对你手里的 EA 有效,有的完全没用——它们的模板表不匹配。
三、为什么不同 EA 需要不同模板

EA 的授权检查有几种常见形态。以 StringFind 边界匹配和 datetime 常量比较为例:

形态 A:逗号分隔白名单

  StringFind("," + list + ",", "," + login + ",")

这种的破解不是"把 417135966 改成你的账号"那么简单。因为比较逻辑是子串匹配,你必须在运行时把 list 字符串原地替换为"当前登录号 + 逗号 + 填充",并且等长覆盖——多写或少写一个字节都会破坏邻接的常量表,导致 EA 初始化直接 INIT_FAILED。

形态 B:datetime 直接比较

  if(TimeCurrent() > D'2026.05.17 23:59') return FAILED;

这种常量的十六进制表示是 time_t 的 little-endian 编码。在 x64 dbg 里可能会看到类似:

  48 B8 C0 C5 34 6A 00 00 00 00    mov rax, 0x6A34C5C0

0x6A34C5C0 就是 2026-05-17 23:59:00 UTC 的 Unix 时间戳。但直接搜这个 DWORD 往往搜不到——因为编译器可能把它拆成 mov eax, 0x6A34C5C0; shl rax, 32 这种两指令形式。


四、跨进程操作的工程细节

EA 辅助工具的核心流程:

  1. CreateToolhelp32Snapshot → 枚举 terminal64.exe
  2. OpenProcess(0x1F3FFF)     → 获取 VM 读写权限
  3. 在 .text 段扫特征码:
     4C 8B 79 18 48 89 61 28 FF D2 EB 18
     (这段指令是 MT5 内部的 MQL dispatch 入口)
  4. 定位到 RVA 0x016CDB3C(当前 Build,随版本变化)
  5. VirtualAllocEx → 目标进程分配 RWX stub page
  6. WriteProcessMemory → 写入 stub 机器码
  7. 原入口写 14 字节绝对跳 FF 25 + abs64

有个容易忽略的点:VirtualAllocEx 在 64 位进程里可能分配到距离目标入口超过正负 2GB 的位置。这时候 E9 rel32 就跳不到——必须改用 FF 25 加 8 字节绝对地址。很多网上的开源工具栽在这。
五、盲扫 vs 定向补丁

如果没有 EA 的源码,就需要"盲扫"——在目标进程的所有可读内存里搜索符合授权数据特征的字节序列。

启发式规则大概长这样:

  候选日期: 匹配 /20[2-3]\d\.(0[1-9]|1[0-2])\.(0[1-9]|[12]\d|3[01])/
  候选账号: 匹配 /\d{5,12}(,\d{5,12})+/
  候选失败文案: UTF-16LE 的中文字符串,hash 后与已知文案库对比

盲扫的局限也很明显——如果 EA 用的是 int64 数值比较而不是字符串,或者白名单是通过 DLL 做远程校验的,纯字符串扫描就打不到。这也是为什么商业级的辅助工具需要针对每个 EA 做单独的模板适配。

ScreenShot_2026-07-20_172230_153.png
六、总结

  阶段        做的事                难点
  文件分析    识别 EX4/EX5 加密层    Build 600+ 多级密钥
  运行时定位  扫特征码找 dispatch    ASLR + 版本差异
  内存补丁    写 stub + JMP          64 位远跳用 FF25
  数据修改    替换授权串/时间戳      等长约束 + 竞态窗口
  通用适配    盲扫 + 启发式          单账号/数值形态难命中
欢迎大家评论区踊跃评论探讨,以上内容仅为平时工作遇到的情况,

无偿分享给大家

本文仅讨论 MetaTrader 平台的编译和内存管理机制。文中涉及的技术描述均为公开的 Windows 进程管理 API 和 x86-64 汇编知识。不提供任何可运行的完整工具。
ScreenShot_2026-07-20_172346_872.png
举报

评论 使用道具

精彩评论2

maxprint
D
| 发表于 昨天 20:43 | 显示全部楼层
高手,完全看不懂
举报

点赞 评论 使用道具

menghuan
DD
| 发表于 2 小时前 | 显示全部楼层
高手,扛不动
举报

点赞 评论 使用道具

发新帖
EA交易
您需要登录后才可以评论 登录 | 立即注册