A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about user-mode development.
 #126  by __Genius__
 Sun Mar 14, 2010 9:35 pm
Hello there,
as you know, you could simply Load Drivers from Kernel Mode using undocumented native Api ZwLoadDriver() .
Descriptions from MSDN,
The ZwLoadDriver routine loads a driver into the system.

NTSTATUS
ZwLoadDriver(
IN PUNICODE_STRING DriverServiceName
);


Parameters
DriverServiceName
Pointer to a counted Unicode string that specifies a path to the driver's registry key, \Registry\Machine\System\CurrentControlSet\Services\DriverName, where DriverName is the name of the driver.

Return Value
ZwLoadDriver returns STATUS_SUCCESS or an appropriate error NTSTATUS value.
As you can see this functions get just one parameter, a pointer to unicode string that specified a path to the your driver's registry path .
you can use it in your kernel dirver for simply calling and loading another driver or use it from user mode by importing it from Ntdll.dll.
the steps for importing a function from dlls like NtDll.dll is quite simple,
using LoadLibrary() function you can Load any Dynamic Link library at run time
Code: Select all
HMODULE hNtdll = NULL;
hNtdll = LoadLibrary( “ntdll.dll” );
if LoadLibrary can load your dll successfully it retrieves a handle.
the next step is using GetProcAddress() function to Getting the Address of the specified dll function .
Code: Select all
GetProcAddress( hNtdll, "ZwLoadDriver");
You can use the codes available in attachment to load a driver at run time using ZwLoadDriver() .
Code: Select all
// ZwLoadDriverR.cpp : Defines the entry point for the console application.
//
/// Revised by : __Genius__
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
typedef struct _LSA_UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PVOID Buffer;
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING;
typedef LSA_UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING;
typedef DWORD (CALLBACK* RTLANSISTRINGTOUNICODESTRING)(PVOID, PVOID,DWORD);
RTLANSISTRINGTOUNICODESTRING RtlAnsiStringToUnicodeString;
typedef DWORD (CALLBACK* RTLFREEUNICODESTRING)(PVOID);
RTLFREEUNICODESTRING RtlFreeUnicodeString;
typedef DWORD (CALLBACK* ZWLOADDRIVER)(PVOID);
ZWLOADDRIVER ZwLoadDriver;

int LoadDriver(char * szDrvName, char * szDrvPath)
{

		char szSubKey[200], szDrvFullPath[256];
		LSA_UNICODE_STRING buf1;
		LSA_UNICODE_STRING buf2;
		int iBuffLen;
		HKEY hkResult;
		char Data[4] ;
		Data[0]=1;
		Data[1]=0;
		Data[2]=0;
		Data[3]=0;
		DWORD dwOK;
		iBuffLen = sprintf(szSubKey,"System\\CurrentControlSet\\Services\\%s",szDrvName);
		szSubKey[iBuffLen]=0;
		dwOK = RegCreateKey(HKEY_LOCAL_MACHINE,(LPCWSTR)szSubKey,&hkResult);
		if(dwOK!=ERROR_SUCCESS)
		return false;
		dwOK=RegSetValueEx(hkResult,L"Type",0,4,(const unsigned char *)Data,4);
		dwOK=RegSetValueEx(hkResult,L"ErrorControl",0,4,(const unsigned char *)Data,4);
		dwOK=RegSetValueEx(hkResult,L"Start",0,4,(const unsigned char *)Data,4);
		GetFullPathName((LPCWSTR)szDrvPath, 256, (LPWSTR)szDrvFullPath, NULL);
		printf("Loading driver: %s\r\n", szDrvFullPath);
		iBuffLen = sprintf(szSubKey,"\\??\\%s",szDrvFullPath);
		szSubKey[iBuffLen]=0;
		dwOK=RegSetValueEx(hkResult,(LPCWSTR)"ImagePath",0,1,(const unsigned char *)szSubKey,iBuffLen);
		RegCloseKey(hkResult);
		iBuffLen = sprintf(szSubKey,"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\%s",szDrvName);
		szSubKey[iBuffLen]=0;
		buf2.Buffer = (PVOID)szSubKey;
		buf2.Length = iBuffLen;
		RtlAnsiStringToUnicodeString(&buf1,&buf2,1);
		dwOK = ZwLoadDriver(&buf1);
		RtlFreeUnicodeString(&buf1);
		iBuffLen=sprintf(szSubKey,"%s%s\\Enum","System\\CurrentControlSet\\Services\\",szDrvName);
		szSubKey[iBuffLen]=0;
		RegDeleteKey(HKEY_LOCAL_MACHINE,(LPCWSTR)szSubKey);
		iBuffLen=sprintf(szSubKey,"%s%s\\Security","System\\CurrentControlSet\\Services\\",szDrvName);
		szSubKey[iBuffLen]=0;
		RegDeleteKey(HKEY_LOCAL_MACHINE,(LPCWSTR)szSubKey);
		iBuffLen=sprintf(szSubKey,"%s%s","System\\CurrentControlSet\\Services\\",szDrvName);
		szSubKey[iBuffLen]=0;
		RegDeleteKey(HKEY_LOCAL_MACHINE,(LPCWSTR)szSubKey);
		iBuffLen=sprintf(szSubKey,"\\\\.\\%s",szDrvName);
		szSubKey[iBuffLen]=0;
		return true;
}
int main(int argc, char *argv[])
{
		printf("Load driver with ZwLoadDriver( )\r\n");
		printf("Date: 8th May 2007\r\n");
		printf("Modifed by: GaRY \r\n\r\n");
		if(argc != 3)
		{
			printf("Usage: %s \r\n", argv[0]);
			exit(-1);
		}
		HMODULE hNtdll = NULL;
		hNtdll = LoadLibrary( L"ntdll.dll" );
		if ( !hNtdll )
		{
			printf( "LoadLibrary( NTDLL.DLL ) Error:%d\n", GetLastError() );
			return false;
		}
		RtlAnsiStringToUnicodeString = (RTLANSISTRINGTOUNICODESTRING)
		GetProcAddress( hNtdll, "RtlAnsiStringToUnicodeString");
		RtlFreeUnicodeString = (RTLFREEUNICODESTRING)
		GetProcAddress( hNtdll, "RtlFreeUnicodeString");
		ZwLoadDriver = (ZWLOADDRIVER)
		GetProcAddress( hNtdll, "ZwLoadDriver");
		if(LoadDriver(argv[1], argv[2]) == false) return false;
		return true;
		return 0;
}
Attachments
ZwLoadDriver() Usermode Sample Applcation
(10.17 KiB) Downloaded 66 times
 #131  by a_d_13
 Sun Mar 14, 2010 10:22 pm
Here's some sample code which gets the load driver privilege for the process:

[syntax="c"]
#define SE_LOAD_DRIVER_PRIVILEGE 10L
BOOLEAN GetPrivilege(ULONG PrivilegeValue, BOOLEAN Enable)
{
BOOLEAN OldVal;
typedef DWORD (WINAPI *pRtlAdjustPrivilege)(ULONG,BOOLEAN,BOOLEAN,PBOOLEAN);
pRtlAdjustPrivilege RtlAdjustPrivilege = (pRtlAdjustPrivilege)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAdjustPrivilege");

if( RtlAdjustPrivilege )
return (RtlAdjustPrivilege(PrivilegeValue, Enable, FALSE, &OldVal) == 0);
else
return FALSE;
}
[/syntax]

You call it like this:
[syntax="c"]
GetPrivilege(SE_LOAD_DRIVER_PRIVILEGE, TRUE);
[/syntax]

Thanks,
--AD