WeChatAppHost.dll-->EncryptBufToFile
char __cdecl EncryptBufToFile_1001D19D(char *appid_1, char *path, void *Src, size_t Size)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
if ( !*((_DWORD *)appid_1 + 4) || (int)Size <= 0 )
return 0;
std::string::string(appid, (int)appid_1);
v12 = v4;
v11 = v4;
sub_1001925F(&v11, path);
sub_10047070(v19, v11, v12);
sub_1001927F(&v11, v19);
sub_100407A0(FileName, v11, v12);
if ( isfileexist_10049860(FileName) )
{
bret = 1;
}
else
{
std::string::string(tmp, "saltiest");
// 1、首先pbkdf2生成AES的key。利用微信小程序id字符串为pass,salt为saltiest 迭代次数为1000。调用pbkdf2生成一个32位的key
pbkdf2_1002398B((int)&aeskey, 0, appid, (int)tmp, 1000, 256);
std::string::_Tidy(tmp, 1, 0);
std::string::string(aesiv, "the iv: 16 bytes");
sub_10023263(v18);
v5 = aesiv;
if ( aesiv[5] >= 0x10u )
v5 = (int *)aesiv[0];
v15 = (int)v5;
v16 = aesiv[4];
aesinit_100237DA(v18, aeskey, 0, (int)&v15);
v26 = 15;
bret = 0;
v25 = 0;
LOBYTE(v24[0]) = 0;
if ( (int)Size <= 1023 )
{
std::string::assign(v24, Src, Size);
}
else
{
std::string::assign(v24, Src, 1023u); // 后续aes加密最大1023字节
bret = 1;
}
v23[4] = 0;
v6 = v24;
v23[5] = 15;
if ( v26 >= 0x10 )
v6 = (void **)v24[0];
v15 = (int)v6;
v16 = v25;
LOBYTE(v23[0]) = 0;
// 2、首先取原始的wxapkg的包得前1023个字节通过AES通过1生成的key和iv(the iv: 16 bytes),进行加密
if ( (unsigned __int8)aes_1002374E(v18, (int)&v15, (int)v23) )
{
std::string::string(tmp, "V1MMWX");
sub_10016125(tmp, v23, 0, 0xFFFFFFFF);
if ( bret )
{
unknown_libname_23(v13);
strresize_10094CD0((int)v13, Size - 1023);
substr_10094D17((void **)v13, (char *)Src + 1023, Size - 1023);
unknown_libname_23(&v15);
v12 = (unsigned __int8)getxokkey_1001D693(appid);// 3、接着利用微信小程序id字符串的倒数第2个字符为xor key,依次异或1023字节后的所有数据,如果微信小程序id小于2位,则xorkey 为 0x66
v11 = strsize_1007EC9D(v13);
v7 = strdata_1004F590(v13);
if ( xor_1001D5F6((int)&v15, v7, v11, v12) )
{
v12 = strsize_1007EC9D(&v15);
v8 = (void *)strdata_1004F590(&v15);
string_10016224(tmp, v8, v12);
}
sub_10094CB1(&v15);
sub_10094CB1(v13);
}
data = tmp;
v12 = (int)tmp[4]; // size
if ( tmp[5] >= (LPCVOID)0x10 )
data = (LPCVOID *)tmp[0];
writefile_10049880(FileName, data, v12); // 4、把AES加密后的数据(1024字节)和xor后的数据一起写入文件,并在文件头部添加V1MMWX标识
std::string::_Tidy(tmp, 1, 0);
bret = 1;
}
else
{
bret = 0;
}
std::string::_Tidy(v23, 1, 0);
std::string::_Tidy(v24, 1, 0);
sub_1002327D(v18);
std::string::_Tidy(aesiv, 1, 0);
if ( aeskey )
(**(void (__thiscall ***)(int, int))aeskey)(aeskey, 1);
}
sub_10040820(FileName);
std::wstring::_Tidy(v19, 1, 0);
std::string::_Tidy(appid, 1, 0);
return bret;
}
py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import argparse
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Hash import SHA1
from Crypto.Cipher import AES
# 微信小程序包 自定义标识
WXAPKG_FLAG = 'V1MMWX'
WXAPKG_FLAG_LEN = len(WXAPKG_FLAG)
def main():
parser = argparse.ArgumentParser(description='PC微信小程序wxapkg包解密工具')
parser.add_argument('--wxid', metavar='微信小程序ID', required=True)
parser.add_argument('--iv', metavar='iv', required=False, default='the iv: 16 bytes')
parser.add_argument('--salt', metavar='salt', required=False, default='saltiest')
parser.add_argument('-f', '--file', metavar='加密的小程序包文件路径', required=True)
parser.add_argument('-o', '--output', metavar='解密后的小程序包文件路径', required=True)
args = parser.parse_args()
key = PBKDF2(args.wxid.encode('utf-8'), args.salt.encode('utf-8'), 32, count=1000, hmac_hash_module=SHA1)
# 读取加密的内容
if not os.path.exists(args.file):
raise Exception('文件不存在')
with open(args.file, mode='rb') as f:
dataByte = f.read()
if dataByte[0:WXAPKG_FLAG_LEN].decode() != WXAPKG_FLAG:
raise Exception('该文件无需解密, 或者不是微信小程序wxapkg加密包')
# 初始化密钥
cipher = AES.new(key, AES.MODE_CBC, args.iv.encode('utf-8'))
# 解密头部1024个字节
originData = cipher.decrypt(dataByte[WXAPKG_FLAG_LEN: 1024 + WXAPKG_FLAG_LEN])
# 初始化xor密钥, 解密剩余字节
xorKey = 0x66
if len(args.wxid) >= 2:
xorKey = ord(args.wxid[len(args.wxid) - 2])
afData = dataByte[1024 + WXAPKG_FLAG_LEN:]
out = bytearray()
for i in range(len(afData)):
out.append(afData[i] ^ xorKey)
originData = originData[0:1023] + out
# 保存解密后的数据
with open(args.output, mode='wb') as f:
f.write(originData)
print('解密成功', args.output)
if __name__ == "__main__":
main()
链接
pc_wxapkg_decrypt
pc_wxapkg_decrypt_python