首页
社区
课程
招聘
[原创]写个简单的注册机
发表于: 2009-11-6 11:03 10504

[原创]写个简单的注册机

2009-11-6 11:03
10504

【文章标题】: 写个简单的注册机
【文章作者】: spacenumen
【使用工具】: OD
【软件介绍】: Splish
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  写一个简单的注册码练习练习,就用论坛里的软件吧!有问题还可以参考一下!
  
  在拿到这个软件的时候,先双击运行看看软件的运行情况!这个软件有三个输入口,在hard Coded输入“abcdefg”点击check提示错误!
  在name上输入“abcdefg”serial上输入“1234567”点击check提示“sorry please try again”。
  
     到这里我们大概知道,软件有两种注册方法,一、用hard Coded。二、用帐号和注册码注册。这个软件没有加壳,我们直接用od载入。
  载入了软件后我们先看看能不能用文本参考。
  载入后程序停在401000处。
  00401000 >/$  6A 00         push    0                                ; /pModule = NULL
  00401002  |.  E8 83070000   call    <jmp.&KERNEL32.GetModuleHandleA> ; \GetModuleHandleA
  00401007  |.  A3 80344000   mov     dword ptr [403480], eax
  0040100C  |.  E8 73070000   call    <jmp.&KERNEL32.GetCommandLineA>  ; [GetCommandLineA
  
     在这里右键点击,选择查找-》所有参考文本字符串。这时出现了出现了一个新的窗口,在这个窗口中找到提示注册失败的文本字串
  “sorry please try again”。双击“sorry please try again”文本字串,跳到004016e9这个地方。
  004016E0  |. /EB 13         jmp     short 004016F5
  004016E2  |> |6A 00         push    0                                ; /Style = MB_OK|MB_APPLMODAL
  004016E4  |. |68 0A304000   push    0040300A                         ; |Title = "Splish, Splash"
  004016E9  |. |68 67304000   push    00403067                         ; |Text = "Sorry, please try again."
  004016EE  |. |6A 00         push    0                                ; |hOwner = NULL
  004016F0  |. |E8 53000000   call    <jmp.&USER32.MessageBoxA>        ; \MessageBoxA
  004016F5  |> \C9            leave
  004016F6  \.  C2 0800       retn    8
  这段代码是调用MessageBoxA函数创建提示失败的对话框。在附近找找,在004016c8 jnz     short 004016E2不相等就跳转提示注册失败
  在004016bc处相等就跳转到提示注册成功。看起来这里是注册的关键地方,我们在004016b6的地方下个断点标记一下。我接着往上看看
  有没有获取帐号和注册码的地方,果然在004015f1附近两次调用了GetWindowTextA函数,获取输入值,一个是存在00403242的地方,另一
  个存在00403236的地址处,这里面肯定是输入的注册码和帐号,我们来验证一下。
     在00401614处按F2下断点,按F9运行,软件停止输入框中等待输入。我们在name上输入“abcdefg”,在serial上输入“1234567”单击check
  程序停止断点00401614处,这时已获取了输入值,我们在数据内存区找到00403242和00403236地址。
  00403230  00 00 00 00 00 00 61 62 63 64 65 66 67 00 00 00  ......abcdefg...
  00403240  00 00 31 32 33 34 35 36 37 38 00 00 00 00 00 00  ..12345678......
  
  这时我们看见00403242存的是刚才输入的注册码serial,00403236存的是帐号name。到这里我们找到了帐号和注册码,我在这里到提示失败
  的地方的汇编注释先贴出来:
  004015E4  /$  55            push    ebp
  004015E5  |.  8BEC          mov     ebp, esp                         ;  判断注册码的函数
  004015E7  |.  6A 20         push    20                               ; /Count = 20 (32.)
  004015E9  |.  68 42324000   push    00403242                         ; |Buffer = Splish.00403242
  004015EE  |.  FF75 0C       push    dword ptr [ebp+C]                ; |hWnd
  004015F1  |.  E8 34010000   call    <jmp.&USER32.GetWindowTextA>     ; \GetWindowTextA
  004015F6  |.  85C0          test    eax, eax
  004015F8  |.  0F84 95000000 je      00401693                         ;  获得输入name,输入为零时跳走
  004015FE  |.  A3 67344000   mov     dword ptr [403467], eax          ;  注册码长度lens
  00401603  |.  6A 0B         push    0B                               ; /Count = B (11.)
  00401605  |.  68 36324000   push    00403236                         ; |Buffer = Splish.00403236
  0040160A  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
  0040160D  |.  E8 18010000   call    <jmp.&USER32.GetWindowTextA>     ; \GetWindowTextA
  00401612  |.  85C0          test    eax, eax                         ;  获得输入serial
  00401614  |.  74 68         je      short 0040167E                   ;  输入为零跳走
  00401616  |.  A3 63344000   mov     dword ptr [403463], eax          ;  len取serial的长度
  0040161B  |.  33C9          xor     ecx, ecx
  0040161D  |.  33DB          xor     ebx, ebx                         ;  变量i
  0040161F  |.  33D2          xor     edx, edx
  00401621  |.  8D35 36324000 lea     esi, dword ptr [403236]          ;  字符串name
  00401627  |.  8D3D 58324000 lea     edi, dword ptr [403258]          ;  缓存hname
  0040162D  |.  B9 0A000000   mov     ecx, 0A                          ;  变量n设10
  00401632  |>  0FBE041E      /movsx   eax, byte ptr [esi+ebx]         ;  取name的第一个字符
  00401636  |.  99            |cdq                                     ;  扩成八字节,就是用符号为给edx赋值
  00401637  |.  F7F9          |idiv    ecx                             ;  edx:eax除于n就是name的第一个字符除于10
  00401639  |.  33D3          |xor     edx, ebx                        ;  余数edx和ebx异或,存入edx
  0040163B  |.  83C2 02       |add     edx, 2                          ;  edx加2
  0040163E  |.  80FA 0A       |cmp     dl, 0A
  00401641  |.  7C 03         |jl      short 00401646
  00401643  |.  80EA 0A       |sub     dl, 0A
  00401646  |>  88141F        |mov     byte ptr [edi+ebx], dl          ;  将name的ebx个字符处理后放到缓存hname的第ebx个字符
  00401649  |.  43            |inc     ebx
  0040164A  |.  3B1D 63344000 |cmp     ebx, dword ptr [403463]         ;  ebx和serial的长度len比较
  00401650  |.^ 75 E0         \jnz     short 00401632
  00401652  |.  33C9          xor     ecx, ecx
  00401654  |.  33DB          xor     ebx, ebx                         ;  变量i=0
  00401656  |.  33D2          xor     edx, edx
  00401658  |.  8D35 42324000 lea     esi, dword ptr [403242]          ;  注册码serial
  0040165E  |.  8D3D 4D324000 lea     edi, dword ptr [40324D]          ;  缓存注册码hserial
  00401664  |.  B9 0A000000   mov     ecx, 0A                          ;  变量n等于10
  00401669  |>  0FBE041E      /movsx   eax, byte ptr [esi+ebx]         ;  将注册码serial的第i字符取出
  0040166D  |.  99            |cdq                                     ;  扩成八位
  0040166E  |.  F7F9          |idiv    ecx                             ;  第一字符除以n,就是除以10
  00401670  |.  88141F        |mov     byte ptr [edi+ebx], dl          ;  把余数放到hserial的第i个里
  00401673  |.  43            |inc     ebx                             ;  i++
  00401674  |.  3B1D 67344000 |cmp     ebx, dword ptr [403467]         ;  i和注册码的长度lens比较大小
  0040167A  |.^ 75 ED         \jnz     short 00401669
  0040167C  |.  EB 2A         jmp     short 004016A8                   ;  有
  0040167E  |>  6A 00         push    0                                ; /Style = MB_OK|MB_APPLMODAL
  00401680  |.  68 0A304000   push    0040300A                         ; |Title = "Splish, Splash"
  00401685  |.  68 A0304000   push    004030A0                         ; |Text = "Please enter your name."
  0040168A  |.  6A 00         push    0                                ; |hOwner = NULL
  0040168C  |.  E8 B7000000   call    <jmp.&USER32.MessageBoxA>        ; \MessageBoxA
  00401691  |.  EB 62         jmp     short 004016F5
  00401693  |>  6A 00         push    0                                ; /Style = MB_OK|MB_APPLMODAL
  00401695  |.  68 0A304000   push    0040300A                         ; |Title = "Splish, Splash"
  0040169A  |.  68 B8304000   push    004030B8                         ; |Text = "Please enter your serial number."
  0040169F  |.  6A 00         push    0                                ; |hOwner = NULL
  004016A1  |.  E8 A2000000   call    <jmp.&USER32.MessageBoxA>        ; \MessageBoxA
  004016A6  |.  EB 4D         jmp     short 004016F5
  004016A8  |>  8D35 4D324000 lea     esi, dword ptr [40324D]          ;  注册码缓存hserial
  004016AE  |.  8D3D 58324000 lea     edi, dword ptr [403258]          ;  帐号缓存hname
  004016B4  |.  33DB          xor     ebx, ebx                         ;  变量i
  004016B6  |>  3B1D 63344000 /cmp     ebx, dword ptr [403463]         ;  i和注册码长度len比较
  004016BC  |.  74 0F         |je      short 004016CD                  ;  相等才可以提示正确
  004016BE  |.  0FBE041F      |movsx   eax, byte ptr [edi+ebx]         ;  hname[i]
  004016C2  |.  0FBE0C1E      |movsx   ecx, byte ptr [esi+ebx]         ;  hserial[i]
  004016C6  |.  3BC1          |cmp     eax, ecx                        ;  如果hname【i】和hserial【i】相等,i++
  004016C8  |.  75 18         |jnz     short 004016E2                  ;  不相等就注册失败
  004016CA  |.  43            |inc     ebx
  004016CB  |.^ EB E9         \jmp     short 004016B6
  004016CD  |>  6A 00         push    0                                ; /Style = MB_OK|MB_APPLMODAL
  004016CF  |.  68 0A304000   push    0040300A                         ; |Title = "Splish, Splash"
  004016D4  |.  68 42304000   push    00403042                         ; |Text = "Good job, now keygen it."
  004016D9  |.  6A 00         push    0                                ; |hOwner = NULL
  004016DB  |.  E8 68000000   call    <jmp.&USER32.MessageBoxA>        ; \MessageBoxA
  004016E0  |.  EB 13         jmp     short 004016F5
  004016E2  |>  6A 00         push    0                                ; /Style = MB_OK|MB_APPLMODAL
  004016E4  |.  68 0A304000   push    0040300A                         ; |Title = "Splish, Splash"
  004016E9  |.  68 67304000   push    00403067                         ; |Text = "Sorry, please try again."
  004016EE  |.  6A 00         push    0                                ; |hOwner = NULL
  004016F0  |.  E8 53000000   call    <jmp.&USER32.MessageBoxA>        ; \MessageBoxA
  004016F5  |>  C9            leave
  004016F6  \.  C2 0800       retn    8
  
  这个注册机制是f1(name)=f2(serial)的形式,name是帐号,serial是注册码,在获取了输入后就计算hname=f1(name)的值
  hname存在00403258。计算代码:
  0040161B  |.  33C9          xor     ecx, ecx
  0040161D  |.  33DB          xor     ebx, ebx                         ;  变量i
  0040161F  |.  33D2          xor     edx, edx
  00401621  |.  8D35 36324000 lea     esi, dword ptr [403236]          ;  字符串name
  00401627  |.  8D3D 58324000 lea     edi, dword ptr [403258]          ;  缓存hname
  0040162D  |.  B9 0A000000   mov     ecx, 0A                          ;  变量n设10
  00401632  |>  0FBE041E      /movsx   eax, byte ptr [esi+ebx]         ;  取name的第i个字符
  00401636  |.  99            |cdq                                     ;  扩成八字节,就是用符号为给edx赋值
  00401637  |.  F7F9          |idiv    ecx                             ;  edx:eax除于n就是name的第一个字符除于10
  00401639  |.  33D3          |xor     edx, ebx                        ;  余数edx和ebx异或,存入edx
  0040163B  |.  83C2 02       |add     edx, 2                          ;  edx加2
  0040163E  |.  80FA 0A       |cmp     dl, 0A
  00401641  |.  7C 03         |jl      short 00401646
  00401643  |.  80EA 0A       |sub     dl, 0A
  00401646  |>  88141F        |mov     byte ptr [edi+ebx], dl          ;  将name的ebx个字符处理后放到缓存hname的第ebx个字符
  00401649  |.  43            |inc     ebx
  0040164A  |.  3B1D 63344000 |cmp     ebx, dword ptr [403463]         ;  ebx和serial的长度len比较
  00401650  |.^ 75 E0         \jnz     short 00401632
  这里可以提取出函数f1,将帐号name的每个字符取出,经过除10取余,和字符位数相异或,再加2的计算处理后存到hname中。我们对应的
  c语言的实现:
          lenn=strlen(name);
          for(i=0;i<lenn;i++)
          {
                  tm=name[i];
                  tm%=10;
                  tm^=i;
                  tm+=2;
                 
                  if(tm>=10)
                  {
                          tm-=10;
                  }
                  hname[i]=tm;
          }
  
  往后就是hserial=f2(serial)值的计算,汇编代码:
  00401652  |.  33C9          xor     ecx, ecx
  00401654  |.  33DB          xor     ebx, ebx                         ;  变量i=0
  00401656  |.  33D2          xor     edx, edx
  00401658  |.  8D35 42324000 lea     esi, dword ptr [403242]          ;  注册码serial
  0040165E  |.  8D3D 4D324000 lea     edi, dword ptr [40324D]          ;  缓存注册码hserial
  00401664  |.  B9 0A000000   mov     ecx, 0A                          ;  变量n等于10
  00401669  |>  0FBE041E      /movsx   eax, byte ptr [esi+ebx]         ;  将注册码serial的第i字符取出
  0040166D  |.  99            |cdq                                     ;  扩成八位
  0040166E  |.  F7F9          |idiv    ecx                             ;  第一字符除以n,就是除以10
  00401670  |.  88141F        |mov     byte ptr [edi+ebx], dl          ;  把余数放到hserial的第i个里
  00401673  |.  43            |inc     ebx                             ;  i++
  00401674  |.  3B1D 67344000 |cmp     ebx, dword ptr [403467]         ;  i和注册码的长度lens比较大小
  0040167A  |.^ 75 ED         \jnz     short 00401669
  
  可以看出f2的计算比较简单,就是serial的每个字符ascii码除于10的余数存到hserial中。
    在计算出hname=f1(name)和hserial=f2(serial)之后就是比较hname和hserial的大小。
  汇编代码:
  004016A8  |> \8D35 4D324000 lea     esi, dword ptr [40324D]          ;  注册码缓存hserial
  004016AE  |.  8D3D 58324000 lea     edi, dword ptr [403258]          ;  帐号缓存hname
  004016B4  |.  33DB          xor     ebx, ebx                         ;  变量i
  004016B6  |>  3B1D 63344000 /cmp     ebx, dword ptr [403463]         ;  i和注册码长度len比较
  004016BC  |.  74 0F         |je      short 004016CD                  ;  相等才可以提示正确
  004016BE  |.  0FBE041F      |movsx   eax, byte ptr [edi+ebx]         ;  hname[i]
  004016C2  |.  0FBE0C1E      |movsx   ecx, byte ptr [esi+ebx]         ;  hserial[i]
  004016C6  |.  3BC1          |cmp     eax, ecx                        ;  如果hname【i】和hserial【i】相等,i++
  004016C8  |.  75 18         |jnz     short 004016E2                  ;  不相等就注册失败
  004016CA  |.  43            |inc     ebx
  004016CB  |.^ EB E9         \jmp     short 004016B6
  
  只有hname和hserial的所有第i个字符相等才能注册成功,有一个不相等在4016c8处就会跳到注册失败提示上去!
  写注册机就是求serial,serial=f2^-1(hserial),hserial=hname=f1(name)。f2是除10的余数,f2的逆f2^-1求出来的值不是唯一的
  是加上10的倍数就可以,就是说serial=hserial+10*n,n是0,1,2,3……,hserial是0到九的数,我们要serial的值是字母的ascii
  值n取70,serial的值在70到80之间是F~P的ascii值,所以我们的注册机代码:
  #include<stdio.h>
  #include<string.h>
  
  main()
  {
          char name[19]="abcdefg";
          char serial[19];
          char hname[19];
          char hserial[19];
          int lenn;
          int lens;
          char ch;
          int tm;
          int i=0;
  
          printf("输入帐号:");
          scanf("%s",name);
          printf("\n");
  
          lenn=strlen(name);
          for(i=0;i<lenn;i++)
          {
                  tm=name[i];
                  tm%=10;
                  tm^=i;
                  tm+=2;
                 
                  if(tm>=10)
                  {
                          tm-=10;
                  }
                  hname[i]=tm;
          }
          printf("注册码:");
          for(i=0;i<lenn;i++)
          {
  
                  printf("%c",(hname[i]+70));
          }
          printf("\n");
          system("pause");
  }
  
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2009年11月06日 10:56:20


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

上传的附件:
收藏
免费 7
支持
分享
最新回复 (5)
雪    币: 145
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
学习一下,分析的很透彻。
2009-11-6 17:50
0
雪    币: 77
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
C语言写的!
2009-11-6 18:05
0
雪    币: 142
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
lz分析的很详细,值得学习。
2009-11-10 21:47
0
雪    币: 365
活跃值: (864)
能力值: ( LV9,RANK:186 )
在线值:
发帖
回帖
粉丝
5
多解了? 還有196557可以, 提交不對
2020-3-19 18:13
0
雪    币: 279
活跃值: (123)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
196557是对的,但是提交上去不对
2020-6-28 13:10
0
游客
登录 | 注册 方可回帖
返回
//