【父子进程/AES/XTEA/SMC】赛后复盘
官方wp:进程重影技术:
进程重映像利用了Windows内核中的缓存同步问题,它会导致可执行文件的路径与从该可执行文件创建的映像节区所报告的路径不匹配。通过在一个诱饵路径上加载DLL,然后卸载它,然后从一个新路径加载它,许多Windows API将返回旧路径。这可能可以欺骗安全产品,使其在错误的路径上查找加载的映像。
主要创建方式就是先打开一个新文件,然后把这个文件挂到删除列表上,在关闭文件句柄后文件就会被删除,但是在还没有关闭的时候此时文件还未删除,此时能向文件中写入数据,然后再把这个文件映射到内存上,再关闭文件句柄,此时文件删除,但是内存中还有文件的映像,达到一定的迷惑杀软的目的。
如果是做题的话,直接用IDA附加开启的子进程,然后发现XTEA,解密得到flag
如果是学技术的话,还是要研究一下 “进程重影” 技术思路。
本文两者都会介绍的。
考点:AES\XTEA\进程与子进程\SMC\进程重影
分析
DIE打开,发现是pe64位,无壳
拖进IDA进行分析
习惯操作,先用FindCrypto扫一下,有没有加密
发现AES加密
https://www.hetianlab.com/headImg.action?news=dec2529b-3afe-4bb7-b235-962cc3469ff6.png
https://edu-cdn.heetian.com/avatar_f36016346e884a6cabbd0af09e89f70c
https://edu-cdn.heetian.com/avatar_b51d5e210bab4d01ab817956e73c6b74
跟踪main函数,看看它到底要干什么
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
j___CheckForDebuggerJustMyCode(&unk_1400A80B9);// vs2022调试debug版c++程序会出现该函数,我也不知道啥用
sub_140001FF0(*argv);
return 0;
}AES核心加密逻辑函数
__int64 __fastcall sub_13F887480(char *a1, char *a2, unsigned int a3, __int64 a4, __int64 a5)
{
__int64 result; // rax
unsigned __int64 i; //
unsigned __int8 v7; //
j___CheckForDebuggerJustMyCode(&unk_13F92800D);
v7 = a3 % 0x10;
if ( a4 )
{
qword_13F91D188 = a4;
sub_13F888EA0();
}
if ( a5 )
qword_13F91D240 = a5;
for ( i = 0i64; i < a3; i += 16i64 )
{
sub_13F889C80(a2);
j_memmove(a1, a2, 0x10ui64);
qword_13F91D180 = (__int64)a1;
sub_13F887850();
qword_13F91D240 = (__int64)a1;
a2 += 16;
a1 += 16;
}
result = v7;
if ( v7 )
{
j_memmove(a1, a2, v7);
qword_13F91D180 = (__int64)a1;
return sub_13F887850();
}
return result;
}跟进了sub_14000A700函数
signed int __fastcall sub_14000A700(const char *a1)
{
char *v1; // rdi
__int64 i; // rcx
DWORD LastError; // eax
signed int result; // eax
HANDLE CurrentProcess; // rax
size_t v6; // rax
DWORD dwCreationDisposition; //
char v8; // BYREF
CHAR FileName; // BYREF
__int64 v10; // BYREF
HANDLE hObject; //
unsigned int v12; //
char v13; // BYREF
int v14; // BYREF
__int64 (__fastcall *v15)(HANDLE, int *, char *, __int64, int); //
HRSRC hResInfo; //
DWORD v17; //
HGLOBAL hResData; //
void *Src; //
DWORD NumberOfBytesWritten; // BYREF
DWORD nNumberOfBytesToWrite; // BYREF
size_t Size; //
void *Block; //
LPCVOID lpBuffer; // BYREF
__int64 (__fastcall *v25)(__int64 *, __int64, _QWORD, _QWORD, int, int, HANDLE); //
__int64 v26; // BYREF
unsigned int v27; // BYREF
HANDLE hHandle; // BYREF
__int64 (__fastcall *v29)(HANDLE *, __int64, _QWORD, HANDLE, DWORD, __int64, _QWORD, _QWORD); //
char v30; // BYREF
int v31; //
__int64 (__fastcall *v32)(HANDLE, _QWORD, char *, __int64, _QWORD); //
char *Str; //
int v34; //
int v35; //
int v36; //
wchar_t *Dest; //
__int64 v38; // BYREF
__int64 v39; //
__int64 v40; // BYREF
__int64 (__fastcall *v41)(__int64 *, __int64, _QWORD, HANDLE, __int64, _QWORD, _DWORD, _QWORD, _QWORD, _QWORD, _QWORD); //
int v42; //
v1 = &v8;
for ( i = 404i64; i; --i )
{
*(_DWORD *)v1 = -858993460;
v1 += 4;
}
j___CheckForDebuggerJustMyCode(&unk_1400A80B9);
strcpy(FileName, "VNctf2023");
v10 = 0x616C7972723073i64;
hObject = CreateFileA(FileName, 0xC0010000, 0, 0i64, 2u, 0x80u, 0i64);// 创建一个文件
if ( hObject == (HANDLE)-1i64 )
{ // 失败
LastError = GetLastError();
return sub_14000257C("Failed - Error Code %08X\r\n", LastError);
}
else
{
v13 = 1; // 创建成功
v15 = (__int64 (__fastcall *)(HANDLE, int *, char *, __int64, int))sub_1400016B3("NtSetInformationFile");
v12 = v15(hObject, v14, v13, 1i64, 13);
if ( v14 >= 0 )
{
hResInfo = FindResourceA(0i64, (LPCSTR)0x66, "shell");// 寻找指定类型和名称的资源位置
v17 = SizeofResource(0i64, hResInfo); // 资源大小
hResData = LoadResource(0i64, hResInfo); // 加载资源
Src = LockResource(hResData);
NumberOfBytesWritten = 0;
nNumberOfBytesToWrite = 0;
LODWORD(Size) = v17 - 4;
Block = j_j_j__malloc_base(v17 - 4);
j_memmove(Block, Src, (unsigned int)Size);
j_memmove(nNumberOfBytesToWrite, (char *)Src + (unsigned int)Size, 4ui64);
GlobalUnlock(hResData);
lpBuffer = 0i64;
NumberOfBytesWritten = sub_1400030BC(Block, v10, lpBuffer, (unsigned int)Size); //关键函数,好像对shell资源进行了 AES加密
if ( NumberOfBytesWritten >= nNumberOfBytesToWrite
&& lpBuffer
&& WriteFile(hObject, lpBuffer, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0i64)// 加密后shell 写到资源到文件
&& (j_free(Block), // 释放
j_free((void *)lpBuffer),
v25 = (__int64 (__fastcall *)(__int64 *, __int64, _QWORD, _QWORD, int, int, HANDLE))sub_1400016B3("NtCreateSection"),// 创建节对象
v12 = v25(v26, 983071i64, 0i64, 0i64, 2, 0x1000000, hObject),
(v12 & 0x80000000) == 0) ) // 猜测上面的代码,就是把shell 资源 写到一个叫 vnctf2023的文件里面
{
result = sub_14000347C(hObject, v27, nNumberOfBytesToWrite);
if ( result ) // 写入成功
{
CloseHandle(hObject);
hHandle = 0i64;
v29 = (__int64 (__fastcall *)(HANDLE *, __int64, _QWORD, HANDLE, DWORD, __int64, _QWORD, _QWORD))sub_1400016B3("NtCreateProcess");// 启动进程
CurrentProcess = GetCurrentProcess();
LOBYTE(dwCreationDisposition) = 1;
result = v29(hHandle, 0x1FFFFFi64, 0i64, CurrentProcess, dwCreationDisposition, v26, 0i64, 0i64);
v12 = result;
if ( result >= 0 )
{
memset(v30, 0, 0x30ui64);
v31 = 0;
v32 = (__int64 (__fastcall *)(HANDLE, _QWORD, char *, __int64, _QWORD))sub_1400016B3("NtQueryInformationProcess");
result = v32(hHandle, 0i64, v30, 48i64, 0i64);
v12 = result;
if ( result >= 0 )
{
Str = (char *)j_j_j__malloc_base(4ui64);
sub_1400039C2(Str, "%x", NumberOfBytesWritten);
v34 = j_strlen(FileName);
v35 = j_strlen(a1);
v36 = j_strlen(Str);
j_strcat(FileName, " ");
j_strcat(FileName, a1);
j_strcat(FileName, " ");
j_strcat(FileName, Str);
v34 += v35 + v36 + 2;
v42 = v34 + 1;
v6 = (unsigned int)(2 * (v34 + 1));
if ( !is_mul_ok(2u, v34 + 1) )
v6 = -1i64;
Dest = (wchar_t *)j_j_j__malloc_base(v6);
sub_140003175(Dest, 0i64, 2 * v34 + 2);
j_mbstowcs(Dest, FileName, v34);
result = sub_140003DBE(hHandle, v30, Dest);
if ( result )
{
j_free(Dest);
memset(v38, 0, 0x1B8ui64);
result = sub_140002176(hHandle, v30, v38);
if ( result )
{
v38 = v38;
v39 = v38 + v27;
v40 = 0i64;
v41 = (__int64 (__fastcall *)(__int64 *, __int64, _QWORD, HANDLE, __int64, _QWORD, _DWORD, _QWORD, _QWORD, _QWORD, _QWORD))sub_1400016B3("NtCreateThreadEx"); //启动线程
result = v41(v40, 0x1FFFFFi64, 0i64, hHandle, v39, 0i64, 0, 0i64, 0i64, 0i64, 0i64);
v12 = result;
if ( result >= 0 )
return WaitForSingleObject(hHandle, 0xFFFFFFFF);
}
}
}
}
}
}
else
{
return CloseHandle(hObject);
}
}
else
{
sub_14000257C("Failed - Error Code %08X\r\n", v12);
return CloseHandle(hObject);
}
}
return result;
}关键函数 sub_140009E20,就是那个对shell资源进行处理的函数
__int64 __fastcall sub_140009E20(__int64 a1, const char *a2, void **a3, unsigned int a4)
{
char *v4; // rdi
__int64 i; // rcx
size_t v6; // rax
char v8; // BYREF
char v9; // BYREF
unsigned int v10; //
BOOL v11; //
int j; //
size_t Size; //
v4 = &v8;
for ( i = 42i64; i; --i )
{
*(_DWORD *)v4 = -858993460;
v4 += 4;
}
j___CheckForDebuggerJustMyCode(&unk_1400A80B9, a2, a3);
v11 = a4 % 0x10 != 0;
v10 = 16 * (v11 + a4 / 0x10);
v6 = v10 + 1;
if ( v10 == -1 )
v6 = -1i64;
*a3 = j_j_j__malloc_base(v6);
sub_140003175(*a3, 0i64, v10 + 1);
sub_140003175(v9, 0i64, 16i64);
if ( j_strlen(a2) <= 0x10 )
Size = j_strlen(a2);
else
Size = 16i64;
j_memmove(v9, a2, Size);
for ( j = 0; 16 * j < a4; ++j )
sub_140002DE7(16 * j + a1, v9, (char *)*a3 + 16 * j, 16i64);// AES解密函数我思考了一下,如果shell进行加密,那么shell还能运行吗?反之,只有解密,才可以正常运行
return v10;
}其余函数也就不用再分析了,可以断定这是AES加密函数。
对shell资源进行AES解密,然后shell程序跑起来
运行该程序,发现我追踪的进程居然挂掉了,又跑起来了另一个进程
可以断定,父进程开子进程
子进程输入flag
https://edu-cdn.heetian.com/avatar_4f922e1c90da41dbb3e9216e87586415
我再次运行,发现jiji.exe没了???
https://edu-cdn.heetian.com/avatar_4e143b56268c4170b84f9b759e285b2c
__int64 __fastcall sub_140007620(const void *a1, __int64 a2, void *a3, unsigned int a4)
{
j___CheckForDebuggerJustMyCode(&unk_1400A800D, a2, a3);
j_memmove(a3, a1, a4);
qword_14009D180 = (__int64)a3;
qword_14009D188 = a2;
sub_140008EA0();
return sub_1400078E0();
}附加下子进程
https://edu-cdn.heetian.com/avatar_c60bd86c7062410ba1bc61402de07d84
https://edu-cdn.heetian.com/avatar_392df969f02f48b5a142e01f8c5320d3
https://edu-cdn.heetian.com/avatar_c09bd6cc8b04494abbe8a3b98fa41833
搜索字符串,但是无法找到关键函数
https://edu-cdn.heetian.com/avatar_f72ce0e8c21a43f78b88b2dc2b5a65d4
直接dump解密后的exe文件
https://edu-cdn.heetian.com/avatar_a4ce8721b7f0440bbcabd55aa5e747d8
断点下在此处,然后运行,找到解密后的文件,dump下来
https://edu-cdn.heetian.com/avatar_a936f0d40f784e5783ee6cb0bfe89b52
D键转地址
https://edu-cdn.heetian.com/avatar_e70f74614fb34d83a964411d273cd8d5
跳转到MZ头部,发现这就是解密后的程序
https://edu-cdn.heetian.com/avatar_0bd1db0ec9434d8faa9667963cc3349e
把它dump下来
https://edu-cdn.heetian.com/avatar_a8aafed89b8e4dedb0cdc5bf8af52a08
__int64 __fastcall sub_1400078E0(__int64 a1, __int64 a2, __int64 a3)
{
__int64 v3; // rcx
unsigned __int8 i; //
j___CheckForDebuggerJustMyCode(&unk_1400A800D, a2, a3);
LOBYTE(v3) = 10;
sub_140007760(v3);
for ( i = 9; i; --i )
{
sub_140008980();
sub_140008DF0();
sub_140007760(i);
sub_140007970();
}
sub_140008980();
sub_140008DF0();
return sub_140007760(0i64);
}得到dump下来的程序
https://edu-cdn.heetian.com/avatar_ba8de1dce7694d6094879188c29a22cf
分析dump下来的程序
https://edu-cdn.heetian.com/avatar_180efc8afbeb4a7bb70c80ccd4bfa8a8
根据关键字符串定位关键函数
__int64 __fastcall sub_140007760(unsigned __int8 a1, __int64 a2, __int64 a3)
{
__int64 result; // rax
unsigned __int8 i; //
unsigned __int8 j; //
j___CheckForDebuggerJustMyCode(&unk_1400A800D, a2, a3);
for ( i = 0; ; ++i )
{
result = i;
if ( i >= 4u ) //这不就是 addroundkey() 函数吗?
break;
for ( j = 0; j < 4u; ++j )
*(_BYTE *)(qword_14009D180 + 4i64 * i + j) ^= byte_14009D190; //对比confuse_us那题,发现没有魔改 ^0x23
}
return result;
}https://edu-cdn.heetian.com/avatar_516dc7a47f134ea1bea7345bc594910b
动调调试走到flag验证的地方
https://edu-cdn.heetian.com/avatar_7d5a745f511545b4bb7f20b37ee0eac2
https://edu-cdn.heetian.com/avatar_a5e9b86d9f0c475e923e9a519fcd2608
动态调试跟进去
https://edu-cdn.heetian.com/avatar_054a31428dff4f8b9d677209bce95d32
成功到达关键的地方,如果不是这么清晰的话,需要U+C键来调
传递的参数
FileName
VNctf2023
C:\Users\Le\Desktop\jijiji.exe
16000
s0rrylahttps://edu-cdn.heetian.com/avatar_74f38241b2ef45158c5844f64f03a5a6
XTEA加密
#include #includevoid decrypt(unsigned int* v, unsigned int* key,unsigned int round) { unsigned int l = v, r = v, sum = 0, delta = 0x88408067; sum = delta * round; for (size_t i = 0; i < round; i++) { sum -= delta; r -= (((l > 5)) + l) ^ (sum + key[(sum >> 11) & 3]); l -= (((r > 5)) + r) ^ (sum + key)^sum;} v = l; v = r;}int main(){ unsigned int v = { 0xADD4F778, 0xA6D7F132, 0x61813290, 0x2D4A40A6, 0x00B05F11, 0xB6D59424, 0x231BBFC6, 0xCD405B31, 0x03020100, 0x00C30504}; unsigned int key = {98,111,109,98}; for(int i=0;i</strong></p>
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]