[160CRACKME]Chafe.2

(一)分析

运行一下这个程序发现,这个程序没有确认按钮,推测是实时获取用户输入,然后在文本框中显示输入是否正确。
OD中打开,自动定位到了主函数。
[160CRACKME]Chafe.2
GetModuleHandle获取窗口句柄,ExitProcess函数是退出程序的进程,中间那个401023函数就是程序运行的主体部分,F7步入,看到一些加载图标,加载光标,注册窗口的api函数等等,
[160CRACKME]Chafe.2
直到ShowWindow函数,才显示出窗口,前面一直是在进行一些窗口的初始化操作
[160CRACKME]Chafe.2
后面一个大循环,在循环里面看到GetMessage函数,这个函数可以实现获取源源不断的消息,因为所有在窗口上的输入消息,都会放到应用程序的消息队列里,然后再发送给窗口回调函数处理。
[160CRACKME]Chafe.2
目的是了解程序如何对用户输入的文本进行操作,势必要跳出循环。
Ctrl+F2重新加载,这次直接按F9让程序跑飞,这样才能输入测试数据。
[160CRACKME]Chafe.2
输入完测试数据之后,可以注意到在循环的下一步,程序开始获取文本框的输入,有个GetDlgItemInt函数,给它下个断点,点一下文本框,程序便停在了这个函数的位置,这样就可以看程序对数据做了什么处理。
首先要弄清楚输入文本都被存入了哪里。
[160CRACKME]Chafe.2
MSDN文档查找一下GetDlgItemInt函数,这个函数意在实现int型读取用户输入文本框的内容并返回。pSuccess指向用户输入的序列号所在的内存单元的地址,即0x0018F920。
GetWindowTextA函数就是获取文本框的文本,把文本存入了Buffer指向的内存(从OD看出Buffer指向的地址是0x0040316C)
[160CRACKME]Chafe.2
下拉发现在对用户名跟序列号处理的代码下面一些奇怪的汇编指令,且没有跳转指向输入正确的提示。推测这里是SMC。[160CRACKME]Chafe.2
先分析一下程序对数据的处理。[160CRACKME]Chafe.2

004012A3    .  A1 0B304000     mov     eax, dword ptr [40300B];常量0x58455443存入eax
004012A8    . BB6C314000       mov     ebx,0040316C           ;ASCII "123456"

004012AD    >  0303            add     eax, dword ptr [ebx]
004012AF    .  43              inc     ebx
004012B0    .  81FB 7C314000   cmp     ebx, 0040317C
004012B6    .^ 75 F5           jnz     short 004012AD;输入的用户名“123456”循环16次每次读取4个字节累加到常量0x58455443

004012B8    .  5B              pop     ebx;输入的序列号存入ebx
004012B9    .  03C3            add     eax, ebx
004012BB    .  3105 D9124000   xor     dword ptr [4012D9], eax;常量0x584554(0x4012D9处的字节码)跟累加后的值异或【SMC】
004012C1    .  C1E8 10         shr     eax, 10;异或后右移16位
004012C4    .  66:2905 D9124  >sub     word ptr [4012D9], ax;异或后的值减去累加后的值,可以注意到0x4012D9指向的不是数据,而是那一段奇怪的代码的地址,明显在对0x4012D9的代码进行修改。【SMC】

现在分析一下这部分SMC,之所以没有跳转指令跳转到提示正确的字符的位置,推测是因为SMC自修改出来的代码就是缺失的跳转语句。
但跳转到自修改出的跳转语句之前,还有一部分bx跟ax异或0x3E次的,
这边有个lods 取串指令(把源串中的元素(字或字节)逐一装入AL或AX中),从si寄存器存放的地址处,也就是0x4011EC处开始取串,然后必须要异或出固定的值0xAFFCCFFB才会有后来的跳转。

这里的循环后期写注册机的时候其实是可以忽略的,因为这个循环主要的作用是进一步验证SMC出的代码是不是jmp到yes字符串,而破解的话只要前面的数据处理就能爆破出来了。
[160CRACKME]Chafe.2
理清程序的大体过程之后可以写注册机。

(二)注册机

源代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string>
using namespace std;
int main()
{	
	char usrname[20] = { 0 };
	int serial = 0x58455443, temp = 0, temp1 = 0,n;
	printf("username:");
	scanf("%s", usrname);
	for (int i = 0; i < 16; i++)
		serial += *(int *)(usrname + i);

	for (int j = 0; j < 0xFFFFFFFF; j++)
	{
		temp = (0x584554 ^ (serial + j))-((serial + j) >> 16);
		if (temp == 0x585426EB)
		{
			printf("serial:%u", j);
			break;
		}
	}
	return 0;
}

后来发现temp = (0x584554 ^ (serial + j))-((serial + j) >> 16);这一步可以优化,用分步运算,
先算高四位的值

(0x58 ^ ((serial + j)>>16))==0x5854,

后算第四位的值,

(0x4554 ^ ((serial + j)&0x0000FFFF))-((serial + j) >> 16)==0x26EB

可以看出最后序列号与累加后的用户名的和其实等于一个常数,优化之后的程序源码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string>
using namespace std;
int main()
{	
	char usrname[20] = { 0 };
	int serial = 0x58455443, temp = 0, temp1 = 0,n;
	printf("username:");
	scanf("%s", usrname);
	for (int i = 0; i < 16; i++)
		serial += *(int *)(usrname + i);

	printf("Serial:%u\n", 0x580C3BA3 - serial);
	return 0;
}

(三)实现

[160CRACKME]Chafe.2
[160CRACKME]Chafe.2

上一篇:A4988驱动NEMA步进电机(42步进电机)


下一篇:Arduino 自定义函数