首页
社区
课程
招聘
[原创]看雪2016 第八题 CrackMe逆向分析
发表于: 2016-11-18 10:40 2951

[原创]看雪2016 第八题 CrackMe逆向分析

2016-11-18 10:40
2951
启动x64_dbg打开crackme,在ReadFile处下断,F9运行,输入666666来到断点处。向上回溯调用栈,来到如下地址(IDA中查看该地址,x64_dbg对中文支持的不好)
.text:000000014000194C                 test    al, al
.text:000000014000194E                 jz      short loc_140001995
.text:0000000140001950                 lea     rcx, aVSI       ; "注册码:"
.text:0000000140001957                 call    print
.text:000000014000195C                 lea     r8, [rsp+30h]
.text:0000000140001961                 lea     rdx, [rsp+20h]
.text:0000000140001966                 lea     rcx, aDaS       ; "%dA%s"
.text:000000014000196D                 call    scanf
.text:0000000140001972                 call    sub_14000A634
.text:0000000140001977                 mov     ecx, [rsp+20h]
.text:000000014000197B                 call    sub_140001300        ; 这里通过注册码计算返回x1
.text:0000000140001980                 test    eax, eax
.text:0000000140001982                 jnz     short loc_1400019AF
.text:0000000140001984                 lea     rcx, aVSI_0     ; "注册码有误!\n"
.text:000000014000198B                 call    print
.text:0000000140001990                 call    sub_14000A634
.text:0000000140001995
.text:0000000140001995 loc_140001995:                          ; CODE XREF: .text:000000014000194Ej
.text:0000000140001995                 xor     eax, eax
.text:0000000140001997                 mov     rcx, [rsp+430h]
.text:000000014000199F                 xor     rcx, rsp
.text:00000001400019A2                 call    sub_1400019D0

发现 scanf的参数为"%dA%s",指定sn的格式为数字+字符,重新开始注册码改为2A2后向下分析,A前面的为sn1,A后面的为sn2。

.text:000000014000197B                 call    sub_140001300
这个函数输入sn1,通过计算后输出x1,计算过程为

int  sub_140001300(signed int a1)
{
	int v1; // er9@1
	signed int v2; // er11@1
	signed int v3; // er8@1
	__int64 v6; // rax@8

	v1 = 0;
	v2 = a1;
	v3 = 1;

	v6 = 0;
	do
	{
		++v6;
		a1 /= 10;
	} while (a1);

	do
	{
		v3 *= 10;
		--v6;
	} while (v6);

	do{
		++v1;
	}while ((signed int)(v1 * v1) % v3 != v2);

	return v1;
}

表达式为:(x1*x1)%up(sn1)=sn1,up()为向上取整。

之后来到函数
00000001400014B0 | 48 89 54 24 10           | mov qword ptr ss:[rsp+10],rdx           |
00000001400014B5 | 89 4C 24 08              | mov dword ptr ss:[rsp+8],ecx            |
00000001400014B9 | 53                       | push rbx                                |
00000001400014BA | 56                       | push rsi                                |
00000001400014BB | 57                       | push rdi                                |
00000001400014BC | 41 56                    | push r14                                |
00000001400014BE | 41 57                    | push r15                                |
00000001400014C0 | 48 83 EC 40              | sub rsp,40                              |
00000001400014C4 | 33 DB                    | xor ebx,ebx                             |
00000001400014C6 | C7 05 EC 47 02 00 01 00  | mov dword ptr ds:[140025CBC],1          |
00000001400014D0 | 44 8B FB                 | mov r15d,ebx                            |
00000001400014D3 | 44 8B C3                 | mov r8d,ebx                             |

这个函数挺大,主要的为下面这段
00000001400018A7 | 48 63 C6                 | movsxd rax,rsi                          | ;a=2
00000001400018AA | 49 63 D6                 | movsxd rdx,r14                          | ;b=2
00000001400018AD | 48 8D 0C 90              | lea rcx,qword ptr ds:[rax+rdx*4]        | ;c = a+b*4
00000001400018B1 | 48 03 D1                 | add rdx,rcx                             | ;b += c
00000001400018B4 | 48 8D 05 05 44 02 00     | lea rax,qword ptr ds:[140025CC0]        | ;t1 [dword]
00000001400018BB | 8B 0D 63 44 02 00        | mov ecx,dword ptr ds:[140025D24]        | ;y=2
00000001400018C1 | 0F AF CF                 | imul ecx,edi                            | ;d = y*x1
00000001400018C4 | 03 0C 90                 | add ecx,dword ptr ds:[rax+rdx*4]        | ;d += t1
00000001400018C7 | 8D 04 7F                 | lea eax,dword ptr ds:[rdi+rdi*2]        | ;e=x1+x1*2
00000001400018CA | 3B C8                    | cmp ecx,eax                             | ;e == d

这里需要e=d才能注册成功,其表达式为
x1+x1*2 == x1*y + t1[b+a+b*4]

通过实验发现sn2不变,则t1不变,sn2为2时t1数据如下:

sn2=2
26 01 00 00 2E 01 00 00 36 00 00 00 3C 01 00 00
0F 01 00 00 3D 01 00 00 3B 01 00 00 35 01 00 00
65 01 00 00 04 01 00 00 00 01 00 00 1C 01 00 00
00 00 00 00 22 01 00 00 3C 01 00 00 39 01 00 00
22 01 00 00 28 01 00 00 1E 01 00 00 00 01 00 00
1C 01 00 00 03 01 00 00 78 01 00 00 24 01 00 00
15 01 00 00 02 00 00 00 02 00 00 00 00 00 00 00
04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a = 2, b=3, y = 2
t = 0128

所以表达式为:x1+x1*2 == x1*2 + 0128
好吧,x1需要等于 0128

由于x1是求余,所以存在多解,需要枚举,代码如下:

#include "stdafx.h"

int  sub_140001300(signed int a1)
{
	int v1; // er9@1
	signed int v2; // er11@1
	signed int v3; // er8@1
	__int64 v6; // rax@8

	v1 = 0;
	v2 = a1;
	v3 = 1;

	v6 = 0;
	do
	{
		++v6;
		a1 /= 10;
	} while (a1);

	do
	{
		v3 *= 10;
		--v6;
	} while (v6);

	do{
		++v1;
		if (v1 > 0x200)
			return -1;
	}while ((signed int)(v1 * v1) % v3 != v2);

	return v1;
}

int _tmain(int argc, _TCHAR* argv[])
{
	for (int i = 2; i < 10000; i++)
	{
		int x = sub_140001300(i);
		if (x > 0)
		{
			printf("%d = %08X\n", i, x);
			if (x == 0x128)
				break;
		}
	}
	//2 = 00016A0A
	//3 = 00010001
	//4 = 00000002
	//5 = 00000005
	//6 = 00000004
	//7 = 00016A0B
	//8 = 00010002
	//9 = 00000003
	//12 = 00016A1A
	//13 = 0001000B
	return 0;
}



sn = 7616A2

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//