Jump to content
Nytro

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

Recommended Posts

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

January 27, 2011 — genesisdatabase

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 http://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;
}

Sursa: Creating your own driver loader in C | Driver Loader | Source Code | Rootkit « Genesis Database

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...