本文主要是介绍160个破解练习之CrackMe 003 Afkayas.2,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
这次要破解的是160个破解练习里的第三个软件,与第二个软件是同一个作者,界面类似,如下:
需要输入用户名和对应的序列号完成注册,当直接点击0K时,出现如下错误提示界面,接着程序自动退出:
由于对VB语言不太了解,直接查询错误字符串并没有搜到,后来知道这是VB调用函数时输入的参数类型不匹配。当我们的密码输入一段数字时,出现如下提示:
那么很明显,这里的序列号输入的就应该是一段数值字符串,上面的错误提示是因为输入的不是数字,在没有检验就直接把参数传给了相应的API函数,导致了错误。
那么我们搜索关键字“You Get Wrong”,定位到关键代码处:
004086D8 51 push ecx
004086D9 EB 60 jmp short AfKayAs_.0040873B ; 跳过错误
004086DB 8B35 14B14000 mov esi,dword ptr ds:[<&MSVBVM50.__vbaSt>; msvbvm50.__vbaStrCat
004086E1 68 08704000 push AfKayAs_.00407008 ; You Get Wrong
004086E6 68 DC6F4000 push AfKayAs_.00406FDC ; \r\n
004086EB FFD6 call esi
004086ED 8BD0 mov edx,eax
004086EF 8D4D E8 lea ecx,dword ptr ss:[ebp-0x18]
004086F2 FF15 94B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrMo>; msvbvm50.__vbaStrMove
004086F8 50 push eax
004086F9 68 28704000 push AfKayAs_.00407028 ; Try Again
004086FE FFD6 call esi
00408700 8945 CC mov dword ptr ss:[ebp-0x34],eax
00408703 8D55 94 lea edx,dword ptr ss:[ebp-0x6C]
00408706 8D45 A4 lea eax,dword ptr ss:[ebp-0x5C]
00408709 52 push edx
0040870A 8D4D B4 lea ecx,dword ptr ss:[ebp-0x4C]
0040870D 50 push eax
0040870E 51 push ecx
0040870F 8D55 C4 lea edx,dword ptr ss:[ebp-0x3C]
00408712 6A 00 push 0x0
00408714 52 push edx
00408715 C745 C4 0800000>mov dword ptr ss:[ebp-0x3C],0x8
0040871C FF15 24B14000 call dword ptr ds:[<&MSVBVM50.#rtcMsgBox>; 错误弹窗
00408722 8D4D E8 lea ecx,dword ptr ss:[ebp-0x18]
00408725 FF15 A8B14000 call dword ptr ds:[<&MSVBVM50.__vbaFreeS>; msvbvm50.__vbaFreeStr
0040872B 8D45 94 lea eax,dword ptr ss:[ebp-0x6C]
0040872E 8D4D A4 lea ecx,dword ptr ss:[ebp-0x5C]
代码右边有相应的提示,通过下断点,随便输入一个用户名和数字序列号后,定位到了这里,得知,在这里弹出了错误提示,地址0x4086D9处的跳转可以跳过错误,但由于序列号错误,这个jmp被前面的跳转跳过了,那么我们把代码定位到前面:
00408671 894D BC mov dword ptr ss:[ebp-0x44],ecx
00408674 8945 B4 mov dword ptr ss:[ebp-0x4C],eax
00408677 74 62 je short AfKayAs_.004086DB ; 跳过正确了,关键跳
00408679 8B35 14B14000 mov esi,dword ptr ds:[<&MSVBVM50.__vbaSt>; msvbvm50.__vbaStrCat
0040867F 68 C06F4000 push AfKayAs_.00406FC0 ; You Get It
00408684 68 DC6F4000 push AfKayAs_.00406FDC ; \r\n
00408689 FFD6 call esi
0040868B 8BD0 mov edx,eax
0040868D 8D4D E8 lea ecx,dword ptr ss:[ebp-0x18]
00408690 FF15 94B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrMo>; msvbvm50.__vbaStrMove
00408696 50 push eax
00408697 68 E86F4000 push AfKayAs_.00406FE8 ; KeyGen It Now
0040869C FFD6 call esi
0040869E 8945 CC mov dword ptr ss:[ebp-0x34],eax
004086A1 8D45 94 lea eax,dword ptr ss:[ebp-0x6C]
004086A4 8D4D A4 lea ecx,dword ptr ss:[ebp-0x5C]
004086A7 50 push eax
004086A8 8D55 B4 lea edx,dword ptr ss:[ebp-0x4C]
004086AB 51 push ecx
004086AC 52 push edx
004086AD 8D45 C4 lea eax,dword ptr ss:[ebp-0x3C]
004086B0 6A 00 push 0x0
004086B2 50 push eax
004086B3 C745 C4 0800000>mov dword ptr ss:[ebp-0x3C],0x8
004086BA FF15 24B14000 call dword ptr ds:[<&MSVBVM50.#rtcMsgBox>; 正确提示
004086C0 8D4D E8 lea ecx,dword ptr ss:[ebp-0x18]
004086C3 FF15 A8B14000 call dword ptr ds:[<&MSVBVM50.__vbaFreeS>; msvbvm50.__vbaFreeStr
004086C9 8D4D 94 lea ecx,dword ptr ss:[ebp-0x6C]
004086CC 8D55 A4 lea edx,dword ptr ss:[ebp-0x5C]
004086CF 51 push ecx
004086D0 8D45 B4 lea eax,dword ptr ss:[ebp-0x4C]
004086D3 52 push edx
004086D4 8D4D C4 lea ecx,dword ptr ss:[ebp-0x3C]
004086D7 50 push eax
004086D8 51 push ecx
004086D9 EB 60 jmp short AfKayAs_.0040873B ; 跳过错误
004086DB 8B35 14B14000 mov esi,dword ptr ds:[<&MSVBVM50.__vbaSt>; msvbvm50.__vbaStrCat
004086E1 68 08704000 push AfKayAs_.00407008 ; You Get Wrong
这段代码的前面有个je跳转,就是这个跳转跳过了正确的提示,调到了错误部分,那么这个跳转就是关键跳了,因此只要把这个跳转进行nop就可以进行爆破了。
但是我们要做的是找到这个序列号生成的算法,我们在这个段的段首下断,然后输入用户名1111和序列号2222,然后单步F8运行,知道出现了我们输入的用户名时开始慢慢分析,最开始出现用户名是在这个地方:
004081EF 8B45 E4 mov eax,dword ptr ss:[ebp-0x1C] ; eax为输入的用户名
004081F2 50 push eax
004081F3 8B1A mov ebx,dword ptr ds:[edx]
004081F5 FF15 F8B04000 call dword ptr ds:[<&MSVBVM50.__vbaLenBs>; msvbvm50.__vbaLenBstr
004081FB 8BF8 mov edi,eax ; 取用户名长度
004081FD 8B4D E8 mov ecx,dword ptr ss:[ebp-0x18]
00408200 69FF 385B0100 imul edi,edi,0x15B38 ; edi=用户名长度 X 0x15B38
00408206 51 push ecx ; ntdll.7777FB62
00408207 0F80 B7050000 jo AfKayAs_.004087C4
0040820D FF15 0CB14000 call dword ptr ds:[<&MSVBVM50.#rtcAnsiVa>; msvbvm50.rtcAnsiValueBstr
00408213 0FBFD0 movsx edx,ax ; 取第一个字符ASCII码
00408216 03FA add edi,edx ; ASCII码与edi的值相加
00408218 0F80 A6050000 jo AfKayAs_.004087C4
0040821E 57 push edi
0040821F FF15 F4B04000 call dword ptr ds:[<&MSVBVM50.__vbaStrI4>; msvbvm50.__vbaStrI4
00408225 8BD0 mov edx,eax ; 数字转字符串,存在edx中
00408227 8D4D E0 lea ecx,dword ptr ss:[ebp-0x20]
0040822A FF15 94B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrMo>; msvbvm50.__vbaStrMove
00408230 8BBD 50FFFFFF mov edi,dword ptr ss:[ebp-0xB0]
00408236 50 push eax
00408237 57 push edi
00408238 FF93 A4000000 call dword ptr ds:[ebx+0xA4]
0040823E 85C0 test eax,eax ; 是否为0
00408240 7D 12 jge short AfKayAs_.00408254
00408242 68 A4000000 push 0xA4
00408247 68 AC6F4000 push AfKayAs_.00406FAC
从我右边的注释可以看到,这段代码是第一个关键部分,首先取出输入的用户名,存放在eax中,然后计算用户名的长度,再存在edi中,然后乘以0x15B38,接着是调用函数取第一个字符的ASCII码,并存放在edx中,再与前面的edi寄存器的值相加,即edi=4*0x15B38+0x31=0x56D11,接着调用函数vbaStrI4函数将数值转换成字符串,如下图左下角所示为355601
那么这个字符串要么就是序列号,要么就是生成序列号时要用到的关键字符串了,我们继续用F8跟踪,找到后面再使用到这个字符串的地方:
004082E3 8B55 E8 mov edx,dword ptr ss:[ebp-0x18]
004082E6 52 push edx ; 前面计算得到的字符串
004082E7 8B19 mov ebx,dword ptr ds:[ecx]
004082E9 FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>; 字符串转换成浮点数
004082EF D905 08104000 fld dword ptr ds:[0x401008] ; 浮点数 10.0000
004082F5 833D 00904000 0>cmp dword ptr ds:[0x409000],0x0
004082FC 75 08 jnz short AfKayAs_.00408306 ; 结果不为0跳转
004082FE D835 0C104000 fdiv dword ptr ds:[0x40100C] ; 10.0000/5.0000
00408304 EB 0B jmp short AfKayAs_.00408311
00408306 FF35 0C104000 push dword ptr ds:[0x40100C]
0040830C E8 578DFFFF call <jmp.&MSVBVM50._adj_fdiv_m32>
00408311 83EC 08 sub esp,0x8
00408314 DFE0 fstsw ax ; 协处理器状态内容
00408316 A8 0D test al,0xD
00408318 0F85 A1040000 jnz AfKayAs_.004087BF
0040831E DEC1 faddp st(1),st
00408320 DFE0 fstsw ax
00408322 A8 0D test al,0xD
00408324 0F85 95040000 jnz AfKayAs_.004087BF
0040832A DD1C24 fstp qword ptr ss:[esp]
0040832D FF15 48B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrR8>; msvbvm50.__vbaStrR8
00408333 8BD0 mov edx,eax
00408335 8D4D E4 lea ecx,dword ptr ss:[ebp-0x1C]
00408338 FF15 94B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrMo>; msvbvm50.__vbaStrMove
0040833E 899D 34FFFFFF mov dword ptr ss:[ebp-0xCC],ebx
00408344 8B9D 58FFFFFF mov ebx,dword ptr ss:[ebp-0xA8]
这里首先获取前面计算得到的字符串,然后转换成浮点数,接着存储浮点数10.00和浮点数5.00,并用fdiv指令进行相除,得到结果为2.00,然后再加上前面计算得到的字符串的浮点值,接着再转换成字符串,即355603,如下图左下角:
再接着经过一点其他内存释放等处理后,来到了这个地方继续进行计算操作:
004083E3 FF15 18B14000 call dword ptr ds:[<&MSVBVM50.__vbaHresu>; msvbvm50.__vbaHresultCheckObj
004083E9 8B8D 58FFFFFF mov ecx,dword ptr ss:[ebp-0xA8]
004083EF 8B55 E8 mov edx,dword ptr ss:[ebp-0x18]
004083F2 52 push edx
004083F3 8B19 mov ebx,dword ptr ds:[ecx]
004083F5 FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>; msvbvm50.__vbaR8Str
004083FB DC0D 10104000 fmul qword ptr ds:[0x401010] ; 355605.00*3.000
00408401 83EC 08 sub esp,0x8
00408404 DC25 18104000 fsub qword ptr ds:[0x401018]
0040840A DFE0 fstsw ax
0040840C A8 0D test al,0xD
0040840E 0F85 AB030000 jnz AfKayAs_.004087BF
00408414 DD1C24 fstp qword ptr ss:[esp]
00408417 FF15 48B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrR8>; msvbvm50.__vbaStrR8
0040841D 8BD0 mov edx,eax
0040841F 8D4D E4 lea ecx,dword ptr ss:[ebp-0x1C]
00408422 FF15 94B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrMo>; msvbvm50.__vbaStrMove
00408428 899D 2CFFFFFF mov dword ptr ss:[ebp-0xD4],ebx
0040842E 8B9D 58FFFFFF mov ebx,dword ptr ss:[ebp-0xA8]
00408434 50 push eax
00408435 8B85 2CFFFFFF mov eax,dword ptr ss:[ebp-0xD4]
0040843B 53 push ebx
0040843C FF90 A4000000 call dword ptr ds:[eax+0xA4]
00408442 85C0 test eax,eax
首先得到了前面计算的字符串“355603”,然后同样转换成了浮点数,然后将它乘以3.00,得到1066809,然后减去2.00,得到了1066807,接着转换成了字符串存储起来。
同样有经过了一段内存释放等操作后,来到了计算的地方:
004084D3 8B8D 58FFFFFF mov ecx,dword ptr ss:[ebp-0xA8]
004084D9 8B55 E8 mov edx,dword ptr ss:[ebp-0x18]
004084DC 52 push edx
004084DD 8B19 mov ebx,dword ptr ds:[ecx]
004084DF FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>; msvbvm50.__vbaR8Str
004084E5 DC25 20104000 fsub qword ptr ds:[0x401020]
004084EB 83EC 08 sub esp,0x8
004084EE DFE0 fstsw ax
004084F0 A8 0D test al,0xD
004084F2 0F85 C7020000 jnz AfKayAs_.004087BF
004084F8 DD1C24 fstp qword ptr ss:[esp]
004084FB FF15 48B14000 call dword ptr ds:[<&MSVBVM50.__vbaStrR8>; msvbvm50.__vbaStrR8
00408501 8BD0 mov edx,eax
00408503 8D4D E4 lea ecx,dword ptr ss:[ebp-0x1C]
首先得到前面计算的字符串1066807(edx),转换成浮点数,减去15.000(0x401020),得到1066822,接着又重新转换成了字符串保存起来。
同样有经过了一段其它的操作后,来到了最后一个计算地方:
004085CE 8B45 E8 mov eax,dword ptr ss:[ebp-0x18]
004085D1 50 push eax ; 密码出来了
004085D2 FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>; msvbvm50.__vbaR8Str
004085D8 8B4D E4 mov ecx,dword ptr ss:[ebp-0x1C] ; 这里是计算出来的正确密码
004085DB DD9D 1CFFFFFF fstp qword ptr ss:[ebp-0xE4]
004085E1 51 push ecx ; ntdll.7777FB62
004085E2 FF15 74B14000 call dword ptr ds:[<&MSVBVM50.__vbaR8Str>; msvbvm50.__vbaR8Str
004085E8 833D 00904000 0>cmp dword ptr ds:[0x409000],0x0
004085EF 75 08 jnz short AfKayAs_.004085F9
004085F1 DCBD 1CFFFFFF fdivr qword ptr ss:[ebp-0xE4] ; 输入密码/真实密码
004085F7 EB 11 jmp short AfKayAs_.0040860A
004085F9 FFB5 20FFFFFF push dword ptr ss:[ebp-0xE0]
004085FF FFB5 1CFFFFFF push dword ptr ss:[ebp-0xE4]
00408605 E8 888AFFFF call <jmp.&MSVBVM50._adj_fdivr_m64>
0040860A DFE0 fstsw ax
0040860C A8 0D test al,0xD
0040860E 0F85 AB010000 jnz AfKayAs_.004087BF
00408614 FF15 34B14000 call dword ptr ds:[<&MSVBVM50.__vbaFpR8>>; msvbvm50.__vbaFpR8
0040861A DC1D 28104000 fcomp qword ptr ds:[0x401028] ; 相除的结果与1比较
00408620 DFE0 fstsw ax
00408622 F6C4 40 test ah,0x40 ; 正确时这里ah=0x40
00408625 74 07 je short AfKayAs_.0040862E
00408627 BE 01000000 mov esi,0x1
0040862C EB 02 jmp short AfKayAs_.00408630
0040862E 33F6 xor esi,esi
00408630 8D55 E4 lea edx,dword ptr ss:[ebp-0x1C]
00408633 8D45 E8 lea eax,dword ptr ss:[ebp-0x18]
00408636 52 push edx
00408637 50 push eax
00408638 6A 02 push 0x2
0040863A FF15 80B14000 call dword ptr ds:[<&MSVBVM50.__vbaFreeS>; msvbvm50.__vbaFreeStrList
00408640 83C4 0C add esp,0xC
00408643 8D4D D8 lea ecx,dword ptr ss:[ebp-0x28]
00408646 8D55 DC lea edx,dword ptr ss:[ebp-0x24]
00408649 51 push ecx ; ntdll.7777FB62
0040864A 52 push edx
0040864B 6A 02 push 0x2
0040864D FF15 08B14000 call dword ptr ds:[<&MSVBVM50.__vbaFreeO>; msvbvm50.__vbaFreeObjList
00408653 F7DE neg esi ; 求补指令
00408655 83C4 0C add esp,0xC
00408658 B9 04000280 mov ecx,0x80020004
0040865D B8 0A000000 mov eax,0xA
00408662 894D 9C mov dword ptr ss:[ebp-0x64],ecx ; ntdll.7777FB62
00408665 66:85F6 test si,si
00408668 8945 94 mov dword ptr ss:[ebp-0x6C],eax
0040866B 894D AC mov dword ptr ss:[ebp-0x54],ecx ; ntdll.7777FB62
0040866E 8945 A4 mov dword ptr ss:[ebp-0x5C],eax
00408671 894D BC mov dword ptr ss:[ebp-0x44],ecx ; ntdll.7777FB62
00408674 8945 B4 mov dword ptr ss:[ebp-0x4C],eax
00408677 74 62 je short AfKayAs_.004086DB ; 跳过正确了,关键跳
00408679 8B35 14B14000 mov esi,dword ptr ds:[<&MSVBVM50.__vbaSt>; msvbvm50.__vbaStrCat
这段代码很关键,因为出现了我们输入的序列号,应该会有对比,然后根据对比的结果,决定后面的关键跳是否会跳转。上面代码片段的开始,获取了我们输入的序列号,即“2222”,然后获取了我们计算的值“1066822”,这两个字符串都转换成了浮点数,然后相除,用输入的序列号/计算得到的序列号,这里大概应该知道1066822就是正确的序列号了,不过我们继续往下验证:
经过了几个异常判断后,接下来就是将相除得到的值与1.00比较,然后取出浮点比较后的返回状态到ax中,我们可以认为如果比较相等,ah的值为0x40,否则为0x20(先不管为什么,后面说),接着后面判断ah的值,如果是ox40,则esi寄存器的值为0x01,并跳过了xor esi,esi这条指令,后面的test si,si就不会为0,这样后面的关键跳不会跳转因此执行正确的弹窗,否则,执行异或指令导致后面test指令的结果为0,因此关键跳跳过了正确提示部分。
因此通过上述分析我们可以得出序列号的算法是:
序列号=(用户名长度 * 0x15B38+用户名第一个字符ASCII码 + 2) * 3 - 2 - 15
下面我们输入用户名“1111”,序列号“1066822”验证:
验证通过,分析到此结束。
下面说一些文中涉及到关于浮点数计算的知识:
x86关于浮点数计算有专门的寄存器,包括8个通用寄存器栈和3个16位的寄存器,分别是状态寄存器、控制寄存器、标志寄存器,如图:
例如上述代码中的fstsw ax指令,将浮点数状态寄存器的值(上图FST右边红色字体内容)写入ax寄存器中,每次进行一次浮点运算后,状态寄存器的值都会改变,所以在前面的浮点比较指令中,我们通过判断就知道要比较的值是否相等(至于为什么状态是0x4000时表示相等自己去推算),附上这个寄存器各位的意义:
0 —— 非法操作异常
1 —— 非规格化操作数异常
2 —— 除数为0异常
3 —— 溢出标志异常
4 —— 下溢标志异常
5 —— 精度异常标志
6 —— 堆栈错误
7 —— 错误汇总状态
8 —— 条件代码位0(c0)
9 —— 条件代码位1(c1)
10 —— 条件代码位2 (c2)
11-13 —— 堆栈顶指针
14 —— 条件代码位3(c3)
15 —— 繁忙标志
分析到此结束,有问题欢迎指出
这篇关于160个破解练习之CrackMe 003 Afkayas.2的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!