新CrackMe160之060 - Snake

这个程序应该也是纯汇编写的吧, PEiD查到是有壳的, 但OD查看应该是没壳的,直接看源码:

00401000 > $  E8 16000000   call Snake.0040101B
00401005   .  6A 00         push 0x0                                 ; /Style = MB_OK|MB_APPLMODAL
00401007   .  68 00144000   push Snake.00401400                      ; |Error
0040100C   .  68 06144000   push Snake.00401406                      ; |An unknown error has occured...
00401011   .  6A 00         push 0x0                                 ; |hOwner = NULL
00401013   .  FF15 50204000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
00401019   .  EB 25         jmp short Snake.00401040
0040101B  /$  33C0          xor eax,eax
0040101D  |.  64:FF30       push dword ptr fs:[eax]
00401020  |.  64:8920       mov dword ptr fs:[eax],esp
00401023  |.  6A 00         push 0x0                                 ; /lParam = NULL
00401025  |.  68 48104000   push Snake.00401048                      ; |DlgProc = Snake.00401048
0040102A  |.  6A 00         push 0x0                                 ; |hOwner = NULL
0040102C  |.  68 00134000   push Snake.00401300                      ; |pTemplate = Snake.00401300
00401031  |.  6A 00         push 0x0                                 ; |/pModule = NULL
00401033  |.  FF15 40204000 call dword ptr ds:[<&KERNEL32.GetModuleH>; |\GetModuleHandleA
00401039  |.  50            push eax                                 ; |hInst = NULL
0040103A  |.  FF15 48204000 call dword ptr ds:[<&USER32.DialogBoxInd>; \DialogBoxIndirectParamA
00401040  |>  6A 00         push 0x0                                 ; /ExitCode = 0x0
00401042  \.  FF15 3C204000 call dword ptr ds:[<&KERNEL32.ExitProces>; \ExitProcess
00401048   .  8B4424 08     mov eax,dword ptr ss:[esp+0x8]
0040104C   .  83F8 10       cmp eax,0x10                             ;  Switch (cases 10..111)
0040104F   .  74 11         je short Snake.00401062
00401051   .  3D 10010000   cmp eax,0x110
00401056   .  74 1D         je short Snake.00401075
00401058   .  3D 11010000   cmp eax,0x111
0040105D   .  74 22         je short Snake.00401081
0040105F   .  33C0          xor eax,eax                              ;  Default case of switch 0040104C
00401061   .  C3            retn
00401062   >  60            pushad                                   ;  Case 10 (WM_CLOSE) of switch 0040104C
00401063   .  6A 00         push 0x0                                 ; /Result = 0x0
00401065   .  FF35 001F4000 push dword ptr ds:[0x401F00]             ; |hWnd = 001E07D8 ('Snake ',class='#32770')
0040106B   .  FF15 4C204000 call dword ptr ds:[<&USER32.EndDialog>]  ; \EndDialog
00401071   .  61            popad
00401072   .  33C0          xor eax,eax
00401074   .  C3            retn
00401075   >  8B4424 04     mov eax,dword ptr ss:[esp+0x4]           ;  Case 110 (WM_INITDIALOG) of switch 0040104C
00401079   .  A3 001F4000   mov dword ptr ds:[0x401F00],eax
0040107E   .  33C0          xor eax,eax
00401080   .  C3            retn
00401081   >  8B4424 0C     mov eax,dword ptr ss:[esp+0xC]           ;  Case 111 (WM_COMMAND) of switch 0040104C
00401085   .  83F8 01       cmp eax,0x1
00401088   .  74 08         je short Snake.00401092
0040108A   .  83F8 02       cmp eax,0x2
0040108D   .^ 74 D3         je short Snake.00401062
0040108F   .  33C0          xor eax,eax
00401091   .  C3            retn
00401092   >  60            pushad
00401093   .  6A 7F         push 0x7F                                ; /Count = 7F (127.)
00401095   .  68 001E4000   push Snake.00401E00                      ; |Name...
0040109A   .  68 E8030000   push 0x3E8                               ; |ControlID = 3E8 (1000.)
0040109F   .  FF35 001F4000 push dword ptr ds:[0x401F00]             ; |hWnd = 001E07D8 ('Snake ',class='#32770')
004010A5   .  FF15 54204000 call dword ptr ds:[<&USER32.GetDlgItemTe>; \GetDlgItemTextA
004010AB   .  85C0          test eax,eax
004010AD   .  75 1C         jnz short Snake.004010CB
004010AF   .  6A 30         push 0x30                                ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
004010B1   .  68 00144000   push Snake.00401400                      ; |Error
004010B6   .  68 26144000   push Snake.00401426                      ; |You forgot to enter a Name...
004010BB   .  FF35 001F4000 push dword ptr ds:[0x401F00]             ; |hOwner = 001E07D8 ('Snake ',class='#32770')
004010C1   .  FF15 50204000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
004010C7   .  61            popad
004010C8   .  33C0          xor eax,eax
004010CA   .  C3            retn
004010CB   >  6A 7F         push 0x7F                                ; /Count = 7F (127.)
004010CD   .  68 001D4000   push Snake.00401D00                      ; |SERIAL...
004010D2   .  68 E9030000   push 0x3E9                               ; |ControlID = 3E9 (1001.)
004010D7   .  FF35 001F4000 push dword ptr ds:[0x401F00]             ; |hWnd = 001E07D8 ('Snake ',class='#32770')
004010DD   .  FF15 54204000 call dword ptr ds:[<&USER32.GetDlgItemTe>; \GetDlgItemTextA
004010E3   .  85C0          test eax,eax
004010E5   .  75 1C         jnz short Snake.00401103
004010E7   .  6A 30         push 0x30                                ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
004010E9   .  68 00144000   push Snake.00401400                      ; |Error
004010EE   .  68 44144000   push Snake.00401444                      ; |You forgot to enter a Serial...
004010F3   .  FF35 001F4000 push dword ptr ds:[0x401F00]             ; |hOwner = 001E07D8 ('Snake ',class='#32770')
004010F9   .  FF15 50204000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
004010FF   .  61            popad
00401100   .  33C0          xor eax,eax
00401102   .  C3            retn
00401103   >  E8 A2010000   call Snake.004012AA                      ; 验证上面是算法
00401108   .  84C0          test al,al                               ; 这里是第一次验证
0040110A   .  75 1C         jnz short Snake.00401128
0040110C   .  6A 30         push 0x30                                ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
0040110E   .  68 00144000   push Snake.00401400                      ; |Error
00401113   .  68 64144000   push Snake.00401464                      ; |There is something wrong with your Serial...
00401118   .  FF35 001F4000 push dword ptr ds:[0x401F00]             ; |hOwner = 001E07D8 ('Snake ',class='#32770')
0040111E   .  FF15 50204000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
00401124   .  61            popad
00401125   .  33C0          xor eax,eax
00401127   .  C3            retn
00401128   >  E8 46000000   call Snake.00401173                      ; 验证上面是算法
0040112D   .  E8 69000000   call Snake.0040119B                      ; 验证上面是算法
00401132   .  E8 D5000000   call Snake.0040120C                      ; 验证上面是算法
00401137   .  84C0          test al,al                               ; 这里是第二次验证
00401139   .  75 1C         jnz short Snake.00401157
0040113B   .  6A 40         push 0x40                                ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
0040113D   .  68 91144000   push Snake.00401491                      ; |Too bad...
00401142   .  68 9C144000   push Snake.0040149C                      ; |Common, you can do better then that! :)
00401147   .  FF35 001F4000 push dword ptr ds:[0x401F00]             ; |hOwner = 001E07D8 ('Snake ',class='#32770')
0040114D   .  FF15 50204000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
00401153   .  61            popad
00401154   .  33C0          xor eax,eax
00401156   .  C3            retn                                     ; 这下面是成功的提示
00401157   >  6A 40         push 0x40                                ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00401159   .  68 C4144000   push Snake.004014C4                      ; |Congratulations!
0040115E   .  68 D5144000   push Snake.004014D5                      ; |Well done!\r\nNow for the more difficult part, try to keygen it...
00401163   .  FF35 001F4000 push dword ptr ds:[0x401F00]             ; |hOwner = 001E07D8 ('Snake ',class='#32770')
00401169   .  FF15 50204000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
0040116F   .  61            popad
00401170   .  33C0          xor eax,eax
00401172   .  C3            retn
00401173  /$  50            push eax
00401174  |.  51            push ecx
00401175  |.  57            push edi
00401176  |.  BF F01A4000   mov edi,Snake.00401AF0
0040117B  |.  FC            cld
0040117C  |.  B9 10000000   mov ecx,0x10
00401181  |.  B0 FF         mov al,0xFF
00401183  |.  F3:AA         rep stos byte ptr es:[edi]
00401185  |.  B9 00010000   mov ecx,0x100
0040118A  |.  B0 00         mov al,0x0
0040118C  |.  F3:AA         rep stos byte ptr es:[edi]
0040118E  |.  B9 10000000   mov ecx,0x10
00401193  |.  B0 FF         mov al,0xFF
00401195  |.  F3:AA         rep stos byte ptr es:[edi]
00401197  |.  5F            pop edi                                  ;  user32.769F5063
00401198  |.  59            pop ecx                                  ;  user32.769F5063
00401199  |.  58            pop eax                                  ;  user32.769F5063
0040119A  \.  C3            retn
0040119B  /$  50            push eax
0040119C  |.  51            push ecx
0040119D  |.  52            push edx
0040119E  |.  56            push esi
0040119F  |.  57            push edi
004011A0  |.  33C9          xor ecx,ecx
004011A2  |.  BE 001E4000   mov esi,Snake.00401E00                   ;  Name...
004011A7  |.  BF 001B4000   mov edi,Snake.00401B00
004011AC  |.  56            push esi
004011AD  |.  B2 00         mov dl,0x0
004011AF  |>  8A06          /mov al,byte ptr ds:[esi]
004011B1  |.  46            |inc esi
004011B2  |.  02D0          |add dl,al
004011B4  |.  84C0          |test al,al
004011B6  |.^ 75 F7         \jnz short Snake.004011AF
004011B8  |.  5E            pop esi                                  ;  user32.769F5063
004011B9  |>  0FB606        /movzx eax,byte ptr ds:[esi]
004011BC  |.  32C2          |xor al,dl
004011BE  |>  2AD0          |/sub dl,al
004011C0  |.  800C07 CC     ||or byte ptr ds:[edi+eax],0xCC
004011C4  |.  75 04         ||jnz short Snake.004011CA
004011C6  |.  FECA          ||dec dl
004011C8  |.^ EB F4         |\jmp short Snake.004011BE
004011CA  |>  41            |inc ecx
004011CB  |.  46            |inc esi
004011CC  |.  803E 00       |cmp byte ptr ds:[esi],0x0
004011CF  |.^ 75 E8         \jnz short Snake.004011B9
004011D1  |.  890D 041F4000 mov dword ptr ds:[0x401F04],ecx
004011D7  |.  32D0          xor dl,al
004011D9  |>  2AC2          /sub al,dl
004011DB  |.  803C07 CC     |cmp byte ptr ds:[edi+eax],0xCC
004011DF  |.  75 04         |jnz short Snake.004011E5
004011E1  |.  FECA          |dec dl
004011E3  |.^ EB F4         \jmp short Snake.004011D9
004011E5  |>  C60407 DD     mov byte ptr ds:[edi+eax],0xDD
004011E9  |.  8AC2          mov al,dl
004011EB  |>  803C07 CC     /cmp byte ptr ds:[edi+eax],0xCC
004011EF  |.  74 06         |je short Snake.004011F7
004011F1  |.  803C07 DD     |cmp byte ptr ds:[edi+eax],0xDD
004011F5  |.  75 04         |jnz short Snake.004011FB
004011F7  |>  FEC8          |dec al
004011F9  |.^ EB F0         \jmp short Snake.004011EB
004011FB  |>  8D0407        lea eax,dword ptr ds:[edi+eax]
004011FE  |.  C600 99       mov byte ptr ds:[eax],0x99
00401201  |.  A3 00174000   mov dword ptr ds:[0x401700],eax
00401206  |.  5F            pop edi                                  ;  user32.769F5063
00401207  |.  5E            pop esi                                  ;  user32.769F5063
00401208  |.  5A            pop edx                                  ;  user32.769F5063
00401209  |.  59            pop ecx                                  ;  user32.769F5063
0040120A  |.  58            pop eax                                  ;  user32.769F5063
0040120B  \.  C3            retn
0040120C  /$  60            pushad
0040120D  |.  BE 001D4000   mov esi,Snake.00401D00                   ;  SERIAL...
00401212  |.  BF 00174000   mov edi,Snake.00401700
00401217  |>  0FB606        /movzx eax,byte ptr ds:[esi]
0040121A  |.  84C0          |test al,al                              ;  Switch (cases 0..39)
0040121C  |.  74 42         |je short Snake.00401260
0040121E  |.  2C 30         |sub al,0x30
00401220  |.  3C 0A         |cmp al,0xA
00401222  |.  72 02         |jb short Snake.00401226
00401224  |.  2C 07         |sub al,0x7                              ;  Default case of switch 0040121A
00401226  |>  8BC8          |mov ecx,eax                             ;  Cases 30 ('0'),31 ('1'),32 ('2'),33 ('3'),34 ('4'),35 ('5'),36 ('6'),37 ('7'),38 ('8'),39 ('9') of switch 0040121A
00401228  |.  24 03         |and al,0x3
0040122A  |.  C0E9 02       |shr cl,0x2
0040122D  |.  BA 10000000   |mov edx,0x10
00401232  |.  84C0          |test al,al
00401234  |.  74 0B         |je short Snake.00401241
00401236  |.  48            |dec eax
00401237  |.  74 06         |je short Snake.0040123F
00401239  |.  C1EA 04       |shr edx,0x4
0040123C  |.  48            |dec eax
0040123D  |.  75 02         |jnz short Snake.00401241
0040123F  |>  F7DA          |neg edx
00401241  |>  8B07          |mov eax,dword ptr ds:[edi]
00401243  |.  03C2          |add eax,edx
00401245  |.  8A00          |mov al,byte ptr ds:[eax]
00401247  |.  84C0          |test al,al                              ;  Switch (cases 0..DD)
00401249  |.  74 2F         |je short Snake.0040127A
0040124B  |.  3C 99         |cmp al,0x99
0040124D  |.  74 11         |je short Snake.00401260
0040124F  |.  3C CC         |cmp al,0xCC
00401251  |.  74 15         |je short Snake.00401268
00401253  |.  3C DD         |cmp al,0xDD
00401255  |.  75 09         |jnz short Snake.00401260
00401257  |.  833D 041F4000>|cmp dword ptr ds:[0x401F04],0x0         ;  Case DD of switch 00401247
0040125E  |.  74 04         |je short Snake.00401264
00401260  |>  61            |popad                                   ;  Default case of switch 00401247
00401261  |.  B0 00         |mov al,0x0
00401263  |.  C3            |retn
00401264  |>  61            |popad
00401265  |.  B0 01         |mov al,0x1
00401267  |.  C3            |retn
00401268  |>  FF0D 041F4000 |dec dword ptr ds:[0x401F04]             ;  Case CC of switch 00401247
0040126E  |.  E8 16000000   |call Snake.00401289
00401273  |.  8918          |mov dword ptr ds:[eax],ebx
00401275  |.  C603 99       |mov byte ptr ds:[ebx],0x99
00401278  |.  EB 05         |jmp short Snake.0040127F
0040127A  |>  E8 0A000000   |call Snake.00401289                     ;  Case 0 of switch 00401247
0040127F  |>  85C9          |test ecx,ecx
00401281  |.  74 03         |je short Snake.00401286
00401283  |.  49            |dec ecx
00401284  |.^ EB BB         |jmp short Snake.00401241
00401286  |>  46            |inc esi
00401287  \.^ EB 8E         \jmp short Snake.00401217
00401289  /$  57            push edi
0040128A  |.  8B07          mov eax,dword ptr ds:[edi]
0040128C  |.  8BD8          mov ebx,eax
0040128E  |.  03C2          add eax,edx
00401290  |>  8907          /mov dword ptr ds:[edi],eax
00401292  |.  C600 99       |mov byte ptr ds:[eax],0x99
00401295  |.  C603 00       |mov byte ptr ds:[ebx],0x0
00401298  |.  83C7 04       |add edi,0x4
0040129B  |.  833F 00       |cmp dword ptr ds:[edi],0x0
0040129E  |.  74 06         |je short Snake.004012A6
004012A0  |.  8BC3          |mov eax,ebx
004012A2  |.  8B1F          |mov ebx,dword ptr ds:[edi]
004012A4  |.^ EB EA         \jmp short Snake.00401290
004012A6  |>  8BC7          mov eax,edi
004012A8  |.  5F            pop edi                                  ;  user32.769F5063
004012A9  \.  C3            retn
004012AA  /$  50            push eax
004012AB  |.  56            push esi
004012AC  |.  BE 00174000   mov esi,Snake.00401700
004012B1  |>  8B06          /mov eax,dword ptr ds:[esi]
004012B3  |.  8326 00       |and dword ptr ds:[esi],0x0
004012B6  |.  83C6 04       |add esi,0x4
004012B9  |.  85C0          |test eax,eax
004012BB  |.^ 75 F4         \jnz short Snake.004012B1
004012BD  |.  BE 001D4000   mov esi,Snake.00401D00                   ;  SERIAL...
004012C2  |>  8A06          /mov al,byte ptr ds:[esi]
004012C4  |.  84C0          |test al,al                              ;  Switch (cases 0..46)
004012C6  |.  74 18         |je short Snake.004012E0
004012C8  |.  3C 30         |cmp al,0x30                             ; 0
004012CA  |.  72 0C         |jb short Snake.004012D8
004012CC  |.  3C 3A         |cmp al,0x3A                             ; 10
004012CE  |.  72 0D         |jb short Snake.004012DD
004012D0  |.  3C 41         |cmp al,0x41                             ; A
004012D2  |.  72 04         |jb short Snake.004012D8
004012D4  |.  3C 47         |cmp al,0x47                             ; G
004012D6  |.  72 05         |jb short Snake.004012DD
004012D8  |>  5E            |pop esi                                 ;  user32.769F5063; Default case of switch 004012C4
004012D9  |.  58            |pop eax                                 ;  user32.769F5063
004012DA  |.  B0 00         |mov al,0x0
004012DC  |.  C3            |retn
004012DD  |>  46            |inc esi                                 ;  Cases 30 ('0'),31 ('1'),32 ('2'),33 ('3'),34 ('4'),35 ('5'),36 ('6'),37 ('7'),38 ('8'),39 ('9'),41 ('A'),42 ('B'),43 ('C'),44 ('D'),45 ('E'),46 ('F') of switch 004012C4
004012DE  |.^ EB E2         \jmp short Snake.004012C2
004012E0  |>  5E            pop esi                                  ;  user32.769F5063; Case 0 of switch 004012C4
004012E1  |.  58            pop eax                                  ;  user32.769F5063
004012E2  |.  B0 01         mov al,0x1
004012E4  \.  C3            retn
004012E5      00            db 00

00401103   >  E8 A2010000   call Snake.004012AA
00401128   >  E8 46000000   call Snake.00401173
0040112D   .  E8 69000000   call Snake.0040119B
00401132   .  E8 D5000000   call Snake.0040120C

不难看出上面4个方法是算法处,
1). 004012AA 只要满足系列号是 0~9, A~F 这些值就可以
2). 00401173 应该是初始化内存空间,00401B00 ~ 00401E00全置0
3). 0040119B 根据用户名一些运行对上面的空间对应位置赋值
4). 0040120C 系列号每一位是计算后是否在内存空间对应的位置有值(这步算法没有分析明白),
看大佬的破文可得,这个方法的算法如下:(出处:https://blog.csdn.net/qq_41483767/article/details/142338679)
动调sub_40120C函数,其作用是模拟贪吃蛇的轨迹,具体如下:
1、贪吃蛇初始长度为1,蛇头位置为0x99
2、提取Serial每一位进行&3计算,得到结果转化为蛇头上下左右行为
0 -> 16 -> ↑
1 -> -16 -> ↓
2 -> -1 -> ←
3 -> 1 -> →
3、每吃到一个0xCC,蛇身+1,蛇头不能撞到蛇身,必须吃完0xCC,最后再吃0xDD,即可弹窗成功
由IDA反编译源码如下:

char __usercall __spoils<ah,ecx> sub_40120C@<al>(int a1@<ebx>)
{
  int v1; // esi@1
  int v2; // eax@2
  int v3; // ecx@5
  int v4; // edx@5
  int v5; // eax@6
  char v6; // al@9

  v1 = (int)byte_401D00;
LABEL_2:
  v2 = *(_BYTE *)v1;
  if ( (_BYTE)v2 )                            // 不为空继续
  {
    LOBYTE(v2) = v2 - 48;
    if ( (unsigned __int8)v2 >= 0xAu )        // 如果>=10(非数字)则-7
      LOBYTE(v2) = v2 - 7;
    v3 = v2;
    LOBYTE(v2) = v2 & 3;                      // 取低位, 类似于 %4 得到0|1|2|3
    LOBYTE(v3) = (unsigned __int8)v3 >> 2;    // 同一个方向循环移动的次数
    v4 = 16;
    if ( (_BYTE)v2 )                          // 这V2作为方向键 0:上,1:下,2:左,3:右
    {
      v5 = v2 - 1;
      if ( !v5 || (v4 = 1, v5 == 1) )
        v4 = -v4;
    }
    while ( 1 )
    {
      v6 = *(_BYTE *)(v4 + dword_401700);     // 00401700 存的是蛇头位置(0x99所在位置)
      if ( v6 )
      {
        if ( v6 == -103 )                     // -103 = 0x99, 碰到蛇身结束
          return 0;
        if ( v6 != -52 )                      // -52 = 0xCC, 相当于水果
        {
          if ( v6 == -35 && !dword_401F04 )   // -35 = 0xDD, 这个作为最后一个吃食,吃完就成功了
            return 1;
          return 0;
        }
        --dword_401F04;
        *(_DWORD *)sub_401289(v3) = a1;
        *(_BYTE *)a1 = -103;
      }
      else
      {
        sub_401289(v3);
      }
      if ( !v3 )
      {
        ++v1;
        goto LABEL_2;
      }
      --v3;
    }
  }
  return 0;
}

从上面代码分析可知系列号可以由0~3这4个数组成最为直观, 也可以其它数字或字母,我们可以先分类一下
0:↑ => 0(1),4(2),8(3),C(4),
1:↓ => 1(1),5(2),9(3),D(4),
2:← => 2(1),6(2),A(3),E(4),
3:→ => 3(1),7(2),B(3),F(4),
每个方向都可以用4个中的一个,括号内数字代表重复执行次数

示例:
用户名为: abcde
经过3). 0040119B这步初始化可得内存为:

00401AF0  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  
00401B00  00 00 00 CC 00 00 00 00 00 00 00 00 00 00 00 00  ...?...........
00401B10  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 DD  ...............?
00401B20  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401B30  00 00 00 00 00 00 00 00 00 00 00 00 00 CC 00 00  .............?.
00401B40  00 00 00 00 00 CC 00 00 00 00 00 00 00 00 00 00  .....?.........
00401B50  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401B60  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401B70  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401B80  00 00 00 00 00 00 00 00 00 00 00 00 00 00 CC 00  ..............?
00401B90  00 00 00 00 00 00 00 00 00 00 99 00 00 00 00 00  ..........?....
00401BA0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401BB0  00 00 00 00 00 00 00 00 00 CC 00 00 00 00 00 00  .........?.....
00401BC0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401BD0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401BE0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401BF0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00401C00  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  

其中00401B00 ~ 00401BFF即为贪吃蛇16*16的地图, CC, DD即为吃食水果, 99为蛇头,长度为1, 要吃完所有水果,其行走路径可以为:
←↑↑→→→→→↓↓↓↓↓↓↓↓←↑←←←←←←←←←←↓↓↓↓→→→→→→→→→→→→↑ (需要注意的是上图中的下方内存数值是增大的,所以方向是加的就是向上的,所以需要相反)
对应数字为: 200333331111111120222222222211113333333333330 (这个是最长的)
也可以为: 24F3DD20EE6DFFF0 (这个是最短的)

接下来就是如何写注册机了, 让程序自动找路径:

#include <stdio.h>
#include <string.h>

int main() {
	char user[51] = {0};
	char code[53] = {0};
	unsigned char map[257] = {0}; 
	int road[257] = {0};
	printf("请输入用户名: ");
	fgets(user, sizeof(user), stdin);
	int i, j, k, len = strlen(user) - 1;
	unsigned char dl = 0;
	for(i=0; i<len; i++){
		dl += user[i];
		dl &= 0xFF;
	}
	for(i=0; i<len; i++){
		code[i] = user[i] ^ dl;
		map[code[i] & 0xFF] = 0xCC;
		road[code[i] & 0xFF] = 0xCC;
		dl -= code[i];
		dl &= 0xFF;
		printf("水果%02d: %02X\r\n", i+1, code[i]&0xFF);
	}
	dl ^= code[i-1];
	code[i] = code[i-1] - dl;
	map[code[i] & 0xFF] = 0xDD;
	map[dl & 0xFF] = 0x99;
	road[code[i] & 0xFF] = 0xDD;
	road[dl & 0xFF] = 0x99;
	printf("结束%02d: %02X\r\n", i+1, code[i]&0xFF);
	printf("蛇头%02d: %02X\r\n", i+2, dl&0xFF);
	//打印地图
	//printf("\n地图\n  ");
	//for(i=0; i<16; i++){ printf(" %02X", i); } 
	//for(i=0; i<16; i++){
	//	printf("\n%02X", i);
	//	for(j=0; j<16; j++) printf(" %02X", map[i*16+j]);
	//}
	//接下来找路径
	printf("\n\n路径");
	j = 0; k = 0;
	int pos = -1, x1,y1,x2,y2,plen; //下一个水果位置
	char path[257] = {0}; //全路径 
	char path1[257] = {0}; //简化路径
	char pstr[4][4] = {{'0','4','8','C'},{'1','5','9','D'},{'2','6','A','E'},{'3','7','B','F'}}; //简化路径代码 
	while(1==1){
		pos = -1;
		plen = 999;
		x1 = dl & 0xF; //列 
		y1 = (dl >> 4) & 0xF;  //行 
		//查找离当前点最近的位置 (先吃完所有0xCC) 
		for(i=0; i<len; i++){
			if(code[i] == -1) continue;
			x2 = code[i] & 0xF;
			y2 = (code[i] >> 4) & 0xF; 
			if(abs(x2-x1) + abs(y2-y1) < plen){
				plen = abs(x2-x1) + abs(y2-y1);
				pos = i;
			} 
		}
		if(pos == -1) { pos = len; } //全部水果吃完了,最后吃0xDD
		x2 = code[pos] & 0xF; 
		y2 = (code[pos] >> 4) & 0xF; 
		//找到最近位置,开始走 
		if(x2 > x1) { //向右
			for(i=0; i<(x2-x1); i++) { path[j++] = '3'; plen = (y1 * 16) + x1 + 1 + i; if(road[plen] == 0) road[plen] = 0xA1FA; }
			plen = (x2-x1) / 4; //临时变量记录能分成几个'F'
			for(i=0; i<plen; i++) path1[k++] = pstr[3][3];
			plen = (x2-x1) % 4; if(plen > 0) path1[k++] = pstr[3][plen-1];
		}
		if(x2 < x1) { //向左
			for(i=0; i<(x1-x2); i++) { path[j++] = '2'; plen = (y1 * 16) + x1 - 1 - i; if(road[plen] == 0) road[plen] = 0xA1FB; }
			plen = (x1-x2) / 4; //临时变量记录能分成几个'E'
			for(i=0; i<plen; i++) path1[k++] = pstr[2][3];
			plen = (x1-x2) % 4; if(plen > 0) path1[k++] = pstr[2][plen-1];
		}
		if(y2 < y1) { //向下
			for(i=0; i<(y1-y2); i++) { path[j++] = '1'; plen = (y1 -1 - i) * 16 + x2; if(road[plen] == 0) road[plen] = 0xA1FC; }
			plen = (y1-y2) / 4; //临时变量记录能分成几个'D'
			for(i=0; i<plen; i++) path1[k++] = pstr[1][3];
			plen = (y1-y2) % 4; if(plen > 0) path1[k++] = pstr[1][plen-1];
		}
		if(y2 > y1) { //向上
			for(i=0; i<(y2-y1); i++) { path[j++] = '0'; plen = (y1 + 1 + i) * 16 + x2; if(road[plen] == 0) road[plen] = 0xA1FD; }
			plen = (y2-y1) / 4; //临时变量记录能分成几个'C'
			for(i=0; i<plen; i++) path1[k++] = pstr[0][3];
			plen = (y2-y1) % 4; if(plen > 0) path1[k++] = pstr[0][plen-1];
		}
		printf("\n找到位置: %02X, 系列号: %s", code[pos]&0xFF, path);
		dl = code[pos];
		code[pos] = -1; 
		if(pos == len) break; //全部吃完了结束 
	} 
	printf("\n\n用户名: %s系列号: %s\n简化为: %s", user, path, path1);
	printf("\n\n路径图\n  ");
	for(i=0; i<16; i++){ printf(" %02X", i); } 
	for(i=0; i<16; i++){
		printf("\n%02X", i);
		for(j=0; j<16; j++){
			plen = road[i*16+j];
			if(plen > 0xFF){ //方向键是中文符号,占2位 
				printf(" %c%c", (plen >> 8) & 0xFF, plen & 0xFF);
			} else printf(" %02X", plen);
		} 
	}
	getchar();
	return 0;
}

这个程序没考虑蛇咬身的情况,与及没有考虑先吃CC的过程中不小心吃到DD了(就是DD刚好在两个CC中间的路上),所以用户名不能太长,加上这个程序会更复杂,需要记录蛇占的所有位置
运行示例:
请输入用户名: snake
水果01: 61
水果02: DF
水果03: B3
水果04: 74
水果05: CE
结束06: BB
蛇头07: 13

路径
找到位置: 61, 系列号: 2200000
找到位置: 74, 系列号: 22000003330
找到位置: B3, 系列号: 2200000333020000
找到位置: CE, 系列号: 2200000333020000333333333330 (这里需要调整 333333333330 => 033333333333)
找到位置: DF, 系列号: 220000033302000033333333333030
找到位置: BB, 系列号: 220000033302000033333333333030222211

用户名: snake
系列号: 220000033302000033333333333030222211
简化为: 6C0B02CFFB030E5

路径图

   00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00  ←  ← 99 00 00 00 00 00 00 00 00 00 00 00 00
02 00  ↓ 00 00 00 00 00 00 00 00 00 00 00 00 00 00
03 00  ↓ 00 00 00 00 00 00 00 00 00 00 00 00 00 00
04 00  ↓ 00 00 00 00 00 00 00 00 00 00 00 00 00 00
05 00  ↓ 00 00 00 00 00 00 00 00 00 00 00 00 00 00
06 00 CC  →  →  → 00 00 00 00 00 00 00 00 00 00 00
07 00 00 00  ← CC 00 00 00 00 00 00 00 00 00 00 00
08 00 00 00  ↓ 00 00 00 00 00 00 00 00 00 00 00 00
09 00 00 00  ↓ 00 00 00 00 00 00 00 00 00 00 00 00
0A 00 00 00  ↓ 00 00 00 00 00 00 00 00 00 00 00 00
0B 00 00 00 CC  →  →  →  →  →  →  → DD  →  →  → 00
0C 00 00 00 00 00 00 00 00 00 00 00  ↑ 00 00 CC  →
0D 00 00 00 00 00 00 00 00 00 00 00  ←  ←  ←  ← CC
0E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

这个示例就无法验证通过,因为出现了DD在吃CC的路上, 所以可以手动调整一下B3到CE之间的路, 程序统一是先走左右再走上下,这一步需要绕过DD, 需要先走上下再走左右
调整后系列号为: 220000033302000003333333333330222211, 简化=> 6C0B02C0FFB30E5
调整后即可通过验证

下面这个示例则可以直接通过:
用户名: Snake
系列号: 000000220003330000033333333331113111111111222200000000
简化为: C468BC0FF793DD1ECC

路径图

   00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 99 00 00 00 00 00 00 00 00 00 00 00 00
02 00 00 00  ↓ 00 00 00 00 00 00 00 00 00 00 00 00
03 00 00 00  ↓ 00 00 00 00 00 00 00  ←  ←  ←  ← CC
04 00 00 00  ↓ 00 00 00 00 00 00 00  ↓ 00 00 00  ↑
05 00 00 00  ↓ 00 00 00 00 00 00 00  ↓ 00 00 00  ↑
06 00 00 00  ↓ 00 00 00 00 00 00 00  ↓ 00 00 00  ↑
07 00  ←  ← CC 00 00 00 00 00 00 00  ↓ 00 00 00  ↑
08 00  ↓ 00 00 00 00 00 00 00 00 00  ↓ 00 00 00  ↑
09 00  ↓ 00 00 00 00 00 00 00 00 00  ↓ 00 00 00  ↑
0A 00 CC  →  →  → 00 00 00 00 00 00  ↓ 00 00 00  ↑
0B 00 00 00 00  ↓ 00 00 00 00 00 00 DD 00 00 00  ↑
0C 00 00 00 00  ↓ 00 00 00 00 00 00 00 00 00 CC  →
0D 00 00 00 00  ↓ 00 00 00 00 00 00 00 00 00  ↑ 00
0E 00 00 00 00  ↓ 00 00 00 00 00 00 00 00 00  ↑ 00
0F 00 00 00 00 CC  →  →  →  →  →  →  →  →  →  → 00

 
 
本节高手录制的视频,点击前往查看

 
 
 

使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载

下面是我的OD的界面布局,我觉得这4个是最常用的界面,其它的我基本上没用到~
OD界面布局

posted @ 2024-12-19 14:16  hankerstudio  阅读(2)  评论(0)    收藏  举报