Авторские статьи Сырая загрузка DLL(скрытая)

Discussion in 'Статьи' started by slesh, 30 Jul 2009.

  1. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    // 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
     

    Attached Files:

    12 people like this.
  2. s0l_ir0n

    s0l_ir0n Active Member

    Joined:
    14 Mar 2009
    Messages:
    399
    Likes Received:
    144
    Reputations:
    18
    А еще один вариант: прописаться в TLS'e загрузить либу, выполнить нужный код и выгрузиться.
     
  3. fker

    fker Member

    Joined:
    26 Nov 2008
    Messages:
    135
    Likes Received:
    64
    Reputations:
    -1
    Очень познавательно. Неплохо было бы в разделе кодинг сделать подраздел статьи и перенести туда самые стоящие темы, тем более такие есть...
    имхо в разделе "Наши статьи" они затеряются..
     
  4. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Ну куда переносить - это дело модераторов )

    2 s0l_ir0n в любом случае где-бы ты не выполнял код, всё равно ты будеш юзать LoadLibrary которую можно похукать. Тем более можно скрыто хукать - в ntdll через LdrpLoadModule
     
  5. [n]-c0der

    [n]-c0der Member

    Joined:
    3 Feb 2009
    Messages:
    83
    Likes Received:
    24
    Reputations:
    -1
    Нет ее лучше оставить тут, потому что раздел статьи это куча мусора, а это раздел кодинга тут как раз, слэш позновательные вещи пишешь) попробуй перекинуть еще на васм)
     
  6. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    А я там не зареган )
     
  7. [n]-c0der

    [n]-c0der Member

    Joined:
    3 Feb 2009
    Messages:
    83
    Likes Received:
    24
    Reputations:
    -1
    А зря там инфы нужной больше чем на ачате
     
  8. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    936
    Likes Received:
    162
    Reputations:
    27
    Спасибо
     
  9. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    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;
    }
    
     
    1 person likes this.
  10. sn0w

    sn0w Статус пользователя:

    Joined:
    26 Jul 2005
    Messages:
    1,023
    Likes Received:
    1,300
    Reputations:
    327
    зобыл копюрайты напесать ;)
     
    1 person likes this.
  11. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    а копирайты на первой странице )
     
  12. Jes

    Jes Elder - Старейшина

    Joined:
    16 Apr 2007
    Messages:
    370
    Likes Received:
    391
    Reputations:
    34
  13. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Ну вот вечно так, сначало напишу, а потом оказывается что ктото это уже сделал до меня (
    Кстати говоря, если компилить это без отладочный инфы, с оптимизацией + без дефолтовых либ, то код получает очень маленький, что очень удобно для юзанья во всяком малваре.
     
    1 person likes this.
  14. flacs

    flacs Member

    Joined:
    28 Jan 2009
    Messages:
    81
    Likes Received:
    31
    Reputations:
    6
    msrem - классный кодер, и копатель ядра NT был...
    куда он делся? никто не знает?
     
  15. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    2 flacs официальные неподтвержденные данные - не справился с управлением и разбился.
    Но неофициальный, неподтвержденным данным - это было лишь прикрытие для ухода. И это всеголишь смерть ника Ms-Rem
     
  16. Gar|k

    Gar|k Moderator

    Joined:
    20 Mar 2009
    Messages:
    1,166
    Likes Received:
    266
    Reputations:
    82
    Загрузка 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-у за то что терпеливо выслушивал меня и отвечал в аське :)
     
    _________________________
  17. _nic

    _nic Elder - Старейшина

    Joined:
    5 May 2006
    Messages:
    651
    Likes Received:
    54
    Reputations:
    3
    Дллка открывается(файл),но не подгружается.На вызове ProgressImport вылазит ERROR_MOD_NOT_FOUND,проблема втом что эту ф-цию построчно перебрал и так непонял где оишбка вылазит :confused: В какую сторону копать?
    ЗЫ:на морозе закаментил
    Code:
    					else if (!ProgressImport(retadr))// обработаем импорт
    					{
    						/*VirtualFree((void*)retadr, 0, MEM_RELEASE);// если ошибка освободим память
    						retadr = 0;*/
    					}
    
    Функция из ддлки нормально отработала ,WTF?
     
    #17 _nic, 17 Mar 2010
    Last edited: 17 Mar 2010
  18. erbolsyn

    erbolsyn New Member

    Joined:
    27 May 2012
    Messages:
    1
    Likes Received:
    0
    Reputations:
    0
    Хоть ветка и старая, но все же, может кому пригодится, нашел еще один баг в функции обработки таблицы импорта:
    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, спасибо за полезный код!