rain灿 发表于 2014-10-12 18:16

一个简单cm的分析

{:5_118:}今天。风清扬大大甩给我一个cm让我干了。。。
然后就有了这个文章=-=

地址先丢出来:链接: http://pan.baidu.com/s/1kT2zj6J 密码: 7ikh

废话不多说了。。。开始了。。。

先载入od

然后查找字符串

发现OK 和 Wrong(错误)
这两个关键字符串。。
于是双击进入OK。
然后找到断首


这里在用户名里输入rain
在密码里输入123
00401410    53            push ebx                            断首下断
00401411    55            push ebp
00401412    56            push esi
00401413    57            push edi
00401414    8BF9            mov edi,ecx
00401416    6A 01         push 1
00401418    E8 93030000   call <jmp.&MFC42.#operator new_823>
0040141D    83C4 04         add esp,4
00401420    85C0            test eax,eax
00401422    74 07         je short 0040142B
00401424    C600 18         mov byte ptr ds:,18
00401427    8BD8            mov ebx,eax
00401429    EB 02         jmp short 0040142D
0040142B    33DB            xor ebx,ebx
0040142D    6A 01         push 1
0040142F    E8 7C030000   call <jmp.&MFC42.#operator new_823>
00401434    83C4 04         add esp,4
00401437    85C0            test eax,eax
00401439    74 07         je short 00401442
0040143B    C600 18         mov byte ptr ds:,18
0040143E    8BF0            mov esi,eax
00401440    EB 02         jmp short 00401444
00401442    33F6            xor esi,esi
00401444    6A 14         push 14
00401446    53            push ebx
00401447    8D8F A0000000   lea ecx,dword ptr ds:
0040144D    E8 58030000   call <jmp.&MFC42.#CWnd::GetWindowTextA_3>               获取用户名
00401452    6A 14         push 14
00401454    56            push esi
00401455    8D4F 60         lea ecx,dword ptr ds:
00401458    E8 4D030000   call <jmp.&MFC42.#CWnd::GetWindowTextA_3>               获取注册码
这是前面的一部分

然后现在讲下怎么爆破。。
先运行起来把。。
然后点一下验证。
发现断下来了



于是F8单步到这里。
(编辑框1和2不能大于10个字节,如果大于就nop把。。)
我这里填的没有大于10字节所以默认的就没跳。
继续F8单步把。。。


现在先讲爆破。。分析就直接略过把。。

然后继续单步。。



单步到这里004014BD

然后按照恒大教给我们的。
nop了。。。。
下面的那个004014C1的跳转没跳。。。
于是不管他。
直接点运行。
哇!成功了!!!!!
咦。。不对啊。。怎么什么都没显示。。。

于是别着急。
仔细看看这两处的代码
004014C3    50            push eax
004014C4    68 50304000   push 00403050                            ; Ok
004014C9    68 2C304000   push 0040302C                            ; Congratulations!This is the key!
004014CE    50            push eax
004014CF    FF15 D8214000   call dword ptr ds:[<&USER32.MessageBoxA>>; USER32.MessageBoxA
004014D5    5F            pop edi
004014D6    5E            pop esi
004014D7    5D            pop ebp
004014D8    5B            pop ebx
004014D9    C3            retn
004014DA    6A 00         push 0
004014DC    68 28304000   push 00403028                            ; Msg
004014E1    68 20304000   push 00403020                            ; Wrong!
004014E6    6A 00         push 0
004014E8    FF15 D8214000   call dword ptr ds:[<&USER32.MessageBoxA>>; USER32.MessageBoxA
004014EE    5F            pop edi
004014EF    5E            pop esi
004014F0    5D            pop ebp
004014F1    5B            pop ebx
004014F2    C3            retn
发现除了内容不同 还有1个地方不同
那就是成功地方是
push eax
push 成功内容
push eax

而失败地方是
push 0
push 失败内容
push 0

发现了什么?。。。
就是成功地方是由eax来确定是不是创建这个窗口的(小菜是这么理解的。。。如有错误 请指出来把。)。。。
下面的失败内容中
push 的是0
而上面的eax
我们单步到那里




发现eax=1

那么我们只要在这把eax赋值为0
就好了把?。
于是就在
004014C3    50            push eax
的前面
004014B8    83D8 FF         sbb eax,-1

修改代码为mov eax,1

在运行看看。是不是成功了?



啊啊啊啊,好开心。。。


下面进入注册码分析:
00401410    53            push ebx
00401411    55            push ebp
00401412    56            push esi
00401413    57            push edi
00401414    8BF9            mov edi,ecx
00401416    6A 01         push 1
00401418    E8 93030000   call <jmp.&MFC42.#operator new_823>
0040141D    83C4 04         add esp,4
00401420    85C0            test eax,eax
00401422    74 07         je short 0040142B
00401424    C600 18         mov byte ptr ds:,18
00401427    8BD8            mov ebx,eax
00401429    EB 02         jmp short 0040142D
0040142B    33DB            xor ebx,ebx
0040142D    6A 01         push 1
0040142F    E8 7C030000   call <jmp.&MFC42.#operator new_823>
00401434    83C4 04         add esp,4
00401437    85C0            test eax,eax
00401439    74 07         je short 00401442
0040143B    C600 18         mov byte ptr ds:,18
0040143E    8BF0            mov esi,eax
00401440    EB 02         jmp short 00401444
00401442    33F6            xor esi,esi
00401444    6A 14         push 14
00401446    53            push ebx
00401447    8D8F A0000000   lea ecx,dword ptr ds:
0040144D    E8 58030000   call <jmp.&MFC42.#CWnd::GetWindowTextA_3>; 取编辑框1.内容 也就是用户名
00401452    6A 14         push 14
00401454    56            push esi
00401455    8D4F 60         lea ecx,dword ptr ds:
00401458    E8 4D030000   call <jmp.&MFC42.#CWnd::GetWindowTextA_3>; 取编辑框2.内容 也就是密码
0040145D    8BFB            mov edi,ebx
0040145F    83C9 FF         or ecx,FFFFFFFF
00401462    33C0            xor eax,eax
00401464    F2:AE         repne scas byte ptr es:
00401466    F7D1            not ecx
00401468    49            dec ecx
00401469    8BFE            mov edi,esi                              ; 以上代码是取编辑框1的长度
0040146B    8BE9            mov ebp,ecx                              ; 4位
0040146D    83C9 FF         or ecx,FFFFFFFF
00401470    F2:AE         repne scas byte ptr es:
00401472    F7D1            not ecx
00401474    49            dec ecx                                  ; 取编辑框2的长度
00401475    83FD 0A         cmp ebp,0A
00401478    77 60         ja short 004014DA                        ; 编辑框1.长度大于10就错误
0040147A    83F9 0A         cmp ecx,0A
0040147D    77 5B         ja short 004014DA                        ; 编辑框2.长度大于10也错误
0040147F    53            push ebx
00401480    E8 7B000000   call 00401500                            ; 算法call1
00401485    56            push esi
00401486    E8 A5000000   call 00401530                            ; 算法call2
0040148B    83C4 08         add esp,8
0040148E    8A0B            mov cl,byte ptr ds:               ; 运算完成的第一个用户名ASCII
00401490    8A16            mov dl,byte ptr ds:               ; 运算完成的第一个密码ASCII
00401492    8AC1            mov al,cl
00401494    3ACA            cmp cl,dl                              ; 互相比较是不是一样
00401496    75 1E         jnz short 004014B6                     ; 如果一样就不跳
00401498    84C0            test al,al
0040149A    74 16         je short 004014B2
0040149C    8A53 01         mov dl,byte ptr ds:               ; 运算完成的第二个用户名ASCII
0040149F    8A4E 01         mov cl,byte ptr ds:               ; 运算完成的第二个密码ASCII
004014A2    8AC2            mov al,dl
004014A4    3AD1            cmp dl,cl                              ; 比较一样不
004014A6    75 0E         jnz short 004014B6                     ; 一样就不跳 不一样就跳
004014A8    83C3 02         add ebx,2                              ; 舍去2个用户名ASCII码 到第三个
004014AB    83C6 02         add esi,2                              ; 舍去2个密码ASCII码 到第三个
004014AE    84C0            test al,al
004014B0^ 75 DC         jnz short 0040148E
004014B2    33C0            xor eax,eax
004014B4    EB 05         jmp short 004014BB                     ; 于是就成功了=-=
004014B6    1BC0            sbb eax,eax
004014B8    83D8 FF         sbb eax,-1
004014BB    85C0            test eax,eax
004014BD    75 1B         jnz short 004014DA
004014BF    85ED            test ebp,ebp
004014C1    74 17         je short 004014DA
004014C3    50            push eax
004014C4    68 50304000   push 00403050                            ; Ok
004014C9    68 2C304000   push 0040302C                            ; Congratulations!This is the key!
004014CE    50            push eax
004014CF    FF15 D8214000   call dword ptr ds:[<&USER32.MessageBoxA>>; USER32.MessageBoxA
004014D5    5F            pop edi
004014D6    5E            pop esi
004014D7    5D            pop ebp
004014D8    5B            pop ebx
004014D9    C3            retn
004014DA    6A 00         push 0
004014DC    68 28304000   push 00403028                            ; Msg
004014E1    68 20304000   push 00403020                            ; Wrong!
004014E6    6A 00         push 0
004014E8    FF15 D8214000   call dword ptr ds:[<&USER32.MessageBoxA>>; USER32.MessageBoxA
004014EE    5F            pop edi
004014EF    5E            pop esi
004014F0    5D            pop ebp
004014F1    5B            pop ebx
004014F2    C3            retn



算法call1:
00401500    8B5424 04       mov edx,dword ptr ss:             ; 算法call1
00401504    56            push esi
00401505    57            push edi
00401506    8BFA            mov edi,edx
00401508    83C9 FF         or ecx,FFFFFFFF
0040150B    33C0            xor eax,eax
0040150D    F2:AE         repne scas byte ptr es:
0040150F    F7D1            not ecx
00401511    49            dec ecx                                  ; rain的长度4
00401512    8BF1            mov esi,ecx
00401514    74 11         je short 00401527
00401516    8A0C10          mov cl,byte ptr ds:             ; 循环读取ASCII
00401519    80F1 03         xor cl,3                                 ; ASCII码与3异或
0040151C    80E9 14         sub cl,14                              ; -20
0040151F    880C10          mov byte ptr ds:,cl
00401522    40            inc eax
00401523    3BC6            cmp eax,esi
00401525^ 72 EF         jb short 00401516
00401527    5F            pop edi
00401528    5E            pop esi
00401529    C3            retn


算法call2:
00401530    8B5424 04       mov edx,dword ptr ss:             ; 算法call 2
00401534    56            push esi
00401535    57            push edi
00401536    8BFA            mov edi,edx
00401538    83C9 FF         or ecx,FFFFFFFF
0040153B    33C0            xor eax,eax
0040153D    F2:AE         repne scas byte ptr es:
0040153F    F7D1            not ecx
00401541    49            dec ecx                                  ; 4
00401542    8BF1            mov esi,ecx
00401544    74 11         je short 00401557
00401546    8A0C10          mov cl,byte ptr ds:             ; 循环取ASCII
00401549    80C1 02         add cl,2                                 ; ASCII+2
0040154C    80F1 10         xor cl,10                              ; 和10异或
0040154F    880C10          mov byte ptr ds:,cl
00401552    40            inc eax
00401553    3BC6            cmp eax,esi
00401555^ 72 EF         jb short 00401546
00401557    5F            pop edi
00401558    5E            pop esi
00401559    C3            retn

总结一下流程:
一上来读取编辑框1.内容的长度
然后计次循环
{
取出ASCII码
然后和3异或-14
}


然后编辑框2.内容的长度
计次循环
{
取出ASCII码
然后+2异或10
}

然后和第一个比较
计算出来的相同就正确


那么下面开始
(注意都是十六进制的运算)
我的用户名是rain
密码未知。
rain通过取ASCII码是72、61、69、6E。
然后和3异或是71、62、6A、6D。
然后-14是5D、4E、56、59




然后因为计算要是同样的
所以既然用户名是4个。
那密码也要是4个。
这个都知道。
然后开始计算
异或有个运算顺序:
   A运算B=C
   A=B运算C
可以用生哥OD里面的逆向计算器
来运算一下。 先勾上16进制


然后5D XOR 10=4D
现在来检验一下。。
10 XOR 4D =5D   检验成功
然后继续运算。 运算4个之后。
密码的ASCII码=4D、5E、46、49
然后别忘了减去2哦。
因为这是算法,+2最后就要-2:
(取出ASCII码
然后+2异或10)

减去2之后密码的ASCII=4B、5C、44、47
然后查ASCII码表 得出
密码=K/DG

填进去。发现正确了=-=


于是就到这里了。。结束


希望所有看过帖子的人回复一个正确的key!
肯定会评分的!!!

微笑的耗子 发表于 2014-10-12 20:10

膜拜支持感谢

Crack杰 发表于 2014-10-12 21:58

学霸啊,学习了,感谢lz发帖

Shark恒 发表于 2014-10-12 22:07

随便甩几个教程出来,就这么霸气~{:6_202:}

穆菲菲 发表于 2014-10-13 18:27

一下子接受不了,留下来慢慢学习,谢谢分享

小明同学 发表于 2014-10-14 15:22

学习了..
...

yexpin 发表于 2014-10-14 15:38

非常感谢分享教程

小高 发表于 2014-10-14 22:37

好技术都是分享心得总结经验得来的!

司辰。 发表于 2015-3-15 23:03

感谢分享~~

Icc 发表于 2017-8-22 11:31

_KaQqi
V"\,LD

#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
        char Name;
        char key;
        int SizeOfName;
        scanf("%s",Name);
        SizeOfName = strlen(Name);
        if(SizeOfName > 10)
                return 0;
        for(int i = 0;i < SizeOfName;i++)
        {
                Name ^= 3;
                Name -= 0x14;
                key = Name;
                key ^= 0x10;
                key -= 2;
        }
        for(int i = 0;i < SizeOfName;i++)
                printf("%c",key);
        while(1);
        return 0;
}
页: [1] 2 3
查看完整版本: 一个简单cm的分析