从已知可用的 QQ 版本 9.9.12-25493(偏移值 0xA996E0)中找到签名函数的真实名称。
方式 A: 如果已安装旧版本 QQ
路径: C:\Program Files\Tencent\QQ\resources\app.asar.unpacked\node_modules\wrapper.node
方式 B: 下载旧版本
- 从 QQ 官网下载历史版本
- 或从网盘/镜像站获取
- 安装后提取 wrapper.node 文件
方式 C: 使用备份
- 检查是否有系统备份或快照
- 从备份中提取 wrapper.node
- x64dbg (推荐): https://x64dbg.com/
- IDA Pro (可选): https://hex-rays.com/
- PE-bear (可选): https://github.com/hasherezade/pe-bear
1. 打开 x64dbg (x64 版本)
2. 文件 → 打开
3. 选择 9.9.12-25493 的 wrapper.node
4. 等待加载完成
加载后,记录模块基址,例如:180000000
已知偏移值: 0xA996E0
模块基址: 0x180000000 (示例)
函数地址 = 基址 + 偏移
= 0x180000000 + 0xA996E0
= 0x180A996E0
使用 Windows 计算器(程序员模式)进行计算。
1. 在 x64dbg 中按 Ctrl+G
2. 输入计算后的地址: 180A996E0
3. 按回车跳转
到达地址后:
方式 A: 查看当前位置
- 右键 →
在符号中跟随 - 或右键 →
标签→ 查看函数名
方式 B: 查看导出表
- 按
Ctrl+E打开导出表 - 查找地址为
180A996E0的函数 - 记录函数名称
方式 C: 查看反汇编窗口顶部
- 函数开头通常会显示函数名或标签
- 例如:
wrapper.?FunctionName@@...或sub_A996E0
验证这是签名函数:
; 应该看到类似这样的代码:
wrapper+A996E0:
48 89 5C 24 08 mov [rsp+8], rbx ; 保存寄存器
48 89 6C 24 10 mov [rsp+10], rbp
48 89 74 24 18 mov [rsp+18], rsi
57 push rdi
48 83 EC 50 sub rsp, 50 ; 分配栈空间
; 参数处理
48 8B F1 mov rsi, rcx ; cmd (第1个参数)
48 8B EA mov rbp, rdx ; src (第2个参数)
4C 8B F0 mov r14, r8 ; src_len (第3个参数)
44 8B F9 mov r15d, r9d ; seq (第4个参数)确认特征:
- ✅ 有 5 个参数的使用
- ✅ 函数体较大(数百字节)
- ✅ 包含复杂的位运算和循环
- ✅ 操作字节数组
安装了 Visual Studio 或 Visual Studio Build Tools
-
打开 Visual Studio Developer Command Prompt
开始菜单 → Visual Studio → Developer Command Prompt -
运行 dumpbin
cd "路径\到\wrapper.node所在目录" dumpbin /EXPORTS wrapper.node > exports.txt
-
分析输出文件
打开
exports.txt,查找 RVA 为A996E0的导出:ordinal hint RVA name 1 0 00001000 node_register_module 2 1 00A996E0 ?可能的函数名? -
记录函数名
找到对应 RVA 的函数名称
1. 打开 IDA Pro (64-bit)
2. File → Open
3. 选择 9.9.12-25493 的 wrapper.node
4. 选择 PE64 格式
5. 等待自动分析完成
1. 按 G (跳转)
2. 输入地址: imagebase+A996E0
或直接输入: .text:00000000A996E0
3. 按回车
到达地址后:
查看函数窗口:
View→Open subviews→Functions- 找到偏移为
A996E0的函数 - 查看函数名列
查看反编译代码:
- 在函数地址处按
F5反编译 - 查看函数签名和名称
// 可能看到类似这样的代码:
__int64 __fastcall sign_function_name(
const char *cmd,
const unsigned char *src,
unsigned __int64 src_len,
int seq,
unsigned char *result)
{
// 函数实现
}1. View → Open subviews → Exports
2. 或按 Shift+F7
3. 查找 RVA 为 A996E0 的导出
4. 记录函数名
pip install pefile创建文件 find_sign_function.py:
import pefile
import sys
# wrapper.node 文件路径
wrapper_path = r"C:\path\to\9.9.12-25493\wrapper.node"
# 已知的偏移值
TARGET_OFFSET = 0xA996E0
try:
pe = pefile.PE(wrapper_path)
print("=" * 70)
print("分析 wrapper.node (9.9.12-25493)")
print("=" * 70)
print(f"\n目标偏移值: 0x{TARGET_OFFSET:X}")
print()
# 查找导出函数
if hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'):
print("导出函数列表:")
print("-" * 70)
print(f"{'序号':<6} {'RVA':<12} {'名称'}")
print("-" * 70)
found = False
for export in pe.DIRECTORY_ENTRY_EXPORT.symbols:
ordinal = export.ordinal
address = export.address
name = export.name.decode() if export.name else f"Ordinal_{ordinal}"
# 检查是否是目标函数
if address == TARGET_OFFSET:
print(f"{ordinal:<6} 0x{address:08X} {name} ⭐⭐⭐ 找到了!")
found = True
else:
print(f"{ordinal:<6} 0x{address:08X} {name}")
if found:
print()
print("=" * 70)
print("✅ 成功找到偏移值对应的函数!")
print("=" * 70)
else:
print()
print("⚠️ 未在导出表中找到该偏移值")
print("可能是内部函数(未导出)")
else:
print("❌ 未找到导出表")
except Exception as e:
print(f"❌ 错误: {e}")
sys.exit(1)python find_sign_function.py示例:
序号 RVA 名称
5 0x00A996E0 sign
或
5 0x00A996E0 createSign
或
5 0x00A996E0 doSignature
下一步:
- 记录函数名称
- 验证函数签名(5个参数)
- 在 9.9.20 版本中查找同名函数
示例:
5 0x00A996E0 ?sign@WrapperClass@@QEAAHPEBDPEBEKHPEAE@Z
解码 Mangled Name:
使用在线工具:https://demangler.com/
或使用命令行:
undname "?sign@WrapperClass@@QEAAHPEBDPEBEKHPEAE@Z"解码后可能得到:
public: int __cdecl WrapperClass::sign(char const *, unsigned char const *, unsigned __int64, int, unsigned char *)
示例:
5 0x00A996E0 Ordinal_5
说明:
- 函数未导出名称,只有序号
- 需要通过序号在 9.9.20 中查找
- 或通过汇编代码特征匹配
说明:
- 函数可能是内部函数(static)
- 未被导出到 DLL 外部
- 只能通过特征码匹配
解决方案:
- 记录函数的汇编特征码
- 在 9.9.20 中搜索相同的特征码
- 或使用 BinDiff 等工具对比两个版本
-
在 9.9.20 的 wrapper.node 中查找同名函数
- 使用 x64dbg 打开 9.9.20 的 wrapper.node - 按 Ctrl+E 查看导出表 - 搜索相同的函数名 - 记录新版本中的偏移值 -
如果函数名相同但偏移不同
- 这是正常的(版本更新导致地址变化) - 使用新版本的偏移值 - 更新 sign.cpp 中的 addrMap -
如果找不到同名函数
- 函数可能被重命名 - 或被内联/优化 - 需要通过特征码匹配
-
解码后在 9.9.20 中查找
- 查找相同的类和方法名 - 注意参数类型可能略有变化
-
在 9.9.20 中查找相同序号
- 序号通常保持一致 - 但不是绝对的 - 需要验证函数特征
如果函数未导出或名称改变,可以使用特征码:
在 x64dbg 中:
- 跳转到 9.9.12-25493 的函数地址 (0xA996E0)
- 选择函数开头的 16-32 字节
- 右键 →
二进制→复制选择 - 记录字节序列,例如:
48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 50
- 打开 9.9.20 的 wrapper.node
- 右键 →
搜索→序列 - 输入特征字节码
- 查找匹配项
- 记录新的偏移值
找到函数后,请填写以下信息:
=== 签名函数信息 ===
9.9.12-25493 版本:
函数名称: [填写]
偏移值: 0xA996E0
导出序号: [填写]
9.9.20-37051 版本:
函数名称: [填写]
偏移值: [待确定]
导出序号: [填写]
函数特征码:
[前16字节的十六进制]
验证状态:
[ ] 函数名匹配
[ ] 参数数量正确 (5个)
[ ] 特征码相似
[ ] 测试通过
✅ 立即执行:
- 用 x64dbg 打开 9.9.12-25493 的 wrapper.node
- 按 Ctrl+E 查看导出表
- 查找 RVA 为
A996E0的函数 - 记录函数名
- 告诉我结果!
⏭️ 替代方案:
- 直接在 9.9.20 中测试已知偏移值
- 使用试错法找到正确偏移
- 或等待社区分享 9.9.20 的信息
💡 最快的方法:
- 如果能访问 9.9.12 版本,用 x64dbg 的 Ctrl+E 查看导出表最直接
- 只需要 1-2 分钟就能找到函数名
💡 如果找到函数名:
- 立即分享给我
- 我们可以在 9.9.20 中快速定位
- 提高成功率!
喵~ 准备好了就开始吧!🐾