Як написати інжектор DLL на C?
Інжекція DLL — це найпоширеніший спосіб змінити виконуваний файл (.exe) під час його роботи. Нижче наведено пояснення того, як написати інжектор DLL на мові програмування C.
Повний код для інжектора DLL на C (пояснення нижче)
// Написано [email protected]
#include
#include
int main() {
STARTUPINFOA StartInfo = { sizeof(STARTUPINFOA) };
PROCESS_INFORMATION ProcessInfo = { 0 };
// Визначимо шлях до цільового виконуваного файлу
LPCSTR targetPath = "C:\\Users\\targetprocess.exe";
// Створимо цільовий процес в призупиненому стані
BOOL success = CreateProcessA(
targetPath, NULL, NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &StartInfo, &ProcessInfo
);
if (!success) {
printf("Не вдалося створити процес!\n");
return 1;
}
// Визначимо шлях до спільної бібліотеки (DLL)
LPCSTR libraryPathUsers\\dlltoinject.dll";
// Отримаємо дескриптор модуля kernel32.dll
HMODULE kernel32Handle = GetModuleHandleA("kernel32.dll");
if (kernel32Handle == NULL) {
printf("Помилка при отриманні дескриптора kernel32.\n");
return 1;
}
// Отримаємо адресу функції LoadLibraryA
FARPROC loadLibraryAddr = GetProcAddress(kernel32Handle, "LoadLibraryA");
if (loadLibraryAddr == NULL) {
printf("Не вдалося знайти LoadLibraryA.\n");
return 1;
}
// Виділимо пам'ять в цільовому процесі для шляху до бібліотеки
LPVOID remoteMemory = VirtualAllocEx(
ProcessInfo.hProcess, NULL, strlen(libraryPath) + 1,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE
);
if (remoteMemory == NULL) {
printf("Не вдалося виділити пам'ять в цільовому процесі.\n");
return 1;
}
// Запишемо шлях до бібліотеки у виділену пам'ять в цільовому процесі
BOOL memoryWritten = WriteProcessMemory(
ProcessInfo.hProcess, remoteMemory,
libraryPath, strlen(libraryPath) + 1, NULL
);
if (!memoryWritten) {
printf("Не вдалося записати в пам'ять процесу.\n");
return 1;
}
// Створимо віддалений потік, який викликає LoadLibraryA з шляхом до бібліотеки
HANDLE remoteThread = CreateRemoteThread(
ProcessInfo.hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)loadLibraryAddr, remoteMemory, 0, NULL
);
if (remoteThread == NULL) {
printf("Не вдалося створити віддалений потік.\n");
return 1;
} else {
// Чекаємо завершення віддаленого потоку
WaitForSingleObject(remoteThread, INFINITE);
CloseHandle(remoteThread);
}
// Продовжимо виконання основного потоку цільового процесу
ResumeThread(ProcessInfo.hThread);
// Очистимо дескриптори
CloseHandle(ProcessInfo.hThreadn");
return 0;
}
Пояснення крок за кроком
Давайте розберемо код, щоб зрозуміти кожну частину детально.
1. Підключення необхідних заголовків
Ми підключаємо стандартні заголовки для вводу-виводу та заголовки Windows API для необхідних функцій та типів.
#include
#include
2. Ініціалізація структур інформації про процес
Ми ініціалізуємо STARTUPINFOA
та PROCESS_INFORMATION
, які необхідні для створення та управління цільовим процесом.
STARTUPINFOA StartInfo = { sizeof(STARTUPINFOA) };
PROCESS_INFORMATION ProcessInfo = { 0 };
3. Визначення шляху та створення цільового процесу
Ми вказуємо шлях до цільового виконуваного файлу та використовуємо CreateProcessA
для запуску процесу в призупиненому стані. Це дозволяє нам маніпулювати процесом до того, як він почне виконання.
// Визначимо шлях до цільового виконуваного файлу
LPCSTR targetPath = "C:\\Users\\targetprocess.exe";
// Створимо цільовий процес в призупиненому стані
BOOL success = CreateProcessA(
targetPath, NULL, NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &StartInfo, &ProcessInfo
);
if (!success) {
printf("Не вдалося створити процес!\n");
return 1;
}
## Визначення шляху до DLL та отримання дескриптора kernel32
Ми встановлюємо шлях до спільної бібліотеки (DLL), яку хочемо завантажити, та отримуємо дескриптор для `kernel32.dll`, який містить функцію `LoadLibraryA`.
// Визначимо шлях до спільної бібліотеки (DLL)
LPCSTR libraryPath = "C:\Users\dlltoinject";
// Отримаємо дескриптор модуля kernel32.dll
HMODULE kernel32Handle = GetModuleHandleA("kernel32.dll");
if (kernel32Handle == NULL) {
printf("Помилка при отриманні дескриптора kernel32.\n");
return 1;
}
```
5. Отримання адреси LoadLibraryA
Ми отримуємо адресу функції LoadLibraryA
в kernel32.dll
, використовуючи GetProcAddress
.
// Отримуємо адресу функції LoadLibraryA
FARPROC loadLibraryAddr = GetProcAddress(kernel32Handle, "LoadLibraryA");
if (loadLibraryAddr == NULL) {
printf("Не вдалося знайти LoadLibraryA.\n");
return 1;
}
6. Виділення пам'яті в цільовому процесі
Ми виділяємо пам'ять в адресному просторі цільового процесу для зберігання шляху до DLL. Для цього використовуємо VirtualAllocEx
.
// Виділяємо пам'ять у цільовому процесі для шляху до бібліотеки
LPVOID remoteMemory = VirtualAllocEx(
ProcessInfo.hProcess, NULL, strlen(libraryPath) + 1,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE
);
if (remoteMemory == NULL) {
printf("Не вдалося виділn");
return 1;
}
7. Запис шляху до DLL в виділену пам'ять
Ми записуємо шлях до DLL у виділену пам'ять цільового процесу за допомогою WriteProcessMemory
.
// Записуємо шлях до бібліотеки у виділену пам'ять в цільовому процесі
BOOL memoryWritten = WriteProcessMemory(
ProcessInfo.hProcess, remoteMemory,
libraryPath, strlen(libraryPath) + 1,n");
return 1;
}
8. Створення віддаленого потоку для завантаження спільної бібліотеки
Ми створюємо віддалений потік у цільовому процесі, який викликає LoadLibraryA
з шляхом до бібліотеки. Це ефективно завантажує спільну бібліотеку в цільовий процес.
// Створюємо віддалений потік, який викликає LoadLibraryA з шляхом до бібліотеки
HANDLE remoteThread = CreateRemoteThread(
ProcessInfo.hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)loadLibraryAddr, remoteMemory, 0, NULL
);
if (remoteThread == NULL) {
printf("Не вдалося створити віддалений потік.\n");
return 1;
} else {
// Чекаємо завершення віддаленого потоку
WaitForSingleObject(remoteThread, INFINITE);
CloseHandle(remoteThread);
}
9. Очистка та відновлення цільового процесу
Після запуску віддаленого потоку ми закриваємо дескриптори потоку та процесу. Наприкінці відновлюємо цільовий процес, щоб він продовжив виконуватися.
// Відновлюємо основний потік цільового процесу
ResumeThread(ProcessInfo.hThread);
// Очистка дескрипторів
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
printf("Спільну бібліотеку успішно завантажено.\n");
Давайте перевіримо, чи це працює:
Вітаємо!
Щоб використати цей простий інжектор, додайте код C до вашого проєкту в Visual Studio. Зовнішні бібліотеки не потрібні — просто встановіть шляхи до вашого цільового виконуваного файлу та DLL у скрипті. І все! Не соромтеся ставити питання, якщо вони виникнуть.
Перекладено з: How to write a simple DLL injector in C