首页
社区
课程
招聘
对《我做的一个简单的Keygenme》的分析及注册机
发表于: 2005-10-23 18:53 8774

对《我做的一个简单的Keygenme》的分析及注册机

2005-10-23 18:53
8774

这个KeyGenMe(作者反复强调说不是CrackMe,^_^)原则上是一机一码(如果谁能不爆破而找到通用码,
欢迎联系AGanNo2@163.com.),主要是由C盘的序列号而产生的不同(调用GetVolumeInformation得到的)。

下面是对整个算法的分析过程:
算法的大体过程是由C盘的序列号(dwVolumeSerialNumber)得到一个字符串(szProduceByDisk),当然
到这里算法并未结束,然后由szProduceByDisk得到最终的szRegKey.

中间用的只是UserName的各位加起来的和dwSumName,当然还用到了szProduceByDisk的各位加起来的和dwSumProduceByDisk。

下边是详细的分析过程:
00401459     55       push ebp
0040145A     56       push esi
0040145B     8BF1     mov esi,ecx
0040145D     57       push edi
0040145E     8D4C24 1>lea ecx,dword ptr ss:[esp+1C]
00401462     E8 91040>call <jmp.&MFC42.#540_CString::CString>
00401467     33ED     xor ebp,ebp
00401469     6A 01    push 1
0040146B     8BCE     mov ecx,esi
0040146D     896C24 3>mov dword ptr ss:[esp+30],ebp
00401471     896C24 1>mov dword ptr ss:[esp+1C],ebp
00401475     896C24 2>mov dword ptr ss:[esp+24],ebp
00401479     E8 B6040>call <jmp.&MFC42.#6334_CWnd::UpdateData>
0040147E     8D4424 1>lea eax,dword ptr ss:[esp+10]
00401482     8BCE     mov ecx,esi
00401484     50       push eax
00401485     E8 56010>call KeyGenMe.004015E0
0040148A     8B5E 60  mov ebx,dword ptr ds:[esi+60]
0040148D     83C9 FF  or ecx,FFFFFFFF
00401490     8BFB     mov edi,ebx
00401492     33C0     xor eax,eax
00401494     33D2     xor edx,edx                                  ; MFC42.73E0E578
00401496     C64424 2>mov byte ptr ss:[esp+2C],1     _
0040149B     F2:AE    repne scas byte ptr es:[edi]    |
0040149D     F7D1     not ecx                         |            ; 得到RegName的长度
0040149F     49       dec ecx                 
004014A0     74 1B    je short KeyGenMe.004014BD
004014A2     0FBE0C13 movsx ecx,byte ptr ds:[ebx+edx]
004014A6     03E9     add ebp,ecx                                  ; 取每一个字符加到ebp中
004014A8     8BFB     mov edi,ebx
004014AA     83C9 FF  or ecx,FFFFFFFF
004014AD     33C0     xor eax,eax
004014AF     42       inc edx                                      ; MFC42.73E0E578
004014B0     F2:AE    repne scas byte ptr es:[edi]
004014B2     F7D1     not ecx
004014B4     49       dec ecx
004014B5     3BD1     cmp edx,ecx                                  ; Name有没有结束?
004014B7   ^ 72 E9    jb short KeyGenMe.004014A2
004014B9 <>  896C24 2>mov dword ptr ss:[esp+20],ebp                ; ebp=26F
004014BD     8D5424 1>lea edx,dword ptr ss:[esp+14]
004014C1     8BCE     mov ecx,esi
004014C3     52       push edx                                     ; MFC42.73E0E578
004014C4     33ED     xor ebp,ebp
004014C6     E8 15010>call KeyGenMe.004015E0
004014CB     8B38     mov edi,dword ptr ds:[eax]                   ; eax="vjtxfthh",这个字符串是由C盘的序列号得到的,
004014CD     83C9 FF  or ecx,FFFFFFFF                              ;每台机器一般不一样,这是在我机器上得到的,关于
004014D0     33C0     xor eax,eax                                  ;如何得到的,后面有分析
004014D2     F2:AE    repne scas byte ptr es:[edi]
004014D4     F7D1     not ecx
004014D6     49       dec ecx
004014D7     8D4C24 1>lea ecx,dword ptr ss:[esp+14]
004014DB     0F95C3   setne bl
004014DE     E8 3D030>call <jmp.&MFC42.#800_CString::~CString>
004014E3     84DB     test bl,bl
004014E5     74 3D    je short KeyGenMe.00401524
004014E7     8B4424 1>mov eax,dword ptr ss:[esp+10]
004014EB     8B5424 1>mov edx,dword ptr ss:[esp+18]               
004014EF     0FBE0C28 movsx ecx,byte ptr ds:[eax+ebp]
004014F3     03D1     add edx,ecx                                  ; 取“vjtxfthh”中的每一个字符加到edx中
004014F5     8BCE     mov ecx,esi
004014F7     895424 1>mov dword ptr ss:[esp+18],edx                ; MFC42.73E0E578
004014FB     8D5424 1>lea edx,dword ptr ss:[esp+14]
004014FF     52       push edx                                     ; MFC42.73E0E578
00401500     45       inc ebp
00401501     E8 DA000>call KeyGenMe.004015E0
00401506     8B38     mov edi,dword ptr ds:[eax]
00401508     83C9 FF  or ecx,FFFFFFFF
0040150B     33C0     xor eax,eax
0040150D     F2:AE    repne scas byte ptr es:[edi]
0040150F     F7D1     not ecx
00401511     49       dec ecx
00401512     3BE9     cmp ebp,ecx
00401514     8D4C24 1>lea ecx,dword ptr ss:[esp+14]
00401518     0F92C3   setb bl
0040151B     E8 00030>call <jmp.&MFC42.#800_CString::~CString>
00401520     84DB     test bl,bl
00401522   ^ 75 C3    jnz short KeyGenMe.004014E7
00401524     8B5424 1>mov edx,dword ptr ss:[esp+10]
00401528     83C9 FF  or ecx,FFFFFFFF
0040152B     8BFA     mov edi,edx                                  ; MFC42.73E0E578
0040152D     33C0     xor eax,eax
0040152F     33ED     xor ebp,ebp
00401531     F2:AE    repne scas byte ptr es:[edi]
00401533     F7D1     not ecx
00401535     49       dec ecx
00401536     74 46    je short KeyGenMe.0040157E
00401538     8A1C2A   mov bl,byte ptr ds:[edx+ebp]                 ; 取“vjtxfthh”(每台机器不一样)
0040153B     8BCE     mov ecx,esi
0040153D     E8 9E010>call KeyGenMe.004016E0                       ; 取得C盘的序列号,存在eax中     
00401542     0FBECB   movsx ecx,bl                                 ;从“vjtxfthh”中逐位取出字符
00401545     0FAFC1   imul eax,ecx                                 ; eax=485ec5b0,C盘的序列号
00401548     0FAF4424>imul eax,dword ptr ss:[esp+18]               ; 376,(“vjtxfthh”相加的和)
0040154D     8B5C24 2>mov ebx,dword ptr ss:[esp+20]                ; 26F,(RegName相加的和)
00401551     33D2     xor edx,edx                                  |
00401553     33C3     xor eax,ebx                                  |
00401555 <>  B9 1A000>mov ecx,1A                                   |
0040155A     F7F1     div ecx                                      |__这几步是由C盘的序列号产生RegKey的过程
0040155C     8D4C24 1>lea ecx,dword ptr ss:[esp+1C]                |
00401560     80C2 41  add dl,41                                    |
00401563     52       push edx                                     |                                   
00401564     E8 C5030>call <jmp.&MFC42.#940_CString::operator+=>
00401569     8B5424 1>mov edx,dword ptr ss:[esp+10]
0040156D     83C9 FF  or ecx,FFFFFFFF
00401570     8BFA     mov edi,edx                                  ; MFC42.73E0E578
00401572     33C0     xor eax,eax
00401574     45       inc ebp
00401575     F2:AE    repne scas byte ptr es:[edi]
00401577     F7D1     not ecx
00401579     49       dec ecx
0040157A     3BE9     cmp ebp,ecx
0040157C   ^ 72 BA    jb short KeyGenMe.00401538
0040157E     8B5424 1>mov edx,dword ptr ss:[esp+1C]               
00401582     8B46 64  mov eax,dword ptr ds:[esi+64]
00401585     52       push edx                                     ;这一步是比较
00401586     50       push eax
00401587     FF15 BC2>call near dword ptr ds:[<&MSVCRT._mbscmp>]   ; msvcrt._mbscmp
0040158D     83C4 08  add esp,8
00401590     85C0     test eax,eax                                 
00401592     6A 00    push 0
00401594     6A 00    push 0
00401596     74 07    je short KeyGenMe.0040159F                    ;爆破在这边,^_^
00401598     68 2C304>push KeyGenMe.0040302C
0040159D     EB 05    jmp short KeyGenMe.004015A4
0040159F     68 20304>push KeyGenMe.00403020
004015A4     8BCE     mov ecx,esi
004015A6     E8 7D030>call <jmp.&MFC42.#4224_CWnd::MessageBoxA>

;下边是由C盘的序列号产生字符串“vjtxfthh”的过程,
;在每台机器上这个字符串会不一样

004015E0     6A FF    push -1
004015E2     68 471C4>push KeyGenMe.00401C47
004015E7     64:A1 00>mov eax,dword ptr fs:[0]
004015ED     50       push eax
004015EE     64:8925 >mov dword ptr fs:[0],esp
004015F5     83EC 10  sub esp,10
004015F8     56       push esi
004015F9     33F6     xor esi,esi
004015FB     57       push edi
004015FC     8D4C24 0>lea ecx,dword ptr ss:[esp+C]
00401600     897424 1>mov dword ptr ss:[esp+14],esi
00401604     E8 EF020>call <jmp.&MFC42.#540_CString::CString>
00401609     8D4C24 0>lea ecx,dword ptr ss:[esp+8]
0040160D     C74424 2>mov dword ptr ss:[esp+20],1
00401615     E8 DE020>call <jmp.&MFC42.#540_CString::CString>
0040161A     6A 0A    push 0A
0040161C     56       push esi
0040161D     56       push esi
0040161E     8D4424 1>lea eax,dword ptr ss:[esp+1C]
00401622     56       push esi
00401623     50       push eax
00401624     6A 0C    push 0C
00401626     56       push esi
00401627     68 40304>push KeyGenMe.00403040                       ; ASCII "C:\"
0040162C     C64424 4>mov byte ptr ss:[esp+40],2
00401631     FF15 002>call near dword ptr ds:[<&KERNEL32.GetVolume>; kernel32.GetVolumeInformationA
00401637     8B4C24 1>mov ecx,dword ptr ss:[esp+10]
0040163B     8D5424 0>lea edx,dword ptr ss:[esp+8]
0040163F     51       push ecx
00401640     68 3C304>push KeyGenMe.0040303C                       ; ASCII "%x"
00401645     52       push edx
00401646     E8 F5020>call <jmp.&MFC42.#2818_CString::Format>
0040164B     8B5424 1>mov edx,dword ptr ss:[esp+14]
0040164F     83C9 FF  or ecx,FFFFFFFF
00401652     8BFA     mov edi,edx
00401654     33C0     xor eax,eax
00401656     83C4 0C  add esp,0C
00401659     F2:AE    repne scas byte ptr es:[edi]
0040165B     F7D1     not ecx
0040165D     49       dec ecx
0040165E     74 35    je short KeyGenMe.00401695
00401660 <>  0FBE0416 movsx eax,byte ptr ds:[esi+edx]              |  ;取序列号的每一位
00401664     0FAF4424>imul eax,dword ptr ss:[esp+10]               |  ;乘以序列号本生
00401669     33D2     xor edx,edx                                  |
0040166B     B9 1A000>mov ecx,1A                                   |___这是关键的几步
00401670     F7F1     div ecx                                      |  ;除1A
00401672     B0 7A    mov al,7A                                    |
00401674     8D4C24 0>lea ecx,dword ptr ss:[esp+C]                 |
00401678     2AC2     sub al,dl                                    |  ;减dl,得到字符串的每一位(al中)
0040167A     50       push eax
0040167B     E8 AE020>call <jmp.&MFC42.#940_CString::operator+=>
00401680     8B5424 0>mov edx,dword ptr ss:[esp+8]                 |
00401684     83C9 FF  or ecx,FFFFFFFF                              |
00401687     8BFA     mov edi,edx                                  |
00401689     33C0     xor eax,eax                                  |
0040168B     46       inc esi                                      |
0040168C     F2:AE    repne scas byte ptr es:[edi]                 |___用来测试是否到了序列号的最后一位的
0040168E     F7D1     not ecx                                      |
00401690     49       dec ecx                                      |
00401691     3BF1     cmp esi,ecx                                  |
00401693   ^ 72 CB    jb short <KeyGenMe.401660>                   |
00401695     8B7424 2>mov esi,dword ptr ss:[esp+28]
00401699     8D4C24 0>lea ecx,dword ptr ss:[esp+C]
0040169D     51       push ecx
0040169E     8BCE     mov ecx,esi
004016A0     E8 95020>call <jmp.&MFC42.#535_CString::CString>
004016A5     C74424 1>mov dword ptr ss:[esp+14],1
004016AD     8D4C24 0>lea ecx,dword ptr ss:[esp+8]
004016B1     C64424 2>mov byte ptr ss:[esp+20],1
004016B6     E8 65010>call <jmp.&MFC42.#800_CString::~CString>
004016BB     8D4C24 0>lea ecx,dword ptr ss:[esp+C]
004016BF     C64424 2>mov byte ptr ss:[esp+20],0
004016C4     E8 57010>call <jmp.&MFC42.#800_CString::~CString>
004016C9     8B4C24 1>mov ecx,dword ptr ss:[esp+18]
004016CD     8BC6     mov eax,esi
004016CF     5F       pop edi                                      ; KeyGenMe.0040148A
004016D0     5E       pop esi                                      ; KeyGenMe.0040148A
004016D1     64:890D >mov dword ptr fs:[0],ecx
004016D8     83C4 1C  add esp,1C
004016DB     C2 0400  retn 4

最后是我写的注册机,用的是VC++嵌入汇编,感觉比较好用,可以“偷”反汇编中的代码^_^。
我声明我只是在两台机器上测试过,如果有问题和我联系(AGanNo2@163.com).


#include<windows.h>
#include<iostream>

char szHexVolumeSerialNumber[8]; //十六二进制的硬盘序列号
char szProduceByDisk[8];  //由硬盘序列号产生的一个字符串
int main()
{
        std::cout<<"我只测试过两台机器,有问题和aganno2@163.com联系\n\n";
        char szUserName[256];
        std::cout<<"请输入UserName:        ";
        std::cin.getline(szUserName,256);

        char szRegKey[256];
   
        //得到逻辑盘C:的序列号
        char szVolumeNameBuffer[MAX_PATH];
        DWORD dwVolumeSerialNumber;
        DWORD dwMaximumComponentLength;
        DWORD dwFileSystemFlags;
        char szFileSystemNameBuffer[MAX_PATH];
        ::GetVolumeInformation("C:\\",szVolumeNameBuffer,sizeof(szVolumeNameBuffer),
                &dwVolumeSerialNumber,&dwMaximumComponentLength,
                &dwFileSystemFlags,szFileSystemNameBuffer,sizeof(szFileSystemNameBuffer));

        //格式化为十六二进制的硬盘序列号
        wsprintf(szHexVolumeSerialNumber,"%08x",dwVolumeSerialNumber);

        //**********************************************
    //下面这个循环用来产生由硬盘序列号产生的一个字符串szProduceByDisk
        byte bChar;
        for(int i=0;i<8;i++)
        {
                bChar=szHexVolumeSerialNumber[i];
                __asm
                {
                        mov   edx, dwVolumeSerialNumber
                        movsx eax, bChar
                    imul  eax,dwVolumeSerialNumber
                        xor   edx,edx
                        mov   ecx,0x1A
                        div   ecx
                        mov   al,0x7A
                        sub   al,dl
                        mov   bChar,al
                }
                szProduceByDisk[i]=bChar; //由硬盘序列号产生的一个字符串的每一位
        }
   
        //dwSumProduceByDisk为szProduceByDisk中的每一位相加和
    DWORD dwSumProduceByDisk=0;
        for(i=0;szProduceByDisk[i]!='\0';i++)
                dwSumProduceByDisk+=szProduceByDisk[i];
        //dwSumName为szUserName中每一位相加和
        DWORD dwSumName=0;
        for(i=0;szUserName[i]!='\0';i++)
                dwSumName+=szUserName[i];
       
        //由szProduceByDisk产生注册码szRegKey的过程
        for(i=0;i<8;i++)
        {
                bChar=szProduceByDisk[i];
                __asm
                {
                        mov eax,dwVolumeSerialNumber
                        movsx ecx,bChar
                        imul eax,ecx
                        imul eax,dwSumProduceByDisk
                        mov ebx,dwSumName
                        xor edx,edx
                        xor eax,ebx
                        mov ecx,0x1A
                        div ecx
                        add dl,0x41
                        mov bChar,dl
                }
                szRegKey[i]=bChar;
        }
        szRegKey[8]='\0';
        std::cout<<"注册码RegKey为: "<<szRegKey<<std::endl;
        std::cout<<"Good Luck!\n";
        system("pause");
        return 0;
}
这是原文件及我写的注册机。附件:keygen.rar


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (8)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
不错,我也正在学,应用VC的内联汇编,大部分情况下可以“偷”反汇编中的代码。
2005-10-23 20:51
0
雪    币: 216
活跃值: (70)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3
good!下了好好研究下
2005-10-23 23:18
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
我觉得写注册机并不难.
对我来说,怎样跟踪来到注册算法处才有难度.
我跟了一个多小时还是跟不到文中所提到的算法处.
一些基本的断点都不能用
例如不能bp GetDlgItemTextA(因为在当前模块中找不到GetDlgItemTextA)
还有为什么用用户名的内存访问断点(用<<从一个简单破解中浅谈破解的思路【原创】>>)的方法去不到

0040149B     F2:AE    repne scas byte ptr es:[edi]    |
0040149D     F7D1     not ecx                         |            ; 得到RegName的长度
0040149F     49       dec ecx                 
004014A0     74 1B    je short KeyGenMe.004014BD
004014A2     0FBE0C13 movsx ecx,byte ptr ds:[ebx+edx]
004014A6     03E9     add ebp,ecx                                  ; 取每一个字符加到ebp中
004014A8     8BFB     mov edi,ebx
004014AA     83C9 FF  or ecx,FFFFFFFF

却去到系统领空.
请问怎样才能跟踪来到算法注册处,谢谢
2005-10-25 22:28
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
我觉得写注册机并不难.
对我来说,怎样跟踪来到注册算法处才有难度.
我跟了一个多小时还是跟不到文中所提到的算法处.
一些基本的断点都不能用
例如不能bp GetDlgItemTextA(因为在当前模块中找不到GetDlgItemTextA)
还有为什么用用户名的内存访问断点(用<<从一个简单破解中浅谈破解的思路【原创】>>)的方法去不到

0040149B     F2:AE    repne scas byte ptr es:[edi]    |
0040149D     F7D1     not ecx                         |            ; 得到RegName的长度
0040149F     49       dec ecx                 
004014A0     74 1B    je short KeyGenMe.004014BD
004014A2     0FBE0C13 movsx ecx,byte ptr ds:[ebx+edx]
004014A6     03E9     add ebp,ecx                                  ; 取每一个字符加到ebp中
004014A8     8BFB     mov edi,ebx
004014AA     83C9 FF  or ecx,FFFFFFFF

却去到系统领空.
请问怎样才能跟踪来到算法注册处,谢谢
2005-10-25 23:03
0
雪    币: 216
活跃值: (131)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
6
最初由 dqkx 发布
我觉得写注册机并不难.
对我来说,怎样跟踪来到注册算法处才有难度.
我跟了一个多小时还是跟不到文中所提到的算法处.
一些基本的断点都不能用
例如不能bp GetDlgItemTextA(因为在当前模块中找不到GetDlgItemTextA)
........


在我(我只是菜鸟)破解的过程中主要用以下几种方法:
1。最简单的也是被n多人用烂的,查看参考字符串,有时并不是你一定想要的,只要是相关的就行了!这也需要运气!

2。拦截相关函数,像你所说的GetWindowTextA,SendMessageW之类的,在我使用的过程中发现这个对用Windows SDK编写的程序特别有用!

3。还有一个相对较麻烦的,就是找到RegisterClass(对于窗口)或DialogBoxParam(对于对话框),查找其堆栈,我们一般可以轻易地得到其窗口过程 (WinProc)函数和处理对话框的函数,然后选准时机在处理函数处下断!

4。最后一个(我就知道这些)就是拦截窗口消息,比如鼠标单击或按钮按下的消息,我一般用OD,不知你用什么,下窗口消息断点你可以参考相关的资料!
2005-10-26 08:33
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
首先真的非常感谢你的回答.对于我这种刚学破解的菜鸟来说,对于很多不是很了解,很多方法经验都需要你们这些大鸟来指点,不然真的会走很多弯路.
请原谅我再问些以下问题

1 对于你的第2点,我对这个keygenme有点疑惑的是
  为什么在OD中,CTRL+N,找不到一些常用的取得字符输入的函数
  例如 GetDlgItemTextA,GetWindowTextA等函数.是隐藏封装了,还是有
  其他不常用的取得字符输入函数?(我对Windows编程不熟悉,只看过
  <<Windows程序设计>>.没接触过Windows SDK)

2 对于你的第3,4点.我没接触过.我发现这种方法没在这个
  crackme &reverseme 论坛上很少提及应用过.你若有时间的话,
  举个例子能写个教程出来吗.我只是大家想多学些方法而已.

3 能大概写写你进入这个keygenme算法的步骤吗,就大概就行了.
2005-10-27 10:53
0
雪    币: 716
活跃值: (162)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
8
非常支持楼上那位仁兄的观点,我也跟踪不到注册算法那里,请高手指教!!!
2005-10-27 13:32
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
厉害啊!!!!!!!!!!!!!!!!!!!!!!!
2005-10-27 17:17
0
游客
登录 | 注册 方可回帖
返回
//