ANTICHAT.XYZ    VIDEO.ANTICHAT.XYZ    НОВЫЕ СООБЩЕНИЯ    ФОРУМ  
Баннер 1   Баннер 2
Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей. Здесь обсуждаются безопасность, программирование, технологии и многое другое. Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
Вернуться   Форум АНТИЧАТ > Программирование > С/С++, C#, Delphi, .NET, Asm
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

Коммуникация с драйвером через прерывания
  #1  
Старый 21.08.2007, 22:59
Аватар для _Great_
_Great_
Флудер
Регистрация: 27.12.2005
Сообщений: 2,372
Провел на форуме:
5339610

Репутация: 4360


Отправить сообщение для _Great_ с помощью ICQ
По умолчанию Коммуникация с драйвером через прерывания

Article: Коммуникация с драйвером через прерывания
Author: Great
Date: 21.08.2007
Lang: C++ / ASM

Некоторые личности сильно задолбали вопросами как можно вызвать код драйвера из юзермодного приложения, причем не используя DeviceIoControl и вообще не создавая девайсов.
Ответ простой - зарегистрировать в системе свое прерывание. Про палевность этого метода промолчу - в конце концов, спалить из ринг0 можно все, что угодно.
Итак, мы собрались установить новый обработчик в таблице дескрипторов прерываний. Подробно о прерываниях и о том, как это сделать, я описал в своей статье "Прерывания в защищенном режиме процессора IA-32", поэтому подробно останавливаться на этом не буду.
Пусть наш желаемый вектор равен F3. Тогда в юзермоде можно будет выполнить что-то типа
Код:
mov eax, 2  ; номер функции
call sys_stub
для вызова функции 2 нашего прерывания (пусть оно имеет много функций), где sys_stub состоит из
Код:
sys_stub:
int 0xF3
ret
Удобно, не правда ли, чем создавать девайс, а потом его открывать и делать DeviceIoControl?
Установку прерывания мы осуществим функцией ConnectSoftwareInterrupt(), которая получит регистр IDTR и создаст запись о дескрипторе прерывания.
Выглядит эта функция следующим образом:
Код:
PVOID
ConnectSoftwareInterrupt(
  IN BYTE Interrupt,
  IN PVOID Handler
  )
/*
Arguments:

  Interrupt - Number of interrupt to connect to

  Handler   - Address of handler routine

Return Value:

  Address of old handler

--*/
{
    DWORD OldCr0;
    DWORD OldHandler;
	IDTR Idtr;
    
    //
    // Disable WP and hardware interrupts; get IDTR
    //

    OldCr0 = DisableWP();
	__asm pushfd;
    __asm cli;
	__asm sidt [Idtr];

    //
    // Fill IDT entry
    //

    OldHandler = Idtr.Table[Interrupt].OffsetLow  | ( Idtr.Table[Interrupt].OffsetHigh << 16 );
    
    Idtr.Table[Interrupt].OffsetLow  = (WORD) ( (DWORD)Handler )       & 0xFFFF;
    Idtr.Table[Interrupt].OffsetHigh = (WORD) ( (DWORD)Handler >> 16 ) & 0xFFFF;
    Idtr.Table[Interrupt].Present    = 1;
    Idtr.Table[Interrupt].Default    = 1;
    Idtr.Table[Interrupt].DPL        = 3;
    Idtr.Table[Interrupt].Selector   = 0x0008;
    
    //
    // Restore hardware interrupts and CR0 value
    //

    __asm popfd;
    RestoreWP(OldCr0);

    return (PVOID) OldHandler;
}
Эта функция сперва отключает бит WP в регистре CR0, чтобы разрешить запись на системные страницы, на коих распологается IDT - мы ведь собираемся ее модифицировать.
Далее запрещаются прерывания - установка вектора должна быть атомарной операцией. Потом мы получаем регистр IDTR и модифицируем запись в IDT, чтобы она указывала на новый обработчик.
После этих нехитрых манипуляций мы восстаналиваем запрещенные прерывания, восстанавливаем старое значение CR0 и возвращаем адрес старого обработчика.

После этого нетрудно предположить вероятный код DriverEntry и DriverUnload:

Код:
#define OUR_INT_NO 0xF3
PVOID OldHandler;

void DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
	DPRINT ("[~] DriverUnload()\n");

	IntConnectSoftwareInterrupt( OUR_INT_NO, OldHandler );
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
	DriverObject->DriverUnload = DriverUnload;
	DPRINT("[~] DriverEntry()\n");

	OldHandler = IntConnectSoftwareInterrupt( OUR_INT_NO, NewHandler );

	DPRINT("[+] Driver initialization successful\n");
	return STATUS_SUCCESS;
}
Далее мы определим две функции, которые будут мапировать и размапировать пользовательский буфер - нам не пойдет прямая работа с юзермодными адресами, т.к. код может содержать повышения и понижения IRQL, что немедленно скажется в виде бсода, если соответствующие адреса были выгружены в своп.
Рассмотрим функцию MapUserBuffer подробнее. Чтобы осуществить задуманное, нам придется заблокировать пользовательский буфер в физической памяти - это делает API MmProbeAndLockPages() и отмапировать его в системное адресное пространство (>2 гб) с помощью API MmMapLockedPagesSpecifyCache.
Можно было, конечно, ограничиться блокированием буфера в физической памяти - все равно ошибка страницы не возникнет, т.к. диспетчер памяти не посмеет выгрузить заблокированный буффер. Но некоторые API ядра не любят, когда адреса аргументов лежат ниже 2 гб, поэтому для пущей безопасности, наглядности и важности отмапируем буфер в системное адресное пространство.
Важно понимать, что в данном случае создается вторая проекция того же буфера - если мы изменим значение по полученному отмапированному системному адресу, изменится и пользовательский буфер - поддержка проекций буферов в ОС Windows реализована совершенно прозрачно для нас.
Обе эти API MmProbeAndLockPages и MmMapLockedPagesSpecifyCache требуют, чтобы буфер описывала структура MDL (Memory Descriptor List - Описатель Участка Памяти, перевод не дословный). Эту структуру можно создать функцией IoAllocateMdl, передав ей в качестве первых двух аргументов начало буфера и его длину. Освобождается эта структура вызовом IoFreeMdl после размапирования.
Api MmProbeAndLockPages в случае успеха блокирует страницы буфера в физической памяти (ОЗУ). Но в случае неудачи она выбрасывает исключение, которое нужно поймать в блоке __try/__except и обработать - мы просто уничтожим MDL и вернем NULL, идентифицируя таким образом ошибку.
Ну и последующий вызов MmMapLockedPagesSpecifyCache создает проекцию буфера на системные адреса, возвращая адрес проекции для последуюзего использования.
Функция UnmapUserBuffer() проделывает противоположные операции - уничтожается проекция через MmUnmapLockedPages, снимается блокировка страниц через MmUnlockPages и уничтожается MDL через IoFreeMdl.

Теперь напишем обработчик нашего прерывания. Вот мы попали в начало обработчика.. сначала не помешало бы перезагрузить селекторы ds,es,fs их соответствующими значениями для ring0:
Код:
DWORD FunctionNumber, Arguments, ArgumentsLength;

__declspec(naked) void NewHandler( void )
{
	// Мы в обработчике прерывания. Инициализируем селекторы значениями селекторов ринг0 сегментов
	__asm {
		push fs
		push es
		push ds

		push 0x30
		pop fs

		push 0x23
		pop ds

		push 0x23
		pop es
После этого можно получить параметры прерывания, которые юзермодный код должен был передать в трех регистрах eax, ecx, edx:

Код:
		//
		// Получаем параметры
		// 
		// При вызове прерывания юзермодный код должен поместить в регистры:
		//  EAX = номер функции
		//  ECX = размер аргументов
		//  EDX = указатель на аргументы
		//  

		mov FunctionNumber, eax
		mov ArgumentsLength, ecx
		mov Arguments, edx
	}
Теперь все готово, чтобы обработать прерывание. Вынесем весь код обработки (с логической точки зрения) в функцию ProcessInterrupt(), а здесь лишь вызовем ее и выполним возврат из прерывания:

Код:
	// Весь код обработки будет ТАМ
	ProcessInterrupt( );

	// Восстанавливаем старые селекторы и выходим из прерывания
	__asm {
		pop ds
		pop es
		pop fs
		iretd
	}
}
Что ж. С технической частью покончено. Осталось включить фантазию и написать код для обработки прерывания. Мы поступим следующим образом: юзермодный код должен передавать в регистрах eax,ecx,edx параметры - в комментариях выше написано, что должно содержаться в каждом регистре.
Мы реализуем три функции с номерами 0, 1 и 2 для пользовательского кода. Функция 0 будет просто показывать сообщение и всё, функция 1 попытается прочитать аргументы, а функция 2 попробует записать число 12345678h по адресу пользовательского буфера, заданного в первом аргументе.
Естественно, аргументы и буфера нужно отмапировать по обозначенным выше причинам нашей функцией MapUserBuffer().
Приступим:

Код:
// Тут код обработчика нашего прерывания
ULONG ProcessInterrupt( )
{
	ULONG Status = STATUS_UNSUCCESSFUL;

	// debug break;
	//debugbreak();

	DPRINT("INT F3 call, FunctionNumber=0x%08x, Arguments=0x%08x, ArgumentsLength=0x%08x\n", FunctionNumber, Arguments, ArgumentsLength);

	switch( FunctionNumber )
	{
	case 0: // Функция 0 - покажем сообщение. Аргументов нет
		DPRINT("Function 0 invoked!\n");
		Status = STATUS_SUCCESS;
		break;

	case 1: // Функция 1 - прочитаем пользовательские аргументы
		{
			PMDL Mdl;
			PVOID MappedArgs = MapUserBuffer( (PVOID)Arguments, ArgumentsLength, FALSE /*read*/, &Mdl );

			DPRINT("Function 1 invoked, arguments mapped at address 0x%08x\n", MappedArgs);
			
			if( MappedArgs )
			{
				if( ArgumentsLength >= 4 )
				{
					for( ULONG i=0; i<ArgumentsLength; i+=4 ) {
						DPRINT("Argument[%d]: 0x%08x\n", i/4, ((ULONG*)MappedArgs)[i/4]);
					}

					Status = STATUS_SUCCESS;
				}
				else
				{
					DPRINT("Too small args\n");
					Status = STATUS_INFO_LENGTH_MISMATCH;
				}

				UnmapUserBuffer( MappedArgs, Mdl );
			}
			else
			{
				DPRINT("Arguments mapping failed\n");
				Status = STATUS_ACCESS_VIOLATION;
			}

			break;
		}

	case 2: // Функция 2 - запишем чтонибудь в пользовательский буфер, его адрес задается первым аргументом, а длина - вторым
		{
			if( ArgumentsLength != sizeof(ULONG)*2 ) // не 2 аргумента?
			{
				DPRINT("Arguments length mismatch: 0x%08x\n", ArgumentsLength);
				Status = STATUS_INFO_LENGTH_MISMATCH;
				break;
			}

			PMDL ArgMdl;
			PVOID MappedArgs = MapUserBuffer( (PVOID)Arguments, ArgumentsLength, FALSE /*read*/, &ArgMdl );

			if( MappedArgs )
			{
				DPRINT("Arguments mapped at address 0x%08x\n", MappedArgs);

				PMDL BufMdl;
				PVOID MappedBuffer = MapUserBuffer( ((PVOID*)MappedArgs)[0], ((ULONG*)MappedArgs)[1], TRUE /*write*/, &BufMdl );

				if( MappedBuffer )
				{
					DPRINT("Buffer mapped at address 0x%08x\n", MappedBuffer);

					if( ((ULONG*)MappedArgs)[1] >= 4 ) // длина буфера больше 4? да - пишем дворд
					{
						*(ULONG*)(((ULONG*)MappedArgs)[0]) = 0x12345678;

						DPRINT("Data written\n");

						Status = STATUS_SUCCESS;
					}
					else
					{
						DPRINT("Too small args\n");
						Status = STATUS_INFO_LENGTH_MISMATCH;
					}

					UnmapUserBuffer( MappedBuffer, BufMdl );
				}
				else
				{
					DPRINT("Buffer mapping failed\n");
					Status = STATUS_ACCESS_VIOLATION;
				}

				UnmapUserBuffer( MappedArgs, ArgMdl );
			}

			break;
		}

	default:
		DPRINT("Unknown function number: 0x%08x\n", FunctionNumber);
		Status = STATUS_INVALID_PARAMETER;
	}

	return Status;
}
Поскольку этот код содержит в основном логику, то в технических пояснениях он, я думаю, не нуждается.

Рассмотрим теперь пример пользовательского приложения:

Код:
include 'win32ax.inc'

.data
buffer rb 10

.code

callstub:
   int 0xF3
   ret

start:

   ; Function 0 test
   xor eax, eax
   xor ecx, ecx
   xor edx, edx
   call callstub

   ; Function 1 test
   mov eax, 1
   mov ecx, 8
   push 0xabcdef01  ; arg2
   push 0x12345678  ; arg1
   mov edx, esp
   call callstub
   add esp, 8

   ; Function 2 test [illegal]
   mov eax, 2
   mov ecx, 0 ; too short args
   push 0
   mov edx, esp
   call callstub
   add esp, 4

   ; Function 2 test [legal]
   mov eax, 2
   mov ecx, 8
   push 10
   push buffer
   mov edx, esp
   call callstub
   add esp, 8

   ret

.end start
Функция callstub осуществляет вызов прерывания - я вынес это в отдельную функцию в связи с тем, что OllyDbg, которым мы соберемся отлаживать эту программу, плохо дружит с инструкцией INT, не устанавливая бряка на следующую за ней команду, поэтому придется делать step over через инструкцию call callstub.

В данном коде осуществляется:
1) вызов функции 0, которая только покажет сообщение и все
2) вызов функции 1, которая покажет переданные аргументы. Мы передаем 0x12345678 и 0xabcdef01
3) заведомо неправильный вызов функции 2 - ей нужно передать два параметра (адрес и длина буфера, куда записать число 12345678h), а мы передаем только один. Поэтому она вернет нам в регистре EAX статус STATUS_INFO_LENGTH_MISMATCH, сообщая о том, что аргументов слишком мало для нее.
4) корректный вызов функции 2 с передачей ей двух аргументов - адреса буфера и его длины. Обработчик записывает в первые 4 байта буфера дворд 12345678, что можно непосредственно наблюдать после выполнения этой функции в окне OllyDbg:
Цитата:
00401000 78 56 34 12 xV4
На этом придется завершить сий рассказ и попрощаться. Удачного компилирования и чтобы без BSoD'ов!

PS. Исходники прилагаются
Вложения
Тип файла: rar article_intservice.rar (4.7 Кб, 7 просмотров)
 
Ответить с цитированием

  #2  
Старый 21.08.2007, 23:05
Аватар для KEZ
KEZ
Banned
Регистрация: 18.05.2005
Сообщений: 1,981
Провел на форуме:
1941233

Репутация: 2726


По умолчанию

конечно, на самом деле, грита никто не задалбливал вопросами.
просто он напился раствориля и ему захотелось пообщаться. методом написания большого кол-ва текста с ядерными названиями и тп ; )
а вообще помог, thx!
 
Ответить с цитированием

  #3  
Старый 21.08.2007, 23:08
Аватар для _Great_
_Great_
Флудер
Регистрация: 27.12.2005
Сообщений: 2,372
Провел на форуме:
5339610

Репутация: 4360


Отправить сообщение для _Great_ с помощью ICQ
По умолчанию

Kez, просто ты не первый, кто спрашивал =\
 
Ответить с цитированием

  #4  
Старый 21.08.2007, 23:50
Аватар для GoreMaster
GoreMaster
Участник форума
Регистрация: 28.05.2007
Сообщений: 125
Провел на форуме:
638513

Репутация: 103
По умолчанию

А че в статьи не перенесете? О_о

Great: Да имхо там затеряется, а тут к самый раз

Последний раз редактировалось _Great_; 22.08.2007 в 00:06..
 
Ответить с цитированием

  #5  
Старый 25.08.2007, 23:52
Аватар для Ni0x
Ni0x
Постоянный
Регистрация: 27.08.2006
Сообщений: 367
Провел на форуме:
2009677

Репутация: 472
По умолчанию

Подумал я тут, и вспомнил про LPC.
Цитата:
Windows LPC (Local/Lightweight Procedure Call) – механизм межпроцессорного взаимодействия, используемый RPC для локальной связи. LPC позволяет процессам, используя LPC порты, взаимодействовать между собой посредством сообщений.
А что если из драйвера открыть LPC порт и из клиентского приложения подключиться к нему? Думаю нужно обдумать тему.
 
Ответить с цитированием

  #6  
Старый 26.08.2007, 08:41
Аватар для _Great_
_Great_
Флудер
Регистрация: 27.12.2005
Сообщений: 2,372
Провел на форуме:
5339610

Репутация: 4360


Отправить сообщение для _Great_ с помощью ICQ
По умолчанию

Цитата:
Сообщение от Ni0x  
Подумал я тут, и вспомнил про LPC.

А что если из драйвера открыть LPC порт и из клиентского приложения подключиться к нему? Думаю нужно обдумать тему.
Тоже вариант. Надо будет посмореть
 
Ответить с цитированием

  #7  
Старый 26.08.2007, 11:17
Аватар для Ni0x
Ni0x
Постоянный
Регистрация: 27.08.2006
Сообщений: 367
Провел на форуме:
2009677

Репутация: 472
По умолчанию

Неправильно сказал. Не из драйвера открыть порт, а из юзермод приложения, а в драйвере можно будет подключиться к этому порту через NtConnectPort.
Код:
NtConnectPort(
OUT PHANDLE     ClientPortHandle,
IN PUNICODE_STRING    ServerPortName,
IN PSECURITY_QUALITY_OF_SERVICE  SecurityQos,
IN OUT PLPCSECTIONINFO    ClientSharedMemory OPTIONAL,
OUT PLPCSECTIONMAPINFO    ServerSharedMemory OPTIONAL,
OUT PULONG     MaximumMessageLength OPTIONAL,
IN OUT PVOID     ConnectionInfo OPTIONAL,
IN OUT PULONG     ConnectionInfoLength OPTIONAL );
Вообще тема интересна сама по себе в первую очередь своей необкатанностью. У многих стандартных процессов виндовс есть свои LPC порты, при детальном рассмотрении темы можно хоть малварь писать с новой технологией инфекта и тд. С помощью тогоже rpc можно делать опосредованный вызов функций winapi, т.е вызов функций на лету через посредник. Здесь открываются огромные просторы и новые техники. Собственно, небольшая статья по LPC: http://shellcode.ru/index.php?name=News&file=article&sid=17 и исходники по теме: http://www.argeniss.com/research/hackwininter.zip
 
Ответить с цитированием
Ответ



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Через какие почт. сервисы можно отправлять не через 25 порт Gawab Болталка 1 12.05.2007 19:13
Прерывания в защищенном режиме процессора Ia-32 _Great_ Авторские статьи 4 18.03.2007 20:46
Получение шела через Cgi приложения k00p3r Чужие Статьи 0 08.06.2005 15:04
Взлом сервера Microsoft IIS 6 Через SQL Запросы [Tsh] *CorPSe* АнтиАдмин 3 08.03.2005 12:16



Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT.XYZ