AJISky's CM_One详解
来源:互联网 发布:课外阅读训练软件 编辑:程序博客网 时间:2024/05/18 01:25
一、
PEID查看,是用汇编语言写的,所以直接看DialogBoxParamA的参数,找到消息循环。在消息循环里面找到0x111(WM_COMMAND),断下慢慢分析:
0040136A |> \3D 11010000 cmp eax,0x1110040136F |. 75 4D jnz X004013BE00401371 |. 8B45 10 mov eax,[arg.3] ; Case 111 (WM_COMMAND) of switch 0040134C00401374 |. 83F8 6A cmp eax,0x6A00401377 |. 75 28 jnz X004013A100401379 |. 8D3D 7A324000 lea edi,dword ptr ds:[<K1>]0040137F |. 33C0 xor eax,eax00401381 |. B9 10000000 mov ecx,0x1000401386 |. F3:AA rep stos byte ptr es:[edi] ; 清000401388 |. 8D3D 1E304000 lea edi,dword ptr ds:[<K2>]0040138E |. B9 10000000 mov ecx,0x1000401393 |. F3:AA rep stos byte ptr es:[edi] ; 清000401395 |. E8 A9FCFFFF call 004010430040139A |. E8 97FDFFFF call 004011360040139F |. /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 = NULL00401145 |. E8 E0020000 call <jmp.&user32.GetDlgItemTextA> ; \GetDlgItemTextA0040114A |. 83F8 00 cmp eax,0x00040114D |. 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] ; sn00401163 |. 8A1F |mov bl,byte ptr ds:[edi] ; K200401165 |. D0EB |shr bl,100401167 02C3 add al,bl00401169 8807 mov byte ptr ds:[edi],al ; K20040116B |. 46 |inc esi0040116C |. 47 |inc edi0040116D |.^ E2 F2 \loopd X00401161 ; F(K2,sn)
这里,取注册码,最大15位,然后和K2运算并更新K2。
40116F到4011BE是分别打开Windows.iso和WinXP.iso。
004011C8 |. B9 B2000000 mov ecx,0xB2 ; 178004011CD |. 8D3D 1E304000 lea edi,dword ptr ds:[<K2>]004011D3 |> 51 /push ecx004011D4 |. 6A 00 |push 0x0 ; /pOverlapped = NULL004011D6 |. 68 76324000 |push offset <返回数据长度> ; |pBytesRead = offset <CM_One.返回数据长度>004011DB |. 6A 01 |push 0x1 ; |BytesToRead = 1004011DD |. 68 16304000 |push offset <ReadBuff> ; |Buffer = offset <CM_One.ReadBuff>004011E2 |. FF35 54304000 |push dword ptr ds:[<hFile1>] ; |hFile = NULL004011E8 |. E8 1F020000 |call <jmp.&kernel32.ReadFile> ; \ReadFile读一个字节004011ED |. 833D 76324000>|cmp dword ptr ds:[<返回数据长度>],0x0004011F4 |. 75 05 |jnz X004011FB ; 数据不为0004011F6 |. E9 DD000000 |jmp <EXIT>004011FB |> 8D35 16304000 |lea esi,dword ptr ds:[<ReadBuff>]00401201 |. 803F 00 |cmp byte ptr ds:[edi],0x0 ; K2数据不为000401204 |. 75 06 |jnz X0040120C00401206 |. 8D3D 1E304000 |lea edi,dword ptr ds:[<K2>] ; 如果为0,指针循环到[0]0040120C |> 8A06 |mov al,byte ptr ds:[esi] ; ReadBuff win.iso0040120E |. 3207 |xor al,byte ptr ds:[edi] ; K200401210 |. A2 18304000 |mov byte ptr ds:[<WriteBuff>],al00401215 |. 47 |inc edi00401216 |. 6A 00 |push 0x0 ; /pOverlapped = NULL00401218 |. 68 76324000 |push offset <返回数据长度> ; |pBytesWritten = offset <CM_One.返回数据长度>0040121D |. 6A 01 |push 0x1 ; |nBytesToWrite = 10040121F |. 68 18304000 |push offset <WriteBuff> ; |Buffer = offset <CM_One.WriteBuff>00401224 |. FF35 50304000 |push dword ptr ds:[<hFile2>] ; |hFile = NULL0040122A |. E8 E3010000 |call <jmp.&kernel32.WriteFile> ; \WriteFile0040122F |. 59 |pop ecx00401230 |.^ 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 X0040129F00401246 |> 6A 00 /push 0x0 ; /pOverlapped = NULL00401248 |. 68 76324000 |push offset <返回数据长度> ; |pBytesRead = offset <CM_One.返回数据长度>0040124D |. 6A 01 |push 0x1 ; |BytesToRead = 10040124F |. 68 16304000 |push offset <ReadBuff> ; |Buffer = offset <CM_One.ReadBuff>00401254 |. FF35 54304000 |push dword ptr ds:[<hFile1>] ; |hFile = NULL0040125A |. E8 AD010000 |call <jmp.&kernel32.ReadFile> ; \ReadFile0040125F |. 833D 76324000>|cmp dword ptr ds:[<返回数据长度>],0x000401266 |. 74 37 |je X0040129F00401268 |. 803F 00 |cmp byte ptr ds:[edi],0x00040126B |. 75 0C |jnz X004012790040126D |. 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] ; ReadBuff0040127B |. 3207 |xor al,byte ptr ds:[edi] ; conKEY0040127D |. 3203 |xor al,byte ptr ds:[ebx] ; K20040127F |. A2 16304000 |mov byte ptr ds:[<ReadBuff>],al00401284 |. 47 |inc edi00401285 |. 43 |inc ebx00401286 |. 6A 00 |push 0x0 ; /pOverlapped = NULL00401288 |. 68 76324000 |push offset <返回数据长度> ; |pBytesWritten = offset <CM_One.返回数据长度>0040128D |. 6A 01 |push 0x1 ; |nBytesToWrite = 10040128F |. 68 16304000 |push offset <ReadBuff> ; |Buffer = offset <CM_One.ReadBuff>00401294 |. FF35 50304000 |push dword ptr ds:[<hFile2>] ; |hFile = NULL0040129A |. E8 73010000 |call <jmp.&kernel32.WriteFile> ; \WriteFile0040129F |> 833D 76324000> cmp dword ptr ds:[<返回数据长度>],0x0004012A6 |.^ 75 9E \jnz X00401246
这里是读Windows.iso的字节,异或K2,异或一个常量(conKEY)后,写入WinXP.iso。
004012A8 |. FF35 50304000 push dword ptr ds:[<hFile2>] ; /hObject = NULL004012AE |. E8 2F010000 call <jmp.&kernel32.CloseHandle> ; \CloseHandle004012B3 |. FF35 54304000 push dword ptr ds:[<hFile1>] ; /hObject = NULL004012B9 |. E8 24010000 call <jmp.&kernel32.CloseHandle> ; \CloseHandle004012BE |. 68 00304000 push 00403000 ; /FileName = "WinXP.iso"004012C3 |. E8 3E010000 call <jmp.&kernel32.LoadLibraryA> ; \LoadLibraryA004012C8 |. 50 push eax ; /hLibModule004012C9 |. E8 2C010000 call <jmp.&kernel32.FreeLibrary> ; \FreeLibrary004012CE |. 68 00304000 push 00403000 ; /FileName = "WinXP.iso"004012D3 |. E8 16010000 call <jmp.&kernel32.DeleteFileA> ; \DeleteFileA004012D8 >\> 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 mus00000060h: 74 20 62 65 20 72 75 6E 20 75 6E 64 65 72 20 57 ; t be run under W00000070h: 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?Th00000050h: 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F ; is program canno00000060h: 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_HEADERGetSN("lili");return 0;}
五、总结
1.了解PE文件格式是关键
2.算出来的sn有时为不可见字符,要怎样输入呢?我只知道用UltraEdit输入16进制数值后,转换成字符模式再复制粘贴。
- AJISky's CM_One详解
- 调制解调器S寄存器详解
- S-Record格式详解
- start.s详解.doc
- S-Record格式详解
- S-Record格式详解
- 2440INIT.s详解
- BOOT.S程序详解
- linux head.s 详解
- S-Record格式详解
- linux head.s 详解
- git clone -s详解
- <s:property>标签详解
- 详解Start.s文件
- B/S详解
- Matlab S-Function详解
- S/PDIF接口规范详解
- brewer's cap theory 详解
- 使用EXPDP IMPDP传输不同数据库的不同表空间(新增网络传输)
- Android进程间通信(IPC)机制Binder简要介绍和学习计划
- qt4.8.2在tq2440开发板上的移植(二)--构建根文件系统
- 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路
- CTime类
- AJISky's CM_One详解
- 过程是数据库对象
- CTime类,CTime 与 CString转换
- 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路
- 面向对象(三)
- STM32 ID
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析
- Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析
- (1)搭建与测试 Spring 的开发环境