首页
论坛
课程
招聘
[原创]Typora 破解 之 逆向分析(上)
2022-4-28 21:01 12150

[原创]Typora 破解 之 逆向分析(上)

2022-4-28 21:01
12150

前言

我是逆向练习生,羽墨。

 

目前最为流行的md文件编辑器,当属Typora,免费,简洁,让人爱不释手

 

但是去年突然开始收费,让人不知所措。。。

 

所以今天用简洁的手法,带大家体验破解第一视角

 

(其实刚收费的时候笔者就尝试过破解,那个时候刚学了几天汇编,打开调试器愣是看了一整天,毛都看不出来。。所以经过一段时间学习,又来了。。这就是不怕贼偷,就怕贼惦 记?。。。)

 

注:上篇主要为分析过程,下篇主要为实现,详情参见Typora破解之内存破解

磨刀霍霍 :准备工作

开发环境识别

用IDA打开 Typora.exe (不建议,可能是我电脑问题,IDA分析了三四个小时。。。),打开后发现程序中有 electron ,V8字样,由于前几天刚好分析了一个IE漏洞,由V8联想到 JavaScript引擎,此时猜测与JS语言有关

 

 

 

打开程序目录,查看一下有没有JS代码,一番查找,看到了asar文件以及node字样,感觉有些眼熟,哪里见过。好的,问一下度娘,百度搜索asar,electron,nodemodules

 

不搜不知道,一搜吓一跳,原来这是使用 NodeJs的electron框架开发的桌面应用,JS也能写桌面程序了。。。原谅我孤陋寡闻

 

继续搜索相关资料,得到以下信息:

 

1.electron 使用了谷歌的 V8引擎以及渲染引擎(意思是这种程序跟个浏览器差不多呗)

 

2.electron 有主进程与渲染进程 ,通过IPC交换信息,渲染进程只负责渲染(难怪我附加调试有好几个进程。。)

 

3.Typora.exe是electron框架,基本与开发者的代码无关(修改框架复杂度太高,一般人不会去动,所以别去逆向它了)

 

4.查看目录发现,在app.asar.unpacked中发现了一个 main.node ,看名字很奇怪,.node文件是啥东西

 

5.app.asar是打包的JS代码,并且只是简单的打包,没有任何加密措施,且electron也没有代码保护措施(圈起来要考)

 

根据第五条信息,笔者尝试使用工具对asar进行解包,解包失败不知道什么原因(或许必须使用NodeJS自带的解包工具?但是解包也是加密文件,我又懒得下载nodejs,需要的时候再解吧。。),放进010editor查看,得到文件名与一些密文,此时陷入了僵局

 

尝试调试

打开typora进程,x64dbg附加,查看有没有有用的信息(刚开始我不知道这个是NodeJS开发,想着通过注册窗口跟踪程序流程,好家伙差点就逆到引擎去了),发现了有好几个进程,后面命令行参数可以看到 渲染 gpu等关键字,并且目录参数指向了app.asar

 

 

根据前面得到的信息,这些进程都是由主进程创建的,程序逻辑是由主进程处理,那么附加主进程看一下(没参数的那个)

 

 

看到了主进程加载了main.node模块,什么.node也能当dll加载 ??, 或许它本来就是一个dll呢(也不排除加壳后,手动加载的情况)

 

那么使用PE工具查一下,VS2017编译的64位DLL。好家伙,以为换个名字我就不认识你了

 

梅开二度 :逻辑分析

好,到这一步,已知信息:

 

1.JS文件被加密

 

2.框架为electron

 

3.框架会加载main.node模块

 

4.解析JS脚本的是V8引擎

 

5.c++支持node api进行开发

 

根据我们的已知信息,来对程序的整体逻辑进行一个简单的分析

 

1.框架对代码无保护且修改框架难度过高,V8引擎不支持解析加密的JS代码,那么JS代码如何运行?

 

​ 站在一个开发者的角度,我可能会想到由框架加载我的解密代码,把js代码解密后送到js引擎去执行就可以了

 

2.那么解密代码放在哪里合适呢?

 

​ 既然框架被编译为二进制了,且根据之前的分析,妥妥的c++开发,想要最简单的方法实现解密,加载同样为c/c++编译的二进制代码即可。在Windows平台上,想要加载代码执行,也就剩动态链接库了。由此可以推测,之前找到的main.node,可能就是解密模块。

逻辑总结

  • 框架加载解密模块
  • 解密模块对app.asar进行解密(解密后会不会把文件写出来呢,如果写出来可以直接拷走。。)
  • 解密后的代码送入JS引擎执行
  • 另外的逻辑 :由解密模块解密app.asar的xxx.js代码,xxx.js代码执行后,由它来负责解密剩下的js代码并执行,可以提高破解难度

精益求精 :main.node分析

1.根据之前的推测,main.node负责解密,按照程序员开发习惯,Ctrl CV实现,也就是使用公开的一些算法

 

2.IDA加载main.node,按照逆向惯例,先搜索一波字符串

 

此时看到了buffer,base64,app.asar等关键字。猜测一下,app.asar加载到buffer然后进行base64解密(哈哈哈,我都笑了)

 

 

3.继续开展搜索工作,base64未免太过简单了吧,使用FindCrypt3插件 ,搜索一下算法常量吧

 

此时找到了AES的算法常量,前两个是重复的,可能是插件问题。

 

 

4.好的,现在面临一个问题,我不懂算法,怎么解密。。。只能去问度娘了,搜索一下AES加密解密原理与 C 实现代码

 

5.根据搜索得知:

  • AES使用最后那个常量数组进行解密
  • AES有五种加密模式,常用的为ECB CBC模式
  • 根据AES密钥长度,有不同的加密轮数(不是很懂哈。。)

6.对解密常量进行交叉引用跟踪,找到这个函数以后,继续对函数进行交叉引用跟踪

 

 

大概经过三四次的跟踪,发现了这个函数,在这个函数里F5查看反编译代码,发现了app.asar字符串的引用

 

 

 

7.此时进行推测,这个函数加载了app.asar的内容,并且调用 SUB_180003E40进行解密

 

8.跟进SUB_180003E40 进行查看 ,此时发现了base64字符串的引用,推测对buffer进行了base64解密

 

 

9.看到很多不认识的API,百度搜索得知,这是Node API,简单去看一下函数功能http://nodejs.cn/api/n-api.html#napi_call_function

1
2
3
4
5
6
NAPI_EXTERN napi_status napi_call_function(napi_env env,            //环境
                                           napi_value recv,         //名为global的值
                                           napi_value func,            //要调用的javascript函数
                                           size_t argc,                //JavaScript函数的参数个数  类似argc
                                           const napi_value* argv,  //JavaScript函数的参数数组  类似argv
                                           napi_value* result);     //返回的JavaScript对象

10.根据文档得到的信息,参照这一部分Node API,得到了如下信息(猜测调用了此函数)笔者对这语法难以理解,程序的目的是把对象进行base64编码?但是看这代码,base64也没有被当作参数传递进去(不纠结了)

1
2
3
4
5
Buffer.from( object, encoding )
object:此参数可以包含字符串,缓冲区,数组或arrayBuffer。
encoding:如果对象是字符串,则用于指定其编码。它是可选参数。其默认值为utf8。
 
Buffer.from(string[, encoding]): 返回一个被 string 的值初始化的新的 Buffer 实例

11.暂时先不管node api的语法与功能,继续往下看

 

 

看到了这部分的函数调用,进入查看,发现与 C实现AES算法结构相似,推测这部分为AES解密

分析总结

根据目前的分析,得到如下信息

  • main.node模块使用node api 进行js函数调用
  • main.node模块使用了AES解密算法(模式未知)

到了这一步,想要继续破解,首先要得到js代码,有两个办法以及面临的问题

 

1.分析算法,找到密钥,如果是CBC模式,还需要找到IV ,之后使用解密算法,解密app.asar的js代码

 

2.分析程序执行流程,找到解密后的缓冲区,直接拷走,得到彻底解密后的js代码

 

面临的问题:

  • nodejs语法不懂,这些api调用的具体js函数不清晰
  • AES解密流程不熟悉,找到密钥或者iv的难度较高(通过加密轮数判断密钥长度,通过算法部分判断加密模式,并找到相关数据)
  • 就算你找到解密AES的办法,它会不会还有别的加密措施与防护措施,例如密钥需经过hash摘要,文件完整性校验等(如果还有加密保护措施,那还得继续分析别的算法,一步一步还原,对于算法不熟悉的人时间成本太大了)

大海捞针 : 寻找JS代码

1.根据之前的分析,我选择第二种获得js代码的办法 , 分析程序执行流程,得到解密后的 JS代码

 

2.分析解密前的 js函数调用, 由之前的分析得知, 参数有两个 , 在V27的位置, V27是由参数 a3 +8 得来的 。好,动态调式一波

 

 

3.x64dbg打开typora.exe,下一个dll断点,根据之前分析,他是动态加载的(多打了个a 懒得换图了)

 

 

4.断点设置完成后,断在loadlibrary ,进入模块入口后 ,去IDA计算偏移,定位到前面分析的函数位置

 

对了,记得使用x64dbg自带的 PEB隐藏功能,并忽略所有异常,这个模块有简单的反调试手段(查看导入表可知,太过简单不分析反调试手段了)

 

 

定位函数位置,直接看后4位即可,同样为模块偏移 674A的位置

 

 

 

5.下断后查看decrypt(命名一下方便)函数的参数,x64架构下,函数参数为 rcx rdx r8 r9 rsp+0x20

 

前四个从左到右,超过四个则入栈,rsp+0x20为起始地址,详情可参考微软x64调用约定

 

 

6.r8 = a3 查看 *(a3 + 8)的值 ,这个值为之前分析的 v27 地址, 也就是argv 继续查看指针指向内容

 

 

 

现在得到了buffer.from js函数的两个参数 ,第一个像是密文,第二个没看出来,不是预料中的base64,所以之前的推断貌似是错的?

 

7.关注一下这两个地址 0000079908482119 00000799083CFEA5 在调用完js函数会有什么改变,直接来到调用的位置,调试器同步来到这个位置

 

 

 

好,来到这个位置再次确认参数, 第五个参数为 rsp+20 , 也就是rax的值, rax为argv ,进入内存查看,得到前面同样的地址 ,也就是 (a3 + 8),步过这个函数,查看对参数的改变

 

8.执行完后查看刚才记录的位置,好的好的,耍我呢,啥都没变,并且后续也没调用相关数据(或许是最后一个参数返回了一个对象,忘记看了,如果返回的话应该是密文相关的东西,并且放到了某个数据结构中,所以在IDA中没看到直接使用的行为)

 

继续分析,到了AES解密代码部分,既然是解密,那肯定得把密文的缓冲区拿过来吧

 

 

首先看到一串16进制的赋值,v46开头的数组 刚好32个字节,也就是256bit 。 有点像是AES-256的样子了

 

然后看到申请了 32字节的内存,v32

 

之后调用了 sub_18000B060函数,对v46 与 v32进行操作, 目测参数为 (目标地址,源地址,大小)

 

进入 sub_18000B060函数查看 ,一大堆运算 ,根本不想看 ,根据之前的推测,可能是作者感觉直接把密钥放在程序中有些不妥,所以对密钥进行一个类似于解密或hash运算的工作(不展开分析了)

 

9.继续分析

 

 

可以看到sub_180007000 函数 ,参数v45 IDA提示我是一个 char[256]的数组,v32为32字节的地址,v10为一串神秘数据

 

可以得到一个结论,在经过 v46的一系列运算,得到了一个同样大小 32字节的数据,再把数据 与 v10神秘数据进行操作,放入v45的256字节的数组中(好家伙 这是密钥吗 搞这么复杂)

 

跟进sub_180007000 查看, 把v10放到了 v45数组的0xF0的位置

 

之后调用了sub_180007800函数对自己的PE文件有些操作,简单看了下前面的汇编,主要内容为,把v32 放到 v45中,大小为32字节

 

 

10.继续分析

 

 

接下来看一下sub_180005c00 函数, 使用了v27 ,之前分析出来的密文地址就在v27中, v30没看出来,应该是传出参数,后面用到了

 

猜测这个函数对密文进行一波操作, 看一下返回值用来做什么,这个伪代码看的头疼,汇编看一下

1
2
3
4
5
.text:0000000180004021                 call    sub_180005C00
.text:0000000180004026                 mov     rbx, rax
.text:0000000180004029                 mov     r14, [rax+8]    ;返回值+8的内容给 r14
.text:000000018000402D                 sub     r14, [rax]       ; r14 - 返回值的内容
.text:0000000180004030                 mov     rcx, r14        ; 得到一个大小 Size

人工反编译一下 首先确定rax为一个指针 *(rax+8) - *rax 就是这个地址里面存储了两个值,拿第二个值减第一个值得到一个size

 

此时猜测,这两个值或许是 密文的开始地址与结束地址?

 

然后用这个size 申请了一块内存 , IDA 命名为 Block , sub_18000B060 之前分析过, 对*v12进行操作, 结果给到Block

 

把V12代入rax中 , *(v12+8) - *v12 , 结束地址减去开始地址得到 size

 

由此可以验证猜测, *v12 为密文开始地址 ,V13为密文大小

 

11.继续分析第三个方框的内容

 

以v13 + 1 的大小 申请了一块内存 v14 , sub_18000B060 对 Block 再次进行操作, 结果给到v14

 

v14的最后一个字节置为0 ,推测已经把密文转换为字符串了 , 需要一个 NULL 结尾

1
2
3
;v15 = r8d   rcx = v13    rbx = v14 
.text:0000000180004094                 movsxd  rcx, r14d
.text:0000000180004097                 movzx   r8d, byte ptr [rcx+rbx-1]

由上可得 v15 = v14[v13-1] , 也就是从v14中取了一个字节的值 ,位置在null字符的前一byte

 

12.继续分析sub_180006AC0

 

 

可以看到,sub_180006AC0 的参数 , v45(256字节数组),block ,v13

 

结合之前对 sub_180007000的分析,可以得知, 目前v45的状态 ,v45[0-31]为32字节的类似密钥的东西 v45[0xF0] 为 v10的神秘数据 ,v13为Block大小

 

跟进简单查看 ,查看后感觉可读性不好,笔者对照汇编代码,重新修改了一下反编译代码

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
__int64 __fastcall sub_180006AC0(v45,block,block_size)
{
 
  if ( block_size )
  {
    v3 = block;
    v5 = v45 + 0xF0 - (_QWORD)block;           //v45+0xF0的地址  减去  block的地址得到v5
    v6 = ((block_size - 1) >> 4) + 1;          //做为外圈循环的次数
    do
    {
      v7 = *v3;             
     //v7为 xmmword 16字节浮点寄存器 ,把block的内容取16字节给v7  16字节符合AES块大小 
     //由此推测block是真正的密文,将在这个函数中进行解密操作
 
      sub_180007320(v3, v45);    //用到了AES解密常量  应该是解密相关  并且对推测的key  也就是前32字节有一些操作
      v8 = 16i64;                //内圈循环16
      do
      {
        result = *((char*)(v3 + v5));       //block地址 + v5偏移  取一个字节内容
        *(char*)v3 ^= result;               //取block的1字节数据,与block地址 + v5偏移  进行异或
        v3 = (__int128 *)((char *)v3 + 1);  //block += 1
        --v8;                                //总共16次 也就是16个字节异或
      }
      while ( v8 );
      v5 -= 16i64;                          //外圈循环  v5 每次-16  也就是每次异或 异或的值都会变化 范围为-16字节
      v45 + 0xF0 = v7;                        //block的16字节内容  给到v45+0xF0
      --v6;                                    //外圈循环次数
    }
    while ( v6 );
  }
  return result;  
}

根据目前的分析,可以推测 ,sub_180006AC0函数为 主要的解密算法函数,看着像是 AES CBC模式,因为对算法不熟悉,大胆猜测一下

 

key存放在v45中, 前32字节 ,也就是256位 , iv存放在 block+v5中 (不清楚对不对)

 

13.继续分析剩下的内容

 

 

好的好的,看着有点头疼,后面的代码大概意思就是,又对解密后的数据进行了一系列操作,最后返回了一个缓冲区

 

读者感兴趣可以自行分析,实在是写不动了

釜底抽薪 : 得到JS代码

1.根据前面的分析,我们已经大致了解了程序流程,来到调用解密函数的函数,只需要在彻底解密后,送到JS引擎执行的时候,拿到解密的JS代码即可

 

 

2.根据上层调用代码,可以得到,解密后返回了一个值,作为调用JS函数的参数 ,定位到678F偏移处,x64dbg同步定位

 

 

3.断下后查看v28的内容 , RSP+20 的位置,然后继续查看这个指针的指针的内容,最后得到了解密后unicode形式的JS代码

 

 

4.把内容拷走,拿到010editor,把00去掉,变成ascii形式,检查一下得到的数据

 

 

看起来跟密钥有关的一串字符编码数据

 

 

搜索一下license相关的数据, 找到不少,看起来也像是代码,应该没问题

指鹿为马 : 破解可行性分析

修改文件破解

如果懂算法与NodeJS,可以通过分析,找到关键的key等数据,对app.asar进行解包解密操作得到JS代码进行修改后,打包回去即可

 

可能遇到的问题:对app.asar进行完整性校验

内存破解

简单说几种思路,由于main.node是后加载的模块,所以内存破解有些难度

  1. 调试器加载 : 参照上述手段,在模块加载通知中断下,定位到解密函数下断,修改内存中的JS代码
  2. 导出表HOOK: 参考病毒木马使用的进程替换(傀儡进程)技术,创建进程后挂起,由于main.node中的node api是使用框架中的导出api,所以可以替换导出函数为自己的函数,在调用时进行参数判断,如果为JS代码,则修改
  3. DLL劫持:替换main.node,由自己加载真正的main.node并调用,调用时,定位到解密函数并hook,等待JS代码并修改
  4. PE代码注入 : 修改框架的PE文件,并加载自己的DLL,加载后进行导出表hook

可能遇到的问题:对main.node或者框架进行完整性校验,更加强大的反调试手段

 

方法还有很多,不再一一列举,这里只能提出思路

点到为止 : 总结

  1. 通过这次逆向分析,踩了不少坑,学到了不少东西,并且加深了逆向技术的基础
  2. 作为一个逆向练习生,遇到不懂的,不会的,应该迎难而上,扬长避短,不可轻言放弃
  3. 遇到一个纠结的地方,不要过度停留,逆向分析应该是分析大方向,站在开发者角度,根据分析出来的功能猜测作者的意图,以找到关键突破点

结语

  1. 由于笔者对算法与Node Js开发并不熟悉,所以没办法得到密钥与其它解密数据(文章中关于算法的一些操作皆为推测,相信熟悉算法的大佬可以看出来密钥所在)
  2. 对于最后得到的JS代码也没办法判断到底完不完整,是否还有未解密的部分,所以只能到此为止了(看起来是完整了)
  3. 经过笔者一段时间的努力,已经成功实现内存破解,详情Typora破解之内存破解

【看雪培训】《Adroid高级研修班》2022年春季班招生中!

最后于 2022-5-17 17:36 被yumoqaq编辑 ,原因:
收藏
点赞11
打赏
分享
打赏 + 80.00雪花
打赏次数 1 雪花 + 80.00
 
赞赏  Editor   +80.00 2022/05/18 欢迎大家多多投稿优质文章,赢取“雪花”奖励~
最新回复 (18)
雪    币: 4970
活跃值: 活跃值 (1641)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bluefish蓝鱼 活跃值 2022-4-28 23:17
2
0
我记得7z有个插件可以解压asar文件的,好像叫Asar7z
雪    币: 1287
活跃值: 活跃值 (1324)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小希希 活跃值 2022-4-29 10:28
3
0
好文章
雪    币: 9217
活跃值: 活跃值 (34232)
能力值: (RANK:105 )
在线值:
发帖
回帖
粉丝
Editor 活跃值 2022-4-29 11:52
4
0
楼主,可以继续研究,感觉离成功还差一步,注册算法分析出来,就可以改为精华了。
雪    币: 3591
活跃值: 活跃值 (2073)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝
yumoqaq 活跃值 3 2022-4-29 12:00
5
0
Editor 楼主,可以继续研究,感觉离成功还差一步,注册算法分析出来,就可以改为精华了。
多谢版主点评,我会继续努力
雪    币: 19
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_vbvedwhm 活跃值 2022-4-29 17:45
6
0
逆向大佬
雪    币: 28
活跃值: 活跃值 (175)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lihuakx 活跃值 2022-4-29 22:53
7
0
可以参考下这个:https://www.52pojie.cn/forum.php?mod=viewthread&tid=1553967&highlight=typor
里面讲了怎么还原js。
这个破解全部在js中。也可以做注册
雪    币: 0
活跃值: 活跃值 (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
nikoladi 活跃值 2022-4-30 19:18
8
0
要学到大佬这个程序,需要学哪些资料啊,希望指点一下。
雪    币: 232
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
毕云涛 活跃值 2022-4-30 21:11
9
0
大佬太强了
雪    币: 435
活跃值: 活跃值 (311)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
钞能力大叔 活跃值 2022-5-3 23:13
11
0
Editor 楼主,可以继续研究,感觉离成功还差一步,注册算法分析出来,就可以改为精华了。
可以参考,支持最新版 https://bbs.pediy.com/thread-272604.htm
雪    币: 2656
活跃值: 活跃值 (451)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
CRoot 活跃值 2022-5-4 21:00
12
0

第一个框是IV,第二个框就是AES的Key

破解的话,其实搞他的离线认证就很简单,把公钥一替换,私钥自己颁发就行了,其他流程都不用动。

雪    币: 3591
活跃值: 活跃值 (2073)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝
yumoqaq 活跃值 3 2022-5-8 11:21
13
0
nikoladi 要学到大佬这个程序,需要学哪些资料啊,希望指点一下。

所有名字带逆向的书都看一遍先……可以网上搜一下相关的

最后于 2022-5-8 11:21 被yumoqaq编辑 ,原因:
雪    币: 711
活跃值: 活跃值 (135)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
涛之雨 活跃值 2022-5-18 18:54
14
1
本帖这个样本应该是1.2+(稳定版)1.2.2~1.3.1(dev),1.3.2-dev的加密算法又改了
https://github.com/taozhiyu/TyProAction/blob/main/scripts/mainUpdate.py
关键函数:buildTyPro
我是放弃了动态解密,选择直接去hook了=_=天天换加密谁受得了
雪    币: 5
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_UTmuH63D 活跃值 2022-5-18 19:09
15
0
雪    币: 5
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_UTmuH63D 活跃值 2022-5-18 19:13
16
0
大佬有联系方式吗
雪    币: 878
活跃值: 活跃值 (39)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
新手村1号 活跃值 2022-5-25 15:27
17
0
想开发一款软件,大佬留个联系方式
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
soocean 活跃值 2022-6-14 19:10
18
0
大佬有邮箱或者其他联系方式吗,有些问题希望和你进一步讨论下
雪    币: 208
活跃值: 活跃值 (24)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sxfenglei 活跃值 2022-6-17 09:30
19
0
涛之雨 本帖这个样本应该是1.2+(稳定版)1.2.2~1.3.1(dev),1.3.2-dev的加密算法又改了 https://github.com/taozhiyu/TyProAction/blob/m ...
访问不了了
游客
登录 | 注册 方可回帖
返回