使用场景
加密autojs
感谢群内大佬指点
@Tsing Yi @沐泠 @ProjectXero @抠脚本人 @I'm zz 等
效果展示
autojs版本
本教程大概的加密步骤
- js转dex
- 压缩项目
- 切割项目, 文件名用 . 开头, 使其不可见
- 创建新的入口文件和project.json
- 混淆入口文件
以上步骤均使用autojs一键完成
不需要电脑, 除非你想要修改加密方法,
跑通本加密工程, 只需要替换你的工程名字即可, 其他的都不用动
就可以一键完成
let projectName = "autojs-dex-first"; let projectDir = files.join(files.getSdcardPath(), "脚本", projectName);
js转dex原理
js --> class --> jar --> dex
步骤
- js --> class
let filePath = "/sdcard/脚本/yashu.js"; if (!files.exists(filePath)) { throw new Error("文件不存在: " + filePath); } // class文件所在文件夹 let dir = "/sdcard/脚本/ayashu"; files.create(dir + "/"); args = ["-version", "200", "-opt", "1", "-encoding", "UTF-8", "-nosource", "-o", "yashu", "-d", dir, filePath]; org.mozilla.javascript.tools.jsc.Main.main(args); toastLog("js转class完成");
各个菜单的意思, 请查看Rhino官网文档
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino/JavaScript_Compiler
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino/Optimization
- class --> jar
let classFilePath = "/sdcard/脚本/ayashu/yashu.class"; let jarFilePath = "/sdcard/脚本/ayashu/yashu.jar"; let r = zipFile(classFilePath, jarFilePath); log(r); function zipFile(classFilePath, jarFilePath) { jarFilePath = new java.io.File(jarFilePath); jarFilePath.delete(); var mArrayList = new java.util.ArrayList(); mArrayList.add(new java.io.File(classFilePath)); new net.lingala.zip4j.core.ZipFile(jarFilePath).addFiles(mArrayList, new net.lingala.zip4j.model.ZipParameters()); return jarFilePath; }
- jar --> dex
去maven官网下载dx.jar, 该文件可以把jar转为dex
https://mvnrepository.com/artifact/com.google.android.tools/dx/1.7
let jarFilePath = "/sdcard/脚本/ayashu/yashu.jar"; let dexFilePath = "/sdcard/脚本/ayashu/yashu.dex"; com.android.dx.command.Main.main(["--dex", "--output", dexFilePath, jarFilePath]);
js调用dex化的js文件
js文件分为两种
- 普通文件
- 模块文件
普通dex文件的调用, 文件入口一般就是这种形式
let dexFilePath = "/sdcard/脚本/ayashu/yashu.dex"; runtime.loadDex(dexFilePath); new Packages["yashu"]()();
模块dex文件调用
假设模块文件是yashu.js, 文件内容为
module.exports = { hello: (name) => { toastLog("hello" + name); }, };
调用模块方法
let dexFilePath = "/sdcard/脚本/ayashu/yashu.dex"; runtime.loadDex(dexFilePath); new Packages["yashu"]()();
没错, 跟普通dex文件调用一样样的, 只是要在引入用的地方requrie一下
main.js, 文件内容如下
let yashu = require("./ysshu"); aaa.hello("牙叔");
以上是单个js文件变为dex的方法, 下面我们来详细看看dex加密一个项目
dex加密项目
1. 初始化一些工具类
let yashuUtil = require("./yashuUtil"); let js2class = require("./dex加密三步曲/js2class"); let class2jar = require("./dex加密三步曲/class2jar"); let jar2dex = require("./dex加密三步曲/jar2dex");
2. 备份项目
yashuUtil.backupProject(projectDir);
3. 提取项目文件中所有js文件
let jsFilePathList = yashuUtil.getJsFilePathList(projectDir);
4, 批量将js转为dex
jsFilePathList.map((filepath) => { changeJsFileToDexFile(filepath); });
5. 压缩项目
let encryptedZipFile = yashuUtil.compressProject();
6. 切割文件
let childFilePathList = yashuUtil.separateFile(encryptedZipFile);
7. 移除多余文件
yashuUtil.finalRemoveIntermediateFile(jsFilePathList);
8. 创建新的mainDex文件
yashuUtil.createMainDex(childFilePathList, encryptedZipFile, projectDir, changeJsFileToDexFile);
9. 创建新的project.json文件
yashuUtil.createNewProject(projectDir);
10. 加密完成
toastLog("牙叔加密完成"); alert("牙叔加密完成");
经过以上步骤, 我们的项目就加密完成了,
项目文件压缩包被切割, 合并函数在入口文件中,
我们来加密入口文件, 也就是上面的第8个步骤: 创建新的mainDex文件
加密入口文件
1. 入口文件原始内容
eval("runtime.unloadAll(true);"); let encryptedZipFile = "===encryptedZipFile==="; let filePathList = "===filePathList==="; mergeFile(filePathList, encryptedZipFile); let zipOutDir = unzipProject(encryptedZipFile); let scriptFilePath = files.join(zipOutDir, "===projectName===", "main.js"); engines.execScriptFile(scriptFilePath, { path: getDir(scriptFilePath) });
2. 我们先使用UglifyJS压缩一下
// UglifyJS online
// https://skalman.github.io/UglifyJS-online/
// https://andrewsun.com/tools/javascript-minifier/
上面两个都可以, 第一个访问速度快一点;
如果网站无法访问, 请关掉代理, 或者更改host;
host需要域名和ip对应
域名查ip
http://ping.chinaz.com/dl.google.com
UglifyJS压缩后的代码
eval("runtime.unloadAll(true);");let encryptedZipFile="===encryptedZipFile===",filePathList="===filePathList===";mergeFile(filePathList,encryptedZipFile);let zipOutDir=unzipProject(encryptedZipFile),scriptFilePath=files.join(zipOutDir,"===projectName===","main.js");function getDir(e){let i=e.split("/");return i.splice(-1,1),i.join("/")}function unzipProject(e,i,t){return i=i||"yashu",t=t||context.getCacheDir(),$zip.unzip(e,t+"/",{password:i}),t}function mergeFile(e,i){e=e.map(e=>new java.io.File(files.path(e))),files.createWithDirs(i);let t=new java.io.BufferedOutputStream(new java.io.FileOutputStream(i)),r=null,a=util.java.array("byte",1048576),l=-1;for(let i=0;i<e.length;i++)for(r=new java.io.BufferedInputStream(new java.io.FileInputStream(e[i]));-1!=(l=r.read(a));)t.write(a,0,l);return r.close(),t.close(),i}engines.execScriptFile(scriptFilePath,{path:getDir(scriptFilePath)});
3. 我们再使用webpack混淆一下
开源项目 webpack-autojs
https://github.com/snailuncle/webpack-autojs
webpack混淆后的代码
var _0x1879=['object','create','default','bind','hasOwnProperty','unloadAll','===encryptedZipFile===','join','===projectName===','split','yashu','getCacheDir','File','path','createWithDirs','BufferedOutputStream','FileOutputStream','java','array','length','BufferedInputStream','FileInputStream','write','close','exports','call','undefined','toStringTag','defineProperty','__esModule'];(function(_0x845909,_0x258a15){var _0x3f0090=function(_0x4164fc){while(--_0x4164fc){_0x845909['push'](_0x845909['shift'] ...... [(_0x3943('0x1b'))](_0x1e78de[_0x426513]));-0x1!=(_0x551275=_0x5359bc['read'](_0x27360d));)_0x5c2c80[_0x3943('0x1c')](_0x27360d,0x0,_0x551275);return _0x5359bc[_0x3943('0x1d')](),_0x5c2c80[_0x3943('0x1d')](),_0x426513;}engines['execScriptFile'](_0xdf190b,{'path':_0x353d18(_0xdf190b)});}]);
上面的混淆效果对应的配置文件scriptConfig.js
var config = { uiMode: false, entry: entry, scriptNamePrefix: "", base64: false, advancedEngines: true, base64RandomStrLength: 100, target: "node", // web || node };
4. 替换一些变量, 为生成新的入口文件做准备
str = str .replace("===encryptedZipFile===", encryptedZipFile) .replace("===projectName===", projectName) .replace('"===filePathList==="', JSON.stringify(childFilePathList));
5. 生成新的入口文件
let newMainFilePath = files.join(projectDir, "yashu.js"); files.write(newMainFilePath, str); changeJsFileToDexFile(newMainFilePath);
经过上面的操作, 我们的入口文件就不是明文了
小技巧
在创建新的入口文件时, 我们要用js处理webpack混淆过的js代码,
要将整个文件内容放到代码里, 替换一些变量字符串,
但是混淆过的代码各种符号都有, 我们可以使用typescript快速将一段代码变为字符串
比如我们要把以下代码变为字符串
_0x5359bc[_0x3943("0x1d")](),_0x5c2c80[_0x3943('0x1d')]()
两边加双引号是不行的, 因为代码本身就有单引号, 也有双引号
口当口当口当, 技巧来了
首先我们新建一个ts文件1.ts
let str = ` `; // 这是反引号
再把上面混淆的代码放到反引号中间
let str = ` _0x5359bc[_0x3943("0x1d")](),_0x5c2c80[_0x3943('0x1d')]() `; // 这是反引号
然后在中断输入以下代码
(tsc是需要配置typescript环境, 请百度ts教程)
tsc 1.ts
运行之后, 就生成1个1.js文件, 文件内容
var str = "\n_0x5359bc[_0x3943(\"0x1d\")](),_0x5c2c80[_0x3943('0x1d')]()\n"; // 这是反引号
经过以上步骤, 我们就可以把代码变为字符串了
总结
经过以上加密, 就可以防止小白破解了,
加密方式公开了, 就不安全了,
自己想办法加强吧
声明
部分内容来自网络