Информация Гайд Пишем свой инжектор с выгрузкой [LoadLibraryA]

CleanLegend

Известный
Автор темы
Всефорумный модератор
474
927
Привет, сегодня напишем простой инжектор с выгрузкой, с использованием функций LoadLibraryA и FreeLibrary

Алгоритм инжекта:
- получаем хэндл процесса в который будем инжектить
- получаем путь до нашей dll
- выделяем память для нашего пути
- записываем его
- получаем адрес LoadLibraryA и вызываем его через CreateRemoteThread​
- ожидаем завершения выполнения DllMain DLL_PROCESS_ATTACH


получаем id процесса:

C++:
DWORD GetProcId(const char* procname)
{
    PROCESSENTRY32 pe;
    HANDLE hSnap;

    pe.dwSize = sizeof(PROCESSENTRY32);
    hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    if (Process32First(hSnap, &pe)) {
        do {
            if (strcmp(pe.szExeFile, procname) == 0)
                break;
        } while (Process32Next(hSnap, &pe));
    }
    return pe.th32ProcessID;
}


C++:
// получаем хэндл процесса
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetProcId("gta_sa.exe"));
    // Указываем путь до нашей dll
    const char* DllPath = "C:\\test.dll";
    // получаем размер строки нашего пути
    size_t SizePatch = strlen(DllPath) + 1;
    // выделяем память в gta_sa с размером нашей строки
    LPVOID pDllPath = VirtualAllocEx(hProcess, NULL, SizePatch, MEM_COMMIT, PAGE_READWRITE);
    // записываем наш путь в выделенную память
    WriteProcessMemory(hProcess, pDllPath, (LPVOID)DllPath, SizePatch, NULL);
    HMODULE kernel = GetModuleHandleA("Kernel32.dll"); // Получаем адрес kernel32
    DWORD Adr = (DWORD)GetProcAddress(kernel, "LoadLibraryA"); // получаем адрес функции LoadLibraryA
    // Вызываем LoadLibraryA в gta_sa.exe с аргументом "C:\\test.dll" и возвращаем адрес нашего потока
    HANDLE hThread = CreateRemoteThread(hProcess, 0, 0,(LPTHREAD_START_ROUTINE)Adr, pDllPath, 0, 0);
    // Ожидаем завершение нашего потока(ждем завершения DllMain с аргументом DLL_PROCESS_ATTACH)
    WaitForSingleObject(hThread, INFINITE);
    // Закрываем дескриптор потока
    CloseHandle(hThread);
    // Освобождаем выделенную память
    VirtualFreeEx(hProcess, pDllPath, SizePatch, MEM_RELEASE);
    // Закрываем дескриптор процесса
    CloseHandle(hProcess);

Алгоритм выгрузки:
- получаем хэндл процесса в который будем инжектить
- получаем адрес нашей загруженной библиотеки
- получаем адрес FreeLibrary и вызываем его через CreateRemoteThread
- ожидаем завершения выполнения DllMain DLL_PROCESS_DETACH

функция для получения адреса dll в другом процессе:
C++:
HMODULE GetModuleHandleExtern(const char *szModuleName, DWORD dwProcessId)
{
    if (!szModuleName || !dwProcessId) { return NULL; }
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
    if (hSnap == INVALID_HANDLE_VALUE) { return NULL; }
    MODULEENTRY32 me;
    me.dwSize = sizeof(MODULEENTRY32);
    if (Module32First(hSnap, &me))
    {
        while (Module32Next(hSnap, &me))
        {
            if (!strcmp(me.szModule, szModuleName))
            {
                CloseHandle(hSnap);
                return me.hModule;
            }
        }
    }
    CloseHandle(hSnap);
    return NULL;
}


C++:
// получаем хэндл процесса
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetProcId("gta_sa.exe"));
    // получаем адрес нашей загруженной библиотеки
    HMODULE module = GetModuleHandleExtern("test.dll", GetProcId("gta_sa.exe"));
    HMODULE kernel = GetModuleHandleA("Kernel32.dll"); // Получаем адрес kernel32
    DWORD Adr = (DWORD)GetProcAddress(kernel, "FreeLibrary"); // получаем адрес функции FreeLibrary
    // Вызываем FreeLibrary в gta_sa.exe с адресом нашей библиотеки и возвращаем адрес нашего потока
    HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)Adr, module, 0, 0);
    // Ожидаем завершение нашего потока(ждем завершения DllMain с аргументом DLL_PROCESS_DETACH)
    WaitForSingleObject(hThread, INFINITE);
    // Закрываем дескриптор потока
    CloseHandle(hThread);
    // Закрываем дескриптор процесса
    CloseHandle(hProcess);
 

#Rin

Известный
Всефорумный модератор
1,214
1,035
Если я допустим хочу выгрузить свою dll мне надо снимать хуки при выгрузке ?
Логично что да. Но все ли хуки ты сможешь снять?
Например хуки виртуальных таблиц DirectX/RakNet определенно у тебя будут конфликтовать.
 
  • Нравится
Реакции: Vintik и SiTrak

dekname

Участник
44
2
Так понимаю, что код вообще не компилировал.


Код:
typedef struct tagPROCESSENTRY32W
{
    DWORD   dwSize;
    DWORD   cntUsage;
    DWORD   th32ProcessID;          // this process
    ULONG_PTR th32DefaultHeapID;
    DWORD   th32ModuleID;           // associated exe
    DWORD   cntThreads;
    DWORD   th32ParentProcessID;    // this process's parent process
    LONG    pcPriClassBase;         // Base priority of process's threads
    DWORD   dwFlags;
    WCHAR   szExeFile[MAX_PATH];    // Path
} PROCESSENTRY32W;

szExeFile - WCHAR, а параметр принимаешь в const char *. Конкретно я, то пофиксил так:


C++:
DWORD GetProcId(std::string_view procname)
{
    PROCESSENTRY32 pe;
    HANDLE hSnap;

    pe.dwSize = sizeof(PROCESSENTRY32);
    hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    if (Process32First(hSnap, &pe)) {
        do {
            if (std::wstring(pe.szExeFile) == std::wstring(procname.begin(), procname.end()))
                break;
        } while (Process32Next(hSnap, &pe));
    }
    return pe.th32ProcessID;
}
 

CleanLegend

Известный
Автор темы
Всефорумный модератор
474
927
Так понимаю, что код вообще не компилировал.


szExeFile - WCHAR, а параметр принимаешь в const char *. Конкретно я, то пофиксил так:
Еще напиши, что гайд просто скопировал и вставил.
В проекте использовалась многобайтовая кодировка и по дефолту функции Process32First переходили в Process32FirstA. а ты скинул структуру для Process32FirstW
 
  • Нравится
Реакции: F0RQU1N and и Vintik