如果有虚拟文件系统元数据 VIRTUAL_FILESYSTEM,并且知道 PAYLOAD_POSITION,我们就可以从pkg 打包的 exe 二进制文件中提取出 javascript 代码。 关于VIRTUAL_FILESYSTEM 和PAYLOAD_POSITION是什么,请查看 pkg介绍。
我们可以直接从 exe 文件中获取到 VIRTUAL_FILESYSTEM 和 PAYLOAD_POSITION。
- 用 vscode 打开 exe 文件
- 在文件底部可以看到 VIRTUAL_FILESYSTEM
- 搜索 'PAYLOAD_POSITION ='就可以得到PAYLOAD_POSITION。
async function extraJsFromPkgExe(exeBinary, VIRTUAL_FILESYSTEM, PAYLOAD_POSITION) {
const snapshotPaths = Object.keys(VIRTUAL_FILESYSTEM);
const exeBuffer = fs.readFileSync(exeBinary);
for(let i=0; i<snapshotPaths.length; i++){
const snapshotPath = snapshotPaths[i];
if(!snapshotPath.includes('node_modules')){
const entityContent = VIRTUAL_FILESYSTEM[snapshotPath][1] || VIRTUAL_FILESYSTEM[snapshotPath][0];
if(entityContent) {
const filePath = getRealPath(snapshotPath);
const content = readFileFromVfs(entityContent);
await saveFile(`./data/codes/${filePath}`, content);
} else {
console.log(`${snapshotPath}未找到`);
}
}
}
function readFileFromVfs(entityContent) {
const [position, size] = entityContent;
const buffer = Buffer.alloc(size);
exeBuffer.copy(buffer, 0, PAYLOAD_POSITION + position, PAYLOAD_POSITION + position + size);
return buffer;
}
}
const getRealPath = (snapshotPath) => {
return snapshotPath.replace(/\\/g, '/').slice(12);
};
// 递归的创建目录
function mkdirsSync(dirname) {
if (fs.existsSync(dirname)) {
return true;
} else {
if (mkdirsSync(path.dirname(dirname))) {
fs.mkdirSync(dirname);
return true;
}
}
}
const ensureDir = (_path) => {
const dir = path.parse(_path).dir;
if(!fs.existsSync(dir)){
mkdirsSync(dir);
}
};
const saveFile = (filePath, buffer) => {
return new Promise((resolve, reject) => {
const source = intoStream(buffer);
ensureDir(filePath);
const dest = fs.createWriteStream(filePath);
source.pipe(dest);
dest.on('close', resolve);
source.on('error', reject);
});
};