代码:If KeGetCurrentIrql < DISPATCH_LEVEL then begin {使用任意内存} End else begin {只能使用不分页内存} End; 下面让我们来看一个简单驱动程序例子SystemModules,该例子的主要动作集中在DriverEntry函数里。我们会分配分页内存(你应该记得DriverEntry运行在IRQL =PASSIVE_LEVEL等级,所以使用分页内存自然是没问题了),然后写进一些信息,再释放,并让系统卸载驱动程序。
代码:unit SystemModules;
interface
uses nt_status, ntoskrnl, native;
function _DriverEntry(pDriverObject:PDRIVER_OBJECT; pusRegistryPath:PUNICODE_STRING): NTSTATUS; stdcall;
implementation
function _DriverEntry(pDriverObject:PDRIVER_OBJECT; pusRegistryPath:PUNICODE_STRING): NTSTATUS; var cb:DWORD; p, pTemp:PVOID; dwNumModules:DWORD; pMessage, pModuleName: PCHAR; buffer: array [0..295] of char; szModuleName: array[0..100] of char; iCnt, iPos: integer; begin DbgPrint('SystemModules: Entering DriverEntry'); cb := 0; ZwQuerySystemInformation(SystemModuleInformation, @p, 0, cb); if cb <> 0 then begin p := ExAllocatePool(PagedPool, cb); if p <> nil then begin DbgPrint('SystemModules: %u bytes of paged memory allocted at address %08X', cb, p); if ZwQuerySystemInformation(SystemModuleInformation, p, cb, cb) = STATUS_SUCCESS then begin pTemp := p; dwNumModules := DWORD(p^); cb := (sizeof(SYSTEM_MODULE_INFORMATION) + 100) * 2; pMessage := ExAllocatePool(PagedPool, cb); if pMessage <> nil then begin DbgPrint('SystemModules: %u bytes of paged memory allocted at address %08X', cb, pMessage); memset(pMessage, 0, cb); inc(PCHAR(pTemp), sizeof(DWORD)); for iCnt := 1 to dwNumModules do begin iPos := (PSYSTEM_MODULE_INFORMATION(pTemp))^.ModuleNameOffset; pModuleName := @((PSYSTEM_MODULE_INFORMATION(pTemp))^.ImageName[iPos]); if (_strnicmp(pModuleName, 'ntoskrnl.exe', length('ntoskrnl.exe')) = 0) or (_strnicmp(pModuleName, 'ntice.sys', length('ntice.sys')) = 0) then begin memset(@szModuleName, 0, sizeof(szModuleName)); strcpy(@szModuleName, pModuleName); _snprintf(@buffer, sizeof(buffer), 'SystemModules: Found %s base: %08X size: %08X', @szModuleName, (PSYSTEM_MODULE_INFORMATION(pTemp))^.Base, (PSYSTEM_MODULE_INFORMATION(pTemp))^._Size); strcat(pMessage, @buffer); end; inc(PCHAR(pTemp), sizeof(SYSTEM_MODULE_INFORMATION)); end; if pMessage[0] <> #0 then begin DbgPrint(pMessage); end else begin DbgPrint('SystemModules: Found neither ntoskrnl nor ntice'); end; ExFreePool(pMessage); DbgPrint('SystemModules: Memory at address %08X released', pMessage); end; end; ExFreePool(p); DbgPrint('SystemModules: Memory at address %08X released', p); end; end; DbgPrint('SystemModules: Leaving DriverEntry'); result := STATUS_DEVICE_CONFIGURATION_ERROR; end;
代码:if cb <> 0 then begin p := ExAllocatePool(PagedPool, cb); ExAllocatePool从分页内存池分配需要数量的内存。如果是不分页内存呢,就把第一个参数PagedPool相应地改成NonPagedPool。ExAllocatePool比用户模式的HeapAlloc 简单一些,只有两个参数:第一个参数是内存池类型(分页、不分页),第二个参数是需要的内存尺寸。简单吧!
代码:if p <> nil then 如果ExAllocatePool 返回非零值,那么它就是一个指向分配buffer的指针。 检查调试信息会发现ExAllocatePool 分配的buffer地址是页尺寸大小的倍数。假如请求的内存的大小大于或等于(>=)页尺寸(我们这个例子中,是明显地大了),分配的内存会从页边界开始分配。
代码:if ZwQuerySystemInformation(SystemModuleInformation, p, cb, cb) = STATUS_SUCCESS then begin pTemp := p; 我们再次调用ZwQuerySystemInformation,这次使用buffer的指针和尺寸作为参数。 如果返回的是STATUS_SUCCESS,那么buffer之中就包含了系统模块列表,数据以SYSTEM_MODULE_INFORMATION(在native.dcu中定义)结构队列的形式存在。
代码:SYSTEM_MODULE_INFORMATION = packed record Reserved: array[0..1] of DWORD; Base: PVOID; _Size: DWORD; Flags: DWORD; Index: WORD; Unknown: WORD; LoadCount: WORD; ModuleNameOffset: WORD; ImageName: array[0..255] of char; end;
代码:for iCnt := 1 to dwNumModules do begin 我们对结构队列循环dwNumModules次数,来寻找ntoskrnl.exe 和 ntice.sys。 在多处理器的系统ntoskrnl.exe模块的名字应该是ntkrnlmp.exe,如果你使用的是带PAE(物理地址扩展)的系统,那么系统会分别地支持ntkrnlpa.exe 和 ntkrpamp.exe。我这里当然假定你不会拥有那么牛的机器了^_^。
假如上文提及的模块被找到,我们就用_snprintf(内核提供)函数格式化字符串,字符串中包含了模块名、基地址和尺寸,然后将字符串加到buffer去。 代码:if pMessage[0] <> #0 then begin DbgPrint(pMessage); end else begin DbgPrint('SystemModules: Found neither ntoskrnl nor ntice'); end; 这里很容易看懂,由于我们前面把字符串都置了零,这里很容易判断我们是否找到了什么东西。 代码:ExFreePool(pMessage); DbgPrint('SystemModules: Memory at address %08X released', pMessage); end; end; ExFreePool(p);