AJISky's CM_One详解

一、

PEID查看,是用汇编语言写的,所以直接看DialogBoxParamA的参数,找到消息循环。在消息循环里面找到0x111(WM_COMMAND),断下慢慢分析:

 

0040136A  |> \3D 11010000   cmp eax,0x111
0040136F  |.  75 4D         jnz X004013BE
00401371  |.  8B45 10       mov eax,[arg.3]                          ;  Case 111 (WM_COMMAND) of switch 0040134C
00401374  |.  83F8 6A       cmp eax,0x6A
00401377  |.  75 28         jnz X004013A1
00401379  |.  8D3D 7A324000 lea edi,dword ptr ds:[<K1>]
0040137F  |.  33C0          xor eax,eax
00401381  |.  B9 10000000   mov ecx,0x10
00401386  |.  F3:AA         rep stos byte ptr es:[edi]               ;  清0
00401388  |.  8D3D 1E304000 lea edi,dword ptr ds:[<K2>]
0040138E  |.  B9 10000000   mov ecx,0x10
00401393  |.  F3:AA         rep stos byte ptr es:[edi]               ;  清0
00401395  |.  E8 A9FCFFFF   call 00401043
0040139A  |.  E8 97FDFFFF   call 00401136

0040139F  |. /EB 37         jmp X004013D8

 

二、分析:

call 00401043是取得用户名后,由它运算出一个长度最大为15的BYTE数组(K2),实际长度以用户名长度为准。

call 00401136比较复杂,先看前面:

00401136  /$  6A 10         push 0x10                                ; /Count = 10 (16.)
00401138  |.  68 5F314000   push offset <sn>                         ; |Buffer = offset <CM_One.sn>
0040113D  |.  6A 67         push 0x67                                ; |ControlID = 67 (103.)
0040113F  |.  FF35 5E324000 push dword ptr ds:[0x40325E]             ; |hWnd = NULL
00401145  |.  E8 E0020000   call <jmp.&user32.GetDlgItemTextA>       ; \GetDlgItemTextA
0040114A  |.  83F8 00       cmp eax,0x0
0040114D  |.  0F84 85010000 je <EXIT>
00401153  |.  8BC8          mov ecx,eax                              ;  循环次数
00401155  |.  8D3D 1E304000 lea edi,dword ptr ds:[<K2>]
0040115B  |.  8D35 5F314000 lea esi,dword ptr ds:[<sn>]
00401161  |>  8A06          /mov al,byte ptr ds:[esi]                ;  sn
00401163  |.  8A1F          |mov bl,byte ptr ds:[edi]                ;  K2
00401165  |.  D0EB          |shr bl,1
00401167      02C3          add al,bl
00401169      8807          mov byte ptr ds:[edi],al                 ;  K2
0040116B  |.  46            |inc esi
0040116C  |.  47            |inc edi
0040116D  |.^ E2 F2         \loopd X00401161                         ;  F(K2,sn)

 

这里,取注册码,最大15位,然后和K2运算并更新K2。

40116F到4011BE是分别打开Windows.iso和WinXP.iso。

 

004011C8  |.  B9 B2000000   mov ecx,0xB2                             ;  178
004011CD  |.  8D3D 1E304000 lea edi,dword ptr ds:[<K2>]
004011D3  |>  51            /push ecx
004011D4  |.  6A 00         |push 0x0                                ; /pOverlapped = NULL
004011D6  |.  68 76324000   |push offset <返回数据长度>                    ; |pBytesRead = offset <CM_One.返回数据长度>
004011DB  |.  6A 01         |push 0x1                                ; |BytesToRead = 1
004011DD  |.  68 16304000   |push offset <ReadBuff>                  ; |Buffer = offset <CM_One.ReadBuff>
004011E2  |.  FF35 54304000 |push dword ptr ds:[<hFile1>]            ; |hFile = NULL
004011E8  |.  E8 1F020000   |call <jmp.&kernel32.ReadFile>           ; \ReadFile读一个字节
004011ED  |.  833D 76324000>|cmp dword ptr ds:[<返回数据长度>],0x0
004011F4  |.  75 05         |jnz X004011FB                           ;  数据不为0
004011F6  |.  E9 DD000000   |jmp <EXIT>
004011FB  |>  8D35 16304000 |lea esi,dword ptr ds:[<ReadBuff>]
00401201  |.  803F 00       |cmp byte ptr ds:[edi],0x0               ;  K2数据不为0
00401204  |.  75 06         |jnz X0040120C
00401206  |.  8D3D 1E304000 |lea edi,dword ptr ds:[<K2>]             ;  如果为0,指针循环到[0]
0040120C  |>  8A06          |mov al,byte ptr ds:[esi]                ;  ReadBuff win.iso
0040120E  |.  3207          |xor al,byte ptr ds:[edi]                ;  K2
00401210  |.  A2 18304000   |mov byte ptr ds:[<WriteBuff>],al
00401215  |.  47            |inc edi
00401216  |.  6A 00         |push 0x0                                ; /pOverlapped = NULL
00401218  |.  68 76324000   |push offset <返回数据长度>                    ; |pBytesWritten = offset <CM_One.返回数据长度>
0040121D  |.  6A 01         |push 0x1                                ; |nBytesToWrite = 1
0040121F  |.  68 18304000   |push offset <WriteBuff>                 ; |Buffer = offset <CM_One.WriteBuff>
00401224  |.  FF35 50304000 |push dword ptr ds:[<hFile2>]            ; |hFile = NULL
0040122A  |.  E8 E3010000   |call <jmp.&kernel32.WriteFile>          ; \WriteFile
0040122F  |.  59            |pop ecx
00401230  |.^ E2 A1         \loopd X004011D3


这里是一个循环,次数为0xB2。读Windows.iso的字节,异或K2后,WinXP.iso。

 

00401232  |.  8D3D 40304000 lea edi,dword ptr ds:[<conKEY>]
00401238  |.  8D35 16304000 lea esi,dword ptr ds:[<ReadBuff>]
0040123E  |.  8D1D 1E304000 lea ebx,dword ptr ds:[<K2>]
00401244  |.  EB 59         jmp X0040129F
00401246  |>  6A 00         /push 0x0                                ; /pOverlapped = NULL
00401248  |.  68 76324000   |push offset <返回数据长度>                    ; |pBytesRead = offset <CM_One.返回数据长度>
0040124D  |.  6A 01         |push 0x1                                ; |BytesToRead = 1
0040124F  |.  68 16304000   |push offset <ReadBuff>                  ; |Buffer = offset <CM_One.ReadBuff>
00401254  |.  FF35 54304000 |push dword ptr ds:[<hFile1>]            ; |hFile = NULL
0040125A  |.  E8 AD010000   |call <jmp.&kernel32.ReadFile>           ; \ReadFile
0040125F  |.  833D 76324000>|cmp dword ptr ds:[<返回数据长度>],0x0
00401266  |.  74 37         |je X0040129F
00401268  |.  803F 00       |cmp byte ptr ds:[edi],0x0
0040126B  |.  75 0C         |jnz X00401279
0040126D  |.  8D1D 1E304000 |lea ebx,dword ptr ds:[<K2>]
00401273  |.  8D3D 40304000 |lea edi,dword ptr ds:[<conKEY>]
00401279  |>  8A06          |mov al,byte ptr ds:[esi]                ;  ReadBuff
0040127B  |.  3207          |xor al,byte ptr ds:[edi]                ;  conKEY
0040127D  |.  3203          |xor al,byte ptr ds:[ebx]                ;  K2
0040127F  |.  A2 16304000   |mov byte ptr ds:[<ReadBuff>],al
00401284  |.  47            |inc edi
00401285  |.  43            |inc ebx
00401286  |.  6A 00         |push 0x0                                ; /pOverlapped = NULL
00401288  |.  68 76324000   |push offset <返回数据长度>                    ; |pBytesWritten = offset <CM_One.返回数据长度>
0040128D  |.  6A 01         |push 0x1                                ; |nBytesToWrite = 1
0040128F  |.  68 16304000   |push offset <ReadBuff>                  ; |Buffer = offset <CM_One.ReadBuff>
00401294  |.  FF35 50304000 |push dword ptr ds:[<hFile2>]            ; |hFile = NULL
0040129A  |.  E8 73010000   |call <jmp.&kernel32.WriteFile>          ; \WriteFile
0040129F  |>  833D 76324000> cmp dword ptr ds:[<返回数据长度>],0x0
004012A6  |.^ 75 9E         \jnz X00401246


这里是读Windows.iso的字节,异或K2,异或一个常量(conKEY)后,写入WinXP.iso。

 

004012A8  |.  FF35 50304000 push dword ptr ds:[<hFile2>]             ; /hObject = NULL
004012AE  |.  E8 2F010000   call <jmp.&kernel32.CloseHandle>         ; \CloseHandle
004012B3  |.  FF35 54304000 push dword ptr ds:[<hFile1>]             ; /hObject = NULL
004012B9  |.  E8 24010000   call <jmp.&kernel32.CloseHandle>         ; \CloseHandle
004012BE  |.  68 00304000   push 00403000                            ; /FileName = "WinXP.iso"
004012C3  |.  E8 3E010000   call <jmp.&kernel32.LoadLibraryA>        ; \LoadLibraryA
004012C8  |.  50            push eax                                 ; /hLibModule
004012C9  |.  E8 2C010000   call <jmp.&kernel32.FreeLibrary>         ; \FreeLibrary
004012CE  |.  68 00304000   push 00403000                            ; /FileName = "WinXP.iso"
004012D3  |.  E8 16010000   call <jmp.&kernel32.DeleteFileA>         ; \DeleteFileA
004012D8 >\>  C3            retn

 

这里关闭文件句柄,用LoadLibraryA打开WinXP.iso,然后关闭并删除它。可见WinXP.iso应该是一个DLL。DLL是PE格式,根据PE格式头部都是固定的原理,得出公式:

N1=F1(name);

K2=F2(name,N1);

K2=sn+(K2>>1);

PE=K2^iWindows.iso;

以上PE和Windows.iso已知,所以可得K2,把K2代入K2=sn+(K2>>1);就可以得SN了。

K=PE^Windows.iso;

sn=K-(K2>>1);

 

三、实际问题

PE文件在格式上是统一的,但格式内的数据略有不同来看看两个PE文件:

00000000h: 4D 5A 50 00 02 00 00 00 04 00 0F 00 FF FF 00 00 ; MZP...........
00000010h: B8 00 00 00 00 00 00 00 40 00 1A 00 00 00 00 00 ; ?......@.......
00000020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000030h: 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 ; ................
00000040h: BA 10 00 0E 1F B4 09 CD 21 B8 01 4C CD 21 90 90 ; ?...???L?悙
00000050h: 54 68 69 73 20 70 72 6F 67 72 61 6D 20 6D 75 73 ; This program mus
00000060h: 74 20 62 65 20 72 75 6E 20 75 6E 64 65 72 20 57 ; t be run under W
00000070h: 69 6E 33 32 0D 0A 24 37 00 00 00 00 00 00 00 00 ; in32..$7........

 

00000000h: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 ; MZ?..........
00000010h: B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ; ?......@.......
00000020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000030h: 00 00 00 00 00 00 00 00 00 00 00 00 F0 00 00 00 ; ............?..
00000040h: 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 ; ..?.???L?Th
00000050h: 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F ; is program canno
00000060h: 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 ; t be run in DOS 
00000070h: 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 ; mode....$.......

 

以上两个PE文件就差哪么一点,特别是IMAGE_DOS_HEADER的e_cblp(第3,4个字节)。如果用前16位来异或Windows.iso可能会出现错误。注意观察会发现“50h”这一行16位基本不变。所以就好以这16个字节进行异或,得出K。

         PE-50h:  69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F

Windows.iso-50h:  25 E2 7D 26 F9 C6 04 27 2D FC 7D 35 EA C7 0D 3A   异或运算

           结果:  4C 91 5D 56 8B A9 63 55 4D 91 5D 56 8B A9 63 55

可见,K为8位,所以sn也为8位。

 

四、注册机源码:

// CM_One_REG.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <wtypes.h>

DWORD g_N1=0;
BYTE g_K1[16],g_K2[16];
const int g_KEY1LEN=16;
const BYTE g_KEY1[8]={0x4C,0x91,0x5D,0x56,0x8B,0xA9,0x63,0x55};
const BYTE g_KEY2[8]={0x26, 0x32, 0x43, 0x1A, 0x2C, 0xB3, 0x5F, 0x42};
void call_0040104390(char *name)
{
	g_N1=0;
	ZeroMemory(g_K1,16);
	ZeroMemory(g_K2,16);
	int len=strlen(name),loop=0xf,i=0,temp=0;
// 	g_N1=(name[0]%name[1]);
// 	g_N1*=name[2];
// 	g_N1++;
// 	g_N1=0xFFFFFFFF/g_N1;
	g_N1=0xFFFFFFFF/((name[0]%name[1])*name[2]+1);
	while(loop--)
	{
		g_N1*=0x342ab;
		g_N1+=0x269EC3;
		g_K1[i]=(char)(((g_N1>>0x10)&0x7FFF)%0x10)+0x4b;
		i++;
	}
	loop=len;
	i=0;
	while(loop--)
	{
		temp=(name[i]>>5)*0x7B;
		if (temp>0)
		{
			while(temp--)
			{
				g_N1=(g_N1*0x123CD)+0x775851;
			}			
		}
		g_N1=(g_N1*0x123CD)+0x269EC3;
		g_K2[i]=(char)(g_N1>>0x10)&0x7FFF;//
		i++;
	}
}
void call_00401136(char *sn)
{
	int len=strlen(sn),loop=0,i=0,temp=0;
	if (len>8)
	{
		printf("sn Error!");
		return;
	}
	loop=len;
	i=0;
	while(loop--)
	{
		g_K2[i]=(g_K2[i]>>1)+sn[i];
		i++;
	}
}
BYTE *GetSN(char *name)
{
	call_0040104390(name);
	BYTE out[10]={0};
	BYTE j=0;
	printf("SN:");
	for (int i=0;i<8;i++)
	{
		//j=((BYTE)g_K2[i])>>1;
		out[i]=g_KEY1[i]-(g_K2[i]>>1);
		//printf("%d:%d - %02X\n",i+1,out[i],out[i],out[i]);
		printf("%02X ",out[i]);
	}
	return out;
}
// BYTE *GetN1(char *sn)
// {
// 	if (strlen(sn)!=8)
// 	{
// 		return NULL;
// 	}
// 	BYTE out[8]={0};
// 	int i=0,j=0,k=0;
// 	for(i=0;i<8;i++)
// 	{
// 		k=g_KEY1[i]-sn[1];
// 		for (j=0;j<0x100;j++)
// 		{
// 			if ((j>>1)==k)
// 			{
// 				break;
// 			}
// 		}
// 		out[i]=j;
// 	}
// 	return out;
// }
int main(int argc, char* argv[])
{
	//printf("SN:");
	IMAGE_DOS_HEADER
	GetSN("lili");	
	return 0;
	
}


五、总结

1.了解PE文件格式是关键

2.算出来的sn有时为不可见字符,要怎样输入呢?我只知道用UltraEdit输入16进制数值后,转换成字符模式再复制粘贴。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值