본문 바로가기
정상을향해/OS·Kernel Driver·Rootkit

2장. 커널 조작 - 파일 핸들 생성 및 심볼릭 링크 추가

by 사이테일 2014. 1. 10.

파일 핸들 생성


유저 모드 프로그램이 커널 드라이버를 사용하려면 유저 모드 프로그램은 해당 드라이버의 핸들을 구해야 한다.


이것은 드라이버가 이름 있는 디바이스로서 등록된 경우에만 가능하다.


일단 드라이버가 이름 있는 디바이스로 등록했다면 유저 모드 프로그램은 파일의 경우와 동일한 방법으로 디바이스 이름을 이용해 핸들을 수할 수 있다.


이는 유닉스에서 모든 것이 파일로 취급되는 것과 상당히 유사하다.


다음은 커널 모드 드라이버가 디바이스를 등록하는 과정을 보여주고 있다.


const WCHAR deviceNameBuffer[] = L"\\Device\\MyDevice";
PDEVICE_OBJECT g_RootkitDevice;		// 디바이스 오브젝트에 대한 전역 포인터 변수
NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,
			IN PUNICODE_STRING RegistryPath)
{
	NTSTATUS		ntStatus;
	UNICODE_STRING		deviceNameUnicodeString;
	// 이름과 심볼릭 링크를 세팅한다.
	RtlInitUnicodeString (&deviceNameUnicodeString,
				deviceNameBuffer);
	// 디바이스 오브젝트 생성
	//
	ntStatus = IoCreateDevice ( DriverObjet,
					0,	// 드라이버 익스텐션
					&deviceNameUnicodeString,
					0x00001234,
					0,
					TRUE,
					&g_RootkitDevice );
	...

위의 예제 코드를 보면 MyDevice라는 이름을 가진 디바이스가 DriverEntry 함수 내에서 생성된다.


1번째 코드에서 "L"은 문자열을 UNICODE로 만든다.


일단 디바이스가 생성되면 유저 모드 프로그램은 그 디바이스를 파일과 같은 방법으로 오픈해서 핸들을 구할 수 있다.


hDevice = CreateFile("\\\\Device\\MyDevice",
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL,
	);
	if ( hDevice == ((HANDLE)-1 )
		return FALSE;


구한 파일 핸들은 ReadFile, WriteFile과 같은 유저 모드 함수의 파라미터로 사용될 수 있다.


또한 IOCTL 명령에도 이용된다.


이런 유저 모드 함수가 호출되면 호출된 함수에 대응되는 IRP가 생성되고 결국엔 드라이버 프로그램이 그것을 처리하게 된다.



심볼릭 링크 추가


심볼릭 링크(Symbolic Link)를 이용하면 파일 핸들을 좀 더 쉽게 사용할 수 있다.


드라이버는 유저 모드 프로그램이 드라이버의 핸들을 쉽게 구할 수 있도록 심볼릭 링크를 이용한다.


심볼릭 링크가 반드시 필요한 것은 아니지만 유저 모드 입장에서는 단순히 심볼릭 이름만 기억하면 되기 때문에 많이 사용된다.


드라이버가 디바이스를 생성한 이후에는 IoCreateSymbolicLink 함수를 호출해서 심볼릭 링크를 생성한다.


루트킷 중에는 심볼릭 링크를 이용하는 것들도 있고 그렇지 않은 것들도 있다.


const WCHAR deviceLinkBuffer[] = L"\\DosDevices\\vicesys2";
const WCHAR deviceNameBuffer[] = L"\\Device\\vicesys2";
NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,
			IN PUNICODE_STRING RegistryPath)
{
	NTSTATUS		ntStatus;
	UNICODE_STRING		deviceNameUnicodeString;
	UNICODE_STRING		deviceLinkUnicodeString;

	// 이름과 심볼릭 링크를 세팅한다.
	RtlInitUnicodeString (&deviceNameUnicodeString,
				deviceNameBuffer);
	RtlInitUnicodeString (&deviceLinkUnicodeString,
				deviceLinkBuffer);
	// 디바이스 오브젝트 생성
	//
	ntStatus = IoCreateDevice ( DriverObject,
					0,	// 드라이버 익스텐션
					&deviceNameUnicodeString,
					FILE_DEVICE_ROOTKIT,
					0,
					TRUE,
					&g_RootkitDevice );
	if ( NT_SUCCESS(ntStatus) ) {
		ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
						 &deviceNameUnicodeString);


심볼릭 링크가 생성되면 유저 모드 프로그램은 "\\.\MyDevice" 문자열을 이용해서 핸들을 구할 수 있다.


심볼릭 링크를 만드는 것은 전적으로 선택사항이다.


그것은 단지 유저 모드 프로그램이 드라이버를 쉽게 찾을 수 있는 편의를 제공할 뿐이다.


hDevice = CreateFile("\\\\.\\MyDevice",
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL
	);
	if (hDevice == ( (HANDLE)-1 )
		return FALSE;