【详细过程】:ComExplorer的注册算法分析
【文章作者】: chimney
【软件名称】: ComExplorer
【保护方式】: 密码
【使用工具】: OD
【操作平台】: winxp
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
最近整理硬盘的时候找到了这个两年前写的笔记,于是整理了下。算法很简单给新手看看。大侠飘过!
【详细过程】
bpx GetWindowTextA 断下N次后注册界面出现。输入假的注册名和注册码后F9.断在
代码:
004328B4 |. FF7424 08 PUSH DWORD PTR SS:[ESP+8] ; |Buffer 004328B8 |. FF71 1C PUSH DWORD PTR DS:[ECX+1C] ; |hWnd 004328BB |. FF15 D4044500 CALL DWORD PTR DS:[<&USER32.GetWindowTex>; \GetWindowTextA ; 断在这 004328C1 |. EB 12 JMP SHORT comexp.004328D5 004328C3 |> FF7424 08 PUSH DWORD PTR SS:[ESP+8] 004328C7 |. 8B10 MOV EDX,DWORD PTR DS:[EAX] 004328C9 |. 8BC8 MOV ECX,EAX 004328CB |. FF7424 08 PUSH DWORD PTR SS:[ESP+8] 004328CF |. FF92 84000000 CALL DWORD PTR DS:[EDX+84] 004328D5 \> C2 0800 RETN 8 F8往下走RETN 后来到 00408F07 . 68 FF000000 PUSH 0FF 00408F0C . 68 68994600 PUSH comexp.00469968 ; ASCII "xmbreeze" 00408F11 . 8D8E A8040000 LEA ECX,DWORD PTR DS:[ESI+4A8] 00408F17 . E8 8D990200 CALL comexp.004328A9 ; 取得输入用户名,放入ESI+4A8,EAX为用户名位数 00408F1C . 68 FF000000 PUSH 0FF 00408F21 . 68 689A4600 PUSH comexp.00469A68 ; ASCII "5211314567" 00408F26 . 8D8E 6C040000 LEA ECX,DWORD PTR DS:[ESI+46C] 00408F2C . E8 78990200 CALL comexp.004328A9 ; 取得输入注册码,放入ESI+46C,EAX为注册码位数 00408F31 . 68 68994600 PUSH comexp.00469968 ; ASCII "xmbreeze" 00408F36 . 8D4C24 0C LEA ECX,DWORD PTR SS:[ESP+C] 00408F3A . E8 02600200 CALL comexp.0042EF41 00408F3F . 8B00 MOV EAX,DWORD PTR DS:[EAX] 00408F41 . 68 98414600 PUSH comexp.00464198 ; /Arg2 = 00464198 ASCII "UNREGISTERED USER" 00408F46 . 50 PUSH EAX ; |Arg1 00408F47 . E8 33330100 CALL comexp.0041C27F ; \comexp.0041C27F 00408F4C . 83C4 08 ADD ESP,8 00408F4F . 8D4C24 08 LEA ECX,DWORD PTR SS:[ESP+8] 00408F53 . 85C0 TEST EAX,EAX 00408F55 . 0F94C3 SETE BL 00408F58 . E8 765F0200 CALL comexp.0042EED3 00408F5D . 84DB TEST BL,BL 00408F5F . 74 0F JE SHORT comexp.00408F70 00408F61 . 6A 01 PUSH 1 00408F63 . 8BCE MOV ECX,ESI 00408F65 . E8 83A70200 CALL comexp.004336ED 00408F6A . 5E POP ESI 00408F6B . 5B POP EBX 00408F6C . 83C4 08 ADD ESP,8 00408F6F . C3 RETN 00408F70 > E8 1BFCFFFF CALL comexp.00408B90 ; 算法Call跟进 00408F75 . 85C0 TEST EAX,EAX 00408F77 . 0F84 AB000000 JE comexp.00409028 跟进后来到: 00408B90 /$ 6A FF PUSH -1 00408B92 |. 68 88B64400 PUSH comexp.0044B688 ; SEH 处理程序安装 00408B97 |. 64:A1 0000000>MOV EAX,DWORD PTR FS:[0] 00408B9D |. 50 PUSH EAX 00408B9E |. 64:8925 00000>MOV DWORD PTR FS:[0],ESP 00408BA5 |. 83EC 08 SUB ESP,8 00408BA8 |. 57 PUSH EDI 00408BA9 |. BF 68994600 MOV EDI,comexp.00469968 ; ASCII "xmbreeze" 00408BAE |. 83C9 FF OR ECX,FFFFFFFF 00408BB1 |. 33C0 XOR EAX,EAX 00408BB3 |. F2:AE REPNE SCAS BYTE PTR ES:[EDI] 00408BB5 |. F7D1 NOT ECX 00408BB7 |. 49 DEC ECX 00408BB8 |. 83F9 08 CMP ECX,8 00408BBB |. 894C24 08 MOV DWORD PTR SS:[ESP+8],ECX 00408BBF |. 7D 10 JGE SHORT comexp.00408BD1 ;用户名长度和8比较小于8则结束 00408BC1 |. 5F POP EDI 00408BC2 |. 8B4C24 08 MOV ECX,DWORD PTR SS:[ESP+8] 00408BC6 |. 64:890D 00000>MOV DWORD PTR FS:[0],ECX 00408BCD |. 83C4 14 ADD ESP,14 00408BD0 |. C3 RETN 00408BD1 |> 53 PUSH EBX 00408BD2 |. 55 PUSH EBP 00408BD3 |. 56 PUSH ESI 00408BD4 |. 68 68994600 PUSH comexp.00469968 ; ASCII "xmbreeze" 00408BD9 |. E8 24300200 CALL comexp.0042BC02 ; 将用户名转化为小写 00408BDE |. 83C4 04 ADD ESP,4 00408BE1 |. 8D4C24 10 LEA ECX,DWORD PTR SS:[ESP+10] 00408BE5 |. 68 FC404600 PUSH comexp.004640FC ; ASCII "6769-" 注册码前5位固定 00408BEA |. E8 52630200 CALL comexp.0042EF41 00408BEF |. 33F6 XOR ESI,ESI 00408BF1 |. 897424 20 MOV DWORD PTR SS:[ESP+20],ESI 00408BF5 |> 8B2D 483E4600 /MOV EBP,DWORD PTR DS:[463E48] ; 0123456789 注册算法要查这张表 00408BFB |. 83C9 FF |OR ECX,FFFFFFFF ; /* 00408BFE |. 8BFD |MOV EDI,EBP ; 表长度 00408C00 |. 33C0 |XOR EAX,EAX 00408C02 |. F2:AE |REPNE SCAS BYTE PTR ES:[EDI] 00408C04 |. F7D1 |NOT ECX 00408C06 |. 49 |DEC ECX ; */ 00408C07 |. 8BC6 |MOV EAX,ESI 00408C09 |. 33D2 |XOR EDX,EDX 00408C0B |. 8BFD |MOV EDI,EBP 00408C0D |. F7F1 |DIV ECX 00408C0F |. 8B4C24 14 |MOV ECX,DWORD PTR SS:[ESP+14] 00408C13 |. 8BC6 |MOV EAX,ESI 00408C15 |. 0FBE1C2A |MOVSX EBX,BYTE PTR DS:[EDX+EBP] 00408C19 |. 33D2 |XOR EDX,EDX 00408C1B |. F7F1 |DIV ECX ; N除以用户名长度,取余,取用户名的第余数位进行计算 00408C1D |. 0FBE82 689946>|MOVSX EAX,BYTE PTR DS:[EDX+469968] ; /* 00408C24 |. 8D1440 |LEA EDX,DWORD PTR DS:[EAX+EAX*2] ; X=D*ASII(N) 8<=N<=40 ASII(N)//用户名的ASII码 00408C27 |. 8D0490 |LEA EAX,DWORD PTR DS:[EAX+EDX*4] ; */ 00408C2A |. 8BD6 |MOV EDX,ESI ; /* 00408C2C |. 0FAFD6 |IMUL EDX,ESI 00408C2F |. 0FAFD6 |IMUL EDX,ESI ; Y=N*N*N*用户名位数 00408C32 |. 0FAFD1 |IMUL EDX,ECX ; */ 00408C35 |. 03D8 |ADD EBX,EAX ; H=X+ASII(N) 00408C37 |. 83C9 FF |OR ECX,FFFFFFFF 00408C3A |. 33C0 |XOR EAX,EAX 00408C3C |. 03DA |ADD EBX,EDX ; Z=Y+H 00408C3E |. F2:AE |REPNE SCAS BYTE PTR ES:[EDI] 00408C40 |. F7D1 |NOT ECX 00408C42 |. 49 |DEC ECX 00408C43 |. 8BC3 |MOV EAX,EBX 00408C45 |. 33D2 |XOR EDX,EDX 00408C47 |. F7F1 |DIV ECX ; Z/10余数就位第N位的注册码值 00408C49 |. 8D4C24 10 |LEA ECX,DWORD PTR SS:[ESP+10] 00408C4D |. 8A042A |MOV AL,BYTE PTR DS:[EDX+EBP] 00408C50 |. 50 |PUSH EAX 00408C51 |. E8 34660200 |CALL comexp.0042F28A ; 合并注册码 00408C56 |. 85F6 |TEST ESI,ESI 00408C58 |. 74 1D |JE SHORT comexp.00408C77 00408C5A |. 8BC6 |MOV EAX,ESI 00408C5C |. 33D2 |XOR EDX,EDX 00408C5E |. B9 03000000 |MOV ECX,3 00408C63 |. F7F1 |DIV ECX 00408C65 |. 85D2 |TEST EDX,EDX ; 若N位3的倍数,则在注册码后面补“-” 00408C67 |. 75 0E |JNZ SHORT comexp.00408C77 00408C69 |. 68 F8404600 |PUSH comexp.004640F8 00408C6E |. 8D4C24 14 |LEA ECX,DWORD PTR SS:[ESP+14] 00408C72 |. E8 EC650200 |CALL comexp.0042F263 ; 加上个"-" 00408C77 |> 46 |INC ESI ; 计算下一位 00408C78 |. 83FE 09 |CMP ESI,9 ; N和9比较小于9则计算下一位 00408C7B |.^ 0F82 74FFFFFF \JB comexp.00408BF5 00408C81 |. 8B5424 10 MOV EDX,DWORD PTR SS:[ESP+10] 00408C85 |. 68 689A4600 PUSH comexp.00469A68 ; /假注册码入栈 00408C8A |. 52 PUSH EDX ; |真注册码入栈 00408C8B |. E8 EF350100 CALL comexp.0041C27F ; \真假判断
码表为:0123456789
注册名有k位(8<=k<=64)
计算第N位注册码:假设第N位用户名位的ASII为X(n),第n位码表的ASII位Y(n)
(X(N%k)*D+Y(N%A)+N*N*N*k)/A余数在查码表,结果即为第N位真的注册码
"6769-"+所有位注册码即为即为最终注册码
说的有点模糊,还是看注册算法描述吧:
代码:
void CComExplorerDlg::OnOk1() { // TODO: Add your control notification handler code here char table[10]={'0','1','2','3','4','5','6','7','8','9'}; //码表 char *first="6769-"; //注册码的头4位,为固定值 char name[64]; char num[64]={0}; char temp[64]={0}; GetDlgItemText(IDC_EDIT1,name,64); int iSizeName=strlen(name); if(iSizeName!=0) { for(int i=0;i<iSizeName;i++) { if(name[i]>='A'&&name[i]<='Z') name[i]=name[i]+32; } int j=0; if(iSizeName<8||iSizeName>64) AfxMessageBox("用户名必须大于7位"); else{ for(int i=0;i<=8;i++,j++) { int itemp=0; itemp=name[i%iSizeName]*13+table[i%10]+i*i*i*iSizeName; num[i]=table[itemp%10]; temp[j]=num[i]; if((i!=0)&&(i%3==0)) { j++; temp[j]='-'; } } strcpy(num,first); strcat(num,temp); SetDlgItemText(IDC_EDIT2,num); } } else AfxMessageBox("请输入用户名!用户名必须大于7位。"); }