Creating your own driver loader in C | Driver Loader | Source Code | Rootkit


Technically, there’s 2 way of loading a rootkit according to Greg Hoglund when he wrote Rootkits: Subverting the Windows Kernel book.  One is called The Quick-And-Dirty Way to Load a Driver.  This method allows you to “load a driver into the kernel without having to create any registry keys.  “Pageable” refers to memory that can be swapped to disk. If a driver is pageable, any part of the driver could be paged out (that is, swapped from memory to disk). Sometimes when memory is paged out, it cannot be accessed; an attempt to do so will result in the infamous Blue Screen of Death (a system crash)” by using an undocumented API call. 

A sample loader that uses this method is called migbot where you can find the source code here.

//----------------------------------------------------------------
// load a sys file as a driver using undocumented method
//----------------------------------------------------------------
bool load_sysfile()
{
	SYSTEM_LOAD_AND_CALL_IMAGE GregsImage;
	WCHAR daPath[] = L"\\??\\C:\\MIGBOT.SYS";
	//////////////////////////////////////////////////////////////
	// get DLL entry points
	//////////////////////////////////////////////////////////////
	if(!(RtlInitUnicodeString = (RTLINITUNICODESTRING)GetProcAddress( GetModuleHandle("ntdll.dll"),"RtlInitUnicodeString")))
	{
		return false;
	}
	
	if(!(ZwSetSystemInformation = (ZWSETSYSTEMINFORMATION)GetProcAddress(GetModuleHandle("ntdll.dll"),"ZwSetSystemInformation" )))
	{
		return false;
	}
	
	RtlInitUnicodeString(&(GregsImage.ModuleName),daPath);
	if(!NT_SUCCESS(ZwSetSystemInformation(SystemLoadAndCallImage,&GregsImage,sizeof(SYSTEM_LOAD_AND_CALL_IMAGE))))
	{
		return false;
	}
	
	return true;
}

What you see above is the loading code for migbotloader. “Migbot does not offer an unload feature; once it is loaded, it cannot be unloaded until reboot. Think of this as a “fire-and-forget” operation. The advantage to using this method is that it can be stealthier than more-established protocols. The downside is that it complicates the rootkit design. For migbot, this is a good solution; but for complex rootkits with many hooks, this method would require supporting too much overhead.”

The other method would be the right way to load a driver!  According to Greg Hoglund, “the established and correct way to load a driver is to use the Service Control Manager (SCM). Using the SCM causes registry keys to be created. When a driver is loaded using the SCM, it is non-pageable. This means your callback functions, IRP-handling functions, and other important code will not vanish from memory, be paged out, or cause Blue Screens of Death. This is a Good Thing.”

bool _util_load_sysfile(char *theDriverName)
{
	char aPath[1024];
	char aCurrentDirectory[515];

	SC_HANDLE sh = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if(!sh)
	{
		return false;
	}

	GetCurrentDirectory( 512, aCurrentDirectory);

	_snprintf(aPath,1022,"%s\\%s.sys",aCurrentDirectory,theDriverName);
	printf("loading %s\n", aPath);

	SC_HANDLE rh = CreateService(sh,
			theDriverName,
			theDriverName,
			SERVICE_ALL_ACCESS,
			SERVICE_KERNEL_DRIVER,
			SERVICE_DEMAND_START,
			SERVICE_ERROR_NORMAL,
			aPath,
			NULL,
			NULL,
			NULL,
			NULL,
			NULL);

	if(!rh)
	{
		if (GetLastError() == ERROR_SERVICE_EXISTS)
		{
			// service exists
			rh = OpenService(sh,theDriverName,SERVICE_ALL_ACCESS);
			if(!rh)
			{
				CloseServiceHandle(sh);
				return false;
			}
		}
		else
		{
			CloseServiceHandle(sh);
			return false;
		}
	}

	// start the drivers
	if(rh)
	{
		if(0 == StartService(rh, 0, NULL))
		{
			if(ERROR_SERVICE_ALREADY_RUNNING == GetLastError())
			{
				// no real problem
			}
			else
			{
				CloseServiceHandle(sh);
				CloseServiceHandle(rh);
				return false;
			}
		}

		CloseServiceHandle(sh);
		CloseServiceHandle(rh);
	}

	return true;
}

What you are about to see will make you smash your screen!

Generally what you are about to read is the source code that i have created to load your own personal driver loader.  This source code has been written and compiled by me a year ago when i first started my venture into rootkit.  Generally it is a CLI menu driven loader, you can choose to load, unload, start and stop the driver you have.  This source code should be easy to compile in most IDE, the IDE that was used was Microsoft Visual Studio C++ 6.0.

Download the compiled source code (.exe) for whatever reason you need!

/*
 * This source code was written by GenesisDatabase
 * Visit https://genesisdatabase.wordpress.com for more source codes!
 *
 * Date of release: 27th January 2011
 */

#include <windows.h>
#include <stdio.h>

#define Cleanup(x, y, z) {x = y; goto z;}
#define FLUSH fflush(stdin);
#define DRIVER_LOADED		0x00000001
#define DRIVER_STARTED		0x00000002
#define DRIVER_STOPPED		0x00000003
#define DRIVER_UNLOADED		0x00000004
#define DRIVER_CANT_LOAD	0x00000010
#define DRIVER_CANT_START	0x00000020
#define DRIVER_CANT_STOP	0x00000030
#define DRIVER_CANT_UNLOAD	0x00000040

typedef struct
{
	DWORD driverstatus;
}DRIVER_LOADER, *PDRIVER_LOADER;

int FileExists(const char *driverpath)
{
	FILE *fExists = fopen(driverpath, "r");
	if(!fExists)
		return 0;

	fclose(fExists);
	return 1;
}

int myLoadDriver(const char *drivername, const char *driverpath)
{
	SC_HANDLE hSCManager;
	SC_HANDLE hService;
	int ret = 1;

	if(!FileExists(driverpath))
		Cleanup(ret, -1, c);

	hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if(!hSCManager)
		Cleanup(ret, -2, c);

	hService = CreateService(
				hSCManager,
				drivername,
				drivername,
				SERVICE_ALL_ACCESS,
				SERVICE_KERNEL_DRIVER,
				SERVICE_DEMAND_START,//SERVICE_DEMAND_START,
				SERVICE_ERROR_NORMAL,
				driverpath,
				NULL,
				NULL,
				NULL,
				NULL,
				NULL);
	if(!hService)
		Cleanup(ret, -3, c);

c:
	if(hService) CloseServiceHandle(hService);
	if(hSCManager) CloseServiceHandle(hSCManager);
	return ret;
}

int myStartDriver(char *drivername)
{
	SC_HANDLE hSCManager;
	SC_HANDLE hService;
	int ret = 1;

	hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if(!hSCManager)
		Cleanup(ret, -1, c);

	hService = OpenService(hSCManager, drivername, SERVICE_ALL_ACCESS);
	if(!hService)
		Cleanup(ret, -2, c);

	if(!StartService(hService, 0, NULL))
		Cleanup(ret, -3, c);

c:
	if(hService) CloseServiceHandle(hService);
	if(hSCManager) CloseServiceHandle(hSCManager);
	return ret;
}

int myStopDriver(char *drivername)
{
	SC_HANDLE hSCManager;
	SC_HANDLE hService;
	SERVICE_STATUS ss;
	int ret = 1;

	hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if(!hSCManager)
		Cleanup(ret, -1, c);

	hService = OpenService(hSCManager, drivername, SERVICE_ALL_ACCESS);
	if(!hService)
		Cleanup(ret, -2, c);

	if(!ControlService(hService, SERVICE_CONTROL_STOP, &ss))
		Cleanup(ret, -3, c);
c:
	if(hService) CloseServiceHandle(hService);
	if(hSCManager) CloseServiceHandle(hSCManager);
	return ret;
}

int myUnloadDriver(const char *drivername)
{
	SC_HANDLE hSCManager;
	SC_HANDLE hService;
	SERVICE_STATUS ss;
	int ret = 1;

	hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if(!hSCManager)
		Cleanup(ret, -1, c);

	hService = OpenService(hSCManager, drivername, SERVICE_ALL_ACCESS);
	if(!hService)
		Cleanup(ret, -2, c);

	// try to stop service first
	ControlService(hService, SERVICE_CONTROL_STOP, &ss);

	if(!DeleteService(hService))
		Cleanup(ret, -4, c);
c:
	if(hService) CloseServiceHandle(hService);
	if(hSCManager) CloseServiceHandle(hSCManager);
	return ret;
}

void funcLoadDriver(DRIVER_LOADER *dl)
{
	char drivername[256+1];
	char driverpath[256+1];
	char selection;
	int err;

	for( ; ; )
	{
		printf(" Enter driver's name\n - ");
		FLUSH;
		scanf("%256[^\n]", drivername);

		printf(" Enter driver's full path\n - ");
		FLUSH;
		scanf("%256[^\n]", driverpath);

		printf(" Confirm (Y - yes | N - no | B - back): ");
		FLUSH;
		scanf("%c", &selection);

		switch(selection)
		{
			case 'y':
			case 'Y':
				printf(" Performing  : myLoadDriver\n");
				err = myLoadDriver(drivername, driverpath);
				dl->driverstatus = DRIVER_LOADED;
				if(err != 1)
				{
					dl->driverstatus = DRIVER_CANT_LOAD;
					printf(" Error       : myLoadDriver (%d)\n", err);
					printf(" GetLastError: (%d)\n", GetLastError());
					return;
				}printf(" Success     : myLoadDriver\n");
				return;
			case 'n':
			case 'N':
				break;
			case 'b':
			case 'B':
				return;
			default:
				printf(" Wrong option selected, default to N\n");
				break;
		}
		printf("\n");
	}
}

void funcStartDriver(DRIVER_LOADER *dl)
{
	char drivername[256+1];
	char selection;
	int err;

	for( ; ; )
	{
		printf(" Enter driver's name\n -  ");
		FLUSH;
		scanf("%256[^\n]", drivername);

		printf(" Confirm (Y - yes | N - no | B - back): ");
		FLUSH;
		scanf("%c", &selection);

		switch(selection)
		{
			case 'y':
			case 'Y':
				printf(" Performing  : myStartDriver\n");
				err = myStartDriver(drivername);
				dl->driverstatus = DRIVER_STARTED;
				if(err != 1)
				{
					dl->driverstatus = DRIVER_CANT_START;
					printf(" Error       : myStartDriver (%d)\n", err);
					printf(" GetLastError: (%d)\n", GetLastError());
					return;
				}printf(" Success     : myStartDriver\n");
				return;
			case 'n':
			case 'N':
				break;
			case 'b':
			case 'B':
				return;
			default:
				printf(" Wrong option selected, default to N\n");
				break;
		}
		printf("\n");
	}
}

void funcStopDriver(DRIVER_LOADER *dl)
{
	char drivername[256+1];
	char selection;
	int err;

	for( ; ; )
	{
		printf(" Enter driver's name\n -  ");
		FLUSH;
		scanf("%256[^\n]", drivername);

		printf(" Confirm (Y - yes | N - no | B - back): ");
		FLUSH;
		scanf("%c", &selection);

		switch(selection)
		{
			case 'y':
			case 'Y':
				printf(" Performing  : myStopDriver\n");
				err = myStopDriver(drivername);
				dl->driverstatus = DRIVER_STOPPED;
				if(err != 1)
				{
					dl->driverstatus = DRIVER_CANT_STOP;
					printf(" Error       : myStopDriver (%d)\n", err);
					printf(" GetLastError: (%d)\n", GetLastError());
					return;
				}printf(" Success     : myStopDriver\n");
				return;
			case 'n':
			case 'N':
				break;
			case 'b':
			case 'B':
				return;
			default:
				printf(" Wrong option selected, default to N\n");
				break;
		}
		printf("\n");
	}
}

void funcUnloadDriver(DRIVER_LOADER *dl)
{
	char drivername[256+1];
	char selection;
	int err;

	for( ; ; )
	{
		printf(" Enter driver's name\n -  ");
		FLUSH;
		scanf("%256[^\n]", drivername);

		printf(" Confirm (Y - yes | N - no | B - back): ");
		FLUSH;
		scanf("%c", &selection);

		switch(selection)
		{
			case 'y':
			case 'Y':
				printf(" Performing  : myUnloadDriver\n");
				err = myUnloadDriver(drivername);
				dl->driverstatus = DRIVER_UNLOADED;
				if(err != 1)
				{
					dl->driverstatus = DRIVER_CANT_UNLOAD;
					printf(" Error       : myUnloadDriver (%d)\n", err);
					printf(" GetLastError: (%d)\n", GetLastError());
					return;
				}printf(" Success     : myUnloadDriver\n");
				return;
			case 'n':
			case 'N':
				break;
			case 'b':
			case 'B':
				return;
			default:
				printf(" Wrong option selected, default to N\n");
				break;
		}
		printf("\n");
	}
}

int main(int argc, char **argv)
{
	DRIVER_LOADER dl;
	int selection;

	for( ; ; )
	{
		printf(" 1 - Load a driver\n"
			   " 2 - Start service\n"
			   " 3 - Stop service\n"
			   " 4 - Unload a driver\n"
			   " 0 - Exit\n"
			   "\n"
			   " Select an option: ");

		FLUSH;
		scanf("%d", &selection);

		switch(selection)
		{
			case 1:
				funcLoadDriver(&dl);
				break;
			case 2:
				funcStartDriver(&dl);
				break;
			case 3:
				funcStopDriver(&dl);
				break;
			case 4:
				funcUnloadDriver(&dl);
				break;
			case 0:
				printf(" Thanks for using...\n");
				FLUSH;
				getchar();
				return 0;
			default:
				break;
		}
		printf("\n");
	}

	FLUSH;
	getchar();
	return 0;
}
Advertisements

5 Responses to “Creating your own driver loader in C | Driver Loader | Source Code | Rootkit”

  1. c Says:

    bravo. I will try this out when i get home. thanks for the info

  2. רוטקיט ברמת הקרנל @ מרכז הכפר Says:

    […] https://genesisdatabase.wordpress.com/2011/01/27/creating-your-own-driver-loader-in-c-driver-loader-s… – טעינת דרייבר. […]

  3. drakenzul Says:

    thanks for sharing this post 🙂

  4. mans Says:

    can i use it in my rat ? or plz tourital for use this if u can

    • genesisdatabase Says:

      It requires you to know more knowledge in the Windows Kernel before you can implement it on your application. Nonetheless the answer is yes, but I can’t provide you with a tutorial at the moment.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: