Back to skills
SKILL.md
Re Crypto Keys
ASecurity密钥与口令提取:硬编码、内存搜索、资源。 触发词:找密钥、硬编码、key extraction、口令
- 112 stars
- 0 votes
- 0 copies
- 0 views
- Added September 19, 2026
Security analysis
92/100- Installs packages at runtime which could introduce malicious dependencies
npx -y skills add dslsdzc/rev-skills --skill re-crypto-keys --agent claude-codeAre you the author of Re Crypto Keys?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/dslsdzc-re-crypto-keys)---
name: re-crypto-keys
description: >
密钥与口令提取:硬编码、内存搜索、资源。
触发词:找密钥、硬编码、key extraction、口令
capabilities: [key-extraction]
---
# 密钥与口令提取
## 何时使用 / 何时不用
- 用:需要解密数据/流量但不知道密钥时(静态优先:硬编码 → 资源 → 导入表;动态:内存转储)
- 用:确认样本是否硬编码了密钥/口令(配置提取)
- 用:密钥是运行时派生的(PBKDF/HKDF)需要还原派生过程
- 不用:算法都还没确认(先 [[re-crypto-id]])
- 不用:密钥通过外部配置/服务器下发(没有本地密钥可提取——诚实告诉用户,见坑 2)
- 不用:只做静态格式分析([[re-triage]] / [[re-format-pe]])
## 工具准备
所有工具先验证再使用。静态搜索可免沙箱;内存转储/动态环节按 [[re-memdump]] 默认转储优先 + [[re-analyze/platform-tips]] 最高原则(运行样本进沙箱)。
### strings —— 可打印串快速扫描(全平台)
- Linux: `apt install binutils` / `dnf install binutils` / `pacman -S binutils`(多数自带)
- macOS: 系统自带 /usr/bin/strings
- Windows/WSL: WSL 内 Linux 版;Windows 本机用 Ghidra 或 `strings.exe`(Sysinternals)
- 验证: `strings --version`(GNU 版有 --version)
### ghidra / rizin —— 反编译与交叉引用搜索(安装见 [[re-ghidra]] / [[re-radare2]])
- 搜索常量/字符串的交叉引用是找"谁用了这个密钥"的关键
- 验证: `ghidra`(GUI)或 `rz-ghidra` 插件可用;`rizin -v`
### 转储产物 —— 内存搜索原料([[re-memdump]] 默认转储)
- 按 [[re-memdump]] 步骤 1 用 `gcore -o out <pid>` 转储;转储时机按明文/代码 materialization 定(单层壳 OEP 附近通常合适,OEP 非通用判据,见 [[re-analyze/platform-tips]] 关键经验)
- 验证: `file out` 确认为 ELF core,`eu-stack -e out` 能跑
### python3 —— 熵块/模式扫描脚本
- 安装与验证见 [[re-proto-rev]] 工具准备(python3)
## 操作步骤
按顺序执行,每步记下结果。策略顺序:**先静态后动态**(见坑 3),每步产物(密钥/口令 + 来源证据:偏移、函数名、转储路径)记录供 [[re-crypto-decrypt]] 使用。
1. **静态:strings / 交叉引用找硬编码**:
```sh
strings -n 6 sample.bin | grep -iE 'key|secret|pass|token|crypt|iv' | head -50
strings -el sample.bin | grep -iE 'key|secret|pass' | head -20 # UTF-16LE(Windows 常见)
strings -n 8 sample.bin | head -100 # 全量扫描人工过一遍
```
- 可疑串(看起来像密钥的固定串)用反编译器查交叉引用:[[re-ghidra]] / [[re-ida]] 右键 Find References——看它被哪个函数读、怎么参与运算(直接进加密参数 → 是密钥;参与查表/比较 → 是口令或盐)
- 反编译器里搜常量(`Search > Memory` / `:> /v 0x...`):32 字节十六进制串、重复的随机数据段
- 十六进制侧: 用 [[re-crypto-id]] 步骤 1 的脚本找 AES S-box 等常量表后,表附近的内存数据常是密钥材料
2. **内存:转储后搜密钥模式(16/32 字节熵块、口令可打印串)**:
```sh
gcore -o out <pid> # 默认转储([[re-memdump]]),按 materialization 定时机
```
```python
data = open('out','rb').read()
import collections, math
# 16/32 字节高熵块(AES-128/256 密钥候选)
def ent(blk):
c = collections.Counter(blk); n = len(blk)
return -sum((v/n)*math.log2(v/n) for v in c.values())
for base in range(0, len(data)-32, 32):
blk = data[base:base+32]
if ent(blk) > 7.0 and 16 <= len(set(blk)) <= 24:
print(f"0x{base:x}: 32B 高熵块")
# 口令/可打印串
import re
for m in re.finditer(rb'[ -~]{8,64}', data):
s = m.group()
if any(k in s.lower() for k in (b'key', b'pass', b'secret', b'pwd')):
print(f"0x{m.start():x}: {s}")
```
- 高熵块命中太多(整个堆都是)→ 结合 [[re-memdump]] 的 maps/偏移缩小到加密上下文附近,或先用步骤 4 的导入表定位函数再取参数
- 密钥可能在堆/栈上碎片化或异或混淆(见坑 1)——找到后先在解密脚本里验证一次([[re-crypto-decrypt]] 步骤 4)
3. **资源文件(.rsrc / 嵌入 blob)**:
- PE: 用 `llvm-objdump -s -j .rsrc sample.exe` 或 Ghidra 看资源段;`7z x sample.exe` 可解出嵌入的 icon/version/自定义资源
- ELF: 找 `.rodata` 里的嵌入 blob(`objdump -s -j .rodata`);结合 [[re-firmware]] 经验——固件里密钥常在配置文件/默认证书里
- 嵌入 blob 可能是序列化配置(JSON/INI 编码的密钥字段),先按文本解析再按二进制挖;blob 是加密的(高熵)→ 回 [[re-crypto-id]],外层可能还有一层解密
4. **导入表线索(Crypt* 函数附近)**:
- `objdump -p sample.exe | grep Crypt` / Ghidra Imports 窗口找 `CryptEncrypt`/`CryptDecrypt`/`BCrypt*`/`RSA*`/`EVP_*`(OpenSSL)
- 找到后反编译该函数:密钥参数(handle/KEYEXCHANGE 结构)通常来自"前面某处设置的固定值"——从函数上溯数据流:常量赋值、全局变量初始化、`CryptSetKeyParam` 的 `pbKeyData` 参数
- 设断点观察参数更直接([[re-gdb]] / [[re-x64dbg]]): `b CryptSetKeyParam` 后看 `pbKeyData` 指向的内存——但注意 [[re-analyze/platform-tips]] 最高原则:运行进沙箱
5. **密钥派生函数(PBKDF)还原**:
- 反编译里认出 `PBKDF2`/`scrypt`/`bcrypt`/`EVP_BytesToKey` 调用 → 密钥 = KDF(口令, 盐, 迭代次数),逐参数提取:口令(硬编码串或用户输入)、盐(固定字节或上下文)、迭代次数(常量)
- 写还原脚本(`pip install cryptography` / `hashlib` 自带 PBKDF2):
```python
import hashlib
key = hashlib.pbkdf2_hmac('sha256', b'passphrase', b'<salt>', 100000, dklen=32)
print(key.hex())
```
- 验证: 派生的 key 与步骤 2 内存里的高熵块一致(说明 KDF 跑完的密钥就在那),或直接用 [[re-crypto-decrypt]] 试解已知密文
- 动态补充: Frida hook KDF 函数看返回 buffer(沙箱内,[[re-sandbox]]),比对静态还原结果
## 跨域联合
- [[re-protocol]]:本网关工作流第 3 步(密钥)——加密通信解密链路的中段(crypto-id → crypto-keys → crypto-decrypt)
- [[re-malware]]:C2 配置提取(硬编码 C2 密钥/口令)——re-malware 第 4 步的密钥环节;恶意样本密钥常埋在配置里([[re-behavior]] 行为确认 + 本技能提取)
- [[re-firmware]]:固件内硬编码口令/密钥挖掘——re-firmware 第 3 步(rootfs 配置/默认证书)
- [[re-memdump]]:默认转储是本技能内存搜索的原料([[re-analyze/platform-tips]] 直读 vs 转储决策表)
- [[re-crypto-decrypt]]:下游——提取的密钥交给解密脚本验证与使用
- [[re-anti-analysis]]:壳内密钥先脱壳(按 materialization 定 dump 点,见 [[re-memdump]] 转储时机)
- [[re-ioc]]:提取出的硬编码密钥/口令可作 YARA 特征与 IOC
## 常见坑与陷阱
- **密钥分片存储/异或混淆**:现象——提取的单块"密钥"解不出明文,或字符串/内存里找不到完整密钥;原因——样本把密钥拆成多段(分片)或与常量异或后存储,运行时重组;对策——反编译找重组逻辑:密钥字节来自多个偏移/多次异或(见坑 3 的"先查硬编码"流程里,确认硬编码时要看引用处的运算);还原出候选后在 [[re-crypto-decrypt]] 里逐个试
- **真随机密钥 ≠ 可从静态提取**:现象——静态/内存搜索全无收获,用户仍要密钥;原因——密钥是启动时 `RAND_bytes` 生成或服务器下发,根本不在样本里(白盒攻击之外无解);对策——诚实报告:本地无可提取密钥,改走密钥派生拦截(hook `RAND_bytes`/KDF 输入)、算法侧攻击(若解密结果可被已知明文验证)或回 [[re-malware]] 看密钥是否由 C2 下发
- **先查是否硬编码再上动态**:现象——样本硬编码了密钥,却先跑沙箱+Frida 折腾半天;原因——没有按静态优先顺序执行;对策——步骤 1 strings/交叉引用是 30 秒检查,静态命中直接跳过动态;动态只在静态无果、且需要运行时材料(KDF 输入、重组逻辑)时上(见 [[re-analyze/platform-tips]] 静态优先思路与最高原则)
- **转储时机过早拿不到运行时密钥**:现象——内存搜索找不到任何高熵块或找到的都对不上;原因——在壳解密/密钥初始化前 dump(拿到的是壳的初始状态,见 [[re-memdump]] 坑 2);对策——确认明文/密钥已 materialize(经典单层壳在 OEP 后、执行过加密调用;多阶段/按需解密按「写→执行转移 + payload 头/导入恢复」判断)再 gcore;必要时在加密函数断点触发后再 dump([[re-gdb]] 配合)
- **内存密钥候选模式漏 AES-192**:现象——高熵块只按 16/32 字节搜,24 字节密钥漏检,解密对不上;原因——AES-128/256 的 16/32 字节是常见假设,AES-192 密钥恰为 24 字节(轮数 12);对策——高熵块搜索窗口覆盖 16/24/32 三档(配合 [[re-crypto-id]] 的轮数 10/12/14 判断定参数),候选命中后先在 [[re-crypto-decrypt]] 试解验证
- **勒索类样本密钥即用即销,事后 dump 必然为空**:现象——确认样本执行过加密,但任何内存转储里都搜不到密钥材料;原因——勒索软件在加密完成后立即清零密钥(wipe),密钥只在加密执行阶段短暂存在于内存(NotPetya/BadRabbit/Phobos 实验可画出密钥存在时间线);对策——在加密阶段(业务逻辑运行中)做多次快照 dump 对比构建时间线,或配合 [[re-gdb]] 在加密函数返回前断住抓参数,比单一事后 dump 可靠
- **密钥明文只在特定执行瞬间出现,转储必错过**:现象——转储搜索无果,但动态跟踪能看到密钥出现;原因——部分样本的主密钥在内存里只在极短窗口以明文存在(如浏览器 v20_master_key 只在解密瞬间出现,VoidStealer 即靠硬件断点抓这一点);对策——先定位密钥使用点(加密函数/派生点),在其上设硬件断点([[re-gdb]]/[[re-x64dbg]],不依赖断点指令)实时截获明文,比"转储后大海捞针"高效
Attribution
Comments
Loading comments…