雪重 Python Developer 知识 汗水 灵感 机遇
2021年8月19日   spider 小程序逆向

微信小程序逆向(一)解包反编译

小程序抓到包,发现加密参数,无从下手怎么办?以xhs为例,学习下如何搞定一个小程序的加密参数。首先我们需要看到代码逻辑,不能凭空想象。

1.手机小程序文件位置

手机连接电脑,进入adb shell su,手机需要root(也可以使用模拟器)

/data/data/com.tencent.mm/MicroMsg/{这是一串hash,每个人不一样}/appbrand/pkg

在pkg文件夹下,我们可能发现多个.wxapkg文件,如果你是刚点开过微信小程序,那么就选择时间最近的那个文件(大小一般在1-2M)

image-20210819214912070

可以运行adb命令,将整个pkg文件夹拷贝到电脑上来

adb pull /data/data/com.tencent.mm/MicroMsg/{这是一串hash,每个人不一样}/appbrand/pkg ./

2.PC小程序文件位置

获取手机小程序文件步骤比较繁琐,下面介绍另一种方式,frida hook pc微信,直接找到小程序文件位置

# -*- coding: UTF-8 -*-
# @Time : 2021/3/2 17:56

import frida
import sys

# 生成文件路径 C:\Users\{User}\Documents\WeChat Files\Applet\...

def on_message(message, data):
    pass

def main(target_process):
    session = frida.attach(target_process)
    script = session.create_script("""
var baseAddr = Module.findBaseAddress('WeChatAppHost.dll');
console.log('WeChatAppHost.dll baseAddr: ' + baseAddr);


var EncryptBufToFile = Module.findExportByName('WeChatAppHost.dll', 'EncryptBufToFile');

if (EncryptBufToFile) {

    console.log('EncryptBufToFile 函数地址: ' + EncryptBufToFile);

    // HOOK函数, 监听参数
    Interceptor.attach(EncryptBufToFile, {
        onEnter: function (args) {
            // console.log(`${args[0]},${args[1]},${args[2]},${args[3]}`);
            // 微信小程序AppId
            this.appId = ptr(args[0]).readPointer().readAnsiString();
            // 微信小程序本地缓存文件路径
            this.apkgFilePath = ptr(args[1]).readPointer().readAnsiString();
            // 小程序代码原始内容(未加密)
            this.originalData = Memory.readByteArray(args[2], args[3].toInt32());
        },
        onLeave: function (retval) {
            console.log('文件解密成功', this.apkgFilePath);

            // 将文件替换为未加密的wxapkg包
            var f = new File(this.apkgFilePath, 'wb');
            f.write(this.originalData);
            f.flush();
            f.close();

            // 释放内存
            delete this.appId;
            delete this.apkgFilePath;
            delete this.originalData;
        }
    });

} else {
    console.log('WeChatAppHost.dll 模块未加载, 请先打开界面中的小程序面板');
}
""")
    script.on('message', on_message)
    script.load()
    print("[!] Ctrl+D on UNIX, Ctrl+Z on Windows/cmd.exe to detach from instrumented program.\n\n")
    sys.stdin.read()
    session.detach()


if __name__ == '__main__':
    main('wechat.exe')

使用方法:

  • pc微信运行状态

  • 运行以上脚本

  • 点击目标小程序,查看输出结果,大功告成

    image-20210819215926160

注意,可能有多个.wxapkg文件,主要关注__APP__.wxapkg文件即可

3.解包反编译

用到的工具,wxappUnpacker,这个教程太多了,不多赘述

运行命令 node wuWxapkg.js ./xhs.wxapkg

就会在当前文件夹生成解包后的文件夹 xhs

image-20210819220402038

可能遇到的坑因为反编译的问题,有时解析失败,比如文件夹名plugin变为plugin:,导致解包失败

D:\worksoft\nodeworkspace\wxappunpacker\wuLib.js:91
        if (err) throw Error("Save file error: " + err);
                 ^

Error: Save file error: Error: ENOENT: no such file or directory, open

根据报错信息修改wuLib.js这个文件即可,比如这样

image-20210819220838517

4.静态查看

可以用vscode打开解包反编译后的文件夹,已知xhs小程序header里有X-sign参数加密,我们先全局搜索定位

exports.DEFAULT_SIGN_HEADER = "X-Sign";

接着搜搜DEFAULT_SIGN_HEADER

t.header[u.DEFAULT_SIGN_HEADER] = (0, u.encryptFeApiToken)(g);

encryptFeApiToken方法看起来就是加密函数了,ctrl+左键跳转过去

image-20210819221521363

到此结束,静态分析我们猜测不到传入的参数和加密逻辑,下一篇我们把它运行起来,动态调试看看