Здравствуйте всем, подскажите пожалуйста, если можно то пример создания резолвера функций mvscrt и Api. То есть в проекте visual studio мы убираем зависимости от Kernel32 например и C Runtime, а потом используя библиотеку lazy importer получаем динамически функцию в процессе выполнения, но нужно помимо этого сделать так чтобы везде не прописывать LI_FIND, LI_GET используя библиотеку lazy importer, а обычно вызывать эти функции, но при этом их динамически получать, пример нашёл в интернете, но что-то не получается пока. Библиотеку импорта создал через dumpbin и последующий def файл пропустил через lib для создания lib файла. Как правильно сделать, уважаемые гуру. Вот пример Код (C++): // resolver.h void crt_init(); void* ___memcpy(void* dst, const void* src, size_t size); // resolver.cpp uintptr_t msvcrtLib = 0; #define _VCRTFunc(fn) LI_GET(msvcrtLib,fn) void crt_init() { msvcrtLib = reinterpret_cast<uintptr_t>(LI_FIND(LoadLibraryA)(_S("msvcrt.dll"))); } // Dynamic memcpy void* ___memcpy(void* dst, const void* src, size_t size) { return _VCRTFunc(memcpy)(dst, src, size); } // resolver_export.cpp #include "resolver.h" #define RESOLVER extern "C" RESOLVER void* __cdecl memcpy(void* dst, const void* src, size_t size) { return ___memcpy(dst, src, size); }
Зачем? Дёргаете PEB библиотеки ntdll.dll Код (C++): unsigned __int64 __readgsqword(unsigned __int32 Offset); #pragma intrinsic(__readgsqword) PEB *__ptr64 peb = (PEB *__ptr64)__readgsqword(0x60); // mov rax, gs:[0x60] (x64) void *__ptr64 NtDllBase = (void *__ptr64)0; LIST_ENTRY *__ptr64 pList = peb->Ldr->InLoadOrderModuleList.Flink; for (unsigned __int32 i = 0; i < 2; i++) { LDR_DATA_TABLE_ENTRY *__ptr64 pDataTable = (LDR_DATA_TABLE_ENTRY *__ptr64)(pList); if (i == 1) { NtDllBase = pDataTable->DllBase; break; } else pList = pList->Flink; } затем ищите в ней функцию LdrLoadDll Код (C++): IMAGE_DOS_HEADER *__ptr64 pDos = (IMAGE_DOS_HEADER *__ptr64)NtDllBase; IMAGE_NT_HEADERS64 *__ptr64 pNt = (IMAGE_NT_HEADERS64 *__ptr64)((unsigned __int64)NtDllBase + pDos->e_lfanew); IMAGE_EXPORT_DIRECTORY *__ptr64 pExpDir = (IMAGE_EXPORT_DIRECTORY *__ptr64)((unsigned __int64)NtDllBase + pNt->OptionalHeader.DataDirectory[0].VirtualAddress); unsigned __int32 *__ptr64 AddrFunc = (unsigned __int32 *__ptr64)((unsigned __int64)NtDllBase + pExpDir->AddressOfFunctions); // номер функции ===LdrLoadDll=== в таблице экспорта ntdll.dll = 138 unsigned __int32 *__ptr64 fn_LdrLoadDll = (unsigned __int32 *__ptr64)0; for (; 138 < pExpDir->NumberOfNames;) { fn_LdrLoadDll = (unsigned __int32 *__ptr64)((unsigned __int64)NtDllBase + AddrFunc[138]); break; } прототип функции LdrLoadDll Код (C++): typedef __int32(__stdcall *__ptr64 _LdrLoadDll)( unsigned short *__ptr64 PathToFile, unsigned __int32 Flags, UNICODE_STRING *__ptr64 ModuleFileName, void *__ptr64 *__ptr64 ModuleHandle ); _LdrLoadDll LdrLoadDll; LdrLoadDll = (_LdrLoadDll)fn_LdrLoadDll; и прототип функции LdrGetProcedureAddress Код (C++): typedef __int32(__stdcall *__ptr64 _LdrGetProcedureAddress)( void *__ptr64 ModuleHandle, STRING *__ptr64 FunctionName, unsigned __int16 Oridinal, void *__ptr64 *__ptr64 FunctionAddress ); _LdrGetProcedureAddress LdrGetProcedureAddress; // номер функции ===LdrGetProcedureAddress=== в таблице экспорта ntdll.dll = 129 unsigned __int32 *__ptr64 fn_LdrGetProcedureAddress = (unsigned __int32 *__ptr64)0; for (; 129 < pExpDir->NumberOfNames;) { fn_LdrGetProcedureAddress = (unsigned __int32 *__ptr64)((unsigned __int64)NtDllBase + AddrFunc[129]); break; } LdrGetProcedureAddress = (_LdrGetProcedureAddress)fn_LdrGetProcedureAddress; В VS: 1. Открываем свойства проекта, идём в C\C++ -> Создание кода -> Основные проверки времени выполнения (ставим "По умолчанию"), Проверка безопасности ("Отключить проверку безопасности (/GS-)") 2. C\C++ -> Дополнительно -> Пропускать имена стандартных библиотек (ставим "Да (/ZI)") 3. Переходим Компоновщик -> Ввод -> Игнорировать все стандартные библиотеки (ставим "Да (/NODEFAULTLIB)") 4. Определяем точку входа в коде программы как Код (C++): void mainCRTStartup(void) { } Всё, теперь имеется загрузчик бибилиотек и функций без kernel32.dll
Спасибо, код понятен, загружаем с более низкого уровня получается, но допустим я вызываю функцию memcpy в программе, а она вызывается динамически, как переопределить её стандартный вызов. --- Сообщение объединено, 2 апр 2024 --- k3rnl, а как переопределить функции, чтобы вызывать их как обычно, но получать динамически их, спасибо, просто понять не могу.
Код (C++): char dst[128]; const char* src = "this is just a source stringos"; LI_FN(memcpy)(dst, src, sizeof(dst)-1);
alex_dz, это понятно, как вызвать просто memcpy, чтобы везде макросы не писать, где требуется множество вызовов этих функций
Очень много используется в библиотеках сторонних, поэтому я хотел узнать, как правильно написать резолвер, чтобы вызывая к примеру memcpy или другую функцию можно было вызвать её как будто она присутствует статически при загрузке естественно, но передавая параметры в другую функцию которая уже динамически её найдёт, в сообщении указал примерный код посмотрите, искал в интернете, нужно создать библиотеку импорта из dll, это я сделал, у меня ошибка в определении функции, я не знаю как оформить правильно, просто пока опыта мало)
Примерно то, что ты хочешь, msvc умеет делать сам через отложенные импорты: /DELAYLOAD (Delay Load Import) | Microsoft Learn Для каждой функции из библиотеки компилятор генерирует заглушку, при первом вызове которой делается загрузка библиотеки, если та ещё не загружена, и поиск нужной функции. Но если тебе надо вручную сделать поиск (например, чтобы не светить названиями библиотек и функций) - то простых способов нет: придётся как-то говорить линкеру, чтобы он использовал твои функции. Например, пройтись по всем экспортам нужных тебе библиотек, на основе этого списка скриптом сделать статическую либу, которая для каждого экспорта сгенерирует заглушку с Lazy Importer'ом, и подложить эту либу линкеру вместо оригинальной либы.
Вы имеете ввиду библиотеку импорта сделать правильно? Но я это сделал, из msvcrt.dll создал библиотеку импорта с именами функций экспорта, потом включил её в каталог дополнительных библиотек в компоновщике
В общем решил вопрос, в силу малого пока опыта понимания процессов на с++ и использования visual studio пришлось много сопутствующих вещей изучать. В общем суть резолвера проста как апельсин и заключается в создании статической библиотеки lib (не библиотеки импорта) из переходников функций, которые перенаправляют вызов уже на поиск реальной функции через библиотеку lazy import, которую включил в эту статическую библиотеку, в основном коде вызываем исходные функции как есть по оригинальным именам, а библиотека уже делает свою работу, естественно как отметили выше нужно отключить все лишние зависимости, а также убрать исключения из проекта, это касается не только основного кода, где используется библиотека, но и в самой библиотеке lib (тоже убрать зависимости). В основной программе определить точку входа как void mainCRTStartup(void). Всем спасибо.