#c #c #windows #security #code-injection
#c #c #Windows #Безопасность #Внедрение кода
Вопрос:
Я пытался запустить 64-разрядную DLL исключительно в виртуальной памяти процессов без «ручного сопоставления» (т. Е. Вручную Разрешая перемещения / импорт).
План состоял в том, чтобы внедрить код в целевое приложение и загрузить модуль с помощью обычных средств, таких как LoadLibrary.
Я предполагал, что LoadLibrary исправит перемещение / импорт модулей самостоятельно, поскольку именно для этого он и предназначен.
После загрузки модуля введенный код получит информацию о модуле с помощью GetModuleInformation, перенесет ее во временный буфер памяти, освободит модуль, выделит память по тому же адресу, по которому он был первоначально загружен, запишет ее обратно и выполнит точку входа.
Я считаю, что на этом последнем шаге возникает ошибка.
Чтобы проверить эту теорию, я жестко запрограммировал адреса точек входа, отладил удаленное приложение с помощью функции Visual Studio «Прикрепить к процессу», эмулировал аналогичную среду для исправления неправильной арифметики указателей, и все это для того, чтобы получить немного больше информации о том, в чем может заключаться ошибка.
Вот некоторая общая информация, которая может быть или не быть полезной:
- Оба приложения (инжектор и DLL) скомпилированы для запуска в 64-разрядных архитектурах
- Тестовое приложение, которое я использовал для тестирования метода внедрения, — это приложение центра обновления Windows (wuauclt.exe — находится в /System32/), он, конечно, компилируется для запуска как 64-разрядный PE
- Хост-компьютер: Windows 7 Home Premium (тип системы: 64-разрядная операционная система)
Что касается информации, относящейся непосредственно к инжектору, идет:
- Метод первичной инъекции кода работает (насколько я могу судить), и я доказал это с помощью отладки caveman с помощью MessageBoxA
- В проекте используется многобайтовый набор символов с отключенной оптимизацией кода. Код был скомпилирован с использованием VS 2013 Ultimate (оба проекта созданы для версии x64)
- Проверки SDL отключены, поскольку используются небезопасные функции (strcpy и друзья)
- Инжектор отлаживается с повышенными привилегиями (такими же высокими, как SE_DEBUG_PRIVILEGES) при каждом запуске.
Предисловие к коду: Приведенный ниже код никоим образом не предназначен для того, чтобы выглядеть красиво или демонстрировать хорошие методы программирования. Имейте это в виду при просмотре кода. Он был специально разработан для тестирования метода внедрения кода, чтобы убедиться, что он работает. Если у вас возникли проблемы с компоновкой, структурой и т. Д. Программы, Не стесняйтесь исправлять их и / или реструктурировать их самостоятельно. Я здесь не по этой причине. Если это не то, что привело к ошибке, то это полностью причина, по которой я здесь 🙂
Код для инжектора: http://pastebin.com/FF5G9nnR
/*
Some of the code was truncated (functions not pertaining to the injection), but
I have verified the code compiles and works correctly with it's injeteme.dll counterpart
*/
#include <Windows.h>
#include <Psapi.h>
#define TARGET_PID 1124
typedef BOOL(WINAPI* pFreeLibrary)(HMODULE);
typedef HMODULE(WINAPI* pLoadLibraryA)(LPCSTR);
typedef HANDLE(WINAPI* pGetCurrentProcess)(void);
typedef BOOL(WINAPI* DLL_MAIN)(HMODULE, DWORD, LPVOID);
typedef HANDLE(WINAPI* pOpenProcess)(DWORD, BOOL, DWORD);
typedef BOOL(WINAPI* pVirtualFree)(LPVOID, SIZE_T, DWORD);
typedef int(__stdcall* pMessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
typedef LPVOID(WINAPI* pVirtualAlloc)(LPVOID, SIZE_T, DWORD, DWORD);
typedef BOOL(WINAPI* pGetModuleInformation)(HANDLE, HMODULE, LPMODULEINFO, DWORD);
typedef BOOL(WINAPI* pWriteProcessMemory)(HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T*);
//////////////////////////////////////////////////////////////////
struct IINFO
{
LPVOID stubAddr;
LPVOID retStatusPtr;
char fullModulePath[MAX_PATH];
DWORD pId, sizeOfCurrStruct;
// DEBUG
pMessageBoxA messageBox;
pOpenProcess openProcess;
pVirtualFree virtualFree;
pFreeLibrary freeLibrary;
pLoadLibraryA loadLibrary;
pVirtualAlloc virtualAlloc;
pGetCurrentProcess getCurrProc;
pWriteProcessMemory writeMemory;
pGetModuleInformation getModInfo;
};
static DWORD WINAPI stub(IINFO *iInfo)
{
HMODULE hMod;
MODULEINFO mInfo;
DLL_MAIN dllMain;
LPVOID lpNewMod, lpTempModBuff;
PIMAGE_DOS_HEADER pIDH;
PIMAGE_NT_HEADERS pINH;
iInfo->messageBox(NULL, iInfo->fullModulePath, NULL, 0);
hMod = iInfo->loadLibrary(iInfo->fullModulePath);
if (!hMod)
return 0;
if (!iInfo->getModInfo(iInfo->getCurrProc(), hMod, amp;mInfo, sizeof(MODULEINFO)))
return 0;
lpTempModBuff = iInfo->virtualAlloc(NULL, mInfo.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpTempModBuff)
return 0;
if (!iInfo->writeMemory(iInfo->getCurrProc(), lpTempModBuff, mInfo.lpBaseOfDll, mInfo.SizeOfImage, NULL))
return 0;
if (!iInfo->freeLibrary(hMod))
return 0;
lpNewMod = iInfo->virtualAlloc(mInfo.lpBaseOfDll, mInfo.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpNewMod)
return 0;
// using wpm since we have already acquired the function
if (!iInfo->writeMemory(iInfo->getCurrProc(), lpNewMod, lpTempModBuff, mInfo.SizeOfImage, NULL))
return 0;
if (!iInfo->virtualFree(lpTempModBuff, 0, MEM_RELEASE))
return 0;
/*if (!iInfo->virtualFree(iInfo, 0, MEM_RELEASE))
return 0;
iInfo->messageBox(NULL, NULL, NULL, 0); */
pIDH = (PIMAGE_DOS_HEADER)lpNewMod;
if (!pIDH)
return 0;
pINH = (PIMAGE_NT_HEADERS)((LPBYTE)lpNewMod pIDH->e_lfanew);
if (!pINH)
return 0;
dllMain = (DLL_MAIN)((LPBYTE)lpNewMod pINH->OptionalHeader.AddressOfEntryPoint);
if (!dllMain)
return 0;
iInfo->messageBox(NULL, NULL, NULL, 0);
dllMain((HINSTANCE)lpNewMod, DLL_PROCESS_ATTACH, NULL);
return 1;
}
static DWORD WINAPI stubEnd(){ return 0; }
//////////////////////////////////////////////////////////////////
int main()
{
HANDLE hThread = 0;
DWORD dwStubSize = 0;
int sucResp = 0, count = 0;
HMODULE hUser32 = 0, hNtdll = 0;
char fullPathName[] = "C:\injectme.dll";
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, TARGET_PID);
if (!hProc || hProc == INVALID_HANDLE_VALUE)
return 0;
__int64 SizeOfStub = (LPBYTE)stubEnd - (LPBYTE)stub;
LPVOID lpStub = VirtualAllocEx(hProc, NULL, SizeOfStub, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpStub)
return 0;
hUser32 = LoadLibraryA("user32.dll");
if (!hUser32)
return 0;
hNtdll = LoadLibraryA("kernel32.dll");
if (!hNtdll)
return 0;
IINFO iInfo = {};
iInfo.retStatusPtr = amp;sucResp;
strcpy(iInfo.fullModulePath, fullPathName);
iInfo.sizeOfCurrStruct = sizeof(IINFO);
iInfo.stubAddr = lpStub;
iInfo.pId = GetCurrentProcessId();
iInfo.messageBox = (pMessageBoxA)GetProcAddress(hUser32, "MessageBoxA");
iInfo.openProcess = (pOpenProcess)GetProcAddress(hNtdll, "OpenProcess");
iInfo.virtualFree = (pVirtualFree)GetProcAddress(hNtdll, "VirtualFree");
iInfo.freeLibrary = (pFreeLibrary)GetProcAddress(hNtdll, "FreeLibrary");
iInfo.loadLibrary = (pLoadLibraryA)GetProcAddress(hNtdll, "LoadLibraryA");
iInfo.virtualAlloc = (pVirtualAlloc)GetProcAddress(hNtdll, "VirtualAlloc");
iInfo.getCurrProc = (pGetCurrentProcess)GetProcAddress(hNtdll, "GetCurrentProcess");
iInfo.writeMemory = (pWriteProcessMemory)GetProcAddress(hNtdll, "WriteProcessMemory");
iInfo.getModInfo = (pGetModuleInformation)GetProcAddress(hNtdll, "K32GetModuleInformation");
LPVOID lpStubInfo = VirtualAllocEx(hProc, NULL, sizeof(IINFO), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpStubInfo)
return 0;
if (!WriteProcessMemory(hProc, lpStub, stub, SizeOfStub, NULL))
return 0;
if (!WriteProcessMemory(hProc, lpStubInfo, amp;iInfo, sizeof(iInfo), NULL))
return 0;
hThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpStub, lpStubInfo, 0, NULL);
if (!hThread || hThread == INVALID_HANDLE_VALUE)
return 0;
WaitForSingleObject(hThread, INFINITE);
return 1;
}
Код для вводимой библиотеки DLL: http://pastebin.com/8WXxcpu1
#include <Windows.h>
BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpParam)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
MessageBoxA(NULL, "Hello from injectme.dll!", "", MB_OK | MB_ICONINFORMATION);
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Ошибка при выполнении приведенного выше кода дословно (при условии, что вы также применили приведенные выше настройки и используете аналогичную среду) в отладчике VS2013 выглядит следующим образом:
«Необработанное исключение в 0x000007FEEA5125D4 в wuauclt.exe : 0xC0000005: Место выполнения с нарушением доступа 0x000007FEEA5125D4.»
После просмотра процесса «wuauclt.exe » в Process Hacker я ясно вижу, что модуль был выделен изначально (при загрузке через LoadLibrary) в 0x7fef67c0000. Это показано в контекстном меню -> в разделе разное-> выгруженные модули.
После двойного щелчка «wuauclt.exe «, вы можете просмотреть виртуальную память приложения, чтобы убедиться, что все работает так, как должно быть. Я могу подтвердить, что для этого текущего сеанса буфер памяти RWX был выделен в 0x7fef67c0000 с точным размером выгруженного модуля, содержащего injectme.Модуль dll. При копании в injectme.dll с CFF Explorer, тогда RVA точки входа кажется 0x132C, что не складывается, учитывая, что ошибка находится намного дальше в памяти. Кроме того, я могу проверить еще два буфера памяти RWX, содержащие заглушку для ввода кода и информационную структуру. Оглядываясь назад, информационная структура, вероятно, не нуждается в RWX. В любом случае, я не могу хоть на жизнь разобраться в ошибке.
Я надеюсь, что вы сможете мне помочь. Я чрезвычайно благодарен за ваше время.
Комментарии:
1. принесите код сюда
2. @manetsus мой плохой, код был перенесен из pastebin. Извините за любые неудобства.
Ответ №1:
Я чувствую, что вам не хватает фундаментального понимания для такого сложного проекта. Вы смешиваете концепции из довольно разных областей.
Сама Windows очень, очень мало заботится о языке программирования, который вы использовали при разработке. Вы получаете либо CLR-код (.Net), либо машинный код. В данном случае это x64. Но Windows действительно не заботится о strcpy
проверках or SDL. С этим должен иметь дело компилятор, а не ОС. Скорее всего strcpy
, он даже не выживет, когда его код будет полностью встроен. Но, по-видимому, по какой-то странной причине у вас отключена оптимизация — опять путаница между компилятором и ОС.
Однако Windows заботится о других концепциях, которые вы не упоминаете. В основном это были бы рандомизация ASLR и DEP — рандомизация компоновки адресного пространства и предотвращение выполнения данных. Это методы, позволяющие не допустить хакеров, а вы взламываете. Так что это не удивительно.
Я не уверен, что под «RWX» вы подразумеваете «Чтение, запись, выполнение», потому что вы должны знать, что это вызывает проблемы. DEP вдохновлен более подходящим названием W ^ X, Write XOR ИЛИ eXecute .
Однако более вероятным виновником является ASLR. Windows по замыслу пытается загружать DLL-файлы по непредсказуемым адресам, поскольку это устраняет целый класс взломов. Похоже, вы предполагаете адрес загрузки, в то время как Windows действительно использует другой адрес.
Последняя ошибка может заключаться в том, что вы не понимаете, где выполняются перемещения. Чтобы увеличить количество совместно используемых страниц, перемещения выполняются в таблице адресов импорта, а не в самом коде. IAT — это таблица батутов и, следовательно, исполняемая. Ваш сбой также может быть отсутствующим IAT.
Комментарии:
1. Прежде всего, я хотел бы искренне поблагодарить вас за ответ. Полное раскрытие, я работаю над этим всего несколько дней и не думал о DEP / ASLR.
2. (Извините, мой предыдущий комментарий был прерван до того, как я смог полностью ответить)
3. Ну, похоже, что нажатие return автоматически отправит комментарий. Я новичок в этом и собираюсь предположить, что они не должны быть очень длинными. Я пытаюсь спросить, продвигаясь вперед, как вы думаете, где я должен сосредоточить свое внимание? Насколько я понимаю, LoadLibrary должен выполнять любые изменения, чтобы переданный ему модуль мог эффективно выполняться. Как только у него появляется возможность сделать это, он просто перемещается в памяти. Его последнее пристанище находится там, где оно началось. Захватывает точку входа «на лету» и не предполагает. Извините, но у меня осталось немного путаницы.
4. @astra: Мое высокоуровневое наблюдение заключается в том, что вы, вероятно, столкнулись с проблемой XY. Хакерство, которое вы пытаетесь осуществить, почти наверняка не лучший способ решить вашу реальную проблему.
5. Это чрезвычайно справедливый ответ. Все вышесказанное сделано в попытке обойти механизмы обнаружения другого процесса. Более того, описанный выше метод будет предназначен исключительно для предварительной инъекции . Процесс, пытающийся обнаружить мой модуль, проанализирует все процессы, которые в данный момент взаимодействуют с ним, поэтому мне требуется использование, казалось бы, доброкачественного хоста, который будет выступать в качестве прикрытия для окончательного внедрения. Процесс, пытающийся заблокировать мой модуль, является процессом античита. Еще раз спасибо за всю помощь, надеюсь, я не докучаю вам всеми своими вопросами.