本文为看雪论坛优秀文章
看雪论坛作者ID:钞能力大叔
目标应用: aHR0cHM6Ly90eXBvcmEuaW8v越来越多的应用开始使用 electron 来构建跨平台桌面应用。从实现方式上来说,其本质还是基于chrome内核的html、js、css构成的应用,基于浏览器,代码必定会暴露在用户侧,任何加密手段只是增加破解门槛跟时间成本而已。认识electron项目文件目录特征
electron打包的项目,最常见的就是 asar 格式的私有编码文件,里面包含文件名、大小、内容偏移量等数据,按文件头部的 json内容 解析即可提取出所有文件。
electron asar解包
目前来说,官方的版本并没有提供保护源码的方法。在github开源的找到个大神提供的解决方案(https://github.com/toyobayashi/electron-asar-encrypt-demo) ,该方案可以把启动文件编译为node二进制文件,作为启动入口,来保护薄弱的js代码。在项目启动时,将加密后的代码进行解密,交回electron流程进行执行,从而避免上述步骤直接解包拿到源代码的可能。经过分析对比,typora用的恰好是这个demo提供的思路。找到上述步骤解压成功的 package.json 文件,main属性就是 electron 项目启动的主入口。把 main.node 拖到ida中, 分析执行流程。结合 electron-asar-encrypt-demo 跟 IDA伪代码, 可以定位到两个关键函数 napi_create_string_utf8 跟 napi_call_function。万能js提取方案
已知经过编译后的node文件, 在执行前,都会调用 napi_create_string_utf8 创建js字符串,所以在调用该函数的时候,基于electron没有自带加密的特性,想要运行js流程,必定会传递明文,所以在加载流程上截断,就可以导出解密后的数据。let napi_create_string_utf8 = Module.getExportByName(null, 'napi_create_string_utf8');
var index = 0;
if (napi_create_string_utf8) {
console.log('绑定成功');
Interceptor.attach(napi_create_string_utf8, {
onEnter: function (args) {
console.log('napi_create_string_utf8', '调用', args[0], args[1].readCString().substring(0, 100), args[2], args[3]);
if (args[2].toInt32() > 100) {
index += 1;
var f = new File('export_' + String(index) + '.js', 'wb');
f.write(args[1].readByteArray(args[2].toInt32()));
f.flush();
f.close();
}
}
});
} else {
console.log('绑定失败');
}
解包项目中的所有 asar文件,就能拿到所有的源代码,并且把解压的文件夹,改成对应的 asar 文件名即可正常运行项目,无需重打包即可调试。
无限试用思路
不想进入注册表这个繁琐的话,可以保存下面的代码, 把名字改成 xxx.reg, 双击运行即可无限畅玩。Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Typora]
"IDate"="1/24/9999"
"SLicense"=""
去除授权功能实现单机版本思路
将所有的网络验证给他删掉/注释掉, 也可以直接把 “是否授权” 的变量,改成true即可。
注册机思路
由于该示例使用了rsa解密,所以要基于官方版本编写注册机就不太行了。一定要出注册机的话,需要先替换截图部分的rsa公钥即可。这个地方使用了node自带的公钥解密,一些语言好像不能直接生成(可能我的打开方式不对),我就直接给出node版本的创建实例。const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const keyPair = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: ''
}
});
fs.writeFileSync("public_key.pem", keyPair.publicKey);
fs.writeFileSync("private_key.pem", keyPair.privateKey);
自建授权网关实现注册机思路
自建网关的话,可以把应用自带的域名,替换成自己的,然后按接口需要的返回值,给他返回响应的数据格式即可。这个实例仅需要修改两处即可。
重打包发版思路
把解压的文件夹打包回 asar格式的文件即可, 这个网上一大把资料。
对于electron加密方式的思考
相对于原生开发来说,js安全做客户端毕竟薄弱,UI交互是没问题的,关键代码可以放到dll、so层去做,但是也没办法避免从js层面去剥离dll层函数的调用。所以目前来说并没有很好的解决方案,本文只是起到抛砖引玉的作用。期待electron有更好、更安全的解决方案。
看雪ID:钞能力大叔
https://bbs.pediy.com/user-home-860779.htm
*本文由看雪论坛 钞能力大叔 原创,转载请注明来自看雪社区