// To Moderators. Если что, то можете перекинуть в статьи. // Для Кодинга - слишком много написано // Для Статей - хз. тема не очень, просто познавательная. // Короче, решать вам ) (С) SLESH 2009 Сырая загрузка DLL (скрытая) ВВЕДЕНИЕ: Иногда появляется такая необходимость чтобы скрытно загрузить и использовать определенную DLL, но не всегда это удается сделать. Существует 3 основных способа подгрузить в своё адресное пространство какую либо DLL: 1) Использование таблицы импорта - самый паливный способ, потому как о загрузке этой DLL будут знать все 2) Использование функции LoadLibrary и GetProcAddress - Дают намного лучше результат, но всё равно DLL можно обнаружить в списке загруженных модулей. 3) Второй способ + манипулирование с системными структурами, для удаления DLL из списка. Способ хорош, но есть один недостаток - При хуке LoadLibrary сразу будет вычислена эта DLL. Так же эти способы обладают большим недостатком - нельзя удалить файл DLL не прекратив работу с ней. Но существует довольно специфический механизм основанный на ручной загрузке DLL в память, не используя существующих функций предназначенных для этой цели. Вот как раз этот метод и будет рассмотрен. АЛГОРИТМ: Теперь можно рассмотреть алгоритм загрузки, использования и выгрузки DLL 1) Считываем заголовки из DLL (DOS + PE + SERCTIONS) 2) На основании данных в этих заголовках выделяем память под нашу DLL 3) Загружаем все секции и заголовки 4) Обрабатываем релоки 5) Обрабатываем таблицу импорта. 6) Передаем управление на точку входа в DLL с флагом указывающим что мы подгружаем DLL 7) т.к. система ничего не знает о нашей DLL то придется самому получать адреса функций из таблицы экспорта. 8) получаем вручную адрес функции и используем её 9) уведомляем DLL и том, что мы её выгружаем 10) освобождаем память. С виду кажется что очень много необходимо сделать, хотя на практике это всё занимает строчек 300-350. Для реализации всего будет использован Си компилятор от VS++ 2008. И так нам необходимо теперь написать 3 функции. HideLoadLibrary - для загрузки DLL HideGetProcAddress - для поиска адресов HideFreeLibrary - для выгрузки DLL Также нам предварительно понадобятся следующие типы Code: #define MAX_SECTIONS 10 // максимальное кол-во секций в файле typedef unsigned long ULONG, *PULONG; typedef unsigned short USHORT, *PUSHORT; // структура для релоков typedef struct _FIXREC { ULONG PageRVA; ULONG BlockSize; USHORT TOR[]; } TFIXREC,*PFIXREC; // структура таблицы импорта typedef struct _IMPORT_TABLE { ULONG LookUp; ULONG TimeStamp; ULONG ForwardChain; ULONG NameRVA; ULONG AddresTableRVA; } IMPORT_TABLE, *PIMPORT_TABLE; #pragma pack(1) // отключаем выравнение // структура таблица адресов typedef struct _ADDRESS_TABLE { USHORT Hint; char Name[]; } ADDRESS_TABLE, *PADDRESS_TABLE; #pragma pack() // выключаем выравнение STEP 1: Загрузка DLL Code: HMODULE __stdcall HideLoadLibrary(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)GetModuleHandleA(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; // возвращаем адрес загруженного модуля в памяти } Обработка релоков представляет из себя следующую функцию: Code: // обработка релоков ULONG ProgressReloc(ULONG filebase) { ULONG PE; ULONG IB; ULONG cnt; ULONG x; ULONG Delta; PFIXREC fixrec; USHORT fixtype; USHORT fixoffset; PE = *(ULONG*)(filebase + 0x3C) + filebase; // получаем адрес PE заголовка IB = *(ULONG*)(PE + 0x34); // IMAGE BASE if (filebase == IB) return 1; // Если совпадает с загруженным адресом, то фиксить не нужно ничего Delta = filebase - IB; // выцесляем дельта смещение. if (!*(ULONG*)(PE + 0xA0)) return 1; // если нет релоков то выходим fixrec = (PFIXREC)(*(ULONG*)(PE + 0xA0) + filebase); // получаем адрес таблицы релоков while (fixrec->BlockSize) // если таблица не пуста { cnt = (fixrec->BlockSize - 8) >> 1; // вычеслим кол-во элементов for (x = 0; x < cnt; x++) { fixtype = (fixrec->TOR[x]) >> 12; // типа фиксации fixoffset = (fixrec->TOR[x]) % 4096; // офсет внутри 4-х килобайтового блока if (!fixtype) continue; // если 0, то фиксация не нужна if (fixtype == 3) // если 3, то прибавить дельта смещение { *(ULONG*)(filebase+fixoffset+fixrec->PageRVA) = *(ULONG*)(filebase+fixoffset+fixrec->PageRVA) + Delta; } else return 0; // все остальные случае вызовут ошибку (хотя их и не будет теоретически) } fixrec = (PFIXREC)((ULONG)fixrec + fixrec->BlockSize); // следующая таблица реловок } return 1; } Обработка таблицы импорта: Code: // Обработчик импорта ULONG ProgressImport(ULONG filebase) { ULONG PE; HMODULE lib; PIMPORT_TABLE ImportTable; PADDRESS_TABLE AddressTable; ULONG IAT_Index; ULONG RVA; ULONG addr; PE = *(ULONG*)(filebase + 0x3C) + filebase; // адрес PE заголовка if (!*(ULONG*)(PE + 0x80)) return 1; // если нет импорта то выходим ImportTable = (PIMPORT_TABLE)(*(ULONG*)(PE + 0x80) + filebase); // адрес таблицыы импорта while (ImportTable->NameRVA) // пока есть DLL откуда нужно импортировать функции { // проверим что DLL была ранее загружена lib = GetModuleHandleA((char*)(ImportTable->NameRVA + filebase)); if (!lib) // если не загружена была, то загрузим её. { lib = LoadLibraryA((char*)(ImportTable->NameRVA + filebase)); } if (!lib) return 0; // если не загрузилась, значит ошибка if (ImportTable->LookUp) // Если импорт идет через LookUp { RVA = ImportTable->LookUp + filebase; } else // если через таблицу адресов импорта { RVA = ImportTable->AddresTableRVA + filebase; } IAT_Index = 0; while (*(ULONG*)RVA) // если есть ссылка на таблицу имен { AddressTable = (PADDRESS_TABLE)(*(ULONG*)RVA + filebase); // получаем адрес структуры где хранится HINT NAME if (AddressTable->Name[0]) // если импорт по имени { addr = (ULONG)GetProcAddress(lib, AddressTable->Name); // найдем адрес } else // если импорт по ординалу { addr = (ULONG)GetProcAddress(lib, (char*)AddressTable->Hint); } // если есть IAT то сохраним в неё найденный адрес if (ImportTable->AddresTableRVA) { *(ULONG*)(ImportTable->AddresTableRVA + filebase + IAT_Index) = addr; } else // иначе сохраним туда откуда брали { *(ULONG*)RVA = addr; } RVA += 4; // сделающий элемент IAT_Index += 4; } ImportTable = (PIMPORT_TABLE)((ULONG)ImportTable+sizeof(IMPORT_TABLE)); // следующая таблица } return 1; } Теперь мы может использовать функцию HideLoadLibrary точно также как и LoadLibrary Важно отметить, что нельзя использовать функцию GetProcAddress для DLL загруженных через HideLoadLibrary. Это связанно с тем, что система предварительно проверяет факт загрузки DLL итд итп. По этому необходимо будет использовать собственную функцию - HideGetProcAddress, которая является полным аналогом GetProcAddress. Но при этом умеет искать адреса в DLL, которые загруженные не только через HideLoadLibrary, но и даже через LoadLibrary. Также после загрузки DLL можно вообще удалить её файл. Как видно из кода, его быстро можно переписать так, чтобы можно было загружать DLL сразу из памяти. Это будет удобно для реализации дополнительной защиты программ. STEP 2: Поиск адресов Как уже было выше сказано – функция HideGetProcAddress находит адреса в DLL. При этом не важно, каким образом была загружена DLL в память, главное чтобы она была корректно загружена (обработка импорта и релоков). Также как GetProcAddress, данная функция может принимать в качестве параметров не только имя функции, но и её ординал. Код функции HideGetProcAddress Code: FARPROC _stdcall HideGetProcAddress(HMODULE hModule, char* lpProcName) { ULONG PE; PIMAGE_EXPORT_DIRECTORY ED; PULONG NamePointerRVA; PUSHORT OrdinalTableRVA; PULONG AddressTableRVA; ULONG ret = 0; USHORT hint = 0; USHORT index; char * name; ULONG addr; ULONG CNT_FUNC; if ((ULONG)lpProcName <= 0xFFFF)// если импорт по ординалу { hint = (USHORT)lpProcName; // запишем наш ординал } if (hModule) // если указан модуль откуда грузить { PE = *(ULONG*)((ULONG)hModule + 0x3C) + (ULONG)hModule;// адрес PE заголовка ED = (PIMAGE_EXPORT_DIRECTORY)(*(ULONG*)((ULONG)PE + 0x78) + (ULONG)hModule); // адрес таблицы экспорта NamePointerRVA = (ULONG*)(ED->AddressOfNames + (ULONG)hModule); // адрес таблицы имен OrdinalTableRVA = (USHORT*)(ED->AddressOfNameOrdinals + (ULONG)hModule); // адрес таблицы ординалов AddressTableRVA = (ULONG*)(ED->AddressOfFunctions + (ULONG)hModule); // адрес таблицы адерсов // вычесляем наибольшее значение - кол-во функций if (ED->NumberOfNames > ED->NumberOfFunctions) { CNT_FUNC = ED->NumberOfNames; } else { CNT_FUNC = ED->NumberOfFunctions; } // пройдемся по всем функциям for (USHORT x = 0; x < CNT_FUNC; x++) { if (x < ED->NumberOfFunctions) // если есть имя у функции { name = (char*)(NamePointerRVA[x] + (ULONG)hModule); // запомним имя index = OrdinalTableRVA[x]; // запомним ординал } else // если имени нет { name = 0; // имени нет index = x; // ординал = текущей позиции } // вычесляем адрес функции addr = AddressTableRVA[index] + (ULONG)hModule; if ((hint == index + ED->Base)|| // если это наш ординал (name && !strcmp(name, lpProcName))) // если есть имя и оно наше { ret = addr; // нашли адрес break; // прекратим обход экспорта } } } return (FARPROC)ret; // вернем адрес } STEP 3: Выгрузка DLL Если в процессе работы нам уже не нужна DLL, то мы можем её выгрузить по средствам функции HideFreeLibrary. Важно отметить, что нестоит выгружать через данную функцию DLL загруженные через LoadLibrary. Хоть эта функция и является аналогом FreeLibrary, но всё же она далека от неё. Код HideFreeLibrary: Code: // функция выгрузки DLL BOOL __stdcall HideFreeLibrary(HMODULE hModule) { PIMAGE_DOS_HEADER DosHeader; PIMAGE_NT_HEADERS PeHeader; BOOL ret = false; ULONG EP; if (hModule) // если указан адрес модуля { DosHeader = (PIMAGE_DOS_HEADER)hModule; // DOS заголово PeHeader = (PIMAGE_NT_HEADERS)(DosHeader->e_lfanew + (ULONG)hModule);// PE заголовок EP = PeHeader->OptionalHeader.AddressOfEntryPoint + (ULONG)hModule; // Точка входа __asm { push 0 push DLL_PROCESS_DETACH // флаг выгрузки DLL push hModule call EP // передаем управление на точку входа в DLL } VirtualFree(hModule, 0, MEM_RELEASE); // очищаем память ret = true; } return ret; } ТЕСТИРОВАНИЕ Для теста попробуем подгрузить копию user32.dll. Найти в ней адрес функции MessageBoxA и вызвать её. Для начала скопируем библиотеку с новым именем: Windows\system32\user32.dll к примеру в e:\u32.dll Код тестовой программы (консольный проект): Code: // переменная для адреса MessageBoxA int (WINAPI *MY_MessageBox)(DWORD, char*, char*, DWORD); int _tmain(int argc, _TCHAR* argv[]) { HMODULE lib; // загрузим скрыто DLL lib = HideLoadLibrary("e:\\u32.dll"); // выведем на экран адрес куда она была загружена printf("LIB=%0.8X\n", lib); if (lib) // если загружена нормально { // ищем адрем функции *(FARPROC *)&MY_MessageBox = HideGetProcAddress(lib, "MessageBoxA"); // выводим найденный адрес printf("MY_MessageBox=%0.8X\n", MY_MessageBox); if (MY_MessageBox) // если адрес найден { // вызываем функцию MY_MessageBox(0, "TEST MSG", "MY MESSAGE BOX", MB_ICONINFORMATION); } HideFreeLibrary(lib); // выгружаем DLL } return 0; } Тестирование показало следующее: 1) Загружаются спокойно DLL написанные на С, FASM и Delphi (остальные не проверял) 2) Многие системные DLL (kernel32.dll, user32.dll) – тоже загружаются без проблем 3) Проблема возникла лишь при загрузке ws2_32.dll. Т.е. сама DLL загрузилась без проблем, а также без проблем были найдены адреса функций. Но функция WSAStartup возвращала значение об ошибке: Возможно, это связано с дополнительной инициализацией DLL, которая происходит в ядре и используется функцией LoadLibrary. ЛИТЕРАТУРА Для полного понимания этого всего, советую почитать следующие вещи 1) ФОРМАТ ИСПОЛНЯЕМЫХ ФАЙЛОВ PortableExecutables (PE) // Hard Wisdom Это txt файл (PEFMT003.TXT) в котором описаны основные структуры PE файла. Находится в аттаче. 2) Путь воина – внедрение в pe/coff файлы // Крис Касперски Хорошее описание PE файлов, особенно таблиц импорта и экспорта. Находится по адресу http://www.insidepro.com/kk/019/019r.shtml P.S. В аттаче найдете исходники всего этого и файл PEFMT003.TXT (С) SLESH 2009
Очень познавательно. Неплохо было бы в разделе кодинг сделать подраздел статьи и перенести туда самые стоящие темы, тем более такие есть... имхо в разделе "Наши статьи" они затеряются..
Ну куда переносить - это дело модераторов ) 2 s0l_ir0n в любом случае где-бы ты не выполнял код, всё равно ты будеш юзать LoadLibrary которую можно похукать. Тем более можно скрыто хукать - в ntdll через LdrpLoadModule
Нет ее лучше оставить тут, потому что раздел статьи это куча мусора, а это раздел кодинга тут как раз, слэш позновательные вещи пишешь) попробуй перекинуть еще на васм)
UPDATE 1 Нашел вот небольшой баг в функции Обработки импорта, в частности глюки при работе с импортом по ординалам. Исправил. Вот нова версия функции Code: ULONG ProgressImport(ULONG filebase) { ULONG PE; HMODULE lib; PIMPORT_TABLE ImportTable; PADDRESS_TABLE AddressTable; ULONG IAT_Index; ULONG RVA; ULONG addr; PE = *(ULONG*)(filebase + 0x3C) + filebase; // адрес PE заголовка if (!*(ULONG*)(PE + 0x80)) return 1; // если нет импорта то выходим ImportTable = (PIMPORT_TABLE)(*(ULONG*)(PE + 0x80) + filebase); // адрес таблицыы импорта while (ImportTable->NameRVA) // пока есть DLL откуда нужно импортировать функции { // проверим что DLL была ранее загружена lib = GetModuleHandleA((char*)(ImportTable->NameRVA + filebase)); if (!lib) // если не загружена была, то загрузим её. { lib = LoadLibraryA((char*)(ImportTable->NameRVA + filebase)); } if (!lib) return 0; // если не загрузилась, значит ошибка if (ImportTable->LookUp) // Если импорт идет через LookUp { RVA = ImportTable->LookUp + filebase; } else // если через таблицу адресов импорта { RVA = ImportTable->AddresTableRVA + filebase; } IAT_Index = 0; while (*(ULONG*)RVA) // если есть ссылка на таблицу имен { AddressTable = (PADDRESS_TABLE)(*(ULONG*)RVA + filebase); // получаем адрес структуры где хранится HINT NAME if ((ULONG)AddressTable < 0x80000000 && AddressTable->Name[0]) // если импорт по имени { addr = (ULONG)GetProcAddress(lib, AddressTable->Name); // найдем адрес } else // если импорт по ординалу { addr = (ULONG)GetProcAddress(lib, (char*)((USHORT)AddressTable)); } // если есть IAT то сохраним в неё найденный адрес if (ImportTable->AddresTableRVA) { *(ULONG*)(ImportTable->AddresTableRVA + filebase + IAT_Index) = addr; } else // иначе сохраним туда откуда брали { *(ULONG*)RVA = addr; } RVA += 4; // сделающий элемент IAT_Index += 4; } ImportTable = (PIMPORT_TABLE)((ULONG)ImportTable+sizeof(IMPORT_TABLE)); // следующая таблица } return 1; }
[offtop] на васме кстати подобный метод описан (в виде нжекта) http://wasm.ru/article.php?article=apihook_2
Ну вот вечно так, сначало напишу, а потом оказывается что ктото это уже сделал до меня ( Кстати говоря, если компилить это без отладочный инфы, с оптимизацией + без дефолтовых либ, то код получает очень маленький, что очень удобно для юзанья во всяком малваре.
2 flacs официальные неподтвержденные данные - не справился с управлением и разбился. Но неофициальный, неподтвержденным данным - это было лишь прикрытие для ухода. И это всеголишь смерть ника Ms-Rem
Загрузка dll из памяти Понадобилось загружать dll из памяти сразу вот переделал несколько функцию Code: // непосредственно функция загрузки DLL из памяти by Gar|k HMODULE __stdcall HideLoadLibraryFromMemory(unsigned char * pMemory) { ULONG retadr = 0; DWORD rb = 0; IMAGE_DOS_HEADER *DosHeader; IMAGE_NT_HEADERS *PeHeader; IMAGE_SECTION_HEADER * Section[MAX_SECTIONS]; if (pMemory != NULL) { // считаем DOS заголовок DosHeader=(IMAGE_DOS_HEADER *)&pMemory[0]; if (DosHeader->e_magic == IMAGE_DOS_SIGNATURE) // проверим сигнатуру { // установим указатель на PE заголовок rb=DosHeader->e_lfanew; // считаем заголовок PeHeader=(IMAGE_NT_HEADERS *)&pMemory[rb]; rb+=sizeof(IMAGE_NT_HEADERS); if (PeHeader->Signature == IMAGE_NT_SIGNATURE) // проверим сигнатуру { // выделим память столько, сколько указано в 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)),&pMemory[rb], sizeof(IMAGE_SECTION_HEADER) * PeHeader->FileHeader.NumberOfSections); // если есть Rich данные то и их тоже скопируем if (sizeof(IMAGE_DOS_HEADER) < DosHeader->e_lfanew) { memcpy((void*)(retadr + sizeof(IMAGE_DOS_HEADER)), &pMemory[sizeof(IMAGE_DOS_HEADER)], DosHeader->e_lfanew - sizeof(IMAGE_DOS_HEADER)); } // обработаем каждую секцию for (int i = 0; i < PeHeader->FileHeader.NumberOfSections; i++) { Section[i]=(IMAGE_SECTION_HEADER *)&pMemory[rb]; rb+=sizeof(IMAGE_SECTION_HEADER); // считаем всё секцию memcpy((void*)(retadr + Section[i]->VirtualAddress),&pMemory[Section[i]->PointerToRawData],Section[i]->SizeOfRawData); } // Обработаем релоки if (!ProgressReloc(retadr)) // если ошибка { VirtualFree((void*)retadr, 0, MEM_RELEASE); // освободим память retadr = 0; } else if (!ProgressImport(retadr))// обработаем импорт { VirtualFree((void*)retadr, 0, MEM_RELEASE);// если ошибка освободим память retadr = 0; } else { rb=PeHeader->OptionalHeader.AddressOfEntryPoint; __asm { mov eax, rb add eax, retadr // EAX = ENTRY POINT push 0 push DLL_PROCESS_ATTACH // ставим флаг что подгрузили DLL push retadr call eax // передадим управление на точку входа в DLL } } } } } // закрываем файл } return (HMODULE)retadr; // возвращаем адрес загруженного модуля в памяти } Спасибо SLESH-у за то что терпеливо выслушивал меня и отвечал в аське
Дллка открывается(файл),но не подгружается.На вызове ProgressImport вылазит ERROR_MOD_NOT_FOUND,проблема втом что эту ф-цию построчно перебрал и так непонял где оишбка вылазит В какую сторону копать? ЗЫ:на морозе закаментил Code: else if (!ProgressImport(retadr))// обработаем импорт { /*VirtualFree((void*)retadr, 0, MEM_RELEASE);// если ошибка освободим память retadr = 0;*/ } Функция из ддлки нормально отработала ,WTF?
Хоть ветка и старая, но все же, может кому пригодится, нашел еще один баг в функции обработки таблицы импорта: Code: // -- cutted -- AddressTable = (PADDRESS_TABLE)(*(ULONG*)RVA + filebase); // получаем адрес структуры где хранится HINT NAME if ((ULONG)AddressTable < 0x80000000 && AddressTable->Name[0]) // если импорт по имени { addr = (ULONG)GetProcAddress(lib, AddressTable->Name); // найдем адрес } else // если импорт по ординалу { addr = (ULONG)GetProcAddress(lib, (char*)((USHORT)AddressTable & 0xFFFF)); // <-- тут } // -- cutted -- ЗЫ. slesh, спасибо за полезный код!