本帖最后由 xiangshen 于 2011-10-24 14:16 编辑
标题:菜鸟分析下一个简单的KeyGenMe软件 发言人:willjhw E-mail:466684954@qq.com 时间:2011/10/23 详细信息:
软件背景资料
运行平台:Win XP
文件名称:KeyGenMe.exe
程序类型:KeyGenMe
文件大小:4.00KB
使用工具
PEID
说明:这是我写的第一篇算法分析的破文,难免有错误存在,望各位大侠指点。
首先用PEID查壳,效果如下:
可以看见这个程序是汇编写的 在004012DE处下个断点 然后程序跑起来,输入Name:abc Password:0123456789 断在了下面: 004012DE E8 4F000000 call 00401332//跟进这个call
004012E3 68 53304000 push 00403053 ; ASCII "ZWATRQLCGHPSXYENVBJDFKMU"
.
.
.
00401332 33C0 xor eax, eax
00401334 B9 00000000 mov ecx, 0
00401339 BE 23304000 mov esi, 00403023 ; ASCII "0123456789"
0040133E 8A06 mov al, byte ptr [esi]
00401340 EB 10 jmp short 00401352
00401342 0FB6C0 movzx eax, al
00401345 80B8 50314000 0>cmp byte ptr [eax+403150], 2
0040134C 75 0A jnz short 00401358
0040134E 41 inc ecx
0040134F 8A0431 mov al, byte ptr [ecx+esi]
00401352 3C 00 cmp al, 0
00401354 ^ 77 EC ja short 00401342 ; 判断注册码是否为空
00401356 EB 07 jmp short 0040135F
00401358 C605 44304000 4>mov byte ptr [403044], 40 ; 这儿应该跳过才对
0040135F BE 00304000 mov esi, 00403000 ; ASCII "abc"
完成了两个功能: 1.
Password为大写字母 2.
.将用户名ascii div 0X18 余数保存起来 00401364 33C9 xor ecx, ecx
00401366 B8 01000000 mov eax, 1
0040136B 33D2 xor edx, edx
0040136D C705 45304000 0>mov dword ptr [403045], 0
00401377 B9 00000000 mov ecx, 0 ; 开始测试用户名
0040137C 8A0C32 mov cl, byte ptr [edx+esi] ; 取当前用户名ascii到cl
0040137F 80F9 00 cmp cl, 0
00401382 74 09 je short 0040138D ; 是否已经取完
00401384 42 inc edx ; 取用户名长度到edx
00401385 000D 45304000 add byte ptr [403045], cl ; 累加用户名ascii到cl
0040138B ^ EB EA jmp short 00401377
0040138D A1 45304000 mov eax, dword ptr [403045]
00401392 B9 18000000 mov ecx, 18
00401397 99 cdq ; 扩展用户名长度edx为eax高位
00401398 F7F9 idiv ecx ; eax/18
0040139A 8815 4F304000 mov byte ptr [40304F], dl ; 存放余数
004013A0 8A0D 44304000 mov cl, byte ptr [403044]
004013A6 80F9 40 cmp cl, 40
004013A9 75 05 jnz short 004013B0
004013AB E9 45010000 jmp 004014F5
004013B0 E9 CB000000 jmp 00401480//jmp到了下一个call
004013B5 C3 retn
继续跟进call里面去 00401510 A0 24304000 mov al, byte ptr [403024]
00401515 3C 45 cmp al, 45 ; 将注册码第二位和0x45比较
00401517 ^ 75 DC jnz short 004014F5 ; 第二次检查
00401519 BF 96124000 mov edi, 00401296
0040151E B9 00010000 mov ecx, 100
00401523 B0 99 mov al, 99
00401525 34 55 xor al, 55 ; 99与55异或
00401527 F2:AE repne scas byte ptr es:[edi] ; 搜索关键字'U'
00401529 85C9 test ecx, ecx
0040152B 74 06 je short 00401533 ; 第三次检查
0040152D 5E pop esi
0040152E 33F6 xor esi, esi
00401530 57 push edi
00401531 ^ EB C2 jmp short 004014F5
00401533 C3 retn
上面的代码说明输入的password里不能有U确定了第二位为E 00401485 33DB xor ebx, ebx
00401487 BF 80144000 mov edi, 00401480
0040148C 83EF 60 sub edi, 60
0040148F B8 DE000000 mov eax, 0DE
00401494 83F0 12 xor eax, 12 ; 0de与12异或
00401497 B9 59000000 mov ecx, 59
0040149C F2:AE repne scas byte ptr es:[edi]
0040149E 85C9 test ecx, ecx
004014A0 74 06 je short 004014A8 ; 又是检查
004014A2 5E pop esi
004014A3 33F6 xor esi, esi
004014A5 57 push edi
004014A6 EB 4D jmp short 004014F5
004014A8 C3 retn
004012E3 68 53304000 push 00403053 ; ASCII "ZWATRQLCGHPSXYENVBJDFKMU"
004012E8 E8 C9000000 call 004013B6
004012ED E8 DC010000 call 004014CE
004012F2 6A 00 push 0
004012F4 FF75 08 push dword ptr [ebp+8]
上面将常量字符串"ZWATRQLCGHPSXYENVBJDFKMU"压入在跟进4012e8去 004013B6 55 push ebp
004013B7 8BEC mov ebp, esp
004013B9 68 23304000 push 00403023 ; ASCII "0123456789"
004013BE E8 7D010000 call 00401540 ; 求注册码长度
004013C3 83F8 0A cmp eax, 0A ; 注册码长度是否为10
004013C6 0F85 29010000 jnz 004014F5
004013CC BE 23304000 mov esi, 00403023 ; ASCII "0123456789"
004013D1 B8 00000000 mov eax, 0
004013D6 BB 00000000 mov ebx, 0
004013DB 33C9 xor ecx, ecx
004013DD EB 06 jmp short 004013E5 ; 开始累加注册码的ascii和到ebx
004013DF 8A0C30 mov cl, byte ptr [eax+esi]
004013E2 03D9 add ebx, ecx
004013E4 40 inc eax
004013E5 83F8 09 cmp eax, 9
004013E8 ^ 72 F5 jb short 004013DF
004013EA 8BC3 mov eax, ebx
004013EC B9 09000000 mov ecx, 9
004013F1 99 cdq
004013F2 F7F9 idiv ecx ; ascii和/长度
004013F4 A3 4A304000 mov dword ptr [40304A], eax ; 存放商
004013F9 8B7D 08 mov edi, dword ptr [ebp+8]
00401406 /76 02 jbe short 0040140A
00401408 |2C 18 sub al, 18
0040140A \A2 4E304000 mov byte ptr [40304E], al
0040140F 33C0 xor eax, eax
00401411 A0 4E304000 mov al, byte ptr [40304E]
00401416 8A2438 mov ah, byte ptr [eax+edi]
00401419 8A36 mov dh, byte ptr [esi]
0040141B 38F4 cmp ah, dh ; 开始比较了
0040141D 0F85 D2000000 jnz 004014F5
确定password的第一位是用户名之和除以0x18的余数再去那个常量字符找对应的位数 00401453 A2 4E304000 mov byte ptr [40304E], al
00401458 33C0 xor eax, eax
0040145A A0 4E304000 mov al, byte ptr [40304E]
0040145F 80EE 41 sub dh, 41
00401462 8AD6 mov dl, dh
00401464 41 inc ecx
00401465 02C2 add al, dl
00401467 3C 18 cmp al, 18
00401469 76 02 jbe short 0040146D
0040146B 2C 18 sub al, 18
0040146D 8A2438 mov ah, byte ptr [eax+edi]
00401470 8A3431 mov dh, byte ptr [ecx+esi]
00401473 38F4 cmp ah, dh
00401475 75 7E jnz short 004014F5
00401477 83F9 08 cmp ecx, 8
0040147A ^ 72 D7 jb short 00401453
这个是确定password的3到9位
004014CE BE 23304000 mov esi, 00403023 ; ASCII "0123456789"
004014D3 A1 4A304000 mov eax, dword ptr [40304A]
004014D8 8A5E 09 mov bl, byte ptr [esi+9]
004014DB 38D8 cmp al, bl
004014DD 75 16 jnz short 004014F5 ; 又是比较
004014DF B8 6C304000 mov eax, 0040306C ; ASCII "Great Job!"
004014E4 8BD8 mov ebx, eax
004014E6 83C3 0B add ebx, 0B
004014E9 6A 00 push 0
004014EB 50 push eax
004014EC 53 push ebx
004014ED 6A 00 push 0
004014EF E8 B4000000 call <jmp.&user32.MessageBoxA>
这个是最后位password的确定,过了就call出正确的MessageBoxA来 最后一位的确定是password前九位之和除以9的商
下面是对应的注册机代码,是用c写的 #include <stdio.h>
#include <string.h>
const char biao[25] = "ZWATRQLCGHPSXYENVBJDFKMU";
int main (void)
{
char name[100], mima[10];
int SumName, LenName, i, Temp;
printf ("Name:");
scanf("%s",name);
SumName = 0;
LenName = 0;
LenName = strlen(name);
//printf("%d",LenName);
for (i = 0; i < LenName; i++)
{
SumName = SumName + (int)name[i];////求出用户名字节之和到SunName
if (SumName > 255)
{
SumName = SumName - 256;
}
}
mima[1] = 'E';//密码第二位必须为E
mima[0] = biao[SumName % 24];//密码第一位
Temp = SumName % 24 + SumName % 24;
if (Temp > 24)
{
Temp = Temp - 24;
}
mima[2] = biao[Temp];//密码第三位
for (i = 3; i <= 8;i++)//循环求出密码4到9位
{
Temp = (int)mima[i - 1] - 65 + Temp;
if (Temp > 24)
{
Temp = Temp - 24;
}
mima[i] = biao[Temp];
}
Temp = 0;
for (i = 0; i < 9; i++)
{
Temp = Temp + (int)mima[i];
}
Temp = Temp / 9;//最后一位前九位之和除以长度
//printf ("\n%c\n",Temp);
mima[9] = (char)Temp;
printf("PASSWORD:");
for (i = 0; i < 10; i++)
{
printf ("%c",mima[i]);
}
printf ("\n");
return 0;
}
看来注册机大家应该明白很多了吧 罗罗嗦嗦讲了一大堆,希望大家能够明白我的意思! 最后把附件给传上来
|