AVALON Uncategorized,零散的一些题目 分析一个二元函数加密的cm

分析一个二元函数加密的cm

环境配置

系统 : win10 64bit \ Linux kali 4.15.0-kali2-amd64
程序 : cztria-1.rar
要求 : 写出注册机
使用工具 :ida pro \ kail 自带的字典 \ peid

开始分析

拿信息

使用peid查看exe的信息:
MASM32 / TASM32
显示是用了汇编语言写的,还挺复杂,而且这说明不能完全相信ida里F5出来的结果,必要时还是要人工分析关键的汇编代码。

静态分析

使用ida打开文件,等待分析完成后查看字符串列表(Shift + F12):

Address Length  Type    String
.rdata:0040223C 0000000D    C   KERNEL32.DLL
.rdata:00402249 0000000A    C   GDI32.dll
.rdata:00402253 0000000C    C   SHELL32.dll
.rdata:0040225F 0000000B    C   USER32.dll
.data:00403000  0000000D    C   DIALOGBOXONE
.data:0040300D  00000013    C   About cz Trial # 3
.data:00403020  00000005    C   open
.data:00403025  0000001F    C   mailto:czdrillard@hushmail.com
.data:00403044  00000007    C   script
.data:0040304B  0000016E    C   Greetz to Gandalf, Falcon, the rest of the GenocideCrew all our friends at Reverse Engineering, and all you crackers there.  Of course no patches and no brute force. All you do is write a keygen and a tutorial explaining the protection. Then you are a new trial member! Hint: figure out what the two equations are the program is solving, then it's not so difficult.
.data:004031B9  00000018    C   http://www.nexus.hu/upx
.data:004031D1  00000014    C                 Error
.data:004031E5  00000014    C          <Registered>
.data:004031F9  00000017    C    Sorry Cracker, wrong.
.data:00403210  00000018    C               You did it!
.data:00403228  00000010    C   Packed with UPX
.data:00403238  00000007    C   STATIC
.data:0040323F  00000009    C   DLGCLASS
.data:00403248  00000006    C   Menu1
.data:0040324E  00000007    C   DLGWIN
.data:00403255  00000005    C   EDIT

根据You did it!字符串定位到关键代码段:

LRESULT __stdcall sub_401133(HWND hWndParent, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  HGDIOBJ h; // ST30_4
  HDC hdc; // ST34_4
  signed int len_of_pass; // eax
  CHAR *name1; // edi
  CHAR *name2; // esi
  char v9; // al
  _BYTE *v10; // edi
  CHAR *password1; // esi
  CHAR *part_from_username; // ebx
  int sum; // ecx
  char part_from_password; // al
  char v15; // dl
  char v16; // al
  int value_from_front_of_the_list; // eax

  switch ( Msg )
  {
    case 1u:
      hWnd = CreateWindowExA(0x200u, ClassName, 0, 0x50000000u, 225, 86, 132, 20, hWndParent, 0, hInst, 0);
      SetFocus(hWnd);
      h = GetStockObject(17);
      hdc = GetDC(hWnd);
      SelectObject(hdc, h);
      ReleaseDC(hWnd, hdc);
      SendMessageA(hWnd, 0x30u, h, 0xFFFF);
      dword_403294 = 0;
      dword_403298 = 0;
      dword_40329C = 0;
      lpPrevWndFunc = SetWindowLongA(hWnd, -4, sub_4014C2);
      dword_403280 = CreateWindowExA(0, aStatic, 0, 0x5000000Eu, 150, 2, 180, 65, hWndParent, 0, hInst, 0);
      ::lParam = LoadImageA(hInst, 0x70, 0, 180, 65, 0);
      SendMessageA(dword_403280, 0x172u, 0, ::lParam);
      break;
    case 2u:
      PostQuitMessage(0);
      break;
    case 0x111u:
      if ( lParam )
      {
        if ( !HIWORD(wParam) )
        {
          switch ( wParam )
          {
            case 0x66:
              SetWindowTextA(hWnd, 0);
              SetDlgItemTextA(hWndParent, 3001, 0);
              RtlZeroMemory(username, 64);
              RtlZeroMemory(password_403360, 64);
              RtlZeroMemory(&unk_4032E0, 64);
              RtlZeroMemory(&unk_4033A0, 64);
              RtlZeroMemory(byte_4032A0, 64);
              dword_403294 = 0;
              dword_403298 = 0;
              dword_40329C = 0;
              SetFocus(hWnd);
              break;
            case 0x65:
              if ( GetWindowTextA(hWnd, username, 64) <= 4 )// username len must > 4
                goto wrong_case;
              len_of_pass = GetDlgItemTextA(hWndParent, 3001, password_403360, 64);
              if ( len_of_pass <= 4 )           // len of pass must > 4
                goto wrong_case;
              len_of_password = len_of_pass;
              SetFocus(hWnd);
              name1 = username;
              name2 = username;
              while ( 1 )
              {
                v9 = *name2++;
                if ( !v9 )
                  break;
                *name1++ = v9 | 0x20;
              }
              v10 = byte_4032A0;
              password1 = password_403360;
              part_from_username = username;
              sum = 0;
              while ( 1 )
              {
                part_from_password = *password1++;
                if ( !part_from_password )      // traversal the password strings
                  break;
                v15 = *part_from_username - part_from_password;
                if ( *part_from_username == part_from_password )
                  goto wrong_case;
                v16 = v15 & 0xF;
                if ( !(v15 & 0xF) )
                  goto wrong_case;
                *v10++ = v16;
                LOBYTE(sum) = v16 + sum;        // sum += ((pfu - pfp) & 0xF)
                ++part_from_username;
              }
              SUM = sum;
              value_from_front_of_the_list = sub_401637();
              LOBYTE(value_from_front_of_the_list) = byte_4032A0[len_of_password >> 2];
              if ( SUM == dword_40326E - value_from_front_of_the_list )
              {
                MessageBoxA(hWndParent, aYouDidIt, aRegistered, 0x2000u);
                RtlZeroMemory(&unk_4032E0, 64);
                RtlZeroMemory(&unk_4033A0, 64);
              }
              else
              {
wrong_case:
                MessageBoxA(hWndParent, Text, Caption, 0x2000u);
                RtlZeroMemory(&unk_4032E0, 64);
                RtlZeroMemory(&unk_4033A0, 64);
              }
              break;
            case 0x67:
              DestroyWindow(hWndParent);
              break;
          }
        }
      }
      else if ( wParam == 32000 )
      {
        DialogBoxParamA(hInst, aDialogboxone, 0, DialogFunc, 0);
        EnableMenuItem(hMenu, 0x7D00u, 0);
      }
      else
      {
        DestroyWindow(hWndParent);
      }
      break;
    default:
      return DefWindowProcA(hWndParent, Msg, wParam, lParam);
  }
  return 0;
}

程序根据用户名和密码字符串的值,生成三个值:
1. SUM 为字符差值控制在一定范围之内的值的和
2. value_from_front_of_the_list 为差值列表特定元素的值: byte_4032A0[len_of_password >> 2]
3. dword_40326E 为F(差值列表)之后的结果,函数中运用到了类似等差数列的一些操作:

int sub_401637()
{
  unsigned __int64 v0; // rax
  signed int index; // ecx
  unsigned int v2; // eax
  unsigned __int64 v3; // rax
  signed int index_j; // ecx
  int result; // eax

  v0 = (len_of_password - 1) * (strangelist_4032A0[len_of_password - 1] * strangelist_4032A0[len_of_password - 1]);// loop_times=x^3
  for ( index = 1; ; index += 2 )
  {
    LODWORD(v0) = v0 - index;
    if ( v0 <= 0 )
      break;
    ++HIDWORD(v0);
  }
  v2 = (HIDWORD(v0) + strangelist_4032A0[len_of_password - 1] + 1) >> 1;
  strangelist_4032A0[len_of_password] = v2;
  v3 = (len_of_password - 1) * (v2 * v2);
  for ( index_j = 1; ; index_j += 2 )
  {
    LODWORD(v3) = v3 - index_j;
    if ( v3 <= 0 )
      break;
    ++HIDWORD(v3);
  }
  LODWORD(v3) = (HIDWORD(v3) + strangelist_4032A0[len_of_password] + 1) >> 1;
  dword_40326E = (HIDWORD(v3) + strangelist_4032A0[len_of_password] + 1) >> 1;
  return result;
}

复写程序

用python吧程序流程复写一遍:

import sys

def get_n(num):
    index = 1
    count = 0
    while 1:
        num = num - index
        if num <= 0:
            break
        index = index + 2
        count = count + 1
    return count

def sub_401637(strange_list,len_list):
    res = strange_list[len_list-1]*strange_list[len_list-1]*(len_list-1)
    n = get_n(res)

    eax = (strange_list[len_list-1]+1+n) >> 1
    strange_list.append(eax)
#  print strange_list
#  print strange_list[-1]
    res = eax * eax * (len_list-1)

    n = get_n(res)
    res = (strange_list[-1]+1+n) >> 1
    return res

def check(username,password):
    SUM = 0
    strange_list = []
    len_of_password = len(password)
    for index in range(0,len_of_password):
        if username[index] == " ":
            tmp = 0
        else:
            tmp = ord(username[index])
        if tmp == ord(password[index]):
            return
        if ((tmp-ord(password[index])) & 0xF) == 0:
            return
        strange_list.append((tmp-ord(password[index])) & 0xF)
        SUM += (tmp-ord(password[index])) & 0xF

    minus_num_40326E = sub_401637(strange_list,len(strange_list))
    value_from_front_of_the_list = strange_list[len_of_password >> 2]
    '''
    print 'sum is ' + str(hex(SUM))
    print 'value_from_front_of_the_list is ' + str(value_from_front_of_the_list)
    print 'minus_num_40326E is ' + str(hex(minus_num_40326E))
    '''
    if SUM == minus_num_40326E - value_from_front_of_the_list:
        print username + ' and ' + password + ' is ok.'

f = open("big.txt")
line = f.readline()
while line:
    username = sys.argv[1]
    if len(username) <= 4:
        print 'please input the right username (len > 4)'
        exit()

    password = line.strip()

    if len(password) <= 4:
        line = f.readline()
        continue

    if len(username) < len(password):
        username = username.ljust(len(password)," ")

#  print username + ' ' + password + str(len(password))
    check(username,password)
    line = f.readline()
f.close()

这里使用的big.txt使用的kali自带的字典:

   99  cd /usr/share/wordlists/
  100  cd dirb
  101  ls
  102  vim small.txt 
  103  vim big.txt 
  104  cp big.txt  ~/playground/

破解成功

使用任意用户名为参数调用程序:

root@kali:~/playground# python test.py blackhat
blackhat and okzjidc is ok.
root@kali:~/playground# python test.py dreamcracker
dreamcracker and laopo is ok.
dreamcracker and bookit is ok.
dreamcracker and cassie is ok.
dreamcracker and cookie is ok.
dreamcracker and packard is ok.
dreamcracker and rocket is ok.
dreamcracker and !am0zAx is ok.
dreamcracker and 3abe74 is ok.
dreamcracker and 1010101010 is ok.
dreamcracker and banma is ok.
dreamcracker and rabia is ok.
dreamcracker and qq,./ is ok.
dreamcracker and aa,./ is ok.
dreamcracker and saok! is ok.
dreamcracker and 2008vps is ok.
dreamcracker and 3000idc is ok.
dreamcracker and cnool.net is ok.
dreamcracker and 3ann35 is ok.
dreamcracker and 2010idc is ok.
dreamcracker and sapling is ok.
dreamcracker and satire is ok.
dreamcracker and satjidc is ok.
dreamcracker and saxon is ok.
dreamcracker and 000000000. is ok.