Skip to content

Latest commit

 

History

History
326 lines (243 loc) · 7.23 KB

File metadata and controls

326 lines (243 loc) · 7.23 KB

查找 wrapper.node 签名函数完整指南

目标

找到 wrapper.node 中签名函数的:

  1. 函数名称(如果有导出名称)
  2. 函数地址
  3. 偏移值(地址 - 模块基址)

方法一:x64dbg 查看导出表(最直接)

Step 1: 加载文件

1. 打开 x64dbg (x64)
2. 文件 → 打开
3. 选择: C:\Program Files\Tencent\QQ\resources\app.asar.unpacked\node_modules\wrapper.node

Step 2: 查看导出表

方式 A: 菜单方式
- 符号 → 导出表
- 或按快捷键 Ctrl+E

方式 B: 符号窗口
- 点击底部的 "符号" 标签
- 找到 wrapper.node 模块
- 展开查看导出函数

Step 3: 分析导出函数

在导出表中,你会看到类似这样的列表:

序号  地址          名称                    模块
----  ------------  ---------------------   ----------
1     180001000     node_register_module    wrapper
2     180002000     napi_register_module    wrapper
3     180A9CE90     ?可疑的签名函数?         wrapper
...

寻找目标函数的线索:

  1. 函数名包含关键字

    • sign, Sign, SIGN
    • encrypt, Encrypt
    • hash, Hash
    • token, Token
    • crypto, Crypto
  2. 地址在已知偏移附近

    • 如果地址是 180A9CE90,模块基址是 180000000
    • 偏移 = A9CE90,这正好是我们要找的!
  3. C++ mangled name

    • ?@ 开头
    • 例如:?sign@Wrapper@@QEAAHPEBD...
  4. 序号导出

    • 只有序号,没有名称
    • 需要逐个检查

Step 4: 验证函数

双击可疑的函数名,跳转到该地址,检查:

正确的函数特征:

; 函数序言
wrapper+A9CE90:
48 89 5C 24 08    mov qword ptr [rsp+8], rbx      ; 保存寄存器
48 89 6C 24 10    mov qword ptr [rsp+10], rbp
48 89 74 24 18    mov qword ptr [rsp+18], rsi
57                push rdi
48 83 EC 50       sub rsp, 50                      ; 分配栈空间

; 参数使用
48 8B F1          mov rsi, rcx                     ; 第1个参数 cmd
48 8B EA          mov rbp, rdx                     ; 第2个参数 src
4C 8B F0          mov r14, r8                      ; 第3个参数 src_len
44 8B F9          mov r15d, r9d                    ; 第4个参数 seq
; 第5个参数 result 在栈上 [rsp+...]

函数体特征:

  • 大量的位运算(and, or, xor, shl, shr)
  • 循环结构(loop, jne, jmp)
  • 内存操作(movzx, movsx)
  • 可能有加密算法特征(MD5, SHA 的魔数常量)

方法二:使用 dumpbin(命令行)

前提条件

安装了 Visual Studio 或 Visual Studio Build Tools

操作步骤

  1. 打开 VS 开发者命令提示符

    • 开始菜单 → Visual Studio → Developer Command Prompt
  2. 运行 dumpbin

    cd "C:\Program Files\Tencent\QQ\resources\app.asar.unpacked\node_modules"
    dumpbin /EXPORTS wrapper.node
  3. 查看输出

    Microsoft (R) COFF/PE Dumper Version ...
    
    File Type: DLL
    
      Section contains the following exports for wrapper.node
    
        ordinal hint RVA      name
    
              1    0 00001000 node_register_module
              2    1 00A9CE90 ?SignFunction...
    
  4. 记录信息

    • RVA (相对虚拟地址) = 偏移值
    • 例如:00A9CE90 就是偏移值 0xA9CE90

方法三:使用 Python 脚本自动化

安装 pefile 库

pip install pefile

运行脚本

创建 find_exports.py

import pefile
import sys

# wrapper.node 路径
dll_path = r"C:\Program Files\Tencent\QQ\resources\app.asar.unpacked\node_modules\wrapper.node"

try:
    pe = pefile.PE(dll_path)
    
    print("=" * 60)
    print("wrapper.node 导出函数列表")
    print("=" * 60)
    print()
    
    if hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'):
        print(f"{'序号':<6} {'RVA':<12} {'名称'}")
        print("-" * 60)
        
        for export in pe.DIRECTORY_ENTRY_EXPORT.symbols:
            ordinal = export.ordinal
            address = hex(export.address) if export.address else "N/A"
            name = export.name.decode() if export.name else f"Ordinal_{ordinal}"
            
            print(f"{ordinal:<6} {address:<12} {name}")
            
            # 高亮可疑函数
            if export.name:
                name_lower = export.name.decode().lower()
                if any(keyword in name_lower for keyword in ['sign', 'encrypt', 'hash', 'token', 'crypto']):
                    print(f"  ^^^ 可疑函数!可能是签名函数")
    else:
        print("未找到导出函数")
    
    print()
    print("=" * 60)
    
except Exception as e:
    print(f"错误: {e}")
    sys.exit(1)

运行:

python find_exports.py

方法四:IDA Pro 查看(专业工具)

Step 1: 加载文件

1. 打开 IDA Pro (64-bit)
2. File → Open
3. 选择 wrapper.node
4. 等待自动分析完成

Step 2: 查看导出函数

1. View → Open subviews → Exports
2. 或按 Shift+F7
3. 查看导出函数列表

Step 3: 分析函数

1. 双击函数名跳转到函数
2. 按 F5 查看反编译代码
3. 分析函数参数和逻辑

反编译代码示例:

__int64 __fastcall sign_function(
    const char *cmd,
    const unsigned char *src,
    unsigned __int64 src_len,
    int seq,
    unsigned char *result)
{
    // 签名处理逻辑
    // ...
    return 0;
}

常见情况处理

情况 1: 找到了明确的函数名

例如找到:doSigncreateSignature

操作:

  1. 记录函数名和偏移值
  2. 更新项目代码,添加函数名注释
  3. 测试该偏移值是否正确

情况 2: 只有序号导出

例如:Ordinal_15(没有函数名)

操作:

  1. 逐个检查序号导出的函数
  2. 根据函数特征判断(5个参数、复杂逻辑)
  3. 记录序号和偏移值

情况 3: C++ mangled name

例如:?sign@WrapperClass@@QEAAHPEBD@Z

操作:

  1. 使用 demangler 解码
  2. 理解函数的真实名称和参数
  3. 记录原始 mangled name 和偏移值

情况 4: 没有找到明显的签名函数

可能原因:

  • 函数没有导出(内部函数)
  • 使用了模糊命名
  • 函数通过其他方式调用

解决方案:

  • 使用动态调试附加到 QQ 进程
  • 设置内存断点捕获签名调用
  • 分析调用栈找到函数地址

记录模板

找到函数后,请记录以下信息:

=== 签名函数信息 ===

QQ 版本: 9.9.20-37051
模块名称: wrapper.node
模块基址: 0x180000000 (示例)

函数名称: [在此填写函数名]
函数地址: 0x180A9CE90 (示例)
偏移值: 0xA9CE90

函数特征:
- 参数数量: 5
- 返回类型: int
- 函数大小: 约 XXX 字节

验证状态:
[ ] 已验证函数序言正确
[ ] 已验证参数使用
[ ] 已在配置文件中测试
[ ] 签名功能正常工作

下一步

找到函数信息后:

  1. 更新 sign.json 配置

    {
      "version": "9.9.20-37051",
      "offset": "0xA9CE90"
    }
  2. 编译并测试

    cmake --build --preset=msvc-release
    start.bat
  3. 验证服务

    http://localhost:8080/ping
    
  4. 分享给社区

    • 在 GitHub Issues 中分享你的发现
    • 帮助其他使用相同 QQ 版本的用户