roger 发表于 2021-3-29 11:20:59

婉若游龙wp

在拿到这个软件的时候,先双击运行看看软件的运行情况!这个软件有三个输入口,在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 , eax
0040100C|.E8 73070000   call    <jmp.&KERNEL32.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地址。
0040323000 00 00 00 00 00 61 62 63 64 65 66 67 00 00 00......abcdefg...
0040324000 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                 ; |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 , eax          ;注册码长度lens
00401603|.6A 0B         push    0B                               ; /Count = B (11.)
00401605|.68 36324000   push    00403236                         ; |Buffer = Splish.00403236
0040160A|.FF75 08       push    dword ptr                 ; |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 , 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           ;字符串name
00401627|.8D3D 58324000 lea   edi, dword ptr           ;缓存hname
0040162D|.B9 0A000000   mov   ecx, 0A                        ;变量n设10
00401632|>0FBE041E      /movsx   eax, byte ptr          ;取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 , dl          ;将name的ebx个字符处理后放到缓存hname的第ebx个字符
00401649|.43            |inc   ebx
0040164A|.3B1D 63344000 |cmp   ebx, dword ptr          ;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           ;注册码serial
0040165E|.8D3D 4D324000 lea   edi, dword ptr           ;缓存注册码hserial
00401664|.B9 0A000000   mov   ecx, 0A                        ;变量n等于10
00401669|>0FBE041E      /movsx   eax, byte ptr          ;将注册码serial的第i字符取出
0040166D|.99            |cdq                                     ;扩成八位
0040166E|.F7F9          |idiv    ecx                           ;第一字符除以n,就是除以10
00401670|.88141F      |mov   byte ptr , dl          ;把余数放到hserial的第i个里
00401673|.43            |inc   ebx                           ;i++
00401674|.3B1D 67344000 |cmp   ebx, dword ptr          ;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           ;注册码缓存hserial
004016AE|.8D3D 58324000 lea   edi, dword ptr           ;帐号缓存hname
004016B4|.33DB          xor   ebx, ebx                         ;变量i
004016B6|>3B1D 63344000 /cmp   ebx, dword ptr          ;i和注册码长度len比较
004016BC|.74 0F         |je      short 004016CD                  ;相等才可以提示正确
004016BE|.0FBE041F      |movsx   eax, byte ptr          ;hname
004016C2|.0FBE0C1E      |movsx   ecx, byte ptr          ;hserial
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           ;字符串name
00401627|.8D3D 58324000 lea   edi, dword ptr           ;缓存hname
0040162D|.B9 0A000000   mov   ecx, 0A                        ;变量n设10
00401632|>0FBE041E      /movsx   eax, byte ptr          ;取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 , dl          ;将name的ebx个字符处理后放到缓存hname的第ebx个字符
00401649|.43            |inc   ebx
0040164A|.3B1D 63344000 |cmp   ebx, dword ptr          ;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;
                  tm%=10;
                  tm^=i;
                  tm+=2;
               
                  if(tm>=10)
                  {
                        tm-=10;
                  }
                  hname=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           ;注册码serial
0040165E|.8D3D 4D324000 lea   edi, dword ptr           ;缓存注册码hserial
00401664|.B9 0A000000   mov   ecx, 0A                        ;变量n等于10
00401669|>0FBE041E      /movsx   eax, byte ptr          ;将注册码serial的第i字符取出
0040166D|.99            |cdq                                     ;扩成八位
0040166E|.F7F9          |idiv    ecx                           ;第一字符除以n,就是除以10
00401670|.88141F      |mov   byte ptr , dl          ;把余数放到hserial的第i个里
00401673|.43            |inc   ebx                           ;i++
00401674|.3B1D 67344000 |cmp   ebx, dword ptr          ;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           ;注册码缓存hserial
004016AE|.8D3D 58324000 lea   edi, dword ptr           ;帐号缓存hname
004016B4|.33DB          xor   ebx, ebx                         ;变量i
004016B6|>3B1D 63344000 /cmp   ebx, dword ptr          ;i和注册码长度len比较
004016BC|.74 0F         |je      short 004016CD                  ;相等才可以提示正确
004016BE|.0FBE041F      |movsx   eax, byte ptr          ;hname
004016C2|.0FBE0C1E      |movsx   ecx, byte ptr          ;hserial
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值,所以我们的注册机代码:
#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>
#include<string.h>
#include <windows.h>

int main()
{
      char name = "abcdefg";

      char hname;

      int lenn;


      int tm;
      int i = 0;

      printf("输入帐号:");
      scanf("%s", name);
      printf("\n");

      lenn = strlen(name);
      for (i = 0; i < lenn; i++)
      {
                tm = name;
                tm %= 10;
                tm ^= i;
                tm += 2;

                if (tm >= 10)
                {
                        tm -= 10;
                }
                hname = tm;
      }
      printf("注册码:");
      for (i = 0; i < lenn; i++)
      {

                printf("%c", (hname + 70));
      }
      printf("\n");
      system("pause");
      return 0;
}


页: [1]
查看完整版本: 婉若游龙wp