吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4874|回复: 4
收起左侧

[原创] 160个Crackme之023学习笔记

  [复制链接]
海天一色001 发表于 2019-5-30 10:11
打开023,输入Name/Serial=“52pojie/1234567890”,程序界面如下:
001.png
Status栏中仍然是错误提示,点击About按钮,弹出提示框:
002.png
初步猜测这个程序可能是当Name文本框中每输入一个字符就进行运算后得到注册码,然后再与输入的Serial进行比较,结果输入到Status框中去。这个程序的关闭按钮和Alt+F4组合键都不管用,只能用右键点击弹出的菜单中选择“Alt+F4”这一项才能关闭,不知道怎么回事。
先查壳,无壳,显示是ASM程序:
003.png
第一步、爆破
将Chafe.1.exe加载入OD中,习惯性地用智能搜索去查字符串,很轻松地得到了各类文本内容:
004.png
双击004012CE这一行正确提示处来到CPU窗口:
005.png
马上看到正确提示来源于上面一句je命令,跳过了错误提示,所以直接将je命令修改为jmp命令,
006.png   
存为可执行文件Chafe.1_jmp.exe,试运行一下,输入name后,在Serial框中刚输入“1”这个字符,下方的Status框中就出现了正确提示,说明爆破成功。
007.png
第二步、追码
撤消刚才爆破时的修改,然后上下观察代码,感觉ASM的代码确实是很短小,一会儿就翻完了。
008.png
因为作者在About中说了不让爆破,要找到注册算法,所以仔细查看004012B6上面,004012B3处是比较命令,只有[eax]=0x10时,才能成功,所以继续向上分析,找到给eax赋值的语句:
从00401239至00401322处应该是判断注册码的代码段,很自然地在段首00401239处下断,然后F9运行程序,不行,程序仍然是暂停状态,再多按几次,仍然是在这里暂停!
不管它,先F8向下,可以走:
从0040123F处看到注释的内容是Switch (cases 1..113),然后看指令,先是[eax]与0x10比较,再与0xF比较,再与0x1比较,均不能相等,再与0x113比较,必须相等,而下面又是要求[eax]=0x10这样才能正确,所以只有00401294处,这里的call可能就是赋值的关键call了。
所以在寄存器窗口将Z标志位的0改为1,使00401292处的jnz short Chafe_1.004012E4指令不成立,可以到下一步去:
到00401294处的call Chafe_1.00401453指令,F7跟入,F8单步,运行一遍后出来了,还是错误,找不到算法!不死心地F9了几次,还是不行。
009.png   
静下心来,回头去看,断点位置在自己认为的判断注册码算法的段首处,可能不是很合适,因为这个断点作用不大,在没有输入任何内容,没来得及给ds:[0x403166]/ ds:[0x403167] /ds:[0x403188]之类的地址进行赋值之前程序就被它中断了,造成[eax]=ds:[0x403166]=0,向下单步运行肯定不正确。所以要找到一个合适的断点来看看:
从开始向下看,到00401076处,自动注释了“GetWindowTextA”,应该是得到输入的文本吧,在这里下断试一试:
Ctrl+F2重载程序,F9运行,不知道怎么回事023程序窗口直接最大化显示,但还好能恢复到原窗口大小。
输入name=“52pojie”,刚在Serial框中输入1个字符“1”时,程序中断到00401076处,此时GetWindowTextA的参数是Count=0x14(20),Buffer= Chafe_1.0040318C,hWnd = 00450750 (class='Edit',parent=01200766),[eax]=0x4;
这个0040318C地址里是什么东西?在这里点右键,选择“数据窗口中跟随—立即数”,内存地址栏中马上显示出一串0来。
F8单步,[eax]马上变成了0x7!此时地址栏里,0040318C地址变成了“52pojie”,刚输入的name,而[eax]=7,可能是[eax]=len(name)了。
[Asm] 纯文本查看 复制代码
00401063   .  8B25 A0314000 mov esp,dword ptr ds:[0x4031A0]
00401069   .  6A 14         push 0x14                                ; /Count = 14 (20.)
0040106B   .  68 8C314000   push Chafe_1.0040318C                    ; |Buffer = Chafe_1.0040318C=str(name)
00401070   .  FF35 74314000 push dword ptr ds:[0x403174]             ; |hWnd = 00470750 (class='Edit',parent=01CD076E)
00401076   .  E8 7D040000   call <jmp.&USER32.GetWindowTextA>        ; \GetWindowTextA
0040107B   .  B9 14000000   mov ecx,0x14                             ;  [ecx]=0x14(20)
00401080   .  2BC8          sub ecx,eax                              ;  [ecx]=0x14-[eax]=0xD(13)
00401082   .  8DB8 8C314000 lea edi,dword ptr ds:[eax+0x40318C]
00401088   >  C607 00       mov byte ptr ds:[edi],0x0
0040108B   .  47            inc edi                                  ;  [edi]=[edi]+1
0040108C   .  49            dec ecx                                  ;  [ecx]=[ecx]-1
0040108D   .^ 75 F9         jnz short Chafe_1.00401088               ;  循环0x14-len(name)次,将后面全变成0
0040108F   .  85C0          test eax,eax
00401091   .  74 10         je short Chafe_1.004010A3                ;  name不能为0
00401093   .  8005 66314000>add byte ptr ds:[0x403166],0x4           ;  给ds:[0x403166]赋值
0040109A   .  C605 68314000>mov byte ptr ds:[0x403168],0x0           ;  ds:[0x403168]=0x0
004010A1   .  EB 06         jmp short Chafe_1.004010A9
004010A3   >  8825 66314000 mov byte ptr ds:[0x403166],ah
004010A9   >  C9            leave
004010AA   .  C3            retn                                     ;  返回到 00401299 (Chafe_1.00401299)

多试了几个name,确定从00401069 到0040108D间代码的作用是取得name字符串并将其格式化,如果len(name)<20,则将name字符串后面用“0”填充成有20位的字符串;如果len(name)>=20则len(name)=19,然后后面用“0”填充,总之,最后一位字符是“0”。
再向下到004010AA处,retn至401299地址,此时ds:[0x403166]=0x8,运行这一句后[eax]=0x8。继续向下又失败了。
(后来的分析中慢慢发现这一段的用处,先格式化得到的字符串,再使ds:[0x403166]= ds:[0x403166]+0x4。)
这样下断可能也不合适,没有找到程序的执行顺序。
再到004012B3处看,由于在最后判断前要让[eax]= 0x10这样才能正确,而之前[eax]可以看到的值必须是0x113,那么只有00401294处call里会给[eax]赋值0x10这样才能正确。由于刚才在00401294处的call Chafe_1.00401453指令,F7跟入,F8单步运行一遍后没有找到算法,但在这个call出来后看到 [eax]= ds:[0x403166],那么找到ds:[0x403166]的赋值语句去试着看看:
010.png
在00401299处右键选择“查找参考—地址常量”命令,立即看到有8处与ds:[0x403166]有关的指令,
011.png
第一个是地址00401093处,一般来说会是首先运行这一句,所以先在这一行下断,并清除原来的断点,重新加载程序,F9运行,输入name=“52pojie”,刚在Serial框中输入1个字符“1”时,程序中断,猜测是每个输入的字符都要经过一定的运算,结果存入ds:[0x403166]中吧。(错误的猜测,在后来的分析过程中发现是Serial框输入时开始先对name框中的内容进行格式化,然后再判断name框的字符串是否全为0,不为0则ds:[0x403166]累加0x4。)继续F8向下,一直到004012B3处,此时[eax]=0x8,还是失败;
干脆将所有为ds:[0x403166]赋值的6个地址都下断试一试:
重载程序,F9运行,输入name=“52pojie”,没变化,刚在Serial框中输入1个字符“1”时,程序中断于00401093处,F9再向下中断于00401093,F9再向下中断于00401398,F9再向下中断于004012B3, F9再向下中断于004014B3仍是失败,说明应该在输入Serial前就已经算好了值,只在这里找ds:[0x403166]是远远不够的:
012.png

013.png
Ctrl+F2重新开始,在内存0x403166处选择“断点—内存写入”,清除其他所有断点,F9运行,粘贴入name=“52pojie”,粘贴入serial=“1234567890”,
此时程序中断于00401493处,
F9运行,又中断于00401093处,
F9运行,又中断于00401398处,
F9运行,又中断于004014B3处,
继续运行,又是00401493—00401093—00401398--004014B3的循环。这和给6个赋值语句都下断的结果差不多,只少了004012B3一处。
结合以前的经验,程序运行顺序应该是:
从00401000开始,到00401018处转到00401023处,再一直执行到004011F7处显示程序界面;
输入name/serial后,在00401239段内利用时间控件进行循环:
到00401294处运行call 00401453,再运行0040146F--0040149B处的代码段,返回到00401299处;
运行计算判断后再call 00401453,再运行00401063—004010AA处的段,返回到00401299处;
继续call 00401453,再运行00401361—004013A0处的段,返回到00401299处;
再call 00401453,再运行0040149C-- 004014C1处的段,返回到00401299处;
代码段的作用继续具体分析:
(1)0040146F--0040149B处,作用是得到输入的注册码,为纯数字时ds:[0x403166]= ds:[0x403166]+0x4;
[Asm] 纯文本查看 复制代码
0040146F   .  8B25 A0314000 mov esp,dword ptr ds:[0x4031A0]
00401475   .  6A 00         push 0x0                                 ; /IsSigned = FALSE
00401477   .  8D45 FC       lea eax,dword ptr ss:[ebp-0x4]           ; |
0040147A   .  50            push eax                                 ; |pSuccess = NULL
0040147B   .  6A 64         push 0x64                                ; |ControlID = 64 (100.)
0040147D   .  FF35 70314000 push dword ptr ds:[0x403170]             ; |hWnd = 008707B6 ('TEXme v1.0',class='TEXcls')
00401483   .  E8 64000000   call <jmp.&USER32.GetDlgItemInt>         ; \[eax]=hex(Serial)
00401488   .  A3 88314000   mov dword ptr ds:[0x403188],eax          ;  ds:[0x403188]=[eax]=0-0x9112478
0040148D   .  837D FC 00    cmp dword ptr ss:[ebp-0x4],0x0
00401491   .  74 07         je short Chafe_1.0040149A
00401493   .  8005 66314000>add byte ptr ds:[0x403166],0x4           ;  此句未运行前ds:[0x403166]=0x8才能正确
0040149A   >  C9            leave
0040149B   .  C3            retn                                     ;  retn 00401299

(2)00401063—004010AA处作用是格式化name字符串并给ds:[0x403166]赋值为ds:[0x403166]+0x4(前面已经分析过了);
(3)00401361—004013A0处作用是循环16次对name字符串进行各种运算,使之最后的值为0-0x9112478=0xF6EEDB88,存入ds:[0x403188]中,并给ds:[0x403166]赋值为ds:[0x403166]+0x4;
[Asm] 纯文本查看 复制代码
00401361   .  8D3D 8C314000 lea edi,dword ptr ds:[0x40318C]          ;  [edi]=ds:[0x40318C](name),导入输入的name字符串
00401367   .  0FBE05 683140>movsx eax,byte ptr ds:[0x403168]         ;  [eax]=ds:[0x403168]
0040136E   .  03F8          add edi,eax                              ;  [edi]=[edi]+[eax]
00401370   .  FE05 68314000 inc byte ptr ds:[0x403168]               ;  ds:[0x403168]=ds:[0x403168]+1
00401376   .  A1 88314000   mov eax,dword ptr ds:[0x403188]          ;  [eax]=ds:[0x403188]
0040137B   .  8B25 A0314000 mov esp,dword ptr ds:[0x4031A0]          ;  [esp]=ds:[0x4031A0]
00401381   .  40            inc eax                                  ;  [eax]=[eax]+1
00401382      FF05 88314000 inc dword ptr ds:[0x403188]              ;  ds:[0x403188]=ds:[0x403188]+1
00401388   .  3307          xor eax,dword ptr ds:[edi]               ;  [eax]=[eax] xor ds:[edi]
0040138A   .  A3 88314000   mov dword ptr ds:[0x403188],eax          ;  循环16次后ds:[0x403188]=[eax]=0-0x9112478=0xF6EEDB88才能正确
0040138F   .  803D 68314000>cmp byte ptr ds:[0x403168],0x10          ;  ds:[0x403168]必等于0x10才行,上面代码需循环16次
00401396   .  75 07         jnz short Chafe_1.0040139F
00401398   .  8005 66314000>add byte ptr ds:[0x403166],0x4           ;  给ds:[0x403166]赋值处
0040139F   >  C9            leave
004013A0   .  C3            retn

(4)0040149C-- 004014C1处判断计算后的注册码,如正确则给ds:[0x403166]赋值为ds:[0x403166]+0x4;
[Asm] 纯文本查看 复制代码
0040149C   .  A1 88314000   mov eax,dword ptr ds:[0x403188]          ;  ds:[0x403188]=0-0x9112478
004014A1   .  05 78241109   add eax,0x9112478                        ;  [eax]=[eax]+0x9112478
004014A6   .  85C0          test eax,eax                             ;  [eax]此时必等于0
004014A8   .  75 09         jnz short Chafe_1.004014B3
004014AA   .  8005 66314000>add byte ptr ds:[0x403166],0x4           ;  此句未运行前ds:[0x403166]必为0xC才能正确
004014B1   .  EB 07         jmp short Chafe_1.004014BA
004014B3   >  C605 66314000>mov byte ptr ds:[0x403166],0x0           ;  给ds:[0x403166]赋值为0,与上方互斥关系,肯定失败,所以必跳过
004014BA   >  8B25 A0314000 mov esp,dword ptr ds:[0x4031A0]
004014C0   .  C9            leave
004014C1   .  C3            retn

从最后正确的结果开始逆向分析,先确定正确的情况该怎么执行代码,一步步向上倒推,在注释栏加上自己的注释;从这四段代码的作用可以看出,程序中只要输入了name与纯数字的serial就可以让给ds:[0x403166]的值达到0xC(12),只要再将注册码填对就可以再给ds:[0x403166]赋值为ds:[0x403166]+0x4,使ds:[0x403166]=0x10(16),让程序界面的satus栏显示正确提示。所以注册码算法在第三段代码的位置:
Ctrl+F2重新开始,在内存00401361处下断,清除其他所有断点,F9运行,粘贴入name=“52pojie”,粘贴入serial=“1234567890”,此时程序中断于00401361处,下方可以看到给edi导入输入的name(“52pojie”):
017.png
为了找到如何对name字符串进行运算得到注册码的,F8单步进行下去,进行分析的结果,是ds:[0x403168]作为循环变量的寄存器,进行循环加1运算(00401370处),然后判断ds:[0x403168]是否为0x10,是则给ds:[0x403166]赋值为ds:[0x403166]+0x4;ds:[0x403188]首先存入的是输入的serial字符串“1234567890”的16进制数值0x499602D2,
014.png
然后加1,变成0x499602D3;到00401388处,[eax]=[eax] xor ds:[edi],
019.png   
此时在信息窗口右键点击第一行的ds:[0040318C],选择“数据窗口中跟随地址”,可以看到内存地址中ASCII码为“52pojie”,而ds:[0040318C]的值是逆向取name字符串前4个字符的16进制ASCII数值:
020.png
F8向下,到0040138A处,将结果0x26E630E6存入ds:[0x403188]中;
继续向下,返回到00401299处,再到004012AB处,命令是retn 0x10,信息窗口中是“返回到 77D18734 (user32.77D18734)”,耐心地F8走,终于返回到程序领空00401207处,继续F8走:
结果在00401230这里陷入了死循环,不断地跳回00401207处。在上面四段代码中没有循环语句,但是能做到循环,说明应该是利用时间控件做到的,我这样单步,时间控件估计不起作用,所以F9一下试试,程序马上又中断到00401361处了;
第二次循环后,ds:[0x403168]=0x2,ds:[0x403188]= 0x4C8940D5;
第三次循环后,ds:[0x403168]=0x3,ds:[0x403188]= 0x25E32FA6;
。。。。。。
第十五次循环后,ds:[0x403168]=0xF,ds:[0x403188]= 0x40EF49B3;
第十六次循环后,ds:[0x403168]=0x10,ds:[0x403188]= 0x40EF49B4;
而0x40EF49B4与0xF6EEDB88相差太大,肯定不是正确的结果,“1234567890”不是“52pojie”对应的注册码;继续向下,ds:[0x403166]=0xC,不是0x10,所以会失败。
那么程序应该从第十六次循环倒推回去,将0xF6EEDB88减去1,再与name字符串从后向前每四位的hex值组成的数值xor,最后的结果就是注册码了。
还是用VB编写注册机吧,下面是最简单的原理代码,到处是错误,主要是数值溢出错误,还有Name字符串长度过长过短等问题没在下面显示。
Serial=0xF6EEDB88
Namestr=text1.text
For i=1 to 16
Namehex=hex(mid(Namestr,i+3,1) & hex(mid(Namestr,i+2,1) & hex(mid(Namestr,i+1,1) & hex(mid(Namestr,i,1)
Serial=Serial xor Namehex
Serial=Serial-1
Next
Text2.text=Serial
注册机已写好,程序源码均在内。一开始就是一个数值溢出问题,上网找了一大堆资料,借用了别人的大数运算代码,总是有问题所以又试着用VC编程,本想VB、VC都是微软同一公司的,界面什么的都相似,只是数值范围不一样,应该好学一些,结果是悲剧,死活不会用,找不到可视化编程的窗体等,还需要以后再重新学习;再就是用易语言了,也是费了九牛二虎之力,终于编写出了易语言的注册机,不知怎么回事,杀毒软件老杀。这两个注册机的源码和程序均放入压缩包里了,如不放心,易语言生成的注册机请勿使用。
附件 023.zip (1018.49 KB, 下载次数: 10) ,含CM原程序、爆破后的程序、注册机、OD的调试文件等。
百度链接是:http://pan.baidu.com/s/1skMkJY9密码: 86pm,160个CM、我已练习过的前23个crackme程序(不含012)都在里面。

免费评分

参与人数 1威望 +1 吾爱币 +7 热心值 +1 收起 理由
Hmily + 1 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

q130545 发表于 2019-5-30 10:26
牛人!看的我一愣一愣的
SnowRen 发表于 2019-5-30 10:27
易语言写的程序老报毒算是基本操作,就是这个原因我都没在用易写程序
Ars 发表于 2019-5-30 16:52
吾爱、小江 发表于 2019-5-30 20:32
写的太棒了,叔,特别详细,
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-1-1 11:29

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表