这是我的逆向分析处女作(希望能够完成riijj的整个系列, ).
写的不好的地方,还请大家多多包涵 .
没什么技术含量, 高手可以飘过,当然能够指点几句那是求之不得了.
目标:riijj系列 cm1.
断RegisterClassEx,由lpWNDCLASS 可以找打DialogFunc.
不废话了, 看反汇编
00401050 > . 817C24 08 110>cmp dword ptr [esp+8], 111 ; DialogFunc
00401058 . 75 74 jnz short 004010CE ; 不是WM_COMMAND则跳走.
0040105A . 8B4424 0C mov eax, dword ptr [esp+C] ; wParam
0040105E . 66:3D EA03 cmp ax, 3EA ; 消息来源是否注册按钮
00401062 . 75 42 jnz short 004010A6
00401064 . E8 C7010000 call <KeyCall> ; 关键call
00401069 . 85C0 test eax, eax
0040106B . 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
0040106D . 68 80504000 push 00405080 ; |Title = "ncrackme"
00401072 . 75 1B jnz short 0040108F ; |
00401074 . A1 B8564000 mov eax, dword ptr [4056B8] ; |
00401079 . 68 64504000 push 00405064 ; |Text = "Registration successful."
0040107E . 50 push eax ; |hOwner => 0066035A ('Newbie smallsize crackme - v1',class='myWindowClass')
0040107F . FF15 C0404000 call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
00401085 . E8 A6020000 call <___setargv>
0040108A . 33C0 xor eax, eax
0040108C . C2 1000 retn 10
0040108F > 8B0D B8564000 mov ecx, dword ptr [4056B8] ; |
00401095 . 68 50504000 push 00405050 ; |Text = "Registration fail."
0040109A . 51 push ecx ; |hOwner => 0066035A ('Newbie smallsize crackme - v1',class='myWindowClass')
0040109B . FF15 C0404000 call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
004010A1 . 33C0 xor eax, eax
004010A3 . C2 1000 retn 10
004010A6 > 66:3D EB03 cmp ax, 3EB
////KeyCall
00401262 |> \A1 BC564000 mov eax, dword ptr [4056BC] ; Dialog句柄.
00401267 |. 8D5424 28 lea edx, dword ptr [esp+28] ; 存放注册号缓冲区
0040126B |. 6A 10 push 10
0040126D |. 52 push edx
0040126E |. 68 E9030000 push 3E9 ; 注册号Edit控件的ID
00401273 |. 50 push eax
00401274 |. FFD6 call esi
00401276 |. 0FBE4424 08 movsx eax, byte ptr [esp+8] ; name[0]
0040127B |. 0FBE4C24 09 movsx ecx, byte ptr [esp+9] ; name[1]
00401280 |. 99 cdq
00401281 |. F7F9 idiv ecx ; eax为商,edx为余数
00401283 |. 8BCA mov ecx, edx ; ecx = 余数.
00401285 |. 83C8 FF or eax, FFFFFFFF
00401288 |. 0FBE5424 0A movsx edx, byte ptr [esp+A] ; name[2]
0040128D |. 0FAFCA imul ecx, edx
00401290 |. 41 inc ecx ; 除数.
00401291 |. 33D2 xor edx, edx
00401293 |. F7F1 div ecx
00401295 |. 50 push eax ; 商作为种子
00401296 >|. E8 A5000000 call <_srand> ; 刚开始这里是被inline进来的srand最后发现是srand
0040129B |. 83C4 04 add esp, 4
0040129E |. 33F6 xor esi, esi
004012A0 |> E8 A5000000 /call <_rand> ; 这里先来个15次rand. 目的是变换种子
004012A5 |. 99 |cdq
004012A6 |. B9 1A000000 |mov ecx, 1A
004012AB |. F7F9 |idiv ecx
004012AD |. 80C2 41 |add dl, 41
004012B0 |. 885434 18 |mov byte ptr [esp+esi+18], dl
004012B4 |. 46 |inc esi
004012B5 |. 83FE 0F |cmp esi, 0F
004012B8 |.^ 72 E6 \jb short 004012A0
004012BA |. 57 push edi ; 保护现场.
004012BB |. 8D7C24 0C lea edi, dword ptr [esp+C]
004012BF |. 83C9 FF or ecx, FFFFFFFF
004012C2 |. 33C0 xor eax, eax
004012C4 |. 33F6 xor esi, esi
004012C6 |. F2:AE repne scas byte ptr es:[edi]
004012C8 |. F7D1 not ecx
004012CA |. 49 dec ecx ; 求用户名的长度.,
004012CB |. 74 59 je short 00401326
004012CD |> 8A4434 0C /mov al, byte ptr [esp+esi+C] ; name[i]
004012D1 |. C0F8 05 |sar al, 5
004012D4 |. 0FBEC0 |movsx eax, al ; eax = name[i] << 5
004012D7 |. 8D1480 |lea edx, dword ptr [eax+eax*4]
004012DA |. 8D04D0 |lea eax, dword ptr [eax+edx*8]
004012DD |. 8D0440 |lea eax, dword ptr [eax+eax*2] ; eax *= 41*3
004012E0 |. 85C0 |test eax, eax
004012E2 |. 7E 0A |jle short 004012EE ; 这里其实永远不会跳,因为上面乘法永不会溢出.
004012E4 |. 8BF8 |mov edi, eax ; 上面的eax作为一个计数器.
004012E6 |> E8 5F000000 |/call <_rand> ; 调用rand 这么多次,目的变化种子.
004012EB |. 4F ||dec edi
004012EC |.^ 75 F8 |\jnz short 004012E6
004012EE |> E8 57000000 |call <_rand> ; 再来调用一次.
004012F3 |. 99 |cdq ; edx = 0
004012F4 |. B9 1A000000 |mov ecx, 1A
004012F9 |. 8D7C24 0C |lea edi, dword ptr [esp+C] ; 用户名地址,这里代码穿插着,这句是为后面求长度服务的.
004012FD |. F7F9 |idiv ecx
004012FF |. 0FBE4C34 2C |movsx ecx, byte ptr [esp+esi+2C] ; OK,这里是就是注册号.取首字节.
00401304 |. 80C2 41 |add dl, 41
00401307 |. 0FBEC2 |movsx eax, dl ; eax = eax%0x1A +'A'
0040130A |. 2BC1 |sub eax, ecx ; 这里关键. 要让ecx = eax
0040130C |. 885434 1C |mov byte ptr [esp+esi+1C], dl ; 这个写入跟上面那个循环的写入是一样的,混淆视听的.
00401310 |. 99 |cdq ; 这里要看上面的减法定. edx = 0 或-1
00401311 |. 33C2 |xor eax, edx ; 这句结合上面一句就是eax = |eax|
00401313 |. 83C9 FF |or ecx, FFFFFFFF
00401316 |. 2BC2 |sub eax, edx ; 这句看edx情况定.
00401318 |. 03D8 |add ebx, eax ; 每次的eax累加到ebx.
0040131A |. 33C0 |xor eax, eax
0040131C |. 46 |inc esi
0040131D |. F2:AE |repne scas byte ptr es:[edi]
0040131F |. F7D1 |not ecx
00401321 |. 49 |dec ecx ; 用户名长度.
00401322 |. 3BF1 |cmp esi, ecx
00401324 |.^ 72 A7 \jb short 004012CD
00401326 |> 5F pop edi ; 恢复这个寄存器.
00401327 |. 8BC3 mov eax, ebx ; 看了这里就知道为什么上面那句减法的结果一定要为零
00401329 |. 5E pop esi
0040132A |. 5B pop ebx
0040132B |. 83C4 30 add esp, 30
0040132E \. C3 retn
0040132F 90 nop
OK, 思路我们已经很明确了, 就是使ebx为零. 即ebx = 0; (1)
而ebx = eax_1 + eax_2 + …+
而在add ebx,eax之前有这两句:
Eax_i = |eax_i| ;
sub eax_i, edx_i ; 这句对eax加零或加1.
所以eax_i >=0; (2)
这样根据(1),(2), 得 eax_i = 0.
哎, 好了不说了,相信大家早都明白了, 我却还在这里啰嗦,
附上垃圾注册机代码:
#include <stdio.h>
#include <stdlib.h>
char name[16];
char regCode[16];
void rep_rand(int c)
{
int i;
for(i= 0;i<c;++i)
rand();
}
void main()
{
int i,j,len,seed;
int count;
char ch;
printf("Enter the Reg name (len>=3):\n");
scanf("%s",name);
len = strlen(name);
seed =(int) (0xFFFFFFFF / ((name[0] % name[1]) * name[2] +1)) ;
srand(seed);
rep_rand(15);
for(i=0;i<len;++i)
{
count = name[i] >> 5;
count += 5*count*8;
count *= 3;
rep_rand(count);
ch = 'A' + rand()%0x1A;
//generate key
regCode[i] = ch;
}
printf("the reg code is : %s \n",regCode);
getch();
}
一组可用序号: jackozoo / YRJHVRYR .
谢谢看到这里的朋友, 第一次写这种文章比较啰嗦.
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!