吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4348|回复: 6
收起左侧

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

  [复制链接]
海天一色001 发表于 2019-6-11 08:54
本帖最后由 海天一色001 于 2019-6-11 09:04 编辑

打开024,与023除了版本号外界面几乎完全相同,输入Name/Serial=52pojie/1234567890”,程序界面如下:
001.png
Status栏中仍然是错误提示,点击About按钮,弹出提示框,内容与023一样(除了版本与时间不一样):
002.png
这个程序同样是关闭按钮和Alt+F4组合键都不管用,只能用右键点击弹出的菜单中选择“Alt+F4”这一项才能关闭。先查壳,无壳,显示是ASM程序:
003.png
第一步、爆破Chafe.2.exe加载入OD中,习惯性地用智能搜索去查字符串,很轻松地得到了各类文本内容:
004.png
双击00401301这一行正确提示处来到CPU窗口:
005.png
这里和023不一样之处在于没找到跳转到正确提示的指令,只在信息窗口看到错误提示上有两个跳转来源“跳转来自0040128A004012A1”:
006.png
先看看第一个跳,00401281处命令是GetDlgItemInt是得到整数,结合023分析应该是得到注册码,而0040129A处的命令是GetWindowTextA则是得到文本,应该是name
007.png
但为什么是先得到注册码后得到name,有点不太理解。先不管这些,试试将0040128A处跳到错误提示的语句改到正确提示的地址00401031上来,
0071.png
将所有修改保存到可执行文件Chafe.2.jmp.exe,试运行一下,鼠标点击到name框,准备输入字符时,下方的Status框中就出现了正确提示,说明这样的爆破也算是成功了。
008.png
第二步、追码
撤消刚才爆破时的修改,然后上下观察代码,没有时间控件了,也没找到直接跳转到成功的语句,这个CM明显比上一个复杂多了。
009.png
已知GetDlgItemInt()函数是得到注册码,所以在00401281处下断,F9运行一下试试:鼠标刚点入name框,程序就中断了,说明程序只要输入name就开始判断了,但没输入时怎么判断呢?虽然不太清楚作者怎么做到的,但此时任何内容都没输入,断在此处不太合适,改在0040129A处再试:这次name框我输进去了“52pojie”,在serial框点鼠标没事,刚点击键盘上的“1”, 界面上还没出现“1”时程序就中断了。F8向下,注释中马上出现了“CTEX”与刚输入的name52pojie”,此时ds:[0x40300B]= CTEX0040316C地址处存放ASCII "52pojie";说明这个断点应该可以使用。
010.png
由于Serial=1太难以在代码中找到具体位置,所以Ctrl+F12重新加载程序,name输入“52pojie”,serial粘贴入“1234567890”,程序又中断于0040129A处。那么就继续单步向下走,多次重载程序运行,代码分析如下:1004012690040128C处,给ds:[0x4012D9]赋值为0x584554,到第(4)步时使用;GetDlgItemInt()得到serial的值,不能为空,将得到的值压入堆栈SS:[EBP-0xAC=0012FA38]中:
[Asm] 纯文本查看 复制代码
00401269   > \C705 D9124000>mov dword ptr ds:[0x4012D9],0x584554
00401273   .  6A 00         push 0x0                                 ; /IsSigned = FALSE
00401275   .  8D45 FC       lea eax,dword ptr ss:[ebp-0x4]           ; |
00401278   .  50            push eax                                 ; |pSuccess = 015E9FC1
00401279   .  6A 64         push 0x64                                ; |ControlID = 64 (100.)
0040127B   .  FF35 50314000 push dword ptr ds:[0x403150]             ; |hWnd = 001A077A ('TEXme v2.0',class='CTEX')
00401281   .  E8 BC010000   call <jmp.&USER32.GetDlgItemInt>         ; \GetDlgItemInt
00401286   .  837D FC 00    cmp dword ptr ss:[ebp-0x4],0x0           ;  Serial不能为空,否则失败
0040128A      74 5F         je short Chafe_2.004012EB
0040128C   .  50            push eax                                 ;  [eax]=hex(serial)

(2) 0040128D004012A1处,GetWindowTextA()函数取得name的字符串,并判断是否为空,空则失败:
[Asm] 纯文本查看 复制代码
0040128D  .  6A 14         push 0x14                                ; /Count = 14(20.)
0040128F  .  68 6C314000   push Chafe_2.0040316C                    ; |Buffer =Chafe_2.0040316C
00401294  .  FF35 54314000 push dword ptrds:[0x403154]             ; |hWnd =0017072E (class='Edit',parent=001A077A)
0040129A  .  E8 AF010000   call<jmp.&USER32.GetWindowTextA>       ; \ GetWindowTextA([font=宋体]所在的句柄,存入的内存地址,取字符串的长度)[/font]
0040129F  .  85C0          test eax,eax                             ;  eax=len(name)
004012A1      74 48         je short Chafe_2.004012EB                ;  name[font=宋体]不为空,否则到失败[/font]

3004012A3004012B6处,以“CTEX”和得到的name文本进行相应的计算,得到的结果存入[eax]中:
[Asm] 纯文本查看 复制代码
004012A3  .  A1 0B304000   mov eax,dword ptr ds:[0x40300B]          ; [eax]="CTEX"[font=宋体]的反向取[/font]ANSI16[font=宋体]进制编码([/font]58455443[font=宋体])[/font]
004012A8  .  BB 6C314000   mov ebx,Chafe_2.0040316C                 ;  ds:[ebx]=name[font=宋体]字符串逆向取[/font]4[font=宋体]位的[/font]ANSI16[font=宋体]进制数值[/font]
004012AD  >  0303          add eax,dword ptr ds:[ebx]               ;  [eax]=[eax]+ds:[ebx]
004012AF  .  43            inc ebx                                  ;  [ebx]=[ebx]+1
004012B0  .  81FB 7C314000 cmpebx,Chafe_2.0040317C                ;  ebx[font=宋体]地址为[/font]0040317C[font=宋体]时结束循环,共循环[/font]16[font=宋体]次[/font]
004012B6  .^ 75 F5         jnz shortChafe_2.004012AD               ;  [font=宋体]构成循环,不断累加[/font]

  4004012B8004012C4取得到的serial数值与[eax]相加,再与ds:[0x4012D9]异或,存入ds:[0x4012D9]中,实际上是修改004012D9004012DC处的指令,正确的结果应该是将004012D9处指令修改成“jmp 00401301”:
[Asm] 纯文本查看 复制代码
004012B8  .  5B            pop ebx                                  ;  [ebx]=hex(serial)
004012B9  .  03C3          add eax,ebx                              ;  [eax]=[eax]+[ebx]
004012BB  .  3105 D9124000 xor dword ptrds:[0x4012D9],eax          ;  ds:[0x4012D9]=ds:[0x4012D9] xor [eax]
004012C1  .  C1E8 10       shr eax,0x10                             ;  [font=宋体]逻辑右移[/font]0x10[font=宋体]位,即取[/font][eax][font=宋体]的高位[/font]
004012C4  .  66:2905 D9124>sub word ptrds:[0x4012D9],ax            ;  ds:[0x4012D9]=ds:[0x4012D9] - [ax]

如下所示,004012D9处未修改时这4个字节的16进制值是00584554
011.png
当与[eax]异或后变成了4AACE7C7
012.png
再减去[ax]后变成了4AAC9CD3
013.png
5)进行0x3E62)次的异或运算,最终结果要达到[ebx]=0xAFFCCFFB
[Asm] 纯文本查看 复制代码
004012CB  .  BE EC114000   mov esi,Chafe_2.004011EC
004012D0  .  B9 3E000000   mov ecx,0x3E
004012D5  .  33DB          xor ebx,ebx                              ;  [ebx][font=宋体]清零[/font]
004012D7  .  EB 04         jmp short Chafe_2.004012DD
004012D9  >  54            push esp
004012DA      45            db 45                                    ;  CHAR 'E'
004012DB      58            db 58                                    ;  CHAR 'X'
004012DC      00            db 00
004012DD  >  AD                   lods dword ptr ds:[esi]                  ;  mov eax,dword ptr[esi]; add esi,4;
004012DE  .  33D8                 xor ebx,eax                              ;  [ebx]=[ebx] xor ds:[esi]
004012E0  .  49            dec ecx                                  ;  [ecx]=0[font=宋体]时循环结束!!!!([/font]62[font=宋体]次)[/font]
004012E1  .^ 75 FA         jnz shortChafe_2.004012DD               ;  [ebx][font=宋体]应该等于[/font]0xAFFCCFFB[font=宋体]才行[/font]
004012E3  .  81FB FBCFFCAF cmpebx,0xAFFCCFFB                      ;  [font=宋体]关键比较[/font]004012E9  .^ 74 EE         je shortChafe_2.004012D9                ;  [font=宋体]关键跳???[/font]

重点就在于第5部分,004012D7处命令跳到了004012DD处,跳过了被第4部分中修改了内容的004012D9004012DC处的4个字节,原来未修改前的内存中存储的是00584554,转换成汇编命令是 push espdb 45db 58db 00,而我用“52pojie/1234567890”这一组内容来调试时,甚至将004012DD004012DF处的代码都给改了,如下所示,这个改动太大了,变成了“rcr dword ptr ss:[esp+ebp*4-0x27CC52B6],cl”,程序肯定不会跳向正确,甚至可能会出现各种错误。实际运行过程中发现,自己一厢情愿的思路是错误的,程序执行中只修改了4个字节,从004012DD处并没有修改,只是和上面的代码被OD合在一起去反汇编解释了一下,好像是错误,实际上仍然能执行。这其实也是计算机原理的知识,以前有一点了解,但不是很明白,遇到这里的例子倒是弄明白了。
这段程序理解时就相当于把004012D7004012DC这五句移走,将最后一句转向正确提示,也就成了以下代码:
mov esi,Chafe_2.004011EC
mov ecx,0x3E
xor ebx,ebx                              ;  [ebx]清零
lods dword ptr ds:[esi]                  ;  [eax]=ds:[esi]
xor ebx,eax
dec ecx                                  ;  [ecx]=0时循环结束!!!!(62次)
jnz short Chafe_2.004012DD               ;  [ebx]应该等于0xAFFCCFFB才行
cmp ebx,0xAFFCCFFB                       ;  关键比较
je short Chafe_2.00401301                ;  关键跳
[ebx]等于0xAFFCCFFB时,下一命令跳到了004012D9,按照修改前的代码看,[ecx]小于0,只会使程序陷入无限的循环之中;所以输入的“name/serial”组合必须在第4部分使生成的指令变成“jmp 00401301”,在ODCPU窗口中看到16进制数值为“EB 26”,内存中查看应该是“26EB”。那么反过来进行逆推就可以得到被修改后的004012D9004012DC这四个内存地址的值:
首先004011EC+3E*3=004012E4,也就是说从004011EC004012E3处的内存总共有62个数值要和[ebx]进行异或运算,最终得到0xAFFCCFFB,所以先把004012D9004012DC这四个内存地址的值用“00”填充,也就是将“38 D9 06 01”修改为“0000 00 00”,再用0xAFFCCFFB004011EC004012E3处的内存总共有62个已知数值进行异或运算,得到004012DB004012DC处修改数值与[eax]异或的结果为“5426EB58”;004012D9004012DA处的值已经确定为EB26,则004012DB004012DC处的数值为5458中的一个;随意选一个值在004012DB中,另一个在004012DC中,再运行一遍,如果xor最终结果为0,则正确,否则再将两处的数值反过来试试,应该就是正确的:经计算,004012DB处的值为54004012DC处的数值为58
014.png

   015.png
004012D9处未修改前这4个字节的原始16进制值是00584554,修改后变成了585426EB;也就是说,第四部分的算法可以整理为:
(0xXXXXYYYY xor 0x00584554)-(0x0000XXXX)=0x585426EB(“0xXXXXYYYY”中,“XXXX”表示[eax]的高四位值,“YYYY”表示[eax]的低四位值),可继续化为:
(0xXXXXYYYY xor 0x00584554)=0x585426EB+0x00000XXXX=0x585400000+(0x26EB+0xXXXX)那么高四位的0xXXXX=0x5854xor 0x0058=0x580C,或者是XXXX=0x5855xor 0x0058=0x580D(有进位的情况)
低四位的YYYY=(0x26EB+0x580C)xor 0x4554= 0x3BA3,或者是YYYY=(0x26EB+0x580D) xor 0x4554= 0x3BAC但实际上0x26EB+0x580D=0x7EF8,没有进位,所以[eax]的高四位值是0x580C,低四位值是0x3BA3,连起来就是0x580C3BA3了。
0x580C3BA3减去第二步中“CTEX”与取得的name字符串运算结果,就是注册码的16进制数值,再转为10进制数值,注册码就出来了。
说起来容易做起来难,主要是VB数据老溢出太令人难受!
注册机主要代码如下:
[Visual Basic] 纯文本查看 复制代码
Serial = 1480938563 '"CTEX"的十六进制数值58455443转换成10进制的结果
        NameStr = Text1.Text                                    
        If NameStr = "" Then NameStr = "52pojie"               
            Text1.Text = NameStr
        If Len(NameStr) > 19 Then NameStr = Mid(NameStr, 1, 19)
        If Len(NameStr) < 19 Then
            For i = 1 To Len(NameStr)
                NameHex(i) = Hex(Asc(Mid(NameStr, i, 1)))
            Next
            For i = Len(NameStr) + 1 To 19
                NameHex(i) = "00"
            Next
        End If
        For i = 1 To 16
            NameUnit = "&H" & NameHex(i + 3) & NameHex(i + 2) & NameHex(i + 1) & NameHex(i)
            nameD = Val(NameUnit)                      
            nameB = DectoBin(Trim(nameD))              
            Serial = Serial + nameD                    
            If Serial >= 4294967296# Then Serial = Serial - 4294967296#
            'Form1.Print Bin2Hex(Dec2Bin(Trim(Str(Serial))))
        Next
        Serial = 1477196707 - Serial
        If Serial < 0 Then Serial = 4294967296# + Serial
        Text2.Text = Serial

附件 024.zip (284.31 KB, 下载次数: 6) ,含CM原程序、爆破后的程序、注册机、OD的调试文件等。
百度链接是:http://pan.baidu.com/s/1skMkJY9密码: 86pm160CM、我已练习过的前24crackme程序(不含012)都在里面。

免费评分

参与人数 4威望 +1 吾爱币 +12 热心值 +4 收起 理由
Hmily + 1 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
神器 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
liphily + 3 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
voyage1969 + 1 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

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

wenguolong 发表于 2019-6-11 09:12
沙发。。。。
bugman168 发表于 2019-6-11 09:40
yjj008818 发表于 2019-6-11 13:02
zzcl558 发表于 2019-6-12 06:03
高手啊,谢谢分享!
木丁哂 发表于 2019-6-12 12:18
学习到了,最近有学习的欲望,希望大佬多分享一点
鲶鱼的忧郁 发表于 2019-6-13 08:50
感谢楼主分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

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

GMT+8, 2024-4-25 12:00

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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