首页
社区
课程
招聘
[原创]Sublime Text 4 Build 4126 RSA 公钥替换分析
发表于: 2022-2-25 17:08 17775

[原创]Sublime Text 4 Build 4126 RSA 公钥替换分析

2022-2-25 17:08
17775

这是一个比较简单的例子,可以用来学习一下如何替换RSA公钥。


相关下载链接:

         macOS https://download.sublimetext.com/sublime_text_build_4126_mac.zip

      Windows https://download.sublimetext.com/sublime_text_build_4126_x64.zip

Linux x86-64 https://download.sublimetext.com/sublime_text_build_4126_x64.tar.xz

         ARM64 https://download.sublimetext.com/sublime_text_build_4126_arm64.tar.xz


官网:https://www.sublimetext.com/download


目标文件:sublime_text.exe (Windows)


调试分析(构造许可、替换RSA公钥):

在载入调试器后,搜索"Unlimited"字符串,定位到调用代码段。


图(1)

如图(1)所示,这里的代码段将会为你拼接一个伪许可,其格式如下:


Name

Unlimited User License

EA7E-1000

00000000000000000000000000000000

00000000000000000000000000000000

00000000000000000000000000000000

00000000000000000000000000000000

00000000000000000000000000000000

00000000000000000000000000000000

00000000000000000000000000000000

00000000000000000000000000000000

00000000000000000000000000000000


到这里我们就有了许可的基本格式了,然后继续Step over。在图(1)的代码段下方会进入一个关键调用(所有验证在这里进行)。如图(2)所示:

图(2)

在图(2)中被选中的调用处,我们Step into,如图(3)所示:

图(3)

你可以通过搜索字符串"E52D"快速跳转到此调用,并向上查找图(3)所示的代码段。图中被选中的这段代码(文件不同出现的位置都可能不同,我们进入此调用后,通过Step over,应该很容易找到它)做了一件事情,那就是将一个数组的每一个字节去异或0x7F(文件不同异或值都可能不同),同时将新的数据放到另一个数组中。


原始数据(偏移:xxxxx8890):

4FFEE24F72797655F937F988727E7E7E7A7F7CFEF47F4FFEF87DFEFE7FA704DD3A1D88BAAE3573846DC60B73662314A3011211B654D371CDE2269EA6D118F67354F7BCD4A3D08102354CA3BEC0C12C655A639073ED4079C106CD4DFA26D38196F9AA9E213268199529BB9E7928850BA47608BC840AFDC8F3AB04CDB886CD2DCBD639426A89D111965C022BBA37648C9FCFE65F6674B0CC61249A76BC447D7E6E


异或0x7F(局部变量:堆栈):

30819D300D06092A864886F70D010101050003818B0030818702818100D87BA24562F7C5D14A0CFB12B9740C195C6BDC7E6D6EC92BAC0EB29D59E1D9AE67890C2B88C3ABDCAFFE7D4A33DCC1BFBE531A251CEF0C923F06BE79B2328559ACFEE986D5E15E4D1766EA56C4E10657FA74DB0977C3FB7582B78CD47BB2C7F9B252B4A9463D15F6AE6EE9237D54C5481BF3E0B09920190BCFB31E5BE509C33B020111


为了获取异或结果,我们可以通过继续Step over,且在图(4)所示的代码段中被选中的位置停下,通过寄存器rsi的值,来定位它的内存位置。

图(4)

现在我们一起来观察一下异或结果,通过观察我们发现,这不是DER格式的RSA Public Key?有点小兴奋,不过我们还是继续Step over,直到到达图(5)所示的代码段中被选中的位置停下。

图(5)

在图(5)中被选中的调用处,我们Step into,如图(6)所示:

图(6)

在图(6)中被选中的调用主要用于许可格式的验证(在这里我们暂时不去详细分析它)。我们Step into后继续Step over,会发现有一小段代码,被用来检查许可内容的行数。如果总行数(非空行)乘上0x20后的结果既不等于0x1A0也不等于0x160,则说明许可内容的行数错误。也就是说我们许可的总行数(非空行)必须是13行或者11行,而我们的伪许可有12行,在这里我们删掉一行0(其它信息看似是必须的),我们就得到了一个新的伪许可。


Name

Unlimited User License

EA7E-1000

00000000000000000000000000000000

00000000000000000000000000000000

00000000000000000000000000000000

00000000000000000000000000000000

00000000000000000000000000000000

00000000000000000000000000000000

00000000000000000000000000000000

00000000000000000000000000000000


接下来我们让程序彻底运行起来,直到我们可以通过help菜单输入许可为止。

图(7)

在许可输入窗口中输入我们新的伪许可(如图(7)所示),然后点击使用许可按钮。程序将在图(3)的位置被断下。我们让程序继续运行,直到再次到达图(6)中被选中的调用处,Setp over后发现许可格式顺利通过(通过该调用下方跳转来判定)。

图(8)

我们继续Step over,到达图(8)中被选中的调用处,此处主要用于完成签名验证(在这里我们暂时不去详细分析它)我们Step into,跟踪分析后发现在内部的子调用中的注解栏中出现了和图(9)类似的信息。

图(9)

这,... 图(9)给我们展示了非常多的信息了,首先它使用了一个第三方库,库名叫tomcrypt,同时也知道了这个子调用的函数原型来自rsa_verify_hash.c这个文件(其它子调用类似)。我们直接bing.com找到这个库(https://www.libtom.net),下载源代码,解压到桌面,找到rsa_verify_hash.c,同时打开源代码文件夹中的pdf,得知图(9)这个子调用的函数原型对应的是rsa_verify_hash这个函数,且功能为RSA签名验证。

经过追踪分析得到了结论:我们新的伪许可中的0字串在转换到16进制后作为签名传递给了对应图(9)的子调用。我们新的伪许可中的非0字串被格式化为"Name\nUnlimited User License\nEA7E-1000",并将它的SHA1结果传递给了对应图(9)的子调用。除此外RSA签名padding使用的是PKCS #1 V1.5格式(被签名内容不够时追加0xFF),且通过公钥信息可以知道我们的模为1024位(RSA-1024)。

根据追踪分析得到的结论,我们找到了逆向计算签名的过程: 首先将"Name\nUnlimited User License\nEA7E-1000"原始信息进行SHA1处理,然后将处理结果进行DER编码,编码完成后使用PKCS #1 V1.5 签名padding(被签名内容不够时追加0xFF),最后使用幂模运算对padding后的数据进行加密,加密结果即是我们最终的签名


至此,我们已然知道我们的许可必须由以下内容构成:


用户名 + 许可类型 + EA7E-1000 + 签名(1024bit)


现在我们终止调试,因为接下来我们需要创建一个新密钥,且使用新密钥的公钥来替换原始公钥,使用新密钥的私钥来进行签名。这里我们直接使用tomcrypt密码库来完成(使用简单,且容易理解)。tomcrypt的RSA功能需要依赖math库,有两个可供选择:tommath、tomfastmath(在这里我们选择tommath)。为了使用一个固定的RSA密钥,所以我们不使用tomcrypt的rsa_make_key。而直接使用openssl来产生一个固定的RSA密钥。


// generate a private key. 

> openssl genrsa -3 -out rsa_prvkey.pem 1024


// convert to traditional DER format private key. 

> openssl rsa -in rsa_prvkey.pem -traditional -out rsa_prvkey.der -outform DER


-traditional:旧版的openssl是不需要这个选项的,新版openssl需要加上。


在产生rsa_prvkey.der文件后,我们可以在程序中直接读取该文件内容,也可以把该文件内容以字节数组的方式添加到代码中(此处我们选择第二种方式)。


const unsigned char prvkey[] = { 内容省略 };


const char *info = "yystarsky\n256 User License\nEA7E-1000";


int main(void) {

    unsigned char pubkey[160], sign[128];

    unsigned char hash[20];

    unsigned long lh, lp, ls, idx;

    rsa_key key;

    int err, hash_idx;


    /* register a math library */

    ltc_mp = ltm_desc;

    

    if (register_hash(&sha1_desc) == -1) {

        printf("Error registering sha1");

        return EXIT_FAILURE;

    }

    hash_idx = find_hash("sha1");

    

    err = rsa_import(prvkey, sizeof(prvkey), &key);

    if (err != CRYPT_OK) {

        printf("hash_memory %s", error_to_string(err));

        goto __err;

    }


    lh = 20;

    err = hash_memory(hash_idx, (const unsigned char*)info, strlen(info), hash, &lh);

    if (err != CRYPT_OK) {

        printf("hash_memory %s", error_to_string(err));

        goto __err;


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2022-5-21 07:50 被Mr.zhong编辑 ,原因: 编辑
上传的附件:
收藏
免费 7
支持
分享
最新回复 (35)
雪    币: 4605
活跃值: (4527)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
学习了,多谢分享
2022-2-25 20:42
0
雪    币: 1250
活跃值: (3560)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
学习了,多谢分享
2022-2-26 10:40
0
雪    币: 6525
活跃值: (3423)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
非常好的文章 ,学习了。
研究了一下,Sublime text 确实如此,但是 Sublime merge 的许可编号似乎必须从 0001 开始,不然会出错
2022-2-27 22:34
0
雪    币: 756
活跃值: (638)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
Kisesy 非常好的文章 [em_63],学习了。 研究了一下,Sublime text 确实如此,但是 Sublime merge 的许可编号似乎必须从 0001 开始,不然会出错
哦,好的,我给它备注上。merge我没分析
2022-2-27 23:22
0
雪    币: 6525
活跃值: (3423)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
Mr.zhong 哦,好的,我给它备注上。merge我没分析[em_1]

感觉 Sublime text 比较简单一些,公钥 sha256 后检测第 30 位,是 0x56 就可以

这个通过暴力枚举就能跑出来,merge 好像要检测3个地方:
  if ( !(v22[18] ^ 0xEA | v22[12] ^ 0xCE | v22[30] ^ 0x56) )
    v15 = v14;
我在试试看能不能枚举出来

最后于 2022-2-28 00:10 被Kisesy编辑 ,原因:
2022-2-28 00:08
0
雪    币: 16429
活跃值: (1690)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
不错,支持下。
2022-2-28 04:55
0
雪    币: 4605
活跃值: (4527)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
Kisesy Mr.zhong 哦,好的,我给它备注上。merge我没分析[em_1] 感觉 Sublime text&a ...
怎么暴力枚举,枚举成这位是56的公钥吗,那私钥怎么定
2022-2-28 07:48
0
雪    币: 1144
活跃值: (4222)
能力值: ( LV5,RANK:69 )
在线值:
发帖
回帖
粉丝
9
Kisesy Mr.zhong 哦,好的,我给它备注上。merge我没分析[em_1] 感觉 Sublime text&a ...
应该都是检测三个字节?
2022-2-28 07:59
0
雪    币: 6525
活跃值: (3423)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
10
yaoguen 怎么暴力枚举,枚举成这位是56的公钥吗,那私钥怎么定

我是用Go生成的,就是随机生成一个1024位的私钥,然后从私钥生成公钥,然后转成 x509 格式,再转成 hex 格式,再计算 sha256 哈希,再比对哈希的某一位


我上传了代码和程序,如果碰撞出了 key 会生成 rsa_prvkey.pem 文件,希望大家都来跑一下,把生成的 key 共享一下(不要跑了,跑不出来)

最后于 2022-2-28 15:59 被Kisesy编辑 ,原因:
上传的附件:
2022-2-28 09:09
0
雪    币: 756
活跃值: (638)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
11
Kisesy yaoguen 怎么暴力枚举,枚举成这位是56的公钥吗,那私钥怎么定 我是用Go生成的,就是随机生成一个1024位的私钥,然后从私钥生成公钥,然 ...
我也试试,看看多长时间能碰出来
2022-2-28 09:43
0
雪    币: 756
活跃值: (638)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
Kisesy yaoguen 怎么暴力枚举,枚举成这位是56的公钥吗,那私钥怎么定 我是用Go生成的,就是随机生成一个1024位的私钥,然后从私钥生成公钥,然 ...

很容易找到一个了,我这里公钥指数取的17。这里只查了第31(偏移30)个字节为56。你们分析的需要检测几个字节啊?我只查到2个字节,但是关键字节就是第31(偏移30)个字节,第32(偏移31)个字节程序似乎没有往哪儿运行, 要不把sha256所有字节一起猜?(哦,不能一起猜,一起猜等于是在找私钥了。图检测字节有误,所以删除了!)


最后于 2022-3-2 15:34 被Mr.zhong编辑 ,原因:
2022-2-28 10:37
0
雪    币: 6525
活跃值: (3423)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
13
Mr.zhong 很容易找到一个了,我这里公钥指数取的17。这里只查了第30个字节为56。你们分析的需要检测几个字节啊?我只查到2个字节,但是关键字节就是第30个字节,第31个字节程序似乎没有往哪儿运行,要不把它的整个 ...
00007FF6747E57F0    | 8A43 0C                | mov al,byte ptr ds:[rbx+C]               |
00007FF6747E57F3    | 8A4B 12                | mov cl,byte ptr ds:[rbx+12]              |
00007FF6747E57F6    | 34 CE                  | xor al,CE                                |
00007FF6747E57F8    | 80F1 EA                | xor cl,EA                                |
00007FF6747E57FB    | 8A53 1E                | mov dl,byte ptr ds:[rbx+1E]              |
00007FF6747E57FE    | 80F2 56                | xor dl,56                                |
00007FF6747E5801    | 08C2                   | or dl,al                                 |
00007FF6747E5803    | 08CA                   | or dl,cl                                 |
00007FF6747E5805    | BF 1B010000            | mov edi,11B                              |
00007FF6747E580A    | 41:0F44FE              | cmove edi,r14d                           | r14d 是 119, 写到 edi 就成功
00007FF6747E580E    | 81FF 19010000          | cmp edi,119                              |
00007FF6747E5814    | 0F85 23010000          | jne sublime_merge.7FF6747E593D           | 不能跳
00007FF6747E581A    | 48:8D15 61E27900       | lea rdx,qword ptr ds:[7FF674F83A82]      | rdx:EntryPoint, 00007FF674F83A82:"E52D"

我是碰撞的 sublime_merge.exe ,这部分代码在 文件偏移:24BF0

最后于 2022-2-28 10:58 被Kisesy编辑 ,原因:
2022-2-28 10:56
0
雪    币: 756
活跃值: (638)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
Kisesy Mr.zhong 很容易找到一个了,我这里公钥指数取的17。这里只查了第30个字节为56。你们分析的需要检测几个字节啊?我只查到2个字节,但是关键 ...

每个版本检测的字节好像都有点变化

最后于 2022-2-28 13:46 被Mr.zhong编辑 ,原因:
2022-2-28 13:45
0
雪    币: 6525
活跃值: (3423)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
15
00007FF6080496C6    | 8A46 0E                | mov al,byte ptr ds:[rsi+E]    |
00007FF6080496C9    | 8A4E 12                | mov cl,byte ptr ds:[rsi+12]   |
00007FF6080496CC    | 34 A5                  | xor al,A5                     |
00007FF6080496CE    | 44:08F8                | or al,r15b                    |
00007FF6080496D1    | 80F1 EA                | xor cl,EA                     |
00007FF6080496D4    | 8A56 1E                | mov dl,byte ptr ds:[rsi+1E]   |
00007FF6080496D7    | 80F2 56                | xor dl,56                     |

还真是,我又下了 4129 版的 sublimetext,又变成检测这几个了,我还以为能写出个通用的注册机呢
2022-2-28 14:12
0
雪    币: 4605
活跃值: (4527)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
好像都要检查3个字节
2022-2-28 14:17
0
雪    币: 756
活跃值: (638)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
17
yaoguen 好像都要检查3个字节
说说
2022-2-28 14:29
0
雪    币: 756
活跃值: (638)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
18
Kisesy 00007FF6080496C6    | 8A46 0E                | mov al,byte ptr ds:[rsi+E]    | 00007FF6080496C9     ...

另外还看了一下mac的好像也是有些不同,感觉这个没有固定检测那些字节。

最后于 2022-2-28 15:06 被Mr.zhong编辑 ,原因:
2022-2-28 15:03
0
雪    币: 1144
活跃值: (4222)
能力值: ( LV5,RANK:69 )
在线值:
发帖
回帖
粉丝
19
Kisesy 00007FF6080496C6 | 8A46 0E | mov al,byte ptr ds:[rsi+E] | 00007FF6080496C9 ...
1字节替换公钥and keygen
2022-2-28 15:11
0
雪    币: 756
活跃值: (638)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
20
小菜鸟一 1字节替换公钥and keygen

只改一个字节的话,怎么因式分解呢?有窍门?

最后于 2022-2-28 15:38 被Mr.zhong编辑 ,原因:
2022-2-28 15:32
0
雪    币: 4605
活跃值: (4527)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
修改N为素数,当N为素数时,RSA采用下面的公式计算私钥:
φ(N)=N-1 
D = 1/E mod (φ(N))
2022-2-28 16:21
1
雪    币: 756
活跃值: (638)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
22
yaoguen 修改N为素数,当N为素数时,RSA采用下面的公式计算私钥: φ(N)=N-1 D = 1/E mod (φ(N))

哦,谢谢!刚一开始还是能理解,但是分析着分析着又绕回到P、Q上去了。

最后于 2022-3-2 03:23 被Mr.zhong编辑 ,原因:
2022-2-28 16:30
0
雪    币: 1144
活跃值: (4222)
能力值: ( LV5,RANK:69 )
在线值:
发帖
回帖
粉丝
23
我乱说的,哈哈
2022-2-28 16:46
0
雪    币: 756
活跃值: (638)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
24
Kisesy 00007FF6080496C6 | 8A46 0E | mov al,byte ptr ds:[rsi+E] | 00007FF6080496C9 ...
你跑出多个字节的钥匙了吗?我做4个字节比对,感觉希望渺茫,已经跑了很长时间了
2022-2-28 19:15
0
雪    币: 6525
活跃值: (3423)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
25
个人感觉不太容易,一两个字节应该还可以,但是要是四五个的话那估计都能把它原始的密钥给跑出来了
这是这个帖子中发现的检查点,估计还有吧
01        0x34
0c        0xce
0e        0xa5
12        0xea
1e        0x56
主要是这也是我第一次搞 rsa,基本的公式都不怎么熟悉,要是高手的话,找到一些捷径,也许能搞出来
2022-2-28 20:36
0
游客
登录 | 注册 方可回帖
返回
//