目录文件

  1. RE.exe 最终的题目文件
  2. resexe .bak 这是进程2的PE文件,将其加密后存放在了RE.exe的资源段

链接:https://pan.baidu.com/s/1gEOMjqnrdsdoZUPE0rAknw
提取码:r5qi


出题思路及考察知识点

出题思路

出了一道多进程的题目,进程1在TLS_CALLBACK0(Reason为DLL_PROCESS_ATTACH) 的时候输入FLAG,如果没有调试,就动态添加TLS_CALLBACK1

这时候EIP来到了 TLS_CALLBACK1(Reason为DLL_PROCESS_ATTACH ), 在其中HOOK掉WriteFile函数,然后ExitProcess()

EIP来到了 TLS_CALLBACK0(Reason为DLL_PROCESS_DETACH) , 将进程2释放出来并启动,在进程2中对flag的前半段进行验证,进程1通过进程2的ExitCode来验证flag的前半段是否正确,如果正确则验证flag 的后半段。

进程1采用的算法就是普通的XXTEA,而进程2采用的是魔改XXTEA(因为如果不调试就HOOK 了WriteFile函数, 在HOOK后的WriteFile函数中修改了解密出来的进程2的PE文件的几个汇编代码,将 xxtea中的 >> 5改为了 >>6)

考察知识点

IAT-HOOK技术, TLS反调试,多进程通信, 去除简单的花指令等。


FLAG

flag为: miniLctf{cbda59ff59e3e90c91c02e9b40b78b}


程序源码

进程1

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
//最终版源码
#include <windows.h>
#include <stdio.h>
#include <Tlhelp32.h>
#include <winternl.h>
#include <winnt.h>
#include "resource.h"

//flag : miniLctf{cbda59ff59e3e90c91c02e9b40b78b},长度为40
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))

//WriteFile函数指针,后面HOOK的时候用
typedef BOOL(WINAPI* PWRITEFILE)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);

//函数声明区
void xxtea_enc(DWORD* v, int n, DWORD const key[4]); //XXTEA 加密
void save_res(); //保存资源文件
void debuger_main_loop(char* name, void* ppi); //调试器主循环
DWORD WINAPI MyWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); //MyWriteFile函数
BOOL SetIATHook(DWORD dwOldFuncAddr, DWORD dwNewFuncAddr, HANDLE hApiModule); //导入表HOOK
BOOL UnIATHook(DWORD dwOldFuncAddr, DWORD dwNewFuncAddr, HANDLE hApiModule); //导入表UNHOOK
char * decstring(char * str); //真正的字符串都被加密了,防止F12找到关键点
void print_console(const char* szMsg); //在TLS中用printf有可能失败
void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved); //TLS回调函数1
void NTAPI TLS_CALLBACK2(PVOID DllHandle, DWORD Reason, PVOID Reserved); //TLS回调函数2
void dec_res(char* buffer, int len); //解密资源文件
void nouse(); //对tls进行操作,否则编译的时候tls结构体没有编译进去

//全局变量区
PWRITEFILE g_dwOldFuncAddr; //H0OK的时候保存旧函数地址
DWORD g_dwNewFuncAddr; //HOOK的时候保存新函数地址
DWORD g_dwIATHookFlag = FALSE; //刚开始是没有HOOK的
HMODULE hAPIModule; //指向要HOOK的API所在的DLL文件的基址
DWORD DELTA = 0x9E3779B9; //XXTEA加密的DELTA
DWORD xxteaKey[] = { 0x12,0x34,0x56,0x78 }; //XXTEA加密所需的KEY
char enc_flag2[20] = { 0x21, 0xa9, 0x21, 0x90, 0x60, 0x30, 0x3b, 0xf5, 0x4e, 0xa8, 0x88, 0x8e, 0xd5, 0x5a, 0x63, 0x43, 0x39, 0x92, 0x11, 0xac }; //加密flag的后20个字符的密文
DWORD dwExitCode = 0; //进程2的退出码,通过这个退出码进行判断flag的前半段是否正确,或者程序是否正在被调试
DEBUG_EVENT debug_event = { 0 }; //用于调试器循环
DWORD tls_nouse = 0; //保存在自定义的TLS结构中,无用
PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { TLS_CALLBACK1, NULL, NULL }; //TLS回调函数数组
IMAGE_TLS_DIRECTORY tls = { (DWORD)&tls_nouse, (DWORD)&tls_nouse, (DWORD)&tls_nouse, (DWORD)pTLS_CALLBACKs,0,0 }; //自定义的TLS结构体,后续直接修改PE文件数据目录表对应TLS的那部分即可
char* pbuffer; //指向共享内存
HANDLE hFileMap; //文件映射句柄


int main()
{
//main函数其实没有被调用
//假的验证程序 假的flag "You_are_too_young_this_is_a_fake_flag!!!"
char fake_enc[] = { 38, 17, 8, 35, 26, 8, 28, 39, 3, 25, 26, 43, 10, 29, 4, 30, 8, 49, 25, 4, 2, 25, 54, 1, 20, 57, 4, 59, 5, 3, 10, 5, 0, 56, 49, 61, 60, 123, 120, 121 };
char flag[100] = { 0 };
printf("Please input your flag: ");
scanf("%s", flag);
int i = 0;
for (i = 0; i < 40; i++)
{
if ((flag[i] ^ 0x7F ^ i) != fake_enc[i])
break;
}
if (i == 40)
{
printf("correct\n");
}
else {
printf("wrong\n");
}
return 0;
}

void xxtea_enc(DWORD* v, int n, DWORD const key[4])
{
DWORD y, z, sum;
unsigned p, rounds, e;
rounds = 6 + 52 / n;
sum = 0;
z = v[n - 1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++)
{
y = v[p + 1];
z = v[p] += MX;
}
y = v[0];
z = v[n - 1] += MX;
} while (--rounds);
}

void save_res() {
char name[] = { 81, 80, 11, 18, 15,0 }; //"./tmp"
char resname[] = { 58, 39, 58, 45, 58, 44, 0 }; //EXERES
decstring(name);
decstring(resname);
HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCEA(IDR_EXERES1), TEXT(resname));
DWORD dwSize = SizeofResource(NULL, hRsrc);
HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
LPVOID pBuffer = LockResource(hGlobal);
dec_res((char *)pBuffer, dwSize);
HANDLE hFile = CreateFile(name,
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);


DWORD dwWritenSize = 0;
BOOL bRet = ::WriteFile(hFile, pBuffer, dwSize, &dwWritenSize, NULL);
FlushFileBuffers(hFile);
CloseHandle(hFile);
}

void debuger_main_loop(char* name, void* ppi)
{
PROCESS_INFORMATION pi = *(PROCESS_INFORMATION*)ppi;
BOOL bRunning = TRUE;
__asm {
call label;
label:
add dword ptr[esp], 5;
ret;
}

while (bRunning)
{
WaitForDebugEvent(&debug_event, INFINITE);
if (debug_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) {
EXCEPTION_DEBUG_INFO exception = debug_event.u.Exception;
switch (exception.ExceptionRecord.ExceptionCode)
{
case STATUS_ACCESS_VIOLATION: {
//print_console("addr: %#X\n", exception.ExceptionRecord.ExceptionAddress);
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_FULL;
GetThreadContext(pi.hThread, &ctx);
ctx.Eip += 5;
ctx.Eax ^= 111111;
SetThreadContext(pi.hThread, &ctx);
}
default:
break;
}
}
if (debug_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) //进程结束,退出调试器
{
dwExitCode = debug_event.u.ExitProcess.dwExitCode;
//print_console("ExitCode : %d\n", dwExitCode);
bRunning = FALSE;
}

//print_console("debug_event_code:%d,pid: %d\n", debug_event.dwDebugEventCode, debug_event.dwProcessId);
ContinueDebugEvent(debug_event.dwProcessId,
debug_event.dwThreadId,
DBG_CONTINUE);
}

Sleep(100);
int a = DeleteFile(name);
//print_console("DeleteFile: %d\n", a);
}

DWORD __stdcall MyWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
{
char* buffer = (char*)lpBuffer;
buffer[0x71C + 2] = 0x6; //魔改xxtea 将>>5 改为 >>6
buffer[0x6AF + 2] = 0x6;
g_dwOldFuncAddr(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
UnIATHook((DWORD)g_dwOldFuncAddr, (DWORD)MyWriteFile, hAPIModule);
return 0;
}

BOOL SetIATHook(DWORD dwOldFuncAddr, DWORD dwNewFuncAddr, HANDLE hApiModule)
{
HMODULE hModule = GetModuleHandle(NULL); //获取当前模块基址
//开始找导入表
IMAGE_DOS_HEADER* pIDH = (IMAGE_DOS_HEADER*)hModule;
IMAGE_NT_HEADERS* pINH = (IMAGE_NT_HEADERS*)(pIDH->e_lfanew + (DWORD)hModule);
IMAGE_IMPORT_DESCRIPTOR* pFirstIID = (IMAGE_IMPORT_DESCRIPTOR*)(pINH->OptionalHeader.DataDirectory[1].VirtualAddress + (DWORD)hModule);
IMAGE_IMPORT_DESCRIPTOR* pTempIID = pFirstIID; //找到了第一个IMAGE_IMPORT_DESCRIPTOR结构

DWORD pOldProtect = 0;

while (pTempIID->FirstThunk && g_dwIATHookFlag == FALSE) //当没有挂钩子并且FirstThunk不为0的时候,继续遍历
{
if (hApiModule == GetModuleHandle((char*)((DWORD)hModule + pTempIID->Name)))
{
DWORD* pTemp = (DWORD*)(pTempIID->FirstThunk + (DWORD)hModule);
while (pTemp)
{
if (*pTemp == (DWORD)dwOldFuncAddr)
{
VirtualProtect(pTemp, 4, PAGE_READWRITE, &pOldProtect);
*pTemp = dwNewFuncAddr;
VirtualProtect(pTemp, 4, pOldProtect, NULL);
g_dwIATHookFlag = TRUE;
break;
}
pTemp++;
}
}
pTempIID++;
if (g_dwIATHookFlag)
break;
}
return g_dwIATHookFlag;
}

BOOL UnIATHook(DWORD dwOldFuncAddr, DWORD dwNewFuncAddr, HANDLE hApiModule)
{
HMODULE hModule = GetModuleHandle(NULL); //获取当前模块基址
IMAGE_DOS_HEADER* pIDH = (IMAGE_DOS_HEADER*)hModule;
IMAGE_NT_HEADERS* pINH = (IMAGE_NT_HEADERS*)(pIDH->e_lfanew + (DWORD)hModule);
IMAGE_IMPORT_DESCRIPTOR* pFirstIID = (IMAGE_IMPORT_DESCRIPTOR*)(pINH->OptionalHeader.DataDirectory[1].VirtualAddress + (DWORD)hModule);
IMAGE_IMPORT_DESCRIPTOR* pTempIID = pFirstIID; //找到了第一个IMAGE_IMPORT_DESCRIPTOR结构

DWORD pOldProtect = 0;

while (pTempIID->FirstThunk && g_dwIATHookFlag == TRUE) //当没有挂钩子并且FirstThunk不为0的时候,继续遍历
{
if (hApiModule == GetModuleHandle((char*)((DWORD)hModule + pTempIID->Name))) //先找该函数所属的模块
{
DWORD* pTemp = (DWORD*)(pTempIID->FirstThunk + (DWORD)hModule);
while (pTemp)
{
if (*pTemp == (DWORD)dwNewFuncAddr)
{
VirtualProtect(pTemp, 4, PAGE_READWRITE, &pOldProtect); //将存储这个地址的地址的属性设置为可读可写
*pTemp = dwOldFuncAddr;
VirtualProtect(pTemp, 4, pOldProtect, NULL); //保护模式
g_dwIATHookFlag = FALSE;
break;
}
pTemp++;
}
}
pTempIID++;
if (!g_dwIATHookFlag)
break;
}
return g_dwIATHookFlag;
}

char * decstring(char* str)
{
for (int i = 0; i < strlen(str); i++)
{
str[i] ^= 0x7F;
}
return str;
}

void print_console(const char* szMsg)
{
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsoleA(hStdout, szMsg, strlen(szMsg), NULL, NULL);
}

void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
__asm {
call label;
label:
add dword ptr[esp], 30; //4字节
ret;
_emit 87; //Welcome_to_2022_miniLCTF\0
_emit 101;
_emit 108;
_emit 99;
_emit 111;
_emit 109;
_emit 101;
_emit 95;
_emit 116;
_emit 111;
_emit 95;
_emit 50;
_emit 48;
_emit 50;
_emit 50;
_emit 95;
_emit 109;
_emit 105;
_emit 110;
_emit 105;
_emit 76;
_emit 67;
_emit 84;
_emit 70;
_emit 0
}
if (Reason == 1) // DLL_PROCESS_ATTACH
{
char szMsg[80] = { 0 };
print_console(szMsg);
bool dwDebugPort = 0; // 监测是否是调试
__asm {
mov eax, fs: [30h]
mov al, BYTE PTR[eax + 2]
mov dwDebugPort, al
}

if (!dwDebugPort) // 动态注册TLS回调函数
{
__asm {
call label1;
label1:
add dword ptr[esp], 5; // 4字节
ret;
}
//print_console("not debug\n");
pTLS_CALLBACKs[1] = TLS_CALLBACK2;
}

char sharememname[] = { 57, 51, 62, 56 ,0 };
decstring(sharememname);
hFileMap = CreateFileMapping(NULL, NULL, PAGE_READWRITE, 0, 0x1000, sharememname);
pbuffer = (char*)MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0X1000);
char inputFlagstr[] = { 47,19,26,30,12,26,95,22,17,15,10,11,95,6,16,10,13,95,25,19,30,24,69,95,0 }; //"Please input your flag: "
print_console(decstring(inputFlagstr));
char _formatstr[] = { 90, 12, 0 }; // %s
decstring(_formatstr);
scanf_s(_formatstr, pbuffer, 41); //限定输入最大长度是40
}
if (Reason == 0) //DLL_PROCESS_DETACH
{
char name[] = { 81, 80, 11, 18, 15,0 }; //"./tmp"
decstring(name);
save_res();
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi;
si.cb = sizeof(si);
CreateProcess(
name,
NULL,
NULL,
NULL,
FALSE,
DEBUG_ONLY_THIS_PROCESS | DEBUG_PROCESS,
NULL,
NULL,
&si,
&pi
);

char correct[] = { 28, 16, 13, 13, 26, 28, 11, 117 ,0 }; //"correct\n"
char wrong[] = { 8, 13, 16, 17, 24, 117, 0 }; //"wrong\n"
char checkdebugerstr[] = { 47, 19, 26, 30, 12, 26, 95, 28, 19, 16, 12, 26, 95, 11, 23, 26, 95, 27, 26, 29, 10, 24, 24, 26, 13, 95, 30, 17, 27, 95, 11, 13, 6, 95, 30, 24, 30, 22, 17, 117, 0 };// "Please close the debugger and try again\n"
debuger_main_loop(name, &pi);
if (dwExitCode == 1) //说明flag的第一部分是正确的
{
//print_console("flag1 is correct\n");
//print_console("flag2: %s\n", &p[20]);
xxtea_enc((DWORD*)&pbuffer[20], 5, xxteaKey);
if (!memcmp(&pbuffer[20], enc_flag2, 20))
{
decstring(correct);
print_console(correct);
}
else {
decstring(wrong);
print_console(wrong);
}
}
else if (dwExitCode == -2) {
decstring(checkdebugerstr);
print_console(checkdebugerstr);
}
else {
decstring(wrong);
print_console(wrong);
}

/*getchar();*/
CloseHandle(hFileMap);
}

}

void NTAPI TLS_CALLBACK2(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
__asm {
call label;
label:
add dword ptr[esp], 5; //4字节
ret;
}
if (Reason == 1)
{
//在这里进行HOOK操作
char szHookApi[] = { 40, 13, 22, 11, 26, 57, 22, 19, 26, 0 }; //"WriteFile"
char szUser32[] = { 20, 26, 13, 17, 26, 19, 76, 77, 81, 27, 19, 19, 0 }; //"kernel32.dll"
//模拟TLS DEBUG -->HOOK
decstring(szHookApi);
decstring(szUser32);
hAPIModule = GetModuleHandle(szUser32);
g_dwOldFuncAddr = (PWRITEFILE)GetProcAddress(hAPIModule, szHookApi);
SetIATHook((DWORD)g_dwOldFuncAddr, (DWORD)MyWriteFile, hAPIModule);
}
ExitProcess(-1);
}

void dec_res(char* buffer, int len)
{
for (int i = 0; i < len; i++)
{
buffer[i] ^= 0x55;
}
}

void nouse()
{
DWORD a = (DWORD)&tls;
}

进程2

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//这是最终在PE文件资源段存着的那个程序源码
//flag为 miniLctf{cbda59ff59e3e90c91c02e9b40b78b} len = 40
#include <windows.h>
#include <stdio.h>
#include <winternl.h>
#include <Tlhelp32.h>

#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))

typedef NTSTATUS(__stdcall* pNtQueryInformationProcess)( //用于反调试
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength
);
typedef PVOID(NTAPI* FnAddVectoredExceptionHandler)(ULONG, _EXCEPTION_POINTERS*); //VEH函数指针

//函数声明区
LONG NTAPI VectExcepHandler(PEXCEPTION_POINTERS pExcepInfo); //自定义的VEH处理函数
BOOL checkdebug1(); //监测调试1,因为进程1通过在CreateProcess启动进程2的时候用了DEBUG_PROCESS,所以进程2 IsDebuggerPresent()返回的是1
BOOL checkdebug2(); //监测调试器,ida.exe olldbg.exe等
DWORD update_delta(int parm); //更新delta
void xxtea_enc(DWORD* v, int n, DWORD const key[4]); //XXTEA加密函数
void getflag(char* input); //从共享内存中读入FLAG
void initwork(); //初始化工作,反调试及注册VEH

//全局变量区
char flag[44] = { 0 };
DWORD DELTA = 0x9E3779B9; // 真正的是 ((0x9E3779B9 ^ 0x12345678 ^ 0x90909090 ^ 123) + 12345) ^111111 -> 0x1c925d64
DWORD xxteaKey[] = { 0x12,0x34,0x56,0x78 }; // 真正的是 {0x12,0x90,0x56,0x78};
FnAddVectoredExceptionHandler MyAddVectoredExceptionHandler;



//flag的前半段加密后的密文
char enc_flag1[20] = { 0x28, 0xe3, 0x7c, 0x6b, 0xdd, 0xd5, 0x41, 0x48, 0xdc, 0x84, 0x37, 0x96, 0x26, 0x32, 0x8a, 0xef, 0x26, 0xb2, 0x76, 0x07 };


int main()
{
initwork();
if (checkdebug1()) {
DELTA ^= 0x90909090;
xxteaKey[1] = 0x90; //如果正在调试
}

DELTA = update_delta(DELTA);
/*printf("p2: DELTA = %#X\n", DELTA);
printf("p2: KEY = %#X, %#X, %#X, %#X\n", xxteaKey[0], xxteaKey[1], xxteaKey[2], xxteaKey[3]);*/

getflag(flag);

xxtea_enc((DWORD*)flag, 5, xxteaKey);
if (memcmp(flag, enc_flag1, 20)) //如果flag的第一部分(前20个字节)是假的
{
/* printf("p2: The first half of flag is incorrect!\n");
printf("p2: wrong\n");*/
return -1;
}
//printf("p2: The first half of flag is correct!\n");
return 1;
}


LONG NTAPI VectExcepHandler(PEXCEPTION_POINTERS pExcepInfo)
{
if (pExcepInfo->ExceptionRecord->ExceptionCode == 0xC0000005) //非法内存访问
{
pExcepInfo->ContextRecord->Eip = pExcepInfo->ContextRecord->Eip + 2;//产生异常的代码2字节
return EXCEPTION_CONTINUE_EXECUTION;
}

return EXCEPTION_CONTINUE_SEARCH;
}

BOOL checkdebug1()
{
return IsDebuggerPresent();
}

BOOL checkdebug2()
{
DWORD ret = 0;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(pe32);
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
return FALSE;
}
BOOL bMore = Process32First(hProcessSnap, &pe32);
while (bMore)
{
if (_stricmp(pe32.szExeFile, "OllyDbg.exe") == 0 || _stricmp(pe32.szExeFile, "ida.exe") == 0 || _stricmp(pe32.szExeFile, "x32dbg.exe") == 0 || _stricmp(pe32.szExeFile, "windbg.exe") == 0)
{
return TRUE;
}
bMore = Process32Next(hProcessSnap, &pe32);
}
CloseHandle(hProcessSnap);
return FALSE;
}

DWORD update_delta(int parm) {
int a = (parm ^ 123) + 12345;

__asm {
call label;
label:
add dword ptr[esp], 5;
ret;

mov eax, a;
xor ebx, ebx;
mov[ebx], ebx;
}
return a;
}

void xxtea_enc(DWORD* v, int n, DWORD const key[4])
{
DWORD y, z, sum;
unsigned p, rounds, e;
rounds = 6 + 52 / n;
sum = 0;
z = v[n - 1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++)
{
y = v[p + 1];
z = v[p] += MX;
}
y = v[0];
z = v[n - 1] += MX;
} while (--rounds);
}


void getflag(char* flag)
{
HANDLE hFileMap = CreateFileMapping(NULL, NULL, PAGE_READWRITE, 0, 0x1000, TEXT("FLAG"));
char* p = (char*)MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0X1000);
memcpy(flag, p, 40);
//printf("p2: get content: %s\n", p);
UnmapViewOfFile(p);
CloseHandle(hFileMap);
}

void initwork()
{
if (!checkdebug2()) {
DELTA ^= 0x12345678; //如果没有ida调试
}
else {
//printf("p2: 检测到调试器软件!, 请退出后重新运行程序\n");
ExitProcess(-2);
}

HMODULE hModule = GetModuleHandle("Kernel32.dll");
MyAddVectoredExceptionHandler = (FnAddVectoredExceptionHandler)::GetProcAddress(hModule, "AddVectoredExceptionHandler");
MyAddVectoredExceptionHandler(0, (_EXCEPTION_POINTERS*)&VectExcepHandler);
}

先build进程2,然后进程2的PE文件每一个字节都异或0X55后,存入到进程1的项目文件中的资源中,build进程1,然后build进程1后的PE文件,修改节表,将.rsrc添加可写属性,然后将数据目录表中TLS项对应的修改下即可

EXP

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
#include <stdio.h>
#include <windows.h>
#define MX1 (((z>>6^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
#define MX2 (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))

void xxtea_dec1(DWORD* v, int n, DWORD const key[4], DWORD delta)
{
DWORD y, z, sum;
unsigned p, rounds, e;

rounds = 6 + 52 / n;
sum = rounds * delta;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--)
{
z = v[p - 1];
y = v[p] -= MX1;
}
z = v[n - 1];
y = v[0] -= MX1;
sum -= delta;
} while (--rounds);
}

void xxtea_dec2(DWORD* v, int n, DWORD const key[4], DWORD delta)
{
DWORD y, z, sum;
unsigned p, rounds, e;

rounds = 6 + 52 / n;
sum = rounds * delta;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--)
{
z = v[p - 1];
y = v[p] -= MX2;
}
z = v[n - 1];
y = v[0] -= MX2;
sum -= delta;
} while (--rounds);
}

char enc_flag1[20] = { 0x28, 0xe3, 0x7c, 0x6b, 0xdd, 0xd5, 0x41, 0x48, 0xdc, 0x84, 0x37, 0x96, 0x26, 0x32, 0x8a, 0xef, 0x26, 0xb2, 0x76, 0x07 };
char enc_flag2[20] = { 0x21, 0xa9, 0x21, 0x90, 0x60, 0x30, 0x3b, 0xf5, 0x4e, 0xa8, 0x88, 0x8e, 0xd5, 0x5a, 0x63, 0x43, 0x39, 0x92, 0x11, 0xac };
int main()
{
DWORD delta = 0x1c925d64; //((0x9E3779B9 ^ 0x12345678 ^ 0x90909090 ^ 123) + 12345) ^111111
DWORD xxteaKey[] = { 0x12,0x90,0x56,0x78 };

xxtea_dec1((DWORD*)enc_flag1, 5, xxteaKey, delta);
delta = 0x9E3779B9;
xxteaKey[1] = 0x34;
xxtea_dec2((DWORD*)enc_flag2, 5, xxteaKey, delta);
for (int i = 0; i < 20; i++)
{
printf("%c", enc_flag1[i]);
}
for (int i = 0; i < 20; i++)
{
printf("%c", enc_flag2[i]);
}

return 0;
}

//miniLctf{cbda59ff59e3e90c91c02e9b40b78b}