HMODULE __stdcall GetLoadLibrary(char * LibFileName)
{
ULONG retadr = 0;
DWORD rb;
HANDLE hFile;
IMAGE_DOS_HEADER DosHeader;
IMAGE_NT_HEADERS PeHeader;
IMAGE_SECTION_HEADER Section[MAX_SECTIONS];
char tmp[1024];
// если dll ранее была загружена
retadr = (ULONG)GetModuleHandle(LibFileName);
if (retadr) return (HMODULE)retadr; // то вернем её адрес и не будем мучатся
// откроем файл на чтение
hFile = CreateFileA(LibFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
// считаем DOS заголовок
ReadFile(hFile, &DosHeader, sizeof(IMAGE_DOS_HEADER), &rb, 0);
if (DosHeader.e_magic == IMAGE_DOS_SIGNATURE) // проверим сигнатуру
{
// если есть какимето данные между DOS заголовком и PE
// то считаем их. В MS компиляторах это часто Rich данные
if (sizeof(IMAGE_DOS_HEADER) < DosHeader.e_lfanew)
{
ReadFile(hFile, &tmp[0], DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER), &rb, 0);
}
// установим указатель в файле на PE заголовок
SetFilePointer(hFile, DosHeader.e_lfanew, 0, FILE_BEGIN);
// считаем заголовок
ReadFile(hFile, &PeHeader, sizeof(IMAGE_NT_HEADERS), &rb, 0);
if (PeHeader.Signature == IMAGE_NT_SIGNATURE) // проверим сигнатуру
{
// считаем 10 секций
ReadFile(hFile, &Section[0], sizeof(IMAGE_SECTION_HEADER)*PeHeader.FileHeader.NumberOfSections, &rb, 0);
// выделим память столько, сколько указано в SIZE OF BASE
retadr = (ULONG)VirtualAlloc(0, PeHeader.OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE);
if (retadr) // если память выделилась
{
// скопируем туда DOS заголовок
memcpy((void*)retadr, &DosHeader, sizeof(IMAGE_DOS_HEADER));
// скопируем туда PE заголовок
memcpy((void*)(retadr + DosHeader.e_lfanew), &PeHeader, sizeof(IMAGE_NT_HEADERS));
// скопируем туда таблицу секций
memcpy((void*)(retadr + DosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS)), &Section[0], sizeof(IMAGE_SECTION_HEADER)* PeHeader.FileHeader.NumberOfSections);
// если есть Rich данные то и их тоже скопируем
if (sizeof(IMAGE_DOS_HEADER) < DosHeader.e_lfanew)
{
memcpy((void*)(retadr + sizeof(IMAGE_DOS_HEADER)), &tmp[0], DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER));
}
// обработаем каждую секцию
for (int i = 0; i < PeHeader.FileHeader.NumberOfSections; i++)
{
// установим указатель в файле не начало секции в файле
SetFilePointer(hFile, Section[i].PointerToRawData, 0, FILE_BEGIN);
// считаем всё секцию
ReadFile(hFile, (void*)(retadr + Section[i].VirtualAddress), Section[i].SizeOfRawData, &rb, 0);
}
// Обработаем релоки
if (!ProgressReloc(retadr)) // если ошибка
{
VirtualFree((void*)retadr, 0, MEM_RELEASE); // освободим память
retadr = 0;
}
else if (!ProgressImport(retadr))// обработаем импорт
{
VirtualFree((void*)retadr, 0, MEM_RELEASE);// если ошибка освободим память
retadr = 0;
}
else
{
__asm
{
mov eax, PeHeader.OptionalHeader.AddressOfEntryPoint
add eax, retadr // EAX = ENTRY POINT
push 0
push DLL_PROCESS_ATTACH // ставим флаг что подгрузили DLL
push retadr
call eax // передадим управление на точку входа в DLL
}
}
}
}
}
CloseHandle(hFile); // закрываем файл
}
return (HMODULE)retadr; // возвращаем адрес загруженного модуля в памяти
}