微信小程序反编译
程序员文章站
2022-04-15 10:48:39
...
1. 下载这位大神的开源项目:https://github.com/qwerty472123/wxappUnpacker.git ,要是啥也没看到注意选择分支试试
2. 使用root后的android手机或模拟器,安装微信并运行一下小程序,在目录“/data/data/com.tencent.mm/MicroMsg/{User}/appbrand/pkg”中找到对应的.wxapkg文件,对应哪一个文件就根据文件修改时间看吧
3. 在项目根目录下安装依赖:
npm install esprima npm install css-tree npm install cssbeautify npm install vm2 npm install uglify-es npm install js-beautify npm install escodegen
4.
node wuWxapkg.js 你的wxapkg文件
补充,处理wxss时报错,wuWxss.js修改为如下:(参考项目中的第一个pull request)
const wu=require("./wuLib.js"); const path=require("path"); const fs=require("fs"); const {VM}=require('vm2'); const cssbeautify=require('cssbeautify'); const csstree=require('css-tree'); function doWxss(dir,cb){ function GwxCfg(){} GwxCfg.prototype={$gwx(){}}; for(let i=0;i<300;i++)GwxCfg.prototype["$gwx"+i]=GwxCfg.prototype.$gwx; let runList={},pureData={},result={},actualPure={},importCnt={},frameName="",onlyTest=true,blockCss=[];//custom block css file which won't be imported by others.(no extension name) function cssRebuild(data){//need to bind this as {cssFile:__name__} before call let cssFile; function statistic(data){ function addStat(id){ if(!importCnt[id])importCnt[id]=1,statistic(pureData[id]); else ++importCnt[id]; } if(typeof data==="number")return addStat(data); for(let content of data)if(typeof content==="object"&&content[0]==2)addStat(content[1]); } function makeup(data){ var isPure=typeof data==="number"; if(onlyTest){ statistic(data); if(!isPure){ if(data.length==1&&data[0][0]==2)data=data[0][1]; else return ""; } if(!actualPure[data]&&!blockCss.includes(wu.changeExt(wu.toDir(cssFile,frameName),""))){ console.log("Regard "+cssFile+" as pure import file."); actualPure[data]=cssFile; } return ""; } let res=[],attach=""; if(isPure&&actualPure[data]!=cssFile){ if(actualPure[data])return '@import "'+wu.changeExt(wu.toDir(actualPure[data],cssFile),".wxss")+'";\n'; else{ res.push("/*! Import by _C["+data+"], whose real path we cannot found. */"); attach="/*! Import end */"; } } let exactData=isPure?pureData[data]:data; for(let content of exactData) if(typeof content==="object"){ switch(content[0]){ case 0://rpx res.push(content[1]+"rpx"); break; case 1://add suffix, ignore it for restoring correct! break; case 2://import res.push(makeup(content[1])); break; } }else res.push(content); return res.join("")+attach; } return ()=>{ cssFile=this.cssFile; if(!result[cssFile])result[cssFile]=""; result[cssFile]+=makeup(data); }; } function runVM(name, code) { let wxAppCode = {}, handle = { cssFile: name }; let gg = new GwxCfg(); let tsandbox = { $gwx: GwxCfg.prototype["$gwx"], __mainPageFrameReady__: GwxCfg.prototype["$gwx"], __wxAppCode__: wxAppCode, setCssToHead: cssRebuild.bind(handle) }; let vm = new VM({ sandbox: tsandbox }); vm.run(code); for (let name in wxAppCode) { if (name.endsWith(".wxss")) { handle.cssFile = path.resolve(frameName, "..", name); wxAppCode[name](); } } } function preRun(dir, frameFile, mainCode, files, cb) { wu.addIO(cb); runList[path.resolve(dir, "./app.wxss")] = mainCode; for (let name of files) if (name != frameFile) { wu.get(name, code => { code = code.slice(0, code.indexOf("\n")); if (code.indexOf("setCssToHead") > -1) runList[name] = code.slice(code.indexOf("setCssToHead")); }); } } function runOnce() { // for (let name in runList) runVM(name, runList[name]); for (let name in runList) { // console.log(name, runList[name]); var start = `var window = window || {}; var __pageFrameStartTime__ = Date.now(); var __webviewId__; var __wxAppCode__={}; var __mainPageFrameReady__ = function(){}; var __WXML_GLOBAL__={entrys:{},defines:{},modules:{},ops:[],wxs_nf_init:undefined,total_ops:0}; var __vd_version_info__=__vd_version_info__||{}; $gwx=function(path,global){ if(typeof global === 'undefined') global={};if(typeof __WXML_GLOBAL__ === 'undefined') {__WXML_GLOBAL__={}; }__WXML_GLOBAL__.modules = __WXML_GLOBAL__.modules || {}; }`; runVM(name, start + " \r\n" + runList[name]); } } function transformCss(style){ let ast=csstree.parse(style); csstree.walk(ast,function(node){ if(node.type=="Comment"){//Change the comment because the limit of css-tree node.type="Raw"; node.value="\n/*"+node.value+"*/\n"; } if(node.type=="TypeSelector"){ if(node.name.startsWith("wx-"))node.name=node.name.slice(3); else if(node.name=="body")node.name="page"; } if(node.children){ const removeType=["webkit","moz","ms","o"]; let list={}; node.children.each((son,item)=>{ if(son.type=="Declaration"){ if(list[son.property]){ let a=item,b=list[son.property],x=son,y=b.data,ans=null; if(x.value.type=='Raw'&&x.value.value.startsWith("progid:DXImageTransform")){ node.children.remove(a); ans=b; }else if(y.value.type=='Raw'&&y.value.value.startsWith("progid:DXImageTransform")){ node.children.remove(b); ans=a; }else{ let xValue=x.value.children&&x.value.children.head&&x.value.children.head.data.name,yValue=y.value.children&&y.value.children.head&&y.value.children.head.data.name; if(xValue&&yValue)for(let type of removeType)if(xValue==`-${type}-${yValue}`){ node.children.remove(a); ans=b; break; }else if(yValue==`-${type}-${xValue}`){ node.children.remove(b); ans=a; break; }else{ let mValue=`-${type}-`; if(xValue.startsWith(mValue))xValue=xValue.slice(mValue.length); if(yValue.startsWith(mValue))yValue=yValue.slice(mValue.length); } if(ans===null)ans=b; } list[son.property]=ans; }else list[son.property]=item; } }); for(let name in list)if(!name.startsWith('-')) for(let type of removeType){ let fullName=`-${type}-${name}`; if(list[fullName]){ node.children.remove(list[fullName]); delete list[fullName]; } } } }); return cssbeautify(csstree.generate(ast),{indent:' ',autosemicolon:true}); } wu.scanDirByExt(dir,".html",files=>{ let frameFile=""; if(fs.existsSync(path.resolve(dir,"page-frame.html"))) frameFile=path.resolve(dir,"page-frame.html"); else if(fs.existsSync(path.resolve(dir,"app-wxss.js"))) frameFile=path.resolve(dir,"app-wxss.js"); else if(fs.existsSync(path.resolve(dir,"page-frame.js"))) frameFile=path.resolve(dir,"page-frame.js"); else throw Error("page-frame-like file is not found in the package by auto."); wu.get(frameFile,code=>{ code=code.slice(code.indexOf('var setCssToHead = function(file, _xcInvalid')); code=code.slice(code.indexOf('\nvar _C= ')+1); let oriCode=code; code=code.slice(0,code.indexOf('\n')); let vm=new VM({sandbox:{}}); pureData=vm.run(code+"\n_C"); let mainCode=oriCode.slice(oriCode.indexOf("setCssToHead"),oriCode.lastIndexOf(";var __pageFrameEndTime__")); console.log("Guess wxss(first turn)..."); preRun(dir,frameFile,mainCode,files,()=>{ frameName=frameFile; onlyTest=true; runOnce(); onlyTest=false; console.log("Import count info: %j",importCnt); for(let id in pureData)if(!actualPure[id]){ if(!importCnt[id])importCnt[id]=0; if(importCnt[id]<=1){ console.log("Cannot find pure import for _C["+id+"] which is only imported "+importCnt[id]+" times. Let importing become copying."); }else{ let newFile=path.resolve(dir,"__wuBaseWxss__/"+id+".wxss"); console.log("Cannot find pure import for _C["+id+"], force to save it in ("+newFile+")."); id=Number.parseInt(id); actualPure[id]=newFile; cssRebuild.call({cssFile:newFile},id)(); } } console.log("Guess wxss(first turn) done.\nGenerate wxss(second turn)..."); runOnce() console.log("Generate wxss(second turn) done.\nSave wxss..."); for(let name in result)wu.save(wu.changeExt(name,".wxss"),transformCss(result[name])); let delFiles={}; for(let name of files)delFiles[name]=8; delFiles[frameFile]=4; cb(delFiles); }); }); }); } module.exports={doWxss:doWxss}; if(require.main===module){ wu.commandExecute(doWxss,"Restore wxss files.\n\n<dirs...>\n\n<dirs...> restore wxss file from a unpacked directory(Have page-frame.html (or app-wxss.js) and other html file)."); }
上一篇: ASP.NET验证控件详解
下一篇: ajax post get发送json