查壳:

拖进OD:

典型的Delphi程序,运行一下试试,可以看到有一个大的框,按了没啥反应

0x01 整体流程分析
拖进IDA:

定位该字符串:

既然是Delphi的程序,用Darkde4反编译试试:

双击TForm1:

可以看到运行程序中间的位置是一个大按钮,该按钮存在两个事件:
- Panel1Click
- Panel1DblClick

来到过程,定位这两个事件的RVA:
- Panel1DblClick -> 0x457E7C
- Panel1Click -> 0x457FB8

来到FormCreate事件,对于一个Delphi程序的窗口程序,首先会先通过FormCreate创建窗体:


这里都调用了unknown_libname_29
函数对字符串进行了处理,这里大概可以知道是将字符串分别复制到a1 + 784
和a1 + 788
的位置。
0x02 破解注册码
载入OD,定位到上面分析到的两个事件的RVA,下断点,然后输入用户名和注册码,点击中间的按钮,程序成功停在0x457FB8,并且在该函数中存在字符串“恭喜恭喜,注册成功”,说明该位置应该是破解的位置:

这里是一个循环,总共进行19循环:

在该循环结束后,会有一个cmp加jnz,说明该位置应该就是关键跳,注意到后面还有一个循环,所以可以将jnz跳转的位置转到0045803D,或者直接nop填充该位置的跳转也可:


nop掉之后直接点中间的框就可以了:

继续注册码算法破解:
经过19次循环之后:

最终可以发现得到36user1218
这样一个字符串,转成表达式:
str(ord(str(strlen(user)))) + user + str(18)
最终会将esi+0x30c指向的值与0x85进行对比:

那么就需要去找到这个位置的值是在哪里赋予的:
仔细查看双击事件和单击事件,可以发现GetText拿到的都是用户名而不是注册码,说明注册码在这两个事件之前就已经验证过了,在循环体中似乎也没有对于esi+0x30c
这个位置进行赋值,说明该位置的值应该在双击事件之前就已经执行了,重新回到DarkDe4
,找事件,通过之前的练习应该也能发现,当按钮点击之后,会通过用户名去生成对应的注册码,再与输入的注册码进行对比,这里也一样,只不过这里的事件是在输入注册码的时候,程序就会不断的调用chkcode
事件对输入的注册码进行校验,所以我们直接定位该函数的RVA,下断点:


输入完用户名之后,点击注册码,程序卡在该函数的起始位置,说明chkCode进行校验了:

往下跟可以看到,进行了StrCat

重新输入一个不同的用户名:test
ebx+0x2F8的值为4,但该函数中并未存在对该位置进行写入的指令

这里的内存地址是会变化的,所以无法直接设置硬件访问断点,那么就只能设置条件断点:

0x04 编写注册机
还是之前的注册模板,修改一下生成注册码的位置就可以了:
关键源码:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'main.py'
#
# Created by: PyQt5 UI code generator 5.15.2
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
import sys
import random
import string
from PyQt5.QtWidgets import QApplication, QMainWindow
from crackMe04 import Ui_MainWindow
class MyMainWindow(QMainWindow, Ui_MainWindow):
pre_serial = '黑头Sun Bird'
med_serial = 'dseloffc-012-OK'
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(4,10)))
def generate_serial(self, name):
return self.pre_serial + str(len(name) + 5) + self.med_serial + name
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_())


Comments NOTHING