-
-
[原创]看雪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,计算过程为
表达式为:(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是求余,所以存在多解,需要枚举,代码如下:
sn = 7616A2
.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期)
赞赏
他的文章
- [原创]C++类成员指针调用 4321
- [原创]VMP3.2授权分析 53966
- [原创]看雪CTF2017 第十二题分析 5080
- [原创]看雪CTF2017 第十一题分析 6218
- [原创]看雪CTF2017 第十题分析 5834
看原图
赞赏
雪币:
留言: