Introduction
Well, I cannot say that this is a regular article. It is rather a small manual and presentation of my tool: Driver Loader, "DLoad
". One may say - there are a lot of device driver loaders on the net, but when I typed in Google search engine: "Driver Loader" - I got only one provided by OSR group on the first page. One can say, search deeper and there are a lot of console utils for this, I will answer: I have finished my school long time ago and now I am an old guy who doesn't have 10 hours of free time daily to waste on searching for such a simple util - I need it in a second, right away; and I don't like messing with console tools, what age we got? I want some nice GUI, intuitive and straightforward user interface (in future I will probably make my Driver Loader voice controlled). So why did I code this one? Because OSRLoader for some reasons doesn't meet my needs? Because I simply don't want to traverse the whole of Google just to find one? Anyways, this version here is the 3rd version of DLoad
, in the package you will also find version 2, which is written in C++ Gtk+, while version 3 is in C# .NET. So, let's see what we have here. While writing this introduction, let me mention 2 things:
[1]. The code is organized in such a way that you can easily take some parts of it and adopt in your own app, rip it apart, mix and then put them back together.
[2]. What actually 3rd version can do:
- Load driver with
ZwSetSystemInformation
- Load driver with
NtLoadDriver
- Load driver with Service Control Manager
- Unload driver
- Delete driver file
- Delete driver registry entries
- Usage of Thread Injection technique
- Injection with
RtlCreateUserThread
- Injection with
CreateRemoteThread
- Injection with
NtCreateThreadEx
- LOAD Mode
- UNLOAD Mode
- Reboot System
- Shutdown System
- Any combination of the above functions
Ok, here we go. I am not going to explain DLoad
v.2 code because it is provided: "just like this", "as an alternative", "maybe you like Gtk?", "whatever...". Besides it is outdated. Let's proceed.
Into the Code
I will explain things in their appearance order. Have a look at the GUI once again. There is no need for "Select Driver" button explanation I think... Ok.
ZwSetSystemInformation
NtLoadDriver
- Service Control Manager
With these methods, you can load driver. ZwSetSystemInformation
is pretty undocumented but has been used for a long long time. In fact, it is not the best method - it is the worst, but still it is. The worst because your driver gets into paged pool, you will not be able to unload it, nor will you be able to delete driver file until system reboot. Ok, how do we call this from C# code. The first thing is to have all native elements declared - for this "Native" class has been created, it looks like this:
public class Native {
.......
public const int NtCurrentProcess = -1;
public const int NtCurrentThread = -2;
public const long NT_SUCCESS = 0x00000000L;
public const int STATUS_SUCCESS = 0;
........
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CLIENT_ID
{
int UniqueProcess;
int UniqueThread;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct UNICODE_STRING
{
public ushort Length;
public ushort MaximumLength;
public string Buffer;
}
...............
[DllImport("ntdll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
unsafe public static extern int ZwSetSystemInformation(
int Value1,
IntPtr Value2,
int Value3
);
I have included there elements needed by DLoad
, you can in a very simple way extend the class for your needs, and create something like this famous "ntdll.h" on the net. Next, we have our "DLoad
" namespace and "DriverLoader
" class, which contains our methods. Like the previous class, you can use this one in your projects easily. Let's take a look at the function.
namespace DLoad {
public class DriverLoader {
public static long ZwStyleLoader(
String DriverPath
)
{ bool en;
int Status; String FullDriverPath = "\\??\\" + DriverPath + '\0'; Native.SYSTEM_LOAD_AND_CALL_IMAGE img;
Status = Native.RtlInitUnicodeString( out (img.ModuleName), FullDriverPath );
if (Status != Native.STATUS_SUCCESS)
return Native.STATUS_INITUNISTRING_FAILURE;
Status = Native.RtlAdjustPrivilege( 10, true, Native.ADJUST_PRIVILEGE_TYPE.AdjustCurrentProcess, out en );
if (Status != Native.STATUS_SUCCESS)
return Native.STATUS_PRIVILEGES_NOT_SET;
IntPtr buffer =
Marshal.AllocCoTaskMem(Marshal.SizeOf(img)); Marshal.StructureToPtr(img, buffer, false);
Status = Native.ZwSetSystemInformation(
Native.SystemLoadAndCallImage, buffer, Marshal.SizeOf(img) );
return Status; }
The coolest thing in this small piece of code is that, man, it is C#! C# for me is a more higher level than interpreted languages, like Perl for example, it is almost like real human language already. Just compare:
static inline char * x_strcpy(char *dest, char *src)
{
int d1, d2, d3;
__asm__ __volatile__ (
"1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al, %%al\n\t"
"jne 1b\n\t"
: "=&a" (d1), "=&S" (d2), "=&D" (d3)
: "1" ((ulong) src), "2" ((ulong) dest))
return dest
}
and
String.Copy
And, still here we got access to Native Windows API! :) Well, otherwise I would never code a thing in C# ;) Back to the subject. This is how it's done. In case of NtLoadDriver
and Service control manager too, 3 methods you have in one single class. Now we call it:
Status = DriverLoader.ZwStyleLoader(FileNamePath);
Status = DriverLoader.NtStyleLoader
(FileNamePath, UnloadDriver, DeleteDriver, DeleteRegEntry, UnloadMode);
DriverLoader.ScmStyleLoader
(FileNamePath, UnloadDriver, DeleteDriver, DeleteRegEntry, UnloadMode);
Next thing: Exit Action.
- Unload driver
- Delete driver file
- Delete driver registry entries
So, this is a standard action which will be performed after loading driver routine. When finally DriverEntry
has been called, what do we do? For example, if your driver just prints "Hello World from driver!" and returns, you simply want it to be unloaded just after execution. So in such a case, you check 'Unload driver' and 'Delete driver registry entries'. If you want driver file to be deleted, you check 'Delete driver file'. And so on. But, if you are testing a more advanced driver, server for example, or driver working with IOCTLs, you don't want it to be unloaded just after execution, in such a case you need to uncheck every Exit Action options.
The next thing is the 'Injection' option - if you will check it, DLoad
will expand presenting a new set of options:
- Injection with
RtlCreateUserThread
- Injection with
CreateRemoteThread
- Injection with
NtCreateThreadEx
Well, the first thing, injection function is implemented in a separate DLL which is built in DLoad
itself. If you check 'use injection' DLoad
will unpack this DLL into windows/ folder and import function from it. Here is a prototype:
DWORD LoadDriverWithInjection(
int ProcID,
char *DriverPath,
int LoadMode,
BOOL UnloadDriverMode,
BOOL DeleteDriverMode,
BOOL DelDrvRegMode,
int Mode,
char *name,
bool un_load
);
So if you will ever need such functionality - you got my DLL already. :)
You may ask, what for? Injection I mean? Well, actually I don't know for sure myself :P It is just here. Anyway, show me another driver loader which uses injection method for loading drivers? Ha! There is no such! And mine is significant by this. Ok, about functions.
[1]. RtlCreateUserThread
- Should work on any windows against any type of process (Notepad, svchost, etc.)
[2]. CreateRemoteThread
- I don't know what more to say about this one than has already been said
[3]. NtCreateThreadEx
- This is the latest Windows specific function (Vista, Server 2008, etc.)
Usage from main app:
[DllImport("DLoadDLL.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int LoadDriverWithInjection(
uint TargProc,
byte[] DriverPath,
int LoadMode,
Boolean UnloadDriverMode,
Boolean DeleteDriverMode,
Boolean DelDrvRegMode,
int Mode,
byte[] DriverName,
Boolean UN_LOAD
);
And then in our main class, we call it:
String TargetProcess = targ_proc_ent.Text;
uint ProcID = Native.GetPidByName(TargetProcess);
String DriverFile = Path.GetFileName(FileNamePath);
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] Test1 = encoding.GetBytes(DriverFile);
byte[] Test2 = encoding.GetBytes(FileNamePath);
StaTus = Native.LoadDriverWithInjection(
ProcID,
Test2,
Native.NTLOADMODE,
UnloadDriver,
DeleteDriver,
DeleteRegEntry,
InjectionModeEx,
Test1,
UnloadMode
);
The next option, if you have checked 'use injection', is to select target process, by default it is Notepad.
Then we got 2 radio buttons:
So, default mode is LOAD mode, and DLoad v.2 [Gtk+] has this mode only. C# version has UNLOAD too. UNLOAD mode is responsible for ... unloading driver! :) simple. For example, if you have loaded driver, without quick unload (I was talking about this somewhere above) and now want to unload it, simply select your driver again (select driver file), check 'UNLOAD' and hit 'Execute' button. Driver will be unloaded. Here is one thing, while selecting method for unload, you can't select 'via ZwSetSystemInformation'
and, method should be the same as when you were loading your driver, so if your driver was loaded with NtLoadDriver
method, it should be unloaded with NtLoadDriver
method (I mean method, not function xD). Hope it is clear.
And last 'widgets' we got here: buttons on the very bottom. From left to the right:
Execute, Info, Exit, Reboot, Shutdown.
Reboot and Shutdown buttons are responsible for rebooting or shutting down machine. They are using Native functions:
void button_reboot_Click(object sender, EventArgs e)
{
bool en;
int Status;
Status = Native.RtlAdjustPrivilege(
19,
true,
Native.ADJUST_PRIVILEGE_TYPE.AdjustCurrentProcess,
out en
);
Status = Native.NtShutdownSystem(
Native.SHUTDOWN_ACTION.ShutdownReboot
);
if (Status != Native.STATUS_SUCCESS)
{
String Debug = String.Format("Failure, Status: {}", Status);
status_output.Text = Debug;
}
}
What makes them more effective: no wait time, no logout window. They are here because I need them here. :) Personally, I am testing drivers on vmware and sometimes there are situations when you need to reboot the machine. Something went wrong but you cannot unload driver coz it got stuck somewhere, or any other bad thing may have happened, or simply fast reboot was needed (I hate to wait until all this business with logging out is done). Off the subject, here is an interesting thing: There is a function, while you are coding Linux kernel modules, which shuts down the computer, without any logging out, in, probably, less than a second! Don't remember its name right now... KernelShutdown maybe? ;) Well, nothing more to explain. Read the code - it is the best self explanatory thing. Thanks for your attention, cheers.
History
- 1st November, 2009: Initial version