Quantcast
Channel: 看雪安全论坛
Viewing all articles
Browse latest Browse all 9556

【原创】闲暇时对COM Explorer 2.0进行算法分析

$
0
0
【文章标题】: 闲暇时对COM Explorer 2.0进行算法分析
【文章作者】: 星晨缘
【使用工具】: OD
【写作时间】: 2013-05-31
【分析难度】: 定位于跟我一样的入门朋友们,高手.前辈们就跳过吧
【文章说明】: 如转载,请保持原文,谢谢!
【作者声明】: 今天闲暇时在看雪里逛了下,看到一位朋友发了个爆破的文章,我就去下载过来看了下,发现安装后里边是有个Key的,但是并不完美,没有对字母大小写进行处理,用大写的话就算不出注册码来,对于好奇,就拿了OD分析了下...不周到或者那里写错之类还请指正,谢谢!本人只是个菜鸟,希望能得到大侠们的指点,谢过!

发了贴子之后才知道这个软件原先已经有人发过了(论坛帖子下方所提示的相似帖子看到的),
地址:http://bbs.pediy.com/showthread.php?t=72984
但我之前并没看过原先的那位大侠的作品,这也太巧了点了吧,人家的还是(时 间: 2008-09-17,21:52:33)的呢!


1.查壳,PEiD查到的是>>Microsoft Visual C++ 6.0 [Overlay],既然没壳就好办多了

2.打开软件,跳出注册窗体,试着注册个试试,
输入用户名:星晨缘,注册码:123456,弹出个MessageBox对话框,这样可以用bp MessageBoxA来下断

3.OD载入,F9运行,下MessageBox断点会断在注册码生成(或说比较)的之后,往回找注册码的算法可能会比较远,所以我在这是下:bp GetWindowTextA断点(比较好找注册码算法),

再次输入注册信息,点一下解锁,让OD给断下来了

代码:

760670ED >  6A 08          push    8                //断在这里,注意取消一下断点哦
760670EF    68 58710676    push    76067158
760670F4    E8 07150100    call    76078600
760670F9    8B7D 0C        mov    edi, dword ptr [ebp+C]
760670FC    33DB            xor    ebx, ebx
760670FE    3BFB            cmp    edi, ebx

然后按Alt+F9,执行到程序领空:
代码:

004328C2  |.  FF7424 08    push    dword ptr [esp+8]                ; /Count
004328C6  |.  FF7424 08    push    dword ptr [esp+8]                ; |Buffer
004328CA  |.  FF71 1C      push    dword ptr [ecx+1C]              ; |hWnd
004328CD  |.  FF15 D0044500 call    dword ptr [<&USER32.GetWindowTex>; \GetWindowTextA
004328D3  |.  EB 12        jmp    short 004328E7                  ;  //执行后返回到这里,这里可以看到堆栈里有注册用户的信息
004328D5  |>  FF7424 08    push    dword ptr [esp+8]
004328D9  |.  8B10          mov    edx, dword ptr [eax]
004328DB  |.  8BC8          mov    ecx, eax
004328DD  |.  FF7424 08    push    dword ptr [esp+8]
004328E1  |.  FF92 84000000 call    dword ptr [edx+84]
004328E7  \>  C2 0800      retn    8

而004328D3的JMP就是跳到返回,F8执行到返回,返回代码如下:
代码:

00408F07  .  68 FF000000  push    0FF
00408F0C  .  68 68994600  push    00469968                        ;  ASCII "星晨缘"
00408F11  .  8D8E A8040000 lea    ecx, dword ptr [esi+4A8]
00408F17  .  E8 9F990200  call    004328BB                        ;  获取用户名
00408F1C  .  68 FF000000  push    0FF                              ;  //执行单步返回到这里
00408F21  .  68 689A4600  push    00469A68                        ;  ASCII "123456"
00408F26  .  8D8E 6C040000 lea    ecx, dword ptr [esi+46C]
00408F2C  .  E8 8A990200  call    004328BB                        ;  获取注册码
00408F31  .  68 68994600  push    00469968                        ;  ASCII "星晨缘"
00408F36  .  8D4C24 0C    lea    ecx, dword ptr [esp+C]
00408F3A  .  E8 12600200  call    0042EF51                        ;  //有点可疑,F7跟进去看看,结果一场空
00408F3F  .  8B00          mov    eax, dword ptr [eax]
00408F41  .  68 98414600  push    00464198
00408F46  .  50            push    eax
00408F47  .  E8 33330100  call    0041C27F
00408F4C  .  83C4 08      add    esp, 8
00408F4F  .  8D4C24 08    lea    ecx, dword ptr [esp+8]
00408F53  .  85C0          test    eax, eax
00408F55  .  0F94C3        sete    bl
00408F58  .  E8 865F0200  call    0042EEE3
00408F5D  .  84DB          test    bl, bl
00408F5F  .  74 0F        je      short 00408F70                  ;  //这里跳了,既然跳了就让它跳吧,前边几个CALL都没什么收获
00408F61  .  6A 01        push    1
00408F63  .  8BCE          mov    ecx, esi
00408F65  .  E8 93A70200  call    004336FD
00408F6A  .  5E            pop    esi
00408F6B  .  5B            pop    ebx
00408F6C  .  83C4 08      add    esp, 8
00408F6F  .  C3            retn
00408F70  >  E8 1BFCFFFF  call    00408B90                        ;  //也跟进去看看,即上边的JE跳到这个CALL的
00408F75  .  85C0          test    eax, eax

代码:

00408B90  /$  6A FF        push    -1                              ;  //CALL所跳到的地方
00408B92  |.  68 98B64400  push    0044B698                        ;  SE 处理程序安装
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, 00469968                    ;  ASCII "星晨缘"
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                          ;  比较用户名是否大于8位,我们输入的只有6位
00408BBB  |.  894C24 08    mov    dword ptr [esp+8], ecx
00408BBF  |.  7D 10        jge    short 00408BD1                  ;  跳不了,重新来过,输入个用户名大于8位的,F2下断
00408BC1  |.  5F            pop    edi
00408BC2  |.  8B4C24 08    mov    ecx, dword ptr [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                              ;  //上边的JGE跳到这里来的
00408BD2  |.  55            push    ebp
00408BD3  |.  56            push    esi
00408BD4  |.  68 68994600  push    00469968                        ;  ASCII "星晨缘"
00408BD9  |.  E8 34300200  call    0042BC12

接着来看看跳转过来的代码吧,00408BE5的注释有点像注册码的格式,分析一下下边的代码吧,果真让找到注册码算法了,试着执行到下边代码
代码:

00408C85  |.  68 689A4600  push    00469A68                        ;  ASCII "123456"
00408C8A  |.  52            push    edx                              ;  //在这里可在寄存器里看到注册码
00408C8B  |.  E8 EF350100  call    0041C27F                        ;  应该就是比较真假码的地方

接下来当然是分析注册算法了00408BE5下个F2断点重新来过,...Go...
代码:

00408BE5  |.  68 FC404600  push    004640FC                        ;  ASCII "6769-"
00408BEA  |.  E8 62630200  call    0042EF51
00408BEF  |.  33F6          xor    esi, esi                        ;  ESI清零,后边用作计数器
00408BF1  |.  897424 20    mov    dword ptr [esp+20], esi          ;  从下边开始就是第二,三段,四段注册码计算代码开始处,与0~9数字进行计算
00408BF5  |>  8B2D 483E4600 /mov    ebp, dword ptr [463E48]        ;  Table码表
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                            ;  取得Table表位数,0xA,后边就用0xA代表Table位数
00408C07  |.  8BC6          |mov    eax, esi                        ;  ESI为计数器
00408C09  |.  33D2          |xor    edx, edx
00408C0B  |.  8BFD          |mov    edi, ebp
00408C0D  |.  F7F1          |div    ecx                            ;  EAX=EAX/0xA,EDX=EAX%0xA,余数用于后边取Table的位数
00408C0F  |.  8B4C24 14    |mov    ecx, dword ptr [esp+14]        ;  ECX=用户位数//n设为用户位数
00408C13  |.  8BC6          |mov    eax, esi
00408C15  |.  0FBE1C2A      |movsx  ebx, byte ptr [edx+ebp]        ;  从Table表取数,Table[EAX%10](是上面第三行所得的余数哦),EDX
00408C19  |.  33D2          |xor    edx, edx
00408C1B  |.  F7F1          |div    ecx                            ;  主要取EAX%n的余数
00408C1D  |.  0FBE82 689946>|movsx  eax, byte ptr [edx+469968]      ;  EAX=Name[EAX%n] >> 上边的余数作为取用户名位数
00408C24  |.  8D1440        |lea    edx, dword ptr [eax+eax*2]      ;  EDX=用户名+用户名*2
00408C27  |.  8D0490        |lea    eax, dword ptr [eax+edx*4]      ;  EAX=用户名+(用户名+用户名*2)*4
00408C2A  |.  8BD6          |mov    edx, esi
00408C2C  |.  0FAFD6        |imul    edx, esi                        ;  EDX=EDX*ESI
00408C2F  |.  0FAFD6        |imul    edx, esi                        ;  EDX=EDX*ESI
00408C32  |.  0FAFD1        |imul    edx, ecx                        ;  EDX=EDX*n
00408C35  |.  03D8          |add    ebx, eax                        ;  EBX=Table[EAX%10]+用户名+(用户名+用户名*2)*4
00408C37  |.  83C9 FF      |or      ecx, FFFFFFFF
00408C3A  |.  33C0          |xor    eax, eax
00408C3C  |.  03DA          |add    ebx, edx                        ;  EBX=EBX+((EDX*ESI)*(EDX*ESI))*n
00408C3E  |.  F2:AE        |repne  scas byte ptr es:[edi]
00408C40  |.  F7D1          |not    ecx
00408C42  |.  49            |dec    ecx                            ;  ECX=0xA
00408C43  |.  8BC3          |mov    eax, ebx                        ;  EAX=EBX
00408C45  |.  33D2          |xor    edx, edx
00408C47  |.  F7F1          |div    ecx                            ;  EAX=EAX/0xA,EDX=EAX%0xA
00408C49  |.  8D4C24 10    |lea    ecx, dword ptr [esp+10]        ;  取保存注册码位置
00408C4D  |.  8A042A        |mov    al, byte ptr [edx+ebp]          ;  al=Table表[EAX/0xA],al即注册码
00408C50  |.  50            |push    eax
00408C51  |.  E8 44660200  |call    0042F29A                        ;  保存注册码
00408C56  |.  85F6          |test    esi, esi
00408C58  |.  74 1D        |je      short 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
00408C67  |.  75 0E        |jnz    short 00408C77
00408C69  |.  68 F8404600  |push    004640F8
00408C6E  |.  8D4C24 14    |lea    ecx, dword ptr [esp+14]
00408C72  |.  E8 FC650200  |call    0042F273                        ;  添加'-'用的函数
00408C77  |>  46            |inc    esi                            ;  i++
00408C78  |.  83FE 09      |cmp    esi, 9                          ;  用于循环次数,总共循环9次
00408C7B  |.^ 0F82 74FFFFFF \jb      00408BF5
00408C81  |.  8B5424 10    mov    edx, dword ptr [esp+10]
00408C85  |.  68 689A4600  push    00469A68                        ;  ASCII "123456"
00408C8A  |.  52            push    edx
00408C8B  |.  E8 EF350100  call    0041C27F

算法分析已经在上边代码里注明了,这里就不再重复同样的工作了!

算法注册机:
代码:

#include <stdio.h>
#include <conio.h>
#include <windows.h>

/*
        COM Explorer 2.0算法注册机 v0.1
        如有错误,请指正,谢谢!代码有点错乱,见笑了!
*/

int Key(unsigned char Name[],int Len,char Key[])//Key主要算法
{
        char Table[] = "0123456789";
        int m = 5;
        for(int i=0;i<9;i++)
        {
                unsigned int k = 0;
                unsigned int t = 0;
                unsigned int n = 0;
                if (Name[i%Len]>'z')
                        n = Name[i%Len] | 0xFFFFFF00;//为了支持中文
                else
                        n = Name[i%Len];
                k = n+(n+n*2)*4+Table[i%0xA];
                t = i * i * i * Len;
                k += t;
                if(m == 9 || m == 13)
                {
                        Key[m] = '-';
                        Key[m+1] = Table[k%0xA];
                        m += 2;
                        continue;
                }
                Key[m++] = Table[k%0xA];
        }
        return 0;
}

int main()
{
        static char key[17] = "6769-";
        unsigned char name[21] = {NULL};
        int len = 0;
        while(true)
        {
                printf("Name:");
                scanf("%20s",name);
                len = strlen((char*)name);
                if(len<8)
                {
                        printf("\n用户名不能小于8位,请重新输入!(请按任意键)");
                        getch();
                        system("cls");
                }
                else
                        break;
        }
        for (int n=0;name[n]!=0;n++)
        {
                if (name[n]>='A' && name[n]<='Z')
                        name[n] += 32;
        }
        Key(name,len,key);
        printf("\nKey:%s\n",key);
        getch();
        return 0;
}


后语:;):

由于头段注册码一跟到算法处就已经存在的了,而且试了台其它机子还是同样的"6769-",由于所保存的注册位置是随机产生的,并不是每次都是在该地址的,跟了很久没跟到算这段代码的位置(可能是我个人的能力有限吧!),因把头段的注册码用作固定的字符串!

哎,这次分析还总算是相对轻松点,不像上次分析一个CrackMe那样费时费力!!!这可能就是经验吧,呵呵.

此文希望能对和我差不多的朋友们有点借用作用

注册过的朋友想重新再玩的话,可到注册表里把HKEY_LOCAL_MACHINE\SOFTWARE\4Developers下的项给删了就可以了

还希望高手,前辈们能指引指引,还有欢迎各位朋友们来拍砖,贴子肯定会有不周到之处,有不周到之处请见谅和建议下,谢谢!

为了方便,我会把软件的等打包一下上传的!

上传的附件
文件类型: rar Text.rar (526.9 KB)

Viewing all articles
Browse latest Browse all 9556


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>