2021 Mar-Dasctf re赛后复盘

本文最后更新于:2 年前

本文首发于看雪论坛

这次比赛, 没有向以前一样爆零了,就很舒服

赛后官方提供了复盘,就用 复盘一下,写一下wp

drinkSomeTea

img

主函数逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
int __cdecl main(int argc, const char **argv, const char **envp)
{
HANDLE v3; // eax
void *v4; // esi
int result; // eax
DWORD v6; // edi
char *v7; // esi
DWORD v8; // ebx
HANDLE v9; // eax
void *v10; // esi
DWORD NumberOfBytesRead; // [esp+Ch] [ebp-8h] BYREF
DWORD NumberOfBytesWritten; // [esp+10h] [ebp-4h] BYREF

sub_401000();
puts(aWelcomeToMyTea);
v3 = CreateFileA(FileName, 0xC0000000, 0, 0, 3u, 0x80u, 0);
v4 = v3;
if ( v3 == (HANDLE)-1 )
{
puts(aIThinkYouDoNot);
result = 0;
}
else
{
v6 = GetFileSize(v3, 0);
if ( v6 < 0xEA60 )
{
SetFilePointer(v4, 0, 0, 0);
NumberOfBytesRead = 0;
ReadFile(v4, &unk_409988, v6, &NumberOfBytesRead, 0);
CloseHandle(v4);
if ( v6 >> 3 )
{
v7 = (char *)&unk_409988;
v8 = v6 >> 3;
do
{
// 关键函数,但是被 嵌入了花指令, 负责了关键部分数据处理
((void (__cdecl *)(char *, void *))loc_4010A0)(v7, &unk_407030);
v7 += 8;
--v8;
}
while ( v8 );
}
v9 = CreateFileA(aTeaPngOut, 0xC0000000, 0, 0, 2u, 0x80u, 0);
v10 = v9;
if ( v9 == (HANDLE)-1 )
{
puts(aIThinkYouDoNot);
}
else
{
NumberOfBytesWritten = 0;
WriteFile(v9, &unk_409988, v6, &NumberOfBytesWritten, 0);
CloseHandle(v10);
puts(aNowThisCupOfTe);
}
result = 0;
}
else
{
puts(aYourTeaIsTooHo);
result = 0;
}
}
return result;
}

去花指令

img

明显的一个 tea 加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int *__cdecl sub_4010A0(int *a1, _DWORD *a2)
{
int *result; // eax
int v3; // [esp+Ch] [ebp-14h]
int i; // [esp+14h] [ebp-Ch]
int v5; // [esp+18h] [ebp-8h]
int v6; // [esp+1Ch] [ebp-4h]

v5 = 0;
v6 = a1[1];
v3 = *a1;
for ( i = 0; i < 32; ++i )
{
v5 -= 0x61C88647;
v3 += (a2[1] + (v6 >> 5)) ^ (v5 + v6) ^ (*a2 + 16 * v6);
v6 += (a2[3] + (v3 >> 5)) ^ (v5 + v3) ^ (a2[2] + 16 * v3);
}
a1[1] = v6;
result = a1;
*a1 = v3;
return result;
}

密钥在main 函数里面

flag{fake_flag!}get out!

解密代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// tea加解密.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

#include <stdio.h>


void decrypt(unsigned int* v, unsigned int* key) {
int l; // [esp+Ch] [ebp-14h]
int sum; // [esp+18h] [ebp-8h]
int r; // [esp+1Ch] [ebp-4h]

r = v[1];
l = v[0];
sum = 0xC6EF3720;
for (size_t i = 0; i < 32; i++) {
//sum -= 0x61C88647;
r -= (key[3] + (l >> 5)) ^ (sum + l) ^ (key[2] + (16 * l));
l -= (key[1] + (r >> 5)) ^ (sum + r) ^ (key[0] + (16 * r));
sum += 0x61C88647;

//r -= ((l *16) + key[2]) ^ (l + sum) ^ ((l >> 5) + key[3]);
//l -= ((r * 16) + key[0]) ^ (r + sum) ^ ((r >> 5) + key[1]);
}
v[0] = l;
v[1] = r;
}

void de_file() {
char file_path[] = { "C:\\Users\\Dell\\Desktop\\Test\\tea.png.out" };

FILE* file_point = fopen(file_path, "rb");
fseek(file_point, 0, SEEK_END);
int len = ftell(file_point);
fseek(file_point, 0, SEEK_SET);
char* file_content = (char*)malloc(len);
memset(file_content, 0,len);

fread(file_content, 1, len, file_point);

fclose(file_point);

char new_file_path[] = { "C:\\Users\\Dell\\Desktop\\Test\\tea.png" };

FILE* new_file_point = fopen(new_file_path, "wb");
char secry_key[] = {
0x66, 0x6C, 0x61, 0x67, 0x7B, 0x66, 0x61, 0x6B, 0x65, 0x5F,
0x66, 0x6C, 0x61, 0x67, 0x21, 0x7D, 0x67, 0x65, 0x74, 0x20,
0x6F, 0x75, 0x74, 0x21, 0x20, 0x0A, 0x00
};

for (int i = 0; i < len; i += 8) {
decrypt((unsigned int*)(file_content + i), (unsigned int*)secry_key);
}
fwrite(file_content, 1, len, new_file_point);
fclose(new_file_point);
}


void main() {

de_file();
}

有点坑, 当使用魔数 0x61C88647 时, 解密的初始化数值必须是 0xC6EF3720

img

Enjoyit-1

img

de4dot 反混淆后,base64 变表解密,得到key, 再修改代码,输入key 即可得到flag

img

将所有等待时间删掉

img

getflag

replace

是一个 hook ,将 IsDebugParent 执行流程替换, 再里面将 最后的比较进行了替换, 有一层很复杂的东西, 手撕不动(指我自己) , 哭了,我怎么这么菜

main 函数

代码简洁,易懂

img

最后替换的函数,也是解题的关键

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from binascii import *
from hashlib import md5

ans=unhexlify("416f6b116549435c2c0f1143174339023d4d4c0f183e7828")
tmps=[0,6,12,18]
seq=[]


for i in range(6):
tmpl=[x+i for x in tmps]
seq=seq+tmpl

print(seq)
arr1=[0 for i in range(24)]
for i in range(24):
arr1[seq[i]]=ans[i]

box=[0x00000080, 0x00000065, 0x0000002F, 0x00000034, 0x00000012, 0x00000037, 0x0000007D, 0x00000040, 0x00000026, 0x00000016, 0x0000004B, 0x0000004D, 0x00000055, 0x00000043, 0x0000005C, 0x00000017, 0x0000003F, 0x00000069, 0x00000079, 0x00000053, 0x00000018, 0x00000002, 0x00000006, 0x00000061, 0x00000027, 0x00000008, 0x00000049, 0x0000004A, 0x00000064, 0x00000023, 0x00000056, 0x0000005B, 0x0000006F, 0x00000011, 0x0000004F, 0x00000014, 0x00000004, 0x0000001E, 0x0000005E, 0x0000002D, 0x0000002A, 0x00000032, 0x0000002B, 0x0000006C, 0x00000074, 0x00000009, 0x0000006E, 0x00000042, 0x00000070, 0x0000005A, 0x00000071, 0x0000001C, 0x0000007B, 0x0000002C, 0x00000075, 0x00000054, 0x00000030, 0x0000007E, 0x0000005F, 0x0000000E, 0x00000001, 0x00000046, 0x0000001D, 0x00000020, 0x0000003C, 0x00000066, 0x0000006B, 0x00000076, 0x00000063, 0x00000047, 0x0000006A, 0x00000029, 0x00000025, 0x0000004E, 0x00000031, 0x00000013, 0x00000050, 0x00000051, 0x00000033, 0x00000059, 0x0000001A, 0x0000005D, 0x00000044, 0x0000003E, 0x00000028, 0x0000000F, 0x00000019, 0x0000002E, 0x00000005, 0x00000062, 0x0000004C, 0x0000003A, 0x00000021, 0x00000045, 0x0000001F, 0x00000038, 0x0000007F, 0x00000057, 0x0000003D, 0x0000001B, 0x0000003B, 0x00000024, 0x00000041, 0x00000077, 0x0000006D, 0x0000007A, 0x00000052, 0x00000073, 0x00000007, 0x00000010, 0x00000035, 0x0000000A, 0x0000000D, 0x00000003, 0x0000000B, 0x00000048, 0x00000067, 0x00000015, 0x00000078, 0x0000000C, 0x00000060, 0x00000039, 0x00000036, 0x00000022, 0x0000007C, 0x00000058, 0x00000072, 0x00000068]
arr2=[0 for i in range(24)]
for i in range(5):
for j in range(24):
arr2[j]=box.index(arr1[j])
arr1=arr2
myInput=''.join(map(chr,arr1))
print(myInput)
flag=myInput.encode()
print(md5(flag).hexdigest()) # 别忘了最后提交md5

这个代码是大师傅写的, 不是我, 在此感谢大师傅

变形栅栏 + 盒子变换

最后 md5 提交

这题,比赛的时候,上面的盒子变换都给我看傻了, 下面的栅栏直接给我干死,然后直接放弃这一题, 看师傅们随随便便解出来,我真的感觉自己是个废物

奇怪的扫雷

这题预期解是 开发扫雷外挂,并在几秒钟内解出来。 然后我也看不懂里面的代码,连异常咋触发的都看不懂, 哭了。靠着师傅们的wp, 勉强维持生活。

img

最后在出题人师傅不留余力的帮助下,完成了 扫雷外挂的开发, 太难了

img

使用工具:

  1. vs2019

  2. spy++

  3. ce

这里面出题人师傅关闭了 aslr , 所以基地址是直接固定的, 格子的大小是 16 * 16 ,sendmessage 点击是呈比例的, 和缩放与布局有关, 其他的也没啥, 具体参考:

https://www.xuenixiang.com/thread-2989-1-1.html 大神写的

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// q师傅扫雷外挂开发.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<Windows.h>
#include "assert.h"


#define MAPHEAD 0x0019627C
#define MAPHEIGHT 0x19623C
#define MAPWIDTH 0x196240

struct SigData {
DWORD sate;
DWORD flag;
}Pro;


int GetScaling() {
// 获取窗口当前显示的监视器
// 使用桌面的句柄.
HWND hWnd = GetDesktopWindow();
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);

// 获取监视器逻辑宽度与高度
MONITORINFOEX miex;
miex.cbSize = sizeof(miex);
GetMonitorInfo(hMonitor, &miex);
int cxLogical = (miex.rcMonitor.right - miex.rcMonitor.left);
int cyLogical = (miex.rcMonitor.bottom - miex.rcMonitor.top);

// 获取监视器物理宽度与高度
DEVMODE dm;
dm.dmSize = sizeof(dm);
dm.dmDriverExtra = 0;
EnumDisplaySettings(miex.szDevice, ENUM_CURRENT_SETTINGS, &dm);
int cxPhysical = dm.dmPelsWidth;
int cyPhysical = dm.dmPelsHeight;

// 缩放比例计算 实际上使用任何一个即可
double horzScale = ((double)cxPhysical / (double)cxLogical);
double vertScale = ((double)cyPhysical / (double)cyLogical);
assert(horzScale == vertScale); // 宽或高这个缩放值应该是相等的


return (int)round(16.0 / horzScale);
}


int main()
{
int height = 0;
int width = 0;
DWORD MainPid = 0;
HWND MainHwnd = FindWindow(NULL, TEXT("奇怪的扫雷"));
GetWindowThreadProcessId(MainHwnd, &MainPid);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, MainPid);

SIZE_T size = 4;
ReadProcessMemory(hProcess, (LPCVOID)MAPWIDTH, &width, 4, &size);
ReadProcessMemory(hProcess, (LPCVOID)MAPHEIGHT, &height, 4, &size);
int LeiCount = 0;
LPCVOID tmp = NULL;
SIZE_T ProSize = 8;

int Scalie = GetScaling();
for (int x = 1; x < height + 1; x++) {
for (int y = 0; y < width; y++) {
ReadProcessMemory(hProcess, (LPCVOID)(MAPHEAD + ((x - 1) * width + y) * 4), &tmp, 4, &size);
ReadProcessMemory(hProcess, (LPCVOID)tmp, &Pro, 8, &ProSize);

int xPos, yPos;
xPos = (y * Scalie) + 26;
yPos = (x * Scalie) + 46;

if (Pro.flag == 0xffffffff) {

SendMessage(MainHwnd, WM_RBUTTONDOWN, 0, MAKELPARAM(xPos, yPos));
SendMessage(MainHwnd, WM_RBUTTONUP, 0, MAKELPARAM(xPos, yPos));
printf("雷 ");

LeiCount++;
}
else {

SendMessage(MainHwnd, WM_LBUTTONDOWN, 0, MAKELPARAM(xPos, yPos));
SendMessage(MainHwnd, WM_LBUTTONUP, 0, MAKELPARAM(xPos, yPos));


printf("无 ");
}
}

printf("\n");
}

printf("\n有雷: %d 个, 高:%d, 宽: %d", LeiCount, height, width);

return 1;
}


getflag


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!