dwxapkg
Version:
对wxapkg/wxvpkg文件进行解包
164 lines (145 loc) • 4.49 kB
JavaScript
var Wxapkg = require("../");
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
const process = require("process");
const WXAPKG_FLAG = "V1MMWX";
const WXAPKG_FLAG_LEN = WXAPKG_FLAG.length;
let fileName = process.argv[2];
if (!fileName) {
new Error(`参数不正确`);
}
wxapkgExts = [".wxapkg", ".wxvpkg", ".wx"];
if (fileName === "*") {
let paths = fs.readdirSync(".");
console.log(paths);
paths.forEach((fileName) => {
fileName = path.resolve(fileName);
var extname = path.extname(fileName);
if (wxapkgExts.includes(extname)) {
processOne(fileName);
}
});
} else {
processOne(fileName);
}
function getKeyIv(wxid) {
const key = crypto.pbkdf2Sync(wxid, "saltiest", 1000, 32, "sha1");
const iv = "the iv: 16 bytes";
return { key, iv };
}
function decrypt(data, wxid) {
const { key, iv } = getKeyIv(wxid);
const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
const xor = wxid.charCodeAt(wxid.length - 2);
const other = [];
for (let i = 1024, j = data.length; i < j; i++) {
other.push(data[i] ^ xor);
}
return Buffer.concat([
decipher.update(data.slice(0, 1024)),
decipher.final(),
Buffer.from(other),
]);
}
function encrypt(data, wxid) {
const { key, iv } = getKeyIv(wxid);
const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
const xor = wxid.charCodeAt(wxid.length - 2);
const other = [];
for (let i = 1023, j = data.length; i < j; i++) {
other.push(data[i] ^ xor);
}
return Buffer.concat([
Buffer.from(WXAPKG_FLAG),
cipher.update(data.slice(0, 1023)),
cipher.final(),
Buffer.from(other),
]);
}
function getWxidFromPath(path) {
path = path.replace(/\\/g, "/");
let regex = /Applet\/wx(\w+)/;
let match = path.match(regex);
if (match) {
return `wx${match[1]}`; // 输出: 7a34380eca23579172
}
return null;
}
function processOne(fileName) {
if (fs.existsSync(fileName)) {
new Error(`${fileName} 不存在`);
}
function getFiles(dir, base = '', files = []) {
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
if (entry.name.startsWith('.')) {
continue;
}
const fullPath = path.join(dir, entry.name);
const relativePath = path.join(base, entry.name);
if (entry.isDirectory()) {
getFiles(fullPath, relativePath, files);
} else if (entry.isFile()) {
const stats = fs.statSync(fullPath);
files.push({ file: fullPath, simName: relativePath, stats });
}
}
return files;
}
fileName = path.resolve(fileName);
var extname = path.extname(fileName);
let isDecode = wxapkgExts.includes(extname);
if (isDecode) {
// 解码
let file = fs.readFileSync(fileName);
let writePath = fileName.replace(extname, "/");
if (file.slice(0, WXAPKG_FLAG_LEN).toString() === WXAPKG_FLAG) {
const wxid = process.argv[3] || getWxidFromPath(fileName);
if (!wxid) {
console.log("使用示例:dwxapkg /a/b/c/aa.wxapkg wxid");
throw new Error(`请指定wxid`);
}
file = decrypt(file.slice(WXAPKG_FLAG_LEN), wxid);
}
let wxapkg = new Wxapkg(file);
let files = wxapkg.decode();
files.forEach((f) => {
let filePath = path.join(writePath, f.name);
let dir = path.dirname(filePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
console.log(filePath);
fs.writeFileSync(filePath, f.chunk, "binary");
});
} else {
// 压缩
let wxapkgFileName = fileName + ".wxapkg";
let list = getFiles(fileName);
let wxapkg = new Wxapkg();
wxapkg.encode(list, wxapkgFileName);
setTimeout(() => {
let wxid;
wxid = process.argv[3];
if (wxid) {
let file = fs.readFileSync(wxapkgFileName);
fs.writeFileSync(wxapkgFileName, encrypt(file, wxid));
return;
}
if (process.platform === "darwin") {
console.log("当前是mac环境,跳过加密");
return;
}
// 提取wxid, 可能是windows环境
wxid = getWxidFromPath(fileName);
if (wxid) {
let file = fs.readFileSync(wxapkgFileName);
fs.writeFileSync(wxapkgFileName, encrypt(file, wxid));
return;
}
console.warn("您当前可能是windows环境, 未指定wxid,已跳过加密");
}, 1000);
}
}