阿虚
Hello World!
Hello World!
国色天香

0x0 环境

——————–

环境:

系统:Windows 10

工具:IDA 7.X

——————–

0x1 跑起来

程序界面如下, 要求输入账号CTFHUB得到正确的解码。随便输入Key点击Try弹出对话框显示字符串“Wrong Code!Try Again!”

http://www.xuwu.org/wp-content/uploads/2020/02/gstx1.png

0x2 IDA分析

载入IDA搜索字符串可以明显的发现有错误和正确的明文字符串。

http://www.xuwu.org/wp-content/uploads/2020/02/gstx2.png

引用错误字符串处然后图形显示能够发现错误和正确的消息提示都在一个函数里面。

http://www.xuwu.org/wp-content/uploads/2020/02/gstx3-1024x313.png

而提示正确还是错误为一处就是这个JZ了

http://www.xuwu.org/wp-content/uploads/2020/02/gstx4-1024x428.png

这个函数有些长,躲个懒可以直接F5。整理精简下这个逻辑明显就是按钮事件回调了。手写过win32窗口程序的Hellword都能立马看出来。要分析解码方法的逻辑就在0x111这个case就行。

LRESULT __stdcall sub_401109(HWND hWndParent, UINT Msg, WPARAM wParam, LPARAM lParam)
{ 
  switch ( Msg )
  {
    case 2u:
      PostQuitMessage(0);
      break;
    case 1u:
	  /.....................
      break;
    case 0x111u:
      if ( wParam == 3 )
      {
		    //................
                if ( v17 != v15 )
                  goto LABEL_35;
              }
              MessageBoxA(0, aSerialIsCorrec, aGoodCracker, 0);
            }
            else
            {
LABEL_35:
              MessageBoxA(0, Text, Caption, 0);
            }  
		    //................
      }
      break;
		    //................
  }
  return 0;
}

0x3 分析解码逻辑

 .text:00401220 case_111:                               ; CODE XREF: sub_401109+1C↑j
.text:00401220                 cmp     [ebp+Msg], 111h
.text:00401227                 jnz     loc_4013BB
.text:0040122D                 mov     eax, [ebp+wParam]
.text:00401230                 cmp     ax, 3
.text:00401234                 jnz     fun_end
.text:0040123A                 shr     eax, 10h
.text:0040123D                 or      ax, ax
.text:00401240                 jnz     fun_end1      
.text:00401246                 xor     eax, eax
.text:00401248                 push    28h ; '('       ; cchMax
.text:0040124A                 push    offset name_buf ; lpString
.text:0040124F                 push    2               ; nIDDlgItem
.text:00401251                 push    [ebp+hWndParent] ; hDlg
.text:00401254                 call    GetDlgItemTextA ; 取name的字符串
.text:00401259                 test    al, al
.text:0040125B                 jz      Sorry           ; 
.text:00401261                 cmp     al, 20h ; ' '
.text:00401263                 jg      Name_can_be_max_32 ; name的长度不能超过0x20个字节 
.text:00401269                 cmp     al, 5
.text:0040126B                 jl      ame_must_be_min_5 ; name的长度不能低于5个字节 
.text:00401271                 lea     ebx, name_buf
.text:00401277                 xor     ecx, ecx
.text:00401279                 mov     al, 5
.text:0040127B                 xor     edx, edx 
.text:0040127D do_while:                               ; CODE XREF: sub_401109+19B↓j
.text:0040127D                 mov     cl, [edx+ebx]
.text:00401280                 xor     cl, 29h
.text:00401283                 add     cl, al          ; name_buf[i] ^ 0x29 + i
.text:00401285                 cmp     cl, 41h ; 'A'
.text:00401288                 jl      short loc_4012A6
.text:0040128A                 cmp     cl, 5Ah ; 'Z'
.text:0040128D                 jg      short loc_4012A6 ; if (name_buf[i] ^ 0x29 + i) < 'A' || (name_buf[i] ^ 0x29 + i) > 'Z'
.text:0040128D                                         ;     jmp loc_4012A6; 
.text:0040128F loc_40128F:                             ; CODE XREF: sub_401109+1A1↓j
.text:0040128F                 mov     name_dec_buf[edx], cl ; cl 的值取决于上面那个跳转
.text:00401295                 mov     (name_dec_buf+1)[edx], 0
.text:0040129C                 inc     dl              ; index += 1;
.text:0040129E                 dec     al              ; al -= 1;
.text:004012A0                 cmp     al, 0
.text:004012A2                 jz      short do_while_break ; 这个循环只会循环五次
.text:004012A4                 jmp     short do_while 
.text:004012A6 loc_4012A6:                             ; CODE XREF: sub_401109+17F↑j
.text:004012A6                                         ; sub_401109+184↑j
.text:004012A6                 mov     cl, 52h ; 'R'
.text:004012A8                 add     cl, al          ; cl = 0x52 + i;
.text:004012AA                 jmp     short loc_40128F ; cl 的值取决于上面那个跳转 
.text:004012AC do_while_break:                         ; CODE XREF: sub_401109+199↑j
.text:004012AC                 xor     edx, edx
.text:004012AE                 mov     eax, 5 
.text:004012B3 do_while_2:                             ; CODE XREF: sub_401109+1D4↓j
.text:004012B3                 mov     cl, [edx+ebx]
.text:004012B6                 xor     cl, 27h
.text:004012B9                 add     cl, al
.text:004012BB                 add     cl, 1           ; name_buf[i] ^ 0x27 + i + 1
.text:004012BE                 cmp     cl, 41h ; 'A'
.text:004012C1                 jl      short loc_4012DF
.text:004012C3                 cmp     cl, 5Ah ; 'Z'
.text:004012C6                 jg      short loc_4012DF ; if (name_buf[i] ^ 0x27 + i + 1) < 'A' || (name_buf[i] ^ 0x27 + i + 1) > 'Z'
.text:004012C6                                         ;     jmp loc_4012DF; 
.text:004012C8 loc_4012C8:                             ; CODE XREF: sub_401109+1DA↓j
.text:004012C8                 mov     (name_dec_buf+5)[edx], cl ; cl 的值取决于上面那个跳转
.text:004012CE                 mov     (name_dec_buf+6)[edx], 0
.text:004012D5                 inc     dl              ; ndex += 1;
.text:004012D7                 dec     al              ; al -= 1;
.text:004012D9                 cmp     al, 0
.text:004012DB                 jz      short do_while2_break ; 这个循环只会循环五次
.text:004012DD                 jmp     short do_while_2 
.text:004012DF loc_4012DF:                             ; CODE XREF: sub_401109+1B8↑j
.text:004012DF                                         ; sub_401109+1BD↑j
.text:004012DF                 mov     cl, 4Dh ; 'M'
.text:004012E1                 add     cl, al          ; cl = 0x4D + i;
.text:004012E3                 jmp     short loc_4012C8 ; cl 的值取决于上面那个跳转 
.text:004012E5 do_while2_break:                        ; CODE XREF: sub_401109+1D2↑j
.text:004012E5                 xor     eax, eax
.text:004012E7                 push    28h ; '('       ; cchMax
.text:004012E9                 push    offset key_buf  ; lpString
.text:004012EE                 push    4               ; nIDDlgItem
.text:004012F0                 push    [ebp+hWndParent] ; hDlg
.text:004012F3                 call    GetDlgItemTextA
.text:004012F8                 test    ax, ax
.text:004012FB                 jz      short check_err ; 密码不能为0
.text:004012FD                 cmp     ax, 0Ah
.text:00401301                 jg      short check_err
.text:00401303                 jl      short check_err ; 密码必须为10位
.text:00401305                 xor     eax, eax
.text:00401307                 xor     ebx, ebx
.text:00401309                 xor     ecx, ecx
.text:0040130B                 xor     edx, edx
.text:0040130D                 lea     eax, key_buf 
.text:00401313 do_while_3:                             ; CODE XREF: sub_401109+234↓j
.text:00401313                 mov     bl, [ecx+eax]
.text:00401316                 mov     dl, name_dec_buf[ecx]
.text:0040131C                 cmp     bl, 0
.text:0040131F                 jz      check_ok
.text:00401325                 add     dl, 5
.text:00401328                 cmp     dl, 5Ah ; 'Z'
.text:0040132B                 jg      short max_5A    ; if (name_dec_buf[ecx] + 5 > 0x5A)
.text:0040132B                                         ;     jmp loc_401341: 
.text:0040132D loc_40132D:                             ; CODE XREF: sub_401109+23B↓j
.text:0040132D                 xor     dl, 0Ch
.text:00401330                 cmp     dl, 41h ; 'A'   ; if ((dl ^ 0x0C) < 'A')
.text:00401330                                         ;     jmp loc_401346;
.text:00401333                 jl      short loc_401346
.text:00401335                 cmp     dl, 5Ah ; 'Z'   ; if ((dl ^ 0x0C) > 'Z')
.text:00401335                                         ;     jmp loc_40134C;
.text:00401338                 jg      short loc_40134C 
.text:0040133A loc_40133A:                             ; CODE XREF: sub_401109+241↓j
.text:0040133A                                         ; sub_401109+247↓j
.text:0040133A                 inc     ecx             ; index++;
.text:0040133B                 cmp     dl, bl
.text:0040133D                 jz      short do_while_3 ; id (dl == key_buf[index])
.text:0040133D                                         ;     do_while3 continue;
.text:0040133F                 jmp     short check_err ; else
.text:0040133F                                         ;     check_err; 
.text:00401341 max_5A:                                 ; CODE XREF: sub_401109+222↑j
.text:00401341                 sub     dl, 0Dh         ; dl -= 0xD;
.text:00401344                 jmp     short loc_40132D 
.text:00401346 loc_401346:                             ; CODE XREF: sub_401109+22A↑j
.text:00401346                 mov     dl, 4Bh ; 'K'
.text:00401348                 add     dl, cl          ; dl = 0x4B + index;
.text:0040134A                 jmp     short loc_40133A ; index++; 
.text:0040134C loc_40134C:                             ; CODE XREF: sub_401109+22F↑j
.text:0040134C                 mov     dl, 4Bh ; 'K'
.text:0040134E                 sub     dl, cl          ; dl = 0x4B - index;
.text:00401350                 jmp     short loc_40133A ; index++; 
.text:00401352 check_err:                              ; CODE XREF: sub_401109+1F2↑j
.text:00401352                                         ; sub_401109+1F8↑j ...
.text:00401352                 push    0               ; uType
.text:00401354                 push    offset Caption  ; "Dont give up..."
.text:00401359                 push    offset Text     ; "Wrong Code!Try Again!"
.text:0040135E                 push    0               ; hWnd
.text:00401360                 call    MessageBoxA
.text:00401365                 jmp     short fun_end1 
.text:00401367 Sorry:                                  ; CODE XREF: sub_401109+152↑j
.text:00401367                 push    0               ; uType
.text:00401369                 push    offset aSorry   ; "Sorry..."
.text:0040136E                 push    offset aEnterName_0 ; "Enter Name!"
.text:00401373                 push    0               ; hWnd
.text:00401375                 call    MessageBoxA
.text:0040137A                 jmp     short fun_end1 
.text:0040137C Name_can_be_max_32:                     ; CODE XREF: sub_401109+15A↑j
.text:0040137C                 push    0               ; uType
.text:0040137E                 push    offset aSorry   ; "Sorry..."
.text:00401383                 push    offset aNameCanBeMax32 ; "Name can be max 32 Chars long!"
.text:00401388                 push    0               ; hWnd
.text:0040138A                 call    MessageBoxA
.text:0040138F                 jmp     short fun_end1 
.text:00401391 ame_must_be_min_5:                      ; CODE XREF: sub_401109+162↑j
.text:00401391                 push    0               ; uType
.text:00401393                 push    offset aSorry   ; "Sorry..."
.text:00401398                 push    offset aNameMustBeMin5 ; "Name must be min 5 Chars long!"
.text:0040139D                 push    0               ; hWnd
.text:0040139F                 call    MessageBoxA
.text:004013A4                 jmp     short fun_end1 
.text:004013A6 check_ok:                               ; CODE XREF: sub_401109+216↑j
.text:004013A6                 push    0               ; uType
.text:004013A8                 push    offset aGoodCracker ; "Good Cracker"
.text:004013AD                 push    offset aSerialIsCorrec ; "Serial is correct! Now write a keygen +"...
.text:004013B2                 push    0               ; hWnd
.text:004013B4                 call    MessageBoxA 
.text:004013B9 fun_end1:                               ; CODE XREF: sub_401109+137↑j
.text:004013B9                                         ; sub_401109+25C↑j ...
.text:004013B9                 jmp     short fun_end

0x4 C语言源码

// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

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

bool check(char* user, char* password)
{
    int user_len = strlen(user);
    if (user_len < 5 || user_len > 0x20)
    {
        return false;
    }

    unsigned char name_dec[0x20] = { 0x0 }; 
    for (int i = 0, x = 5; x > 0; x--, i++)
    {
        unsigned char tmp = (user[i] ^ 0x29) + x;
        if (tmp < 'A' || tmp > 'Z')
        {
            tmp = 0x52 + x;
        }

        name_dec[i] = tmp;
    }

    for (int i = 0, x = 5; x > 0; x--, i++)
    {
        unsigned char tmp = (user[i] ^ 0x27) + x + 1;
        if (tmp < 'A' || tmp > 'Z')
        {
            tmp = 0x4D + x;
        }

        name_dec[i + 5] = tmp;
    }

    int key_len = strlen(password);
    if (key_len == 0)
    {
        return false;
    }

    if (key_len != 10)
    {
        return false;
    }

    for (int i = 0; i < key_len; i++)
    {
        unsigned char k = password[i];
        unsigned char t = name_dec[i] + 5;
        if (t > 0x5A)
        {
            t -= 0xD;
        }

        t ^= 0xC;
        if (t < 'A')
        {
            t = 0x4B + i;
        }
        else if (t > 'Z')
        {
            t = 0x4B - i;
        }

        if (t != k)
        {
            return false;
        }
    }

    return true;
}

bool reg(char* user, char* password)
{
    int user_len = strlen(user);
    if (user_len < 5 || user_len > 0x20)
    {
        return false;
    }
     
    for (int i = 0, x = 5; x > 0; x--, i++)
    {
        unsigned char tmp = (user[i] ^ 0x29) + x;
        if (tmp < 'A' || tmp > 'Z')
        {
            tmp = 0x52 + x;
        }

        password[i] = tmp;
    }

    for (int i = 0, x = 5; x > 0; x--, i++)
    {
        unsigned char tmp = (user[i] ^ 0x27) + x + 1;
        if (tmp < 'A' || tmp > 'Z')
        {
            tmp = 0x4D + x;
        }

        password[i + 5] = tmp;
    }

    for (int i = 0; i < 10; i++)
    { 
        unsigned char t = password[i] + 5;
        if (t > 0x5A)
        {
            t -= 0xD;
        }

        t ^= 0xC;
        if (t < 'A')
        {
            t = 0x4B + i;
        }
        else if (t > 'Z')
        {
            t = 0x4B - i;
        }

        password[i] = t;
    }

    return true;
}

int main()
{
    char name[256] = { 0x0 };
    char password[256] = { 0x0 };

    std::cout << "in name: \n";
    std::cin >> name; 

    std::cout << "in password: \n";
    std::cin >> password;

    reg(name, password);

    if (check(name, password))
    {
        std::cout << "ok \n";
    }

    return 0;
}

阿虚

文章作者

发表评论

textsms
account_circle
email

Hello World!

国色天香
0x0 环境 -------------------- 环境: 系统:Windows 10 工具:IDA 7.X -------------------- 0x1 跑起来 程序界面如下, 要求输入账号CTFHUB得到正确的解码。随…
扫描二维码继续阅读
2020-02-18