NepCTF-九龙拉棺-复现

First Post:

Last Update:

解题步骤

首先对main函数进行分析,可以看出主要的内容都在创建的线程中。线程之间通过全局变量实现同步,静态分析即可看出执行顺序。

线程一:

使用rc4初始化block,key为MessageBoxA,长度为0x3478,之后信号量变为3。

线程三:

使用base32加密block中的内容

线程二:

用来进行反调试的线程,原理很简单,就是定时校验代码段的完整性,在线程启动前将断点打好就可以绕过。还有查看drx7寄存器的状态来判断硬件断点。

知道这些就没必要一个一个加密进行分析了,直接打断点看一看这个资源加密(或者该说是解密后的样子,定位到最后一个对该资源地址操作的地址,在线程六中打断点即可看到资源被解密成了一个pe文件,在线程六中作为子进程启动。

将该pe文件dump出来即可进行分析,子进程用到了MapViewOfFile函数,实现对输入的访问,对输入的后半段进行tea加密后,与密文进行比较,返回比较结果。

输入的其余部分在线程七中进行tea加密,两段tea差别在于key不一样,对两段tea进行解密即可得到flag。

一些收获

提升进程权限

提升权限代码,要对一个任意进程给予相应的权限,要修改进程的访问令牌,首先要获得进程的访问令牌,通过以下代码可以获取访问令牌

1
OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken)

之后对令牌进行检查和修改

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
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "advapi32.lib")

BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
)
{
TOKEN_PRIVILEGES tp;
LUID luid;

if ( !LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid ) ) // receives LUID of privilege
{
printf("LookupPrivilegeValue error: %u\n", GetLastError() );
return FALSE;
}

tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;

// Enable the privilege or disable all privileges.

if ( !AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL) )
{
printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
return FALSE;
}

if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)

{
printf("The token does not have the specified privilege. \n");
return FALSE;
}

return TRUE;
}

检测硬件断点

这段代码首先会用GetThreadContext来获取drx7寄存器的值,判断是否存在硬件断点,判断存在硬件断点后,试图去掉硬件断点,也就是给drx7赋值为0,如果不行就退出进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int sub_4015E0()
{
HANDLE CurrentThread; // esi
CONTEXT Context; // [esp+4h] [ebp-2D0h] BYREF

memset(&Context.Dr0, 0, 0x2C8u);
Context.ContextFlags = 65599;
CurrentThread = GetCurrentThread();
if ( !GetThreadContext(CurrentThread, &Context) || !Context.Dr7 )
return 0;
Context.Dr7 = 0;
SetThreadContext(CurrentThread, &Context);
Context.ContextFlags = 65599;
if ( GetThreadContext(CurrentThread, &Context) )
{
if ( Context.Dr7 )
ExitProcess(0xFFFFFF9D);
}
return 1;
}