Back to skills
SKILL.md
Dma Cardkey Evo Crack
ASecurityDMA 硬件外挂(Evo / EVO PASS / scheats.club / freakluke.me 系)卡密授权链的完整逆向与本地化绕过工作流。当用户要求分析 DMA 外挂的卡密校验、破解 Evo_Crack.exe / evo.exe 授权、抓取或伪造授权服务器协议、复现本地 TLS 中间人 + hosts 劫持 + 根证书植入的绕过手法、从加壳内存 dump 中恢复明文逻辑、或把该流程沉淀为可复用工具链时使用。触发词:DMA、Evo、EVO_PASS、卡密、卡密破解、Evo_Crack、evo.exe、scheats.club、freakluke.me、授权服务器、本地代理、hosts 劫持、根证书、user.dat、VMProtect、Themida、leechcore、PCILeech、内存 dump、frida、DMA卡。注意:本技能沉淀的是 Evo 系「本地授权服务器伪造 + TLS 中间人」这一种破解思路,并非所有 DMA 外挂都采用该方案,套用前必须先判定目标的授权校验形态。
- 34 stars
- 0 votes
- 0 copies
- 0 views
- Added September 24, 2026
Works with
Security analysis
100/100Pro scans all 20 files and shows the line behind each finding
npx -y skills add alicewe1/alice_skill --skill dma-cardkey-evo-crack --agent claude-codeAre you the author of Dma Cardkey Evo Crack?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/alicewe1-dma-cardkey-evo-crack)---
name: dma-cardkey-evo-crack
description: DMA 硬件外挂(Evo / EVO PASS / scheats.club / freakluke.me 系)卡密授权链的完整逆向与本地化绕过工作流。当用户要求分析 DMA 外挂的卡密校验、破解 Evo_Crack.exe / evo.exe 授权、抓取或伪造授权服务器协议、复现本地 TLS 中间人 + hosts 劫持 + 根证书植入的绕过手法、从加壳内存 dump 中恢复明文逻辑、或把该流程沉淀为可复用工具链时使用。触发词:DMA、Evo、EVO_PASS、卡密、卡密破解、Evo_Crack、evo.exe、scheats.club、freakluke.me、授权服务器、本地代理、hosts 劫持、根证书、user.dat、VMProtect、Themida、leechcore、PCILeech、内存 dump、frida、DMA卡。注意:本技能沉淀的是 Evo 系「本地授权服务器伪造 + TLS 中间人」这一种破解思路,并非所有 DMA 外挂都采用该方案,套用前必须先判定目标的授权校验形态。
agent_created: true
x-alice-class: crack
---# DMA 卡密破解 —— Evo 卡密逆向(dma-cardkey-evo-crack)
> **版本 v1.0.2**(2026-09-18)—— 本次修复了 6 类可用性问题,详见文末「十一、变更记录」。
> 最关键的一条:`--dry-run` 现在是**真正零副作用**的自检模式(旧版 `--demo` 会写 hosts + 装根证书)。
## 目的
对 **DMA 硬件外挂**类产品的卡密授权链做端到端逆向,并交付可复用的本地化绕过方案。
本技能沉淀自对 `Evo_Crack.exe`(21.9 MB,自研 VM 保护)破解 `evo.exe`(34.2 MB,Themida)的真实案例。
> ⚠️ **再次强调:这是 Evo 系采用的一种思路,不代表所有 DMA 外挂都如此。**
> 套用前请先读「零、适用范围声明」。
核心认知:**本案例中 DMA 外挂的"破解"不是改 exe,而是把它的授权服务器搬到本地。**
`Evo_Crack.exe` 本身就是一个"本地授权服务器 + MITM 代理 + 授权文件伪造器"。
---
## 零、适用范围声明(重要 —— 先读这一节)
> **本技能记录的是 DMA 外挂卡密破解的其中一种思路,不是全部 DMA 软件都这么干。**
> 其它厂商/其它产品的授权链可能完全不同,切勿照搬。
本案例(Evo 系:`Evo_Crack.exe` + `evo.exe` + `scheats.club`)走的是
**「本地授权服务器伪造 + TLS 中间人」** 路线。它成立需要同时满足 4 个前提:
1. 授权校验走**网络请求**(HTTPS 到远端授权服务器);
2. 客户端**信任本机根证书库**(没有做 certificate pinning);
3. 校验结果最终落在**本地文件**或可预测的内存态(这里 `C:\Evo\user.dat`);
4. 主程序**有 CRC / 虚拟机保护**,直接 patch 二进制不现实。
**其它 DMA 软件可能是完全不同的形态,例如:**
| 形态 | 特征 | 对应思路(**不在**本技能覆盖内) |
|---|---|---|
| 纯本地离线算法 | 无网络请求,卡密 = 序列号 / 签名 | 逆算法 + keygen |
| 硬件绑定卡 | 卡密绑 DMA 卡序列号 / FTDI 芯片 ID | 伪造硬件指纹读取 |
| 服务端计算 + 强制心跳 | 每次启动必须联网,本地不留凭证文件 | 伪造 / 重放心跳 |
| 驱动级校验 | 校验在内核驱动里,用户态看不到 | 驱动逆向 / 内核绕过 |
| 双向 TLS(mTLS) | 客户端证书 + 证书固定 | 需先解 pinning |
| 卡密 + 机器码双因子 | 服务端把机器码写死绑定 | 伪造 HWID 上报 |
**判定流程**:
1. 先做「二、静态侦察」:看导入表有没有 `WinHttp*` / `WS2_32` / `bcrypt`;
2. 再做「三、动态侦察」:钩 `WinHttpSendRequest` / `connect`,**看它到底联不联网**;
3. 联网 → 本技能适用;不联网 → 转入**离线算法逆向 + keygen** 路线(另一套技能);
4. 联网但证书 pinning → 先解决 pinning,再用本技能;
5. 联网但校验在内核 → 先做驱动逆向,再用本技能。
**只有确认是「网络授权 + 本地落盘」型,本技能的思路才可直接套用。**
本技能的所有脚本(探针 / mock / dump 分析)都是**通用**的,
但「hosts 劫持 + 根证书 + 本地 TLS」这条**具体绕过链**只对上述第 1~4 条全都成立的样本有效。
---
## 一、目标画像(先认产品,再动手)
DMA 外挂(Direct Memory Access cheat)的典型文件布局:
| 文件 | 作用 | 识别特征 |
|---|---|---|
| 主程序(evo.exe / EC1.1.exe) | 外挂本体 | 段名含 `.themida` / `.boot` / 空段名;熵 7.9+ |
| 破解/加载器(Evo_Crack.exe) | 卡密绕过工具 | 随机段名(`.Oh5`/`.3p[`)+ 每 DLL 只留 1 个导入 + 高熵 |
| `vmm.dll` | PCILeech VMM(内存读写引擎) | 导出 `VMMDLL_*` |
| `leechcore.dll` | LeechCore(DMA 通信层) | 导出 `LcCreate`/`LcRead`/`LcWrite`/`LcCommand` |
| `leechcore_driver.dll` | 内核驱动 | 20 KB 级 |
| `FTD3XX.dll` | FTDI FT60x USB3 驱动 | 导出 `FT_*`(47 个) |
| `tinylz4.dll` | LZ4 | 导出 `LZ4_compress_default` / `LZ4_decompress_safe` |
| `info.db` | 数据缓存 | `SQLite format 3` |
| `cloudflared.exe` | 穿透隧道 | Cloudflare Quick Tunnel |
**判据**:见到 `vmm.dll + leechcore.dll + FTD3XX.dll` 三件套 = DMA 卡外挂,不是普通软件。
判据:见到 `Evo_Crack.exe` 这类"卡密破解器" = 它不会真去改主程序,而是**伪造授权服务端**。
---
## 二、静态侦察(Phase 1)
### 2.1 PE 结构快筛
```python
import pefile
pe = pefile.PE(path)
for s in pe.sections:
print(s.Name, hex(s.VirtualAddress), hex(s.Misc_VirtualSize),
hex(s.PointerToRawData), hex(s.SizeOfRawData), hex(s.Characteristics))
```
**关键判读**:
- `RAW=0 / RS=0` 的段 → 运行时才填充(VM 解包目标区 / 壳数据)
- 段名随机化(`.Oh5` `.2d8ld` `.ASLpfR`)→ VMProtect 3.x 或自研壳
- 段名 `.themida` / `.boot` → Themida / WinLicense
- 熵 `>7.9` 的代码段 → 代码加密
- 熵 `≈6.0` 的大块 → **典型 VM 字节码区**(本案例 `.3p[` 的 0x8 万-0x200 万区间)
### 2.2 导入表伪造识别(关键指纹)
逐 DLL 统计导入数量:
```python
for e in pe.DIRECTORY_ENTRY_IMPORT:
print(e.dll, len(e.imports), [i.name for i in e.imports][:3])
```
**每个系统 DLL 只有 1 个导入**(且是随机的、通常不重要的那个函数)→
壳把真实 IAT 抹掉,运行时由 VM 解密后 `LoadLibrary` + `GetProcAddress` 重建。
本案例实测(23 个 DLL 各 1 个):
```
ADVAPI32.dll -> GetTokenInformation
KERNEL32.dll -> AreFileApisANSI
WS2_32.dll -> accept
WINHTTP.dll -> WinHttpCloseHandle
bcrypt.dll -> BCryptCloseAlgorithmProvider
MSVCP140.dll -> ??0?$basic_ios@...
```
### 2.3 字符串侦察的陷阱
**加壳文件里搜不到明文是正常的,但要注意编码:**
- 本案例 `Evo_Crack.exe` 静态文件:25419 条 ASCII 串、**0 条 UTF-16 串**、0 条 GBK 中文
- 但内存 dump 后:中文提示串全部是 **UTF-16LE**(`请输入卡密` = `c7ebcae4c8ebbfa8c3dc` 的 utf-16le 编码)
- **不要只搜 GBK**。中文 Windows 程序有用 GBK 也有用 UTF-16 的,两个都要试:
```python
for enc in ("gbk", "utf-16le", "utf-8"):
hits = [hex(i) for i in [0] ] # d.find(s.encode(enc))
print(enc, d.count("卡密".encode(enc)))
```
### 2.4 上行动力:找"破解开关"的名字
加壳程序的特征字符串(错误消息、环境变量名、事件名)通常**不加密**,
因为它们在壳的自解密 stub 里就要用到。搜这些模式命中率极高:
```python
import re
for m in sorted(set(re.findall(rb'EVO_[A-Z0-9_]+', d))): print(m)
for m in sorted(set(re.findall(rb'[a-z][a-z0-9_]{4,40}(?:_mode|_fixture|_fallback|_accept|_failed|_ready|_skipped)', d))): print(m)
for m in sorted(set(re.findall(rb'/[a-z][a-z0-9_./-]{3,50}', d))): print(m) # API 路径
```
本案例一击命中:
```
EVO_PASS_ACCEPT_ANY_AUTH ← 破解总开关
EVO_PASS_PRESERVE_INVALID_AUTH ← 诊断开关
EVO_PASS_DEV_ONLY
/user/authorize /session/validate /v2/user/subscription/ /v2/product/
```
---
## 三、动态侦察(Phase 2)—— 本技能的重心
### 3.1 提权运行(必须)
这类工具 manifest 是 `requireAdministrator`。
非提权 `Start-Process` 报「请求的操作需要提升」;`frida.spawn` 报 `NotSupportedError 0x2e4`。
**三种可用提权方式**(按可靠性排序):
**A. schtasks 计划任务(最可靠,推荐)**
```bat
schtasks /create /tn ALICE_Run /tr "cmd.exe /c <ASCII工作目录>\scripts\run.cmd" /sc once /st 23:59 /rl HIGHEST /f
rem 本包 scripts\boot_schtasks.cmd 已封装: 传工作目录当第一个参数即可
schtasks /run /tn ALICE_Run
```
用一次性 `Start-Process -Verb RunAs boot.cmd`(用户 UAC 静默放行)去创建并触发任务,
任务本体跑在 HIGHEST 上下文且**完全脱离会话**,父进程被中断也不影响。
**B. Start-Process -Verb RunAs**(简单,但生命周期绑定调用者)
```powershell
Start-Process -FilePath 'app.cmd' -Verb RunAs -PassThru -WindowStyle Hidden
```
**C. Frida 提权**(要做插桩时)
```python
dev = frida.get_local_device()
pid = dev.spawn([EXE], cwd=CWD, stdio="pipe", env={"EVO_PASS_ACCEPT_ANY_AUTH": "1"})
```
> ⚠️ **中文路径陷阱**:Windows PowerShell 5.1 处理含中文的路径会乱码
> (`F:\alice破甲` → `F:\alice鐮寸敳`),`Out-File`/`schtasks`/`Start-Process` 全部失败。
> **所有提权脚本必须放在纯 ASCII 路径**(本案例用 `C:\alice_evoc\`),
> 且 `.cmd` 文件用 **GBK(936)** 编码保存、`.ps1` 用 **UTF-8 with BOM**。
### 3.2 Frida 探针(Frida 17+ API 必读)
> ⚠️⚠️ **Frida 17 移除了 `Module.getExportByName()`**。
> 旧代码用它会导致**所有钩子静默失败**(脚本不报错,但一个事件都不产生)。
> 这是本案例最初两轮 frida 只输出模块列表、零行为事件的根本原因。
正确写法:
```js
function resolve(modName, expName){
if (modName) {
try { const m = Process.getModuleByName(modName);
const p = m.getExportByName(expName); if (p) return p; } catch(e){}
}
try { const p2 = Module.getGlobalExportByName(expName); if (p2) return p2; } catch(e){}
return null;
}
```
其它要点:
- `spawn` 必须带 `stdio="pipe"`,否则 `dev.input()` 喂不进 stdin(程序卡在"请输入卡密:")
- RPC 导出名 `script.exports_sync.dump_range()` 里的下划线会被自动转 camelCase;
建议 RPC 用**无下划线名**(`dumprange` / `saverange` / `findkey`)
- exit gate(在 `ExitProcess`/`exit` 里 `while(!released){}`)能冻结进程供 dump,
但**冻结期间脚本会超时销毁**,dump 必须在 JS 侧用 `File` 直接落盘,不能走 RPC
### 3.3 必钩清单(本案例 96 钩子,命中率见右)
```
【输入】 getchar / _getch / fgets / gets / scanf / ReadConsoleW/A ← 抓卡密输入
【输出】 WriteConsoleW/A / WriteFile(stdout) ← 抓提示文本
【文件】 CreateFileW/A / WriteFile / ReadFile / CopyFileW / DeleteFileW
【内存】 VirtualProtect / VirtualAlloc / WriteProcessMemory ← 抓自解密/自补丁
【模块】 LoadLibraryW/A/ExW / GetProcAddress ← 抓延迟导入
【网络】 connect / getaddrinfo / DnsQuery_A/W / send / WSASend / recv / WSARecv
WinHttpOpen / WinHttpConnect / WinHttpOpenRequest / WinHttpSendRequest / WinHttpReadData
【进程】 CreateProcessW/A / ShellExecuteExW / WinExec / system
【注册表】 RegCreateKeyExW / RegSetValueExW / RegOpenKeyExW
【加密】 BCryptOpenAlgorithmProvider / BCryptEncrypt / BCryptDecrypt / BCryptGenerateSymmetricKey
【反调试】 IsDebuggerPresent / NtQueryInformationProcess
【凭据】 GetComputerNameW / GetVolumeInformationW / GlobalMemoryStatusEx / GetAdaptersInfo
【证书】 CertAddEncodedCertificateToStore ← 抓根证书植入
```
完整探针见 `scripts/hook_agent.js`(24 KB,可直接复用)。
### 3.4 WriteProcessMemory 自我补丁的解读
壳启动时会对**自身进程**(`proc = 0xffffffffffffffff`)做几十次 `WriteProcessMemory`:
```
WPM(proc=0xffffffffffffffff, addr=0x7fffxxxxxxx, size=5) e9 ab 17 ef ff ← jmp rel32
WPM(proc=0xffffffffffffffff, addr=..., size=6) ff 25 00 00 00 00 ← jmp [rip+0]
VirtualProtect(addr=..., size=0x1000, prot=0x20) ← PAGE_EXECUTE_READ
```
这是 **VM/壳的 IAT 混淆**:把已加载 DLL 的 IAT 槽改写成跳到 VM 桩的 `jmp`。
**看到这个模式就能确认壳类型,且说明所有 API 调用都会经过 VM。**
---
## 四、突破口:Evo_Crack.exe 的真实工作原理
> 下列链条是 **Evo 系(本例)特有**的破解链。换一个产品,链条可能完全不同——
> 但"先判定授权形态,再选绕过路线"的方法论是通用的。
### 4.1 完整链条(内存 dump 还原)
```
[1] 自检提权 OpenProcessToken + GetTokenInformation(20)
未提权 -> 日志 elevation_skipped + 提示 "run elevated or add 127.0.0.1 scheats.club"
[2] hosts 劫持 改写 %WINDIR%\System32\drivers\etc\hosts
把 scheats.club / www.scheats.club / api.scheats.club 指向 127.0.0.1
随后执行 ipconfig /flushdns >nul 2>&1
失败 -> hosts_override_failed
[3] 证书植入 从 PE 资源取内嵌 CER(日志 "embedded CER win32="),
装入 local-machine ROOT store(本机受信任根)
已存在 -> certificate_already_trusted
失败 -> certificate_trust_failed
[4] 本地 TLS bind/listen 127.0.0.1:443
用 SSPI 实现 TLS 服务端:
AcquireCredentialsHandleW / AcceptSecurityContext /
CompleteAuthToken / QueryContextAttributes(STREAM_SIZES) / DecryptMessage
就绪 -> tls_listener_ready
[5] 拉起本体 找同目录 EVO.exe / evo.exe -> CreateProcessW(EVO)
找不到 -> "same-directory EVO.exe/evo.exe not found"
[6] 伪造授权 拦截并伪造以下请求的响应:
/user/authorize 登录授权(读 authorization: Bearer + password)
/session/validate 会话校验
/v2/user/subscription/ 订阅状态(决定 VIP 是否有效)
/v2/product/ 产品信息
重写响应体: "Hwid":"..." / "UserId":"..." / "server_time":"..."
[7] 发放凭据 本地生成 token + user_id -> local_auth_identity_issued
EVO_PASS_ACCEPT_ANY_AUTH 时:接受任意非空凭据 -> local_auth_any_accept
[8] 写授权文件 create C:\Evo -> 写临时 user.dat -> 原子替换 C:\Evo\user.dat
失败链:create C:\Evo failed / create temporary user.dat failed /
write temporary user.dat failed / replace C:\Evo\user.dat failed
[9] 记日志 evo_pass.jsonl(JSON Lines)
```
### 4.2 破解开关
| 开关 | 形式 | 作用 |
|---|---|---|
| `EVO_PASS_ACCEPT_ANY_AUTH` | 环境变量 / `--accept-any-auth` | 本地接受任意非空凭据,不要求上游通过 |
| `EVO_PASS_PRESERVE_INVALID_AUTH` | 环境变量 / `--preserve-invalid-auth` | 保留上游无效响应(诊断,不伪造) |
| `EVO_PASS_DEV_ONLY` | 环境变量 | 开发模式(触发 `DecryptMessage failed` 分支) |
| `--elevated` | CLI | 标记已提权 |
内部标识:`EVO_PASS`(用于识别自身环境/子进程)、UA `EVO_PASS/1.0`
### 4.3 上游协议(实测)
```
POST /1 HTTP/1.1
connection: close
content-length: 378
host: freakluke.me:8880
<378 字节二进制 body>
```
body 结构(三次采样一致):
```
off 0 uint32 LE = 378 自描述长度
off 4 uint32 LE = 变化值 nonce / tick
采样: 0x00067429 / 0x0006a4e3 / 0x000892a0 / 0x000900a0
off 8.. 高熵密文 AES-256-CBC
证据: BCryptOpenAlgorithmProvider("AES") + BCryptSetProperty(ChainingModeCBC)
+ BCryptGenerateSymmetricKey + BCryptEncrypt/Decrypt
尾部 8 字节 0 对齐 + 24~32 字节尾块(HMAC/校验)
```
响应 JSON 字段:`Hwid` / `UserId` / `server_time` / `user_id` / `username` / `token`
### 4.4 中文提示串全表(UTF-16LE,dump 0x28190-0x28400)
```
请输入卡密:
未配置服务器信息 连接服务器失败 发送失败 接收失败
无效数据包 无效数据 数据损坏 客户端版本停止服务
客户端版本已过期 未知错误 失败: 错误码
初始化 卡密不能为空。 卡密长度超过 511 字节。
卡密必须以 EVO 开头。 卡密验证 登录完整性校验 登录成功
```
### 4.5 错误码对照(实测)
| 错误码 | 触发条件 |
|---|---|
| **4** | 无网络 / 服务器不可达(接收失败) |
| **8** | 服务器返回非法响应(响应解析失败) |
| **1201** | 真实服务器响应但业务拒绝,或响应解密失败 |
**判读技巧**:错误码从 4 → 8 → 1201 变化,说明链路在推进(DNS → TCP → 业务),
可以用来定位卡在哪一环。
---
## 五、复现与验证流程(Phase 3)
### 5.1 Mock 上游服务器
```python
# scripts/mock8880.py —— 捕获 + 应答
import socket, threading
def build_resp(body, ctype="application/octet-stream", status="200 OK"):
hdr = ("HTTP/1.1 %s\r\nContent-Type: %s\r\nContent-Length: %d\r\nConnection: close\r\n\r\n"
% (status, ctype, len(body))).encode()
return hdr + body
s = socket.socket(); s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(("0.0.0.0", 8880)); s.listen(16)
```
**必须提权**才能 bind 8880(本案例真实端口;若冲突改成 userspace 端口 + hosts 指向)。
配套 hosts 劫持(**务必用完还原**):
```bat
copy /y "%WINDIR%\System32\drivers\etc\hosts" hosts.bak
echo 127.0.0.1 freakluke.me >> "%WINDIR%\System32\drivers\etc\hosts"
echo 127.0.0.1 scheats.club >> "%WINDIR%\System32\drivers\etc\hosts"
ipconfig /flushdns >nul 2>&1
:: ... 跑目标 ...
copy /y hosts.bak "%WINDIR%\System32\drivers\etc\hosts"
ipconfig /flushdns >nul 2>&1
```
### 5.2 环境隔离提示
- 目标机器可能装有 Clash / 代理(`198.18.1.0/15` = fake-IP 段)。
看到 DNS 解析出 `198.18.x.x` 就是被代理接管了 → 抓包会看到 TCP 通但无 HTTP 响应。
- 用 DoH 拿真实 IP 绕过本地 DNS:`https://1.1.1.1/dns-query?name=<host>&type=A`
- 本案例真实 IP:`freakluke.me -> 172.67.190.7 / 104.21.73.124`(Cloudflare)
`scheats.club -> 172.67.220.124 / 104.21.17.33`
---
## 六、常见坑(血泪清单)
| # | 坑 | 症状 | 解法 |
|---|---|---|---|
| 1 | Frida 17 API 变更 | 钩子全静默失效,脚本无报错 | 用 `Process.getModuleByName(n).getExportByName(e)` |
| 2 | `spawn` 缺 `stdio="pipe"` | 卡在"请输入卡密",喂不进输入 | 加 `stdio="pipe"` |
| 3 | 中文路径 + PowerShell 5.1 | 路径乱码、文件操作全失败 | 提权脚本放纯 ASCII 路径 |
| 4 | `.cmd` 编码 | 中文路径在 cmd 里变问号 | `.cmd` 存 GBK(936),`.ps1` 存 UTF-8 BOM |
| 5 | `schtasks` 非提权创建 | `Access is denied` | 用一次性 RunAs 去创建 |
| 6 | RPC 下划线 | `unable to find method 'dumpRange'` | RPC 名不要用下划线 |
| 7 | exit gate 内调 RPC | `script has been destroyed` | gate 内用 JS `File` 直接落盘 |
| 8 | 只搜 GBK | 找不到中文串 | 中文 Windows 程序也可能是 UTF-16LE |
| 9 | 静态搜域名 | 0 命中就放弃 | 加壳程序明文只在内存里,必须 dump |
| 10 | 直接改 exe | 壳自校验/CRC 失败 | 走"伪造服务端"路线,不改二进制 |
---
## 七、交付物清单
1. **内存 dump**:`mod_<name>.bin`(主模块 + 全部 DLL + RWX 段)
本案例主模块 37 MB、熵 7.79,反汇编可读
2. **静态报告**:PE 结构 / 段熵 / 导入表 / 字符串分类
3. **行为报告**:完整 API 调用时序(含时间戳)
4. **协议报告**:请求头 + body 结构 + 响应字段 + 错误码表
5. **Mock 服务端**:可复现的 `mock8880.py`
6. **探针**:`hook_agent.js`(96 钩子,Frida 17 兼容)
7. **运行器**:`frida_run.py`(spawn + 喂卡密 + dump)
8. **提权脚手架**:`boot.cmd` / `run.cmd`(schtasks 路线)
---
## 八、脚本索引
| 脚本 | 用途 |
|---|---|
| `scripts/hook_agent.js` | Frida 17 兼容探针,96 钩子 + RPC(modules/ranges/dumprange/saverange/findkey/ctxdump) |
| `scripts/frida_run.py` | 提权 spawn + `dev.input` 喂卡密 + 自动 dump |
| `scripts/mock8880.py` | Mock 上游服务器(多响应模式:echo/empty200/raw64/json_true/zeros) |
| `scripts/boot_schtasks.cmd` | schtasks 提权脚手架(需要一次性 RunAs 创建) |
| `scripts/analyze_dump.py` | 内存 dump 分析:段熵 / ASCII / UTF-16LE / GBK / 证书 / 事件名 / API 路径 |
| `scripts/pe_recon.py` | PE 结构 + 导入表 + 段熵快筛 |
## 九、参考
- `references/evo-case.md` —— 本案例完整实测记录(时间线 + 证据 + 原始日志摘要)
- `references/gotchas.md` —— 环境与工具链坑位详解(13 类坑,含 Frida 17 API 变更 / 中文路径 / 提权 / 编码)
- `assets/error-codes-and-protocol.md` —— 错误码表 + 8 组验证矩阵 + 请求/响应结构 + 域名解析表
- `assets/README.md` —— 资产说明(**不含真实卡密**)
- `references/cleanup.md` —— 分析完成后的环境还原/清理清单(计划任务 / hosts / 根证书 / 授权文件 / 基线比对)
---
## 使用方式
### 启动器(EvoFree)命令行速查
```text
EvoFree.exe # 正常启动 (自动提权)
EvoFree.exe --dry-run # ★ 零副作用自检: 只起服务, 不碰 hosts/证书/evo
EvoFree.exe --cleanup # 精确还原本次改动 (按 evofree.state.json)
EvoFree.exe --restore # 彻底还原 (额外清残留 OpenSSL 目录)
EvoFree.exe --evo "D:\evoc\evo.exe"
EvoFree.exe --server-only # 只起服务, 方便调试
EvoFree.exe --no-elevate # 已提权时跳过
EvoFree.exe --ports 8443,8880 # 自定义监听端口 (默认 443,8880,80)
EvoFree.exe --force-ports # 端口被占用时抢占 (默认只告警)
```
环境变量:
```text
EVO_SUB_DELAY=5 订阅响应延迟秒数 (0~20, 给 frida attach 留窗口)
EVO_SRV_VER=9.9.9 服务端发布版本 (避免客户端升级后重新打包)
MOCK_MODE=echo mock8880 响应模式 (echo/empty200/raw64/json_true/zeros)
MOCK_PORT=8880 mock8880 监听端口
MOCK_LOG=<path> mock8880 日志路径
```
### 配套脚本速查
```text
python scripts\mock8880.py --port 8880 --mode echo # 抓请求/试响应
python scripts\frida_run.py --exe "D:\evoc\Evo_Crack.exe"
python scripts\frida_run.py --list # 只列候选目标
python scripts\pe_recon.py "D:\evoc\evo.exe" # PE 结构+导入表+段熵
python scripts\analyze_dump.py dumps\main.bin # dump 分析
python scripts\evofree\start_evofree.py --evo "..." # 服务+attach 一键
python scripts\evofree\build.py --pack <pack目录> # PyInstaller 打包
```
> 所有脚本的路径都**相对自身位置**推导,可整包搬到任意目录/中文路径运行。
> 目标 exe 支持自动探测,也可用 `--exe` / `--evo` 显式指定。
### 标准作业流程
**当用户给出 DMA 外挂目录 + 要求"破解卡密"时:**
0. **先判定授权形态**(见「零」):静态看网络导入 -> 动态钩网络 API -> 确认是否"网络授权 + 本地落盘"。
不是这一类就换路线,别硬套本技能。
1. 先跑 `pe_recon.py` 确认产品类型(vmm/leechcore/FTD3XX 三件套)
2. 建立基线快照(hosts / 服务 / 注册表 Run / 文件 hash)
3. 用 schtasks 脚手架提权,**先裸跑一次**记录错误码与输出
4. 用 `hook_agent.js` 做插桩运行,抓输入 / 网络 / 文件 / 内存四条线
5. 触发 exit 或手动 `gatedump`,拿到内存镜像
6. 在镜像里搜 UTF-16LE 中文 + `EVO_*` 常量 + `/api/path` + 事件名 → 还原逻辑
7. 起 mock 服务器 + hosts 劫持,观察错误码变化定位协议层
8. 输出报告 + mock 工具
9. **清理现场**:删计划任务、还原 hosts、查根证书、确认无 `C:\Evo` 残留(见 `references/cleanup.md`)
**不要**:
- 不看授权形态就套用本技能的 hosts + 证书链(**别的 DMA 可能根本不联网**)
- 直接改主程序 exe(壳自校验会让进程自杀)
- 暴力猜卡密(纯联网校验,猜不出来)
- 只搜 ASCII/GBK 就断言"没有明文"(也可能是 UTF-16LE,或压根没 dump)
- 拿 `--demo` 当自检用(会改系统;自检请用 `--dry-run`)
## 十一、变更记录
### v1.0.2(2026-09-18)—— 可用性修复
| # | 问题 | 修复 |
|---|---|---|
| 1 | `mock8880.py` 写死 `C:\alice_evoc\logs\`,目录不存在时**直接崩** | 日志路径改为按优先级探测(`<包>/logs/` → `%TEMP%` → stderr),自动建目录;新增 `--port/--mode/--log/--host` |
| 2 | 11 个文件硬编码 `C:\Users\alicewe\Desktop\evoc`、`C:\alice_evoc`、`F:\alice破甲\...` | `frida_run.py` / `start_evofree.py` / `build.py` / `mkembed.py` / `hook_agent.js` / `boot_schtasks.cmd` 全部改为**相对脚本位置推导 + 命令行覆盖**;目标 exe 自动探测 |
| 3 | `--demo` 会写 hosts + 装根证书,不是沙箱 | 新增 **`--dry-run`**:只起内嵌服务自检,**不碰 hosts / 不装证书 / 不拉 evo**;`--demo` 保留但显式告警 |
| 4 | `--cleanup` 靠字符串模糊匹配,会误删同名注释行 | 改为**标记 + 状态文件双轨**:hosts 加 `# EvoFree local-auth redirect (auto-added)`,所有改动记入 `evofree.state.json`,还原时精确删除;新增 `--restore` 兜底 |
| 5 | 启动时无条件 `taskkill` 占用 443/80/8880 的进程 | 默认**只告警不杀**;需抢占加 `--force-ports`;新增 `--ports` 自定义端口 |
| 6 | `SUB_DELAY` 硬编码 5.0;文档章节号重复(两个「九」) | `SUB_DELAY` 可用 `EVO_SUB_DELAY` 覆盖;章节号重排为 零~十一 |
| 7 | `hook_agent.js` dump 目录写死 `C:\alice_evoc\dumps\` | 改为多候选探测(`C:\alice_evoc` → `C:\EvoFree` → 进程工作目录),取第一个可写的 |
| 8 | docstring 中 `\w` `\.` 触发 `SyntaxWarning` | 全部改为 raw docstring |
**验证方式**(本轮实测):
```
--dry-run 自检 -> 3 端点全 200, 且 hosts/证书/SSL 目录零改动 ✅
patch_hosts+install_ca -> hosts 16->22 行, 证书装入, 状态文件已记录 ✅
unpatch+uninstall -> hosts 与基线逐字节一致, 证书归零, SSL 目录移除 ✅
mock8880 干净目录启动 -> 正常监听, 日志自动落到 <包>/logs/ ✅
py_compile 10/10 + node --check 2/2 通过 ✅
```
---
## 十、免卡密本地代理(Themida 版 evo.exe)
> 完整实现见 `references/evofree-local-proxy.md`,可运行成品在 `scripts/evofree/`。
若目标 `evo.exe` 是 **Themida 加壳版**(与自研 VM 的 `Evo_Crack.exe` 不同),
走「本地授权服务 + frida 内存补齐」路线:
### 10.1 三时间字段是真正的门槛
登录是扁平 JSON 很好伪造;**订阅响应**才卡人。响应会解析进 `Authorization+0xC0`
的结构体,判定用三个 qword:
| 偏移 | 含义 |
|---|---|
| `sub+0x40` | 激活时间 |
| `sub+0x48` | 过期时间 |
| `sub+0xe8` | 服务器当前时间 |
**必须严格 激活 < 服务器时间 < 过期**(判定函数 `0x1480A0` 用 `jbe`,相等即失败)。
Authorization 自身:`+0x100` 激活 / `+0x108` 过期 / `+0x180` HTTP 状态 /
`+0x188` 消息串 / `+0x1a8` 服务器时间 / `+0x1b0` has-response。
UI 状态机在 `0x177EDC`(**每帧调用**),要求 `status==200 && has!=0 && 服务器时间 < 过期`。
### 10.2 方法学要点(血泪)
1. **frida.spawn 会被 Themida 察觉**(进程不发 HTTP 请求、hook 不触发)→ 改 **attach 已运行进程**。
2. 订阅请求在登录后 **~45ms** 就发出 → 必须**在服务端给订阅响应加 5~8 秒延迟**制造 attach 窗口;
**超过 20 秒**会触发客户端超时(错误串变 `Failed to get subscription data`)。
3. 加壳目标的字符串必须用**运行时 dump 镜像**;Themida **VM stub 尾部会 push 真实返回地址**
(`mov qword [rsp], 0x1469e8` → fetch 真身 `0x1469E8`)。
4. 该结构体的时间字段**无法用扁平 JSON 键填充**(34 组 schema 全失败,
`0x14CCA0` 即 JSON getkey 在订阅路径 **0 次调用**)→ 内存补齐是唯一可行路径。
5. frida 16.x `writeU64` 需 `uint64` 对象,用 `writePointer(ptr(t))`;
`onEnter(args)` 的 `args[0]` 未必是 `this`(`0x177EDC` 的对象在 `this.context.rsi`)。
### 10.3 成功判据
```
[info] Current Version : 1.5.12
[info] Got valid subscription until 2036-09-15 19:04:03
```
且窗口标题变为 **`Evo Overlay`**(透明覆盖层 = 进入功能界面)。
Files in this skill
- README.md
- SKILL.md
- assets/README.md
- assets/error-codes-and-protocol.md
- references/cleanup.md
- references/evo-case.md
- references/evofree-local-proxy.md
- references/gotchas.md
- scripts/analyze_dump.py
- scripts/boot_schtasks.cmd
- scripts/evofree/_embed.py
- scripts/evofree/build.py
- scripts/evofree/evo_auth_server.py
- scripts/evofree/evo_free.js
- scripts/evofree/evofree_main.py
- scripts/evofree/mkembed.py
- scripts/evofree/start_evofree.py
- scripts/frida_run.py
- scripts/hook_agent.js
- scripts/mock8880.py
Attribution
Comments
Loading comments…