CrackMe-006

160CrackMe-06

0x01 信息收集

image20210301170932919.png

Ok这个按钮默认是灰色的无法点击,然后Cancella是将Codice清0

根据About的提示:

image20210301171145773.png

image20210301171115098.png

说明是需要先输入正确的Nome和Codice

EXEINFO查壳,Delphi的程序:

image20210301171213251.png

拖进DarckDe4反编译

查看过程:

image20210301171434205.png

  • CodiceChange:Codice的值被修改触发的事件
  • OkClick:点击Ok触发的事件
  • NomeChange:Nome的值被修改触发的事件
  • CancellaClick:点击CancellaClick触发的事件
  • AboutClick:点击About触发的事件

拖进IDA,在IDA中,对应事件的回调函数被命名为:模块名_事件名:

所以这里的五个事件对应的回调函数名为:

  • TPrincipale_CodiceChange
  • TPrincipale_OkClick
  • TPrincipale_NomeChange
  • TPrincipale_CancellaClick
  • TPrincipale_AboutClick

在IDA中将所有的Delphi相关的签名加上,然后导出MAP,通过OD的LoadMapEx插件加载MAP文件,方便寻找函数

TPrincipale_CodiceChange

int __usercall TPrincipale_CodiceChange@<eax>(int a1@<eax>, int a2@<ebx>, int a3@<esi>)
{
  int v3; // ebx
  int v4; // eax
  int v5; // edx
  void *v6; // ST00_4
  int v7; // edx
  unsigned int v9; // [esp-14h] [ebp-24h]
  void *v10; // [esp-10h] [ebp-20h]
  int *v11; // [esp-Ch] [ebp-1Ch]
  int v12; // [esp-8h] [ebp-18h]
  int v13; // [esp-4h] [ebp-14h]
  unsigned int v14; // [esp+0h] [ebp-10h]
  int System::AnsiString; // [esp+4h] [ebp-Ch]
  void *v16; // [esp+8h] [ebp-8h]
  int v17; // [esp+Ch] [ebp-4h]
  int savedregs; // [esp+10h] [ebp+0h]

  System::AnsiString = 0;
  v14 = 0;
  v13 = a2;
  v12 = a3;
  v3 = a1;
  v11 = &savedregs;
  v10 = &loc_442D56;
  v9 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v9);
  TControl::GetText(*(TControl **)(a1 + 736));
  v4 = __linkproc__ ValLong(v16, &v17);
  if ( v17 )
  {
    Sysutils::IntToStr(v4);
    Controls::TControl::SetText(*(Controls::TControl **)(v3 + 736), System::AnsiString);
  }
  if ( *(_BYTE *)(*(_DWORD *)(v3 + 720) + 71) )
  {
    TControl::GetText(*(TControl **)(v3 + 736));
    v6 = v16;
    TControl::GetText(*(TControl **)(v3 + 732));
    if ( (unsigned __int8)sub_442A3C(v14, v6) )
    {
      LOBYTE(v7) = 1;
      (*(void (__fastcall **)(_DWORD, int, _DWORD, int, int *, void *, unsigned int))(**(_DWORD **)(v3 + 716) + 96))(
        *(_DWORD *)(v3 + 716),
        v7,
        **(_DWORD **)(v3 + 716),
        v12,
        v11,
        v10,
        v9);
    }
    else
    {
      (*(void (__fastcall **)(_DWORD, _DWORD, _DWORD, int, int *, void *, unsigned int))(**(_DWORD **)(v3 + 716) + 96))(
        *(_DWORD *)(v3 + 716),
        0,
        **(_DWORD **)(v3 + 716),
        v12,
        v11,
        v10,
        v9);
    }
  }
  else
  {
    LOBYTE(v5) = 1;
    (*(void (__fastcall **)(_DWORD, int, _DWORD, int, int *, void *, unsigned int))(**(_DWORD **)(v3 + 716) + 96))(
      *(_DWORD *)(v3 + 716),
      v5,
      **(_DWORD **)(v3 + 716),
      v12,
      v11,
      v10,
      v9);
  }
  __writefsdword(0, v14);
  v16 = &loc_442D5D;
  System::__linkproc__ LStrClr(&v14);
  System::__linkproc__ LStrClr(&System::AnsiString);
  return System::__linkproc__ LStrClr(&v16);
}

这里输入

image20210301180349338.png

此时修改的是Nome的值,所以触发的是NomeChange的事件,可以看到两次GetText分别都是Get Nome和Codice

image20210301180244268.png

往下调用了442A3C函数,这里猜测应该就是用来判断Nome和Codice是否合法的函数:

image20210301180622826.png

首先判断Nome的长度是否大于5,汇编指令表示为jle

image20210301180908296.png

这里三个Strlen都是对Nome的长度进行判断,过了之后进入一个循环:

image20210301181209536.png

这里循环体的算法可以大致理解为:

Nome = '123456'
sum = 0
Nome_len = len(Nome)
sum += Nome_len
for i in range(0, Nome_len-1):
    sum += (i + 1) * ord(Nome[i]) * ord(Nome[i+1])

最终得到0x9F8E,十进制40846

往下压入了Codice的值,并且调用了StrToInt,这里测试输入的值为123得到0x7b

image20210301182515230.png

Codice = '123'

hex(int(Codice,10)) => 0x7b

然后将上面得到的0x9F8E减去0x7b再与0x29A对比

image20210301182931851.png

那么这里应该就是关键比较了,将jnz用nop填充之后,往下执行,直接运行程序,最终可以看到,此时程序中的Ok这个按钮已经变成了可点击的状态。

image20210301183048350.png

然后看到CodiceChange,可以看到该函数也调用了442A3C对两个值进行判断,那么可以得出NomeChange和CodiceChange的真正逻辑判断是同样的,根据此就可以写出注册机了。

0x02 编写注册机

main.py:

import sys
import random
import string
from PyQt5.QtWidgets import QApplication, QMainWindow
from crackMe06 import Ui_MainWindow


class MyMainWindow(QMainWindow, Ui_MainWindow):
    name = ''
    serial = ''

    def __init__(self, parent=None):
        super(MyMainWindow, self).__init__(parent)
        self.setupUi(self)
        self.pushButton.clicked.connect(self.generate_name_serial)

    def generate_name(self):
        return ''.join(random.sample(string.ascii_letters + string.digits, random.randint(6,10)))

    def generate_serial(self, name):
        sum = 0
        Nome_len = len(self.name)
        sum += Nome_len
        for i in range(0, Nome_len-1):
            sum += (i + 1) * ord(self.name[i]) * ord(self.name[i+1])
        return str(sum - 0x29A)

    def generate_name_serial(self):
        self.name = self.generate_name()
        self.serial = self.generate_serial(self.name)
        self.textEdit.setText(self.name)
        self.textEdit_2.setText(self.serial)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    myWin = MyMainWindow()
    myWin.show()
    sys.exit(app.exec_())

avatar