首页
社区
课程
招聘
[原创]一个有趣的CrackMe的分析与注册机的编写 by lantie@15PB
发表于: 2017-9-8 23:20 10794

[原创]一个有趣的CrackMe的分析与注册机的编写 by lantie@15PB

2017-9-8 23:20
10794

[toc]

目录(MarkDown自动生成的目录截图):

有弹出信息框,猜测是MessageBoxA

VC6.0编写的程序

有MFC42.dll 是MFC程序的动态库,动态编译的VC6 MFC程序

断下之后,查看调用堆栈(使用Alt+K键或是点击工具栏k),找到自己模块,查看代码

可以发现有一些字符串

可见可能是按钮事件的代码,跟踪代码到这个函数的上一层,如果是mfc42模块说明这个函数的开始就是按钮事件的开始,如果不是,继续再往上分析

跟踪之后发现到了mfc42模块,也找到了按钮事件的特征,说明是有字符串的代码所在的函数就是按钮事件的代码,脱到函数开始,然后开始分析!~

按钮事件起始地址:00401410

由于本题目采用的是共享库编译,且MFC DLL是序号导出的函数,所以直接在OD中看反汇编不是太方便,为了能更快速的分析代码,可以使用IDA Pro的强大功能 F5 静态分析,与OD动态调试相结合


可以发现按钮函数里只有一个是函数 sub_4015E0 是自己的函数,参数是2个,所以猜测是用户名和密码。

跟踪代码可以发现 调用 call 4015E0 的堆栈信息是用户名和密码

对F5之后的伪代码 进行修改,由于上个代码可以发现传递的参数是字符串,且在上一个函数中有CString对象的拷贝赋值,所以参数类型应该是CString&,修改参数类型,以及参数名称

修改完参数和参数名称之后仔细分析一下伪代码

仔细分析可以发现这段代码中有两个函数很关键,一个是解密函数sub_4015a0,一个是求hash的函数sub_401550,有两个值很重要,一个是解密的起始地址(伪代码中的data_start),一个是解密长度(伪代码中的len)。
下一步就是验证分析的结果已经查看关键的信息的值和调用情况

动态跟踪查看 call 402000的结果eax

根据eax=402010 大概猜测是代码地址,所以解密的是代码
查看其反汇编和内存区段信息可以看出是在代码段.text1

根据区段名称,可以猜测可能是专门添加的区段。
再继续分析下面的代码,发现 call 402ac0 的返回值也是代码地址00402ac0

再继续单步跟踪,可以看出以下计算的值就是要解密的大小


到此,关键的值已经分析出来了,就是

由于求hash值,这个操作不可逆,所以只能使用暴力破解,暴力破解需要不停的执行代码,所以需要将解密函数和求hash的函数从IDA中抠出来,写代码暴力破解。

使用 IDA f5 查看解密函数,并修改参数和参数类型

可以看出以上代码没有引用其他的变量或是函数,所以将其直接复制到VS中即可。

求hash函数的伪代码中有函数调用,也有全局变量,这些需要都统计

需要将引用的函数以及变量全部扣出来,才可以。所以先分析引用的函数以及变量的功能并为其命名,然后再抠代码
查看IDA的伪代码,可以分析出如下结果

InitHashTable函数的代码分析如下:

分析完代码中的引用函数和变量之后,最后需要确定变量g_hashTbale的大小。从InitHashTable函数中可以看出g_hashTbale的大小应该是数据段中g_hashTbale的地址到g_IsInit的地址。在IDA中查看两个变量的地址

我们只需要将以上两种优化加入循环,暴力破解的速度就会增加很多。优化的代码如下:

使用OD动态跟踪程序,当输入的密码前4位是前面算出来的字符串BEEF时,内存中会正确解密代码,然后完成对用户名和密码前4位之后的验证和判断,验证函数就是之前分析的call 402010。代码解密之后的部分代码截图:

解密完成后,我们可以使用OD中的Ollydump插件dump已经解密的整个内存信息。然后再使用OD分析。

使用 F5 查看代码 很多函数调用无法分清到底哪个函数是做什么的,所以只能先动态调试,尝试多组用户名和密码,,观察CALL调用时参数和返回值等信息。

经过多组用户名和密码的尝试,OD与IDA动静结合分析,终于发现 402010处代码的一些函数的功能。

由于本文是后面补的,分析是在1年多以前了,所以一些OD动态调试记录的注释已经丢失,所以没办法将详细的过程分析,有的是思路和代码,供大家参考

对于以上来看,最关键的就是00402800处函数 与 004021a0处函数。两个函数最终计算出的来的值必须是一致的才算是正确。所以需要仔细分析两个函数的代码。为了计算大数方便,我使用了python来编写这两个函数的等价代码。

004021a0处函数,此函数的主要功能就是将传入的密码每两个字节转为一个16进制数据,并且与0x86进行异或
传入的值不是0-F的就返回0

换句话说,由于上面的函数只支持0-F的16进制值,可以简化为一张表,这张表对应 0-F 中的值。代码如下:

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 1
支持
分享
打赏 + 2.00雪花
打赏次数 1 雪花 + 2.00
 
赞赏  orz1ruo   +2.00 2017/09/09
最新回复 (23)
雪    币: 486
活跃值: (489)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
2
看雪的MarkDown  不能自动生成目录,这是一个Bug?
2017-9-8 23:22
0
雪    币: 47147
活跃值: (20460)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
3
蓝铁 看雪的MarkDown 不能自动生成目录,这是一个Bug?
目前还没这功能,以后可以考虑增加
2017-9-9 00:04
0
雪    币: 459
活跃值: (398)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
4
看看学习下
2017-9-9 08:45
0
雪    币: 1355
活跃值: (339)
能力值: ( LV13,RANK:920 )
在线值:
发帖
回帖
粉丝
5
详细,条理清晰,支持。
2017-9-9 09:35
0
雪    币: 6694
活跃值: (3514)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
6
   
2017-9-9 10:18
0
雪    币: 106
活跃值: (1993)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
7
老西
2017-9-9 10:30
0
雪    币: 308
活跃值: (230)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
8
666写得很详细。
2017-9-9 18:08
0
雪    币: 1176
活跃值: (1264)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
9
支持  ....
2017-9-9 20:57
0
雪    币: 775
活跃值: (2292)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
10
谢谢分享,让我们这些菜逼又对分析的思路深入一步了,唯今苦叹数学差矣,让我对密码学入门简直太难
2017-9-10 11:26
0
雪    币: 206
活跃值: (108)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
11
顶一个
2017-9-29 13:19
0
雪    币: 49
活跃值: (118)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
顶我大薛老师一下
2017-9-30 14:35
0
雪    币: 6584
活跃值: (4541)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
13
好详细
2017-10-9 10:09
0
雪    币: 35
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
15PB的老师  还是有两把刷子的
2017-10-10 10:33
0
雪    币: 9
活跃值: (180)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
15
讲的好细致
2017-12-19 21:39
0
雪    币: 888
活跃值: (2370)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
挺详细的教程贴
2018-6-13 10:24
0
雪    币: 300
活跃值: (2477)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
mark
2018-6-13 11:26
0
雪    币: 99
活跃值: (31)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
def bigmul(strings,otc):
    result = 0
    j = len(strings)
    for i in strings:
        tmp = i - 48
        result += (i - 48)
        j -= 1
        if (j>0):
            result *= otc
    return result

def crack4(name):
    a = 'BEEF'
    tmp = hex(bigmul(name,10) * bigmul(map(ord,'201510261314'),10))[2:-1]
    for i in tmp:
        t = ord(i)
        if(t > 0x40):
            t -= 39
        a += hex(t ^ 0x86)[2:4]
    return a

print crack4(map(ord,'your name'))
2018-9-5 13:58
0
雪    币: 232
活跃值: (929)
能力值: ( LV4,RANK:44 )
在线值:
发帖
回帖
粉丝
19
薛老师,这个可以不用爆破的,代码解密就是从0x402010开始的一个4字节的循环异或,可以找其他函数头匹配一下特征,除非他写的裸函数,实际上并没有。匹配的特征是push -1;push xxxxxxxx;mov eax,fs:[0],第9个字节开始正好有4字节0,那解密前402019处3F AB 9F 59其实就是密钥,算上偏移,密码前四位的值就是0x9FAB3F59^0xD9EE7A1B=0x46454542
2020-1-14 15:26
2
雪    币: 290
活跃值: (193)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
很少看到思路这么清晰这么详细的WP
2020-6-21 17:41
0
雪    币: 344
活跃值: (922)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
BIX
21
学到很多。
2020-8-11 14:25
0
雪    币: 2087
活跃值: (472)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
22
过了BEEF的算法,但后面的过不来,这个cm和这篇wp确实能学到好多东西
2020-9-22 08:37
0
雪    币: 217
活跃值: (351)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
判断求出的hash值与 0xAFFE390F 是否一致,不是继续
关于这一条中的0xAFFE390F是在哪找到的?
2020-10-28 19:44
0
雪    币: 217
活跃值: (351)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
初七的果子狸 判断求出的hash值与 0xAFFE390F 是否一致,不是继续 关于这一条中的0xAFFE390F是在哪找到的?
不好意思,刚才没仔细看,现在找到了。。。。
2020-10-28 19:56
0
游客
登录 | 注册 方可回帖
返回
//