首页
社区
课程
招聘
[原创]向Typora学习electron安全攻防
2022-5-3 23:02 19089

[原创]向Typora学习electron安全攻防

2022-5-3 23:02
19089

【原创】向Typora学习electron安全攻防

 

@钞能力大叔

 

目标应用: 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_utf8napi_call_function

万能js提取方案

已知经过编译后的node文件, 在执行前,都会调用 napi_create_string_utf8 创建js字符串,所以在调用该函数的时候,基于electron没有自带加密的特性,想要运行js流程,必定会传递明文,所以在加载流程上截断,就可以导出解密后的数据。

 

直接上frida大法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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, 双击运行即可无限畅玩。

1
2
3
4
5
Windows Registry Editor Version 5.00
 
[HKEY_CURRENT_USER\Software\Typora]
"IDate"="1/24/9999"
"SLicense"=""

去除授权功能实现单机版本思路

将所有的网络验证给他删掉/注释掉, 也可以直接把 “是否授权” 的变量,改成true即可。

 

 

注册机思路

由于该示例使用了rsa解密,所以要基于官方版本编写注册机就不太行了。一定要出注册机的话,需要先替换截图部分的rsa公钥即可。

 

 

这个地方使用了node自带的公钥解密,一些语言好像不能直接生成(可能我的打开方式不对),我就直接给出node版本的创建实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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有更好、更安全的解决方案。


[培训]《安卓高级研修班(网课)》月薪三万计划

最后于 2022-5-3 23:05 被钞能力大叔编辑 ,原因:
收藏
点赞8
打赏
分享
打赏 + 80.00雪花
打赏次数 1 雪花 + 80.00
 
赞赏  Editor   +80.00 2022/06/23 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (28)
雪    币: 2640
活跃值: (3574)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
值得怀疑 2022-5-4 09:48
2
0
frida 怎么在这里使用?
雪    币: 439
活跃值: (422)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
钞能力大叔 2022-5-4 10:42
3
0
值得怀疑 frida 怎么在这里使用?
frida "安装路径/Typora.exe" -l 脚本
雪    币: 302
活跃值: (888)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
pUnicorn 2022-5-4 12:59
4
0

学习了

最后于 2022-5-4 13:00 被pUnicorn编辑 ,原因:
雪    币: 4049
活跃值: (3082)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
yumoqaq 3 2022-5-4 15:04
5
0

楼主可否用最新版本的Typora详细解释一下,有些看不懂啊,我尝试在内存代码中加入 s = true ; 但是失败了,报错提示 意外的标识符

最后于 2022-5-4 15:06 被yumoqaq编辑 ,原因:
雪    币: 439
活跃值: (422)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
钞能力大叔 2022-5-4 16:09
6
0
yumoqaq 楼主可否用最新版本的Typora详细解释一下,有些看不懂啊,我尝试在内存代码中加入 s = true ; 但是 ...
最新版可用哦,内存替换没试过,不过意外的标识符,应该是语法错了,你可以把替换后的js存出来,检查下语法。
雪    币: 4049
活跃值: (3082)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
yumoqaq 3 2022-5-4 18:01
7
0
钞能力大叔 最新版可用哦,内存替换没试过,不过意外的标识符,应该是语法错了,你可以把替换后的js存出来,检查下语法。

我测试的是1.25版,前几天下的,真不行啊。。所有关联的地方都调整了,报错 无效或意外的token , 楼主方便的话可以交流一下吗 ,我现在的疑惑是 版本问题还是内存破解不可行。。 或者楼主可以发我一份1.25破解的版本让我研究一下吗。。

最后于 2022-5-4 18:10 被yumoqaq编辑 ,原因:
雪    币: 439
活跃值: (422)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
钞能力大叔 2022-5-4 18:25
8
0
yumoqaq 钞能力大叔 最新版可用哦,内存替换没试过,不过意外的标识符,应该是语法错了,你可以把替换后的js存出来,检查下语法。 我测试的是1.25版,前几 ...
你说的这种情况,每次启动都会调用接口校验的,内存补丁的方案并没有直接改代码来的方便。 我这边测试1.2.5 32、64都没问题。
雪    币: 229
活跃值: (579)
能力值: ( LV4,RANK:41 )
在线值:
发帖
回帖
粉丝
9
0

按照该篇写的crack,复制到 C:\Program Files\Typora 运行 typora_with_pro.exe 即可


将 "hasActivated=${s||!1}"修改为"hasActivated=${s||!0}"

上传的附件:
雪    币: 439
活跃值: (422)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
钞能力大叔 2022-5-6 09:29
10
0
wx_卖女孩的小火柴_588616 按照该篇写的crack,复制到 C:\Program Files\Typora 运行 typora_with_pro.exe 即可将 "hasAc ...
s是全局变量,这么改只是在激活页面呈现出“已激活”的效果而已。
雪    币: 229
活跃值: (579)
能力值: ( LV4,RANK:41 )
在线值:
发帖
回帖
粉丝
11
0
钞能力大叔 s是全局变量,这么改只是在激活页面呈现出“已激活”的效果而已。

我又改了一下,可以完美破解了


替换字符串如下:

;; 移除签名
const n;;/*
`,t\);;*/
JSON\.parse\(n\.;;JSON.parse(t.

;; 破解网络验证, 本机自动生成
async function\(e,t,n\){.*}\(t,n,o\);;async function(e,t,n){t={fingerprint:await M(),email:e,license:t,type:global.devVersion?"dev":""};return await Z(await Buffer.from(JSON.stringify(t),"utf8").toString("base64"))?[!0,""]:[!1,"Please input a valid license code"];}(t,n,o)

;; 破解renew
\(H\(o,n,i\),B\(t,e\)\);;H(o,n,i)

修改后,需要激活一次(本机)就可以了,再次启动不会弹框。


如果版本更新了,可以修改 typora_with.txt 导出最新的js,然后做相应的补丁,当前版本: 1.2.5 。

上传的附件:
雪    币: 4049
活跃值: (3082)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
yumoqaq 3 2022-5-6 18:31
12
0
wx_卖女孩的小火柴_588616 我又改了一下,可以完美破解了替换字符串如下:;; 移除签名 const n;;/* `,t\);;*/ JSON\.parse\(n\.;;JSON.pars ...
大哥能发我一份修改后的js代码吗
雪    币: 229
活跃值: (579)
能力值: ( LV4,RANK:41 )
在线值:
发帖
回帖
粉丝
13
0
yumoqaq 大哥能发我一份修改后的js代码吗

0.js 是修改后的, 1.js 是修改前的,实际上可以查看补丁直接替换就好了

上传的附件:
  • 0.js (260.76kb,68次下载)
  • 1.js (260.73kb,54次下载)
雪    币: 10085
活跃值: (2115)
能力值: ( LV5,RANK:71 )
在线值:
发帖
回帖
粉丝
joker陈 2022-5-7 15:36
14
0
请教下electron能不能动态执行个runjavascript,可以的话该怎么跟踪呢
雪    币: 3884
活跃值: (2237)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lylxd 2022-5-7 16:16
15
0

赞!

最后于 2022-5-7 17:00 被lylxd编辑 ,原因:
雪    币: 149
活跃值: (1978)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
saloyun 2022-5-10 09:00
16
0
赞!
雪    币: 4089
活跃值: (8230)
能力值: ( LV9,RANK:181 )
在线值:
发帖
回帖
粉丝
nevinhappy 2 2022-5-10 09:44
17
0

看之前的破解,有人提出来对asar可以进行文件劫持,直接将修改后的License.js放置到"resources\node_modules\"下面,加载优先级会先加载这个文件。不用再打包回去了!

最后于 2022-5-10 09:46 被nevinhappy编辑 ,原因:
上传的附件:
雪    币: 2093
活跃值: (1819)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
洪七公. 2022-5-10 15:45
18
0
赞!
雪    币: 108
活跃值: (853)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yangya 2022-5-10 21:02
19
0
nevinhappy 看之前的破解,有人提出来对asar可以进行文件劫持,直接将修改后的License.js放置到"resources\node_modules\"下面,加载优先级会先加 ...
这个不行,放进去还是没激活
雪    币: 3281
活跃值: (1023)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
CRoot 2022-5-10 21:33
20
0
这个是老版本的,新版的叫Atom.js。而且还加了AES解密,所以之前的劫持是不能用的了。
雪    币: 247
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
Y4WN 2022-5-10 23:31
21
0

楼主,1.25版本修改了js,运行程序后,报错显示解密后的js文件最前部有乱码。猜测是我的加密和打包方式有误,想请教一下您用的方法

最后于 2022-5-11 01:46 被Y4WN编辑 ,原因:
雪    币: 439
活跃值: (422)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
钞能力大叔 2022-5-11 10:51
22
0
Y4WN 楼主,1.25版本修改了js,运行程序后,报错显示解密后的js文件最前部有乱码。猜测是我的加密和打包方式有误,想请教一下您用的方法
检查下是不是 utf8编码 跟 utf8-bom编码的问题。 
雪    币: 247
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
Y4WN 2022-5-11 12:23
23
0
钞能力大叔 检查下是不是 utf8编码 跟 utf8-bom编码的问题。

问题解决,加解密的脚本问题(需要好好学汇编

最后于 2022-5-12 11:53 被Y4WN编辑 ,原因:
雪    币: 40
活跃值: (1406)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
快乐的小跳蛙 2022-5-11 15:33
24
0
Y4WN 检查了,不是utf编码原因,但乱码16字节,之后是正确的js代码
我的也是执行0.js失败的,我的是utf8编码
雪    币: 238
活跃值: (163)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ka1t4v 2022-7-17 02:04
25
0
wx_卖女孩的小火柴_588616 我又改了一下,可以完美破解了替换字符串如下:;; 移除签名 const n;;/* `,t\);;*/ JSON\.parse\(n\.;;JSON.pars ...
可以发份源码么,想学习一下
游客
登录 | 注册 方可回帖
返回