Ручное внедрение DLL - PullRequest
       37

Ручное внедрение DLL

0 голосов
/ 20 апреля 2019

Я пытаюсь научиться вводить dll вручную, но не могу заставить работать код dll.Я новичок в Windows C ++, поэтому любые советы по улучшению моего кода приветствуются.Я также разместил только соответствующий код.

Инжекторная программа:

hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, getPID(TARGET_NAME));

DWORD gotDLL = GetFullPathName(DLL_NAME, MAX_PATH, dllPath, NULL);

hFile = CreateFile(dllPath, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

dllFileSize = GetFileSize(hFile, NULL);
memAddrForDLL = VirtualAllocEx(hProcess, NULL, dllFileSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

loadedDLL = HeapAlloc(GetProcessHeap(), NULL, dllFileSize);

// Load dll into allocated memory in current process
ReadFile(hFile, loadedDLL, dllFileSize, &bytesRead, NULL))

// Find offset of dll entry point
IMAGE_NT_HEADERS* pOldNtHeader = reinterpret_cast<IMAGE_NT_HEADERS*>(reinterpret_cast<BYTE*>(loadedDLL) + reinterpret_cast<IMAGE_DOS_HEADER*>(loadedDLL)->e_lfanew);
IMAGE_OPTIONAL_HEADER* pOldOptHeader = &pOldNtHeader->OptionalHeader;

entryPointOffset = pOldOptHeader->AddressOfEntryPoint;

// Load dll into allocated memory in target process
WriteProcessMemory(hProcess, memAddrForDLL, loadedDLL, bytesRead, NULL)

LPTHREAD_START_ROUTINE entryPoint = (LPTHREAD_START_ROUTINE)((unsigned __int64)memAddrForDLL + entryPointOffset);

CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibrary, entryPoint, NULL, NULL)

DLL:

DWORD WINAPI OnDllAttach(LPVOID base){
    typedef void func(void);
    func* f = (func*)0x00007FF605EC5835;
    f();
    FreeLibraryAndExitThread(static_cast<HMODULE>(base),1);
}

BOOL WINAPI OnDllDetach(){
    return TRUE;
}

BOOL WINAPI DllMain(_In_ HINSTANCE hinstDll,
                    _In_ DWORD fdwReason,
                    _In_opt_ LPVOID lpvReserved){
    typedef void func(void);
    func* f = (func*)0x00007FF605EC5835;
    f();
    switch(fdwReason) {
        case DLL_PROCESS_ATTACH:
            DisableThreadLibraryCalls(hinstDll);
            CreateThread(nullptr, 0, OnDllAttach, hinstDll, 0, nullptr);
            return TRUE;
        case DLL_PROCESS_DETACH:
            if(lpvReserved == nullptr)
                return OnDllDetach();
            return TRUE;
        default:
            return TRUE;
    }
}

Целевая программа содержит эту функцию:

void printer(){
    cout << "test" << endl;
}

Мой инжектор выдает следующий вывод

1. Attempting to attatch to process target.exe
--- Got target.exe PID: 14640
--- Got target.exe Handle: 0x0000000000000084
2. Attempting to allocate memory
--- Found dll: D:\projects\injector\hack.dll
--- Got hack.dll Handle: 0x0000000000000088
--- Allocated memory in target.exe at 0x0000017BEB690000
3. Attempting to copy dll to target.exe
--- Allocated memory at 0x00000226A060FFE0
--- Loaded hack.dll in current process at 0x00000226A060FFE0
--- hack.dll is a valid DLL
--- Loaded hack.dll into target.exe at 0x0000017BEB690000
4. Attempting to execute dll
--- Offset from start of file to entrypoint: 0x3cf6
--- Began execution of hack.dll in target.exe at 0x0000017BEB693CF6

Используя Гидру, я могу подтвердить, что это правильное смещение для точки входа dll.Но при запуске моего инжектора ничего не происходит в целевом процессе, я также пытался использовать cout для печати сообщения из dll, но я ничего не получаю (я не думаю, что это сработает, потому что ничего не было перемещено)

Я использовал

CreateRemoteThread(hProcess, NULL, NULL, entryPoint, memAddrForDLL, NULL, NULL)

до того, как 4-й параметр называется lpStartAddress, и я подумал, что это должно хотеть точку входа, но это приводило к аварийному завершению целевого процесса, и каждый пример, который я видел, использовал то, что у меня сейчас есть.в моем коде.

В моей DLL я вызываю функцию в целевом процессе по адресу.

РЕДАКТИРОВАТЬ: я тестирую это на моем собственном консольном приложении.

Ответы [ 2 ]

0 голосов
/ 15 мая 2019

Самая основная форма внедрения DLL:

  • Выделение памяти в целевом процессе с использованием VirtualAllocEx ()
  • Запись пути к DLL в эту область памяти с помощью WriteProcessMemory
  • Вызов LoadLibrary () через CreateRemoteThread () в целевом процессе
  • Передача области памяти, в которую записан путь к DLL, на этот вызов

У вас уже есть это, но ваша цель - вручную отобразить DLL и избегать использования LoadLibrary (). Код, который вы предоставили, не сработает, есть еще около 5 шагов. Вам нужно эмулировать все, что обычно делает LoadLibrary ():

  • Загрузка необработанных двоичных данных
  • Карта разделов в целевой процесс
  • шеллкод инжектора загрузчика
  • Есть ли перемещения
  • Исправление импорта
  • Выполнить обратные вызовы TLS
  • Позвоните в DllMain
  • Cleanup

Преимущества сопоставления вручную состоят в том, что вы будете скрыты от ToolHelp32Snapshot (), пройдя список связанных модулей в PEB и NtQueryVirtualMemory.

Если вы хотите сделать это правильно, с достойной проверкой ошибок, это около 350 строк кода, и это становится сложным. Все это делается путем анализа PE-заголовка.

  1. Получить идентификатор процесса цели
  2. Считать файл DLL
  3. Выделите память в целевом процессе того же размера, что и ImageBase из PE-заголовка
  4. Цикл по секциям PE после анализа заголовка PE
  5. Запишите раздел в память по правильному относительному адресу
  6. Запись шелл-кода в целевой процесс
  7. Вызовите CreateRemoteThread и настройте свой шеллкод на выполнение
  8. Ваш шеллкод исправляет импорт и перемещает
  9. Ваш Shellcode выполняет обратные вызовы TLS
  10. Вышеуказанные 2 шага выполняются при разборе DataDirectory в необязательном заголовке
  11. Вызов DllMain () с аргументом DLL_PROCESS_ATTACH

Теперь ваша DLL загружена, и выполняется переключение DLL_PROCESS_ATTACH. Конечно, это сложнее, но это идея.

Я бы ничего не знал об этом, если бы мой друг Бройхон не научил меня этому, поэтому я хочу верить этому ответу. Удачи

0 голосов
/ 20 апреля 2019

.DLL, загруженный в память, - это не то же самое, что файл .DLL на диске. Расположение разделов не одно и то же, и вам нужно иметь дело с перемещениями, таблицей импорта и списком загруженных модулей PEB. Вы в основном должны повторно реализовать NTDLL!Ldr*.

Вызов CreateRemoteThread на LoadLibrary - это другой метод, и при этом параметр потока должен указывать на путь .DLLs в удаленном процессе, а не на точку входа.

...