160个CrackMe系列-004-ajj.1

selph
selph
发布于 2020-10-17 / 694 阅读
0
0

160个CrackMe系列-004-ajj.1

前言

这是160个CreakMe系列的第004个CM,难度:☆;

这个程序是Delphi编写的,要完成这次的逆向分析需要了解Delphi程序的运行过程。

本次分析使用到的环境和工具如下:

  • 操作系统:Windows 10 2004(物理机)
  • 工具:x32dbg,DelphiDecompiler
  • IDE:Visual Studio 2019

软件分析

image-20201015123101032

依旧是用户名+序列号的验证,那么这次的分析目标也依旧是:实现验证的破解,以及分析出来序列号的算法

这是没有确认按钮,应该是用户名和注册码验证成功后会自动显示图片,第一次见这种情况

分析目标1:暴力破解

拖入x32dbg,依然是先查字符串,这个软件是中文的,猜测这个软件的提示也是中文的,搜索成功两个字:

image-20201015123228272

直接定位到显示注册成功的地方:

image-20201015123337052

这里有个可疑的跳转,会跳过这个注册成功,那就让这个跳转失效试试:

image-20201015123440654

验证成功:

image-20201015123522347

到这里暴力破解就完成了

分析目标2:注册机

用户名abcd,注册码1234,用这个去进行测试:

image-20201015125231712

上面这段do-while循环算了半天,算出来34abcd18,但丝毫没有影响到最终做判断的esi+30c也就是0x022b1c00这个地址的值,所以目前还不知道这算的是啥玩意,也不是注册码。

这是一个Delphi程序,反汇编分析的手感怪怪的,应该是有什么姿势不太对,我去查了关于Delphi反汇编相关的资料,参考某大佬的基础讲解(参考资料链接在下方),仿佛有所顿悟

参考资料:用实例讲解如何读懂DELPHI程序的反编译

https://www.52pojie.cn/thread-615448-1-1.html

大概浏览之后,这里印象比较深刻的有如下三点:

  1. 我们了解到Delphi程序是基于事件的,可通过专门的工具(dede、IDR)来辅助分析和定位,我们对这些控件的操作都是一个事件

  2. Delphi反汇编里,函数调用参数大多都放在eax里,返回值放在edx里

  3. 通过观察call所在地址,可以判断是否是用户函数,如果是用户函数需要进去看看

到这里我们分析这个CM所需要的前置知识应该是够了,可以继续分析了:

工具可以从52破解上下载,这里我用的是DelphiDecompiler

拖入exe一键分析:

image-20201015165016210

我们发现这个exe有个可疑事件叫做chkcode,双击点进去:

image-20201015165209284

大概看了一下,静态分析也看不出个啥玩意,记下地址到x32dbg里下断点动态分析去:

image-20201015165627314

随便下了个断点,当我输入注册码的时候,断点中断了,说明这里跟我们输入的注册码有关

这里自动注释冒出来了个“黑头Sun Bird”和“desloffc-012-OK”

这里很可能是用来拼接正确注册码的

再次进入断点,这里似乎显示出来了正确的注册码:

image-20201015185735226

拿去试一试:

image-20201015185829054

果然正确了,来观察一下这个注册码的结构:

"黑头Sun Bird" + 一个数字 +“desloffc-012-OK”+ 用户名

问题在于中间的这个数字要怎么计算

再次中断一步一步走看一看:

image-20201015191037849

可以轻易发现,这里的esi里装的是用户名长度,将这个长度+5,然后转换成字符串,然后进行拼接

关于转换int到str这个call是怎么发现是转换的呢,就按照这个地址去DelphiDecompiler里查看:

image-20201015191211740

这里提示说是IntToStr

那么到此,这个注册码的生成规则就很明确了

编写注册机

源代码:

据说C++可以用中文变量名,赶紧尝试一下

----啊这真的敲得好累啊,真就一个变量敲大半天,还是老老实实敲英文变量名吧

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

int main() {
	char 用户名[12] = { 0 };
	char 序列号[100] = { 0 };
	char 中间数字[10] = { 0 };

	printf("请输入用户名:");scanf_s("%s",用户名,12);
	sprintf_s(中间数字, "%d", strlen(用户名)+5);
	
	strcpy_s(序列号, "黑头Sun Bird");
	strcat_s(序列号, 中间数字);
	strcat_s(序列号, "dseloffc-012-OK");
	strcat_s(序列号, 用户名);

	printf("序列号是:%s\r\n", 序列号);

	return 0;
}

效果演示

image-20201015192613454

总结

刚开始做这个的时候,我看反汇编看的有点懵,经过搜索发现,Delphi程序是基于事件来运行的,需要借助相关辅助工具去进行事件的定位,了解了这个之后,一切都变得如此的简单。

这次的教训是,要分析一个程序,需要先了解这个编程语言编写的程序有什么特点,是否需要什么辅助工具来协助。


评论