var hSCManager:THANDLE; hService:THANDLE; acModulePath: array [0..MAX_PATH] of char; _ss:SERVICE_STATUS; hDevice:THANDLE;
adwInBuffer: array [0..NUM_DATA_ENTRY] of DWORD; adwOutBuffer: array [0..NUM_DATA_ENTRY] of DWORD; dwBytesReturned:DWORD; IOCTL_GET_PHYS_ADDRESS: DWORD; lpTemp: PChar; iRetValue: boolean;
{生成控制码} function CTL_CODE(DeviceType, Func, Method, Access: DWORD): DWORD; begin result := (((DeviceType) SHL 16) or ((Access) SHL 14) or ((Func) SHL 2) or (Method)); end;
begin IOCTL_GET_PHYS_ADDRESS := CTL_CODE(FILE_DEVICE_UNKNOWN, $800, METHOD_BUFFERED, FILE_READ_ACCESS + FILE_WRITE_ACCESS); hSCManager := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS); if hSCManager <> 0 then begin GetFullPathName(PChar('VirtToPhys.sys'), sizeof(acModulePath), acModulePath, lpTemp); hService := CreateService(hSCManager, 'VirtToPhys', 'Virtual To Physical Address Converter', SERVICE_START + SERVICE_STOP + _Delete, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, acModulePath, nil, nil, nil, nil, nil); if hService <> 0 then begin {驱动程序的DriverEntry过程将被调用} if StartService(hService, 0, lpTemp) = true then begin {驱动程序将接收IRP_MJ_Create I/O请求包(IRP)} hDevice := CreateFile('\\.\slVirtToPhys', GENERIC_READ+GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0); if hDevice <> INVALID_HANDLE_VALUE then begin {准备送往驱动程序的数据包} adwInBuffer[0] := GetModuleHandle(nil); adwInBuffer[1] := GetModuleHandle('kernel32.dll'); adwInBuffer[2] := GetModuleHandle('user32.dll'); adwInBuffer[3] := GetModuleHandle('comctl32.dll'); {驱动程序将接收IRP_MJ_DEVICE_CONTROL I/O请求包} iRetValue := DeviceIoControl(hDevice, IOCTL_GET_PHYS_ADDRESS, @adwInBuffer, sizeof(adwInBuffer), @adwOutBuffer, sizeof(adwOutBuffer), dwBytesReturned, nil); if (iRetValue = true) and (dwBytesReturned <> 0) then begin {取程序名} GetModuleFileName(adwInBuffer[0], acModulePath, sizeof(acModulePath)); ShowMessage(Format('Modules BASE Physical'#13#10 + '----------------------------------'#13#10 + '%s %8.8X %8.8X'#13#10 + 'kernel32.dll %8.8X %8.8X'#13#10 + 'user32.dll %8.8X %8.8X'#13#10 + 'comctl32.dll %8.8X %8.8x', [ExtractFileName(acModulePath), adwInBuffer[0], adwOutBuffer[0], adwInBuffer[1], adwOutBuffer[1], adwInBuffer[2], adwOutBuffer[2], adwInBuffer[2], adwOutBuffer[2]])); end else begin ShowMessage('Can''t send control code to device.'); end; {Driver will receive IRP of type IRP_MJ_CLOSE} CloseHandle(hDevice); end else begin ShowMessage('Device is not present.'); end; {DriverUnload proc in our driver will be called} ControlService(hService, SERVICE_CONTROL_STOP, _ss); end else begin ShowMessage('Can''t start driver.'); end; DeleteService(hService); CloseServiceHandle(hService); end else begin ShowMessage('Can''t register driver.'); end; CloseServiceHandle(hSCManager); end else begin ShowMessage('Can''t connect to Service Control Manager.'); end; end. 这个代码包括了注册和启动驱动程序,以及作为客户端程序和设备进行通讯的代码。代码将输入的数据发送给设备,并将设备返回的数据格式化并显示出来。 驱动被装载后,VirtToPhys驱动程序创建了一个名为"devVirtToPhys"的设备,内部设备名称无法被Win32应用程序使用,因此,如果我们的驱动程序对应的设备对象希望被用户模式的代码打开的话,就必须在"\??"目录中创建一个符号连接,指向"\Device"目录中的设备对象,然后,当调用者需要获取设备句柄时,I/O管理器就能够找到它。 VirtToPhys驱动程序在"\??"目录中创建了指向"devVirtToPhys"设备的符号连接"slVirtToPhys",真实设备的全名是"\Device\devVirtToPhys",这样,当StartService函数执行后,系统中就多了三个新的对象:"\Driver\VirtToPhys"驱动、"\Device\devVirtToPhys"设备和符号连接"\??\slVirtToPhys"。 现在来看看控制程序源代码,当驱动被启动后,我们只需要使用CreateFile函数来打开驱动,以此获得一个文件句柄。函数原型如下: 代码:function CreateFile(lpFileName: PChar; dwDesiredAccess, dwShareMode: DWORD; lpSecurityAttributes: PSecurityAttributes;dwCreationDisposition, dwFlagsAndAttributes: DWORD; hTemplateFile: THandle): THandle; stdcall; 这个函数可以创建或者打开一个已存在的对象,而不仅仅是文件。函数的参数描述如下: ◎ lpFileName--指向以0结尾的表示设备名称的字符串,这里要用到指向设备对象的符号连接名 ◎ dwDesiredAccess--指定访问设备的方式,可以有两个取值:GENERIC_READ表示写操作,允许将数据写到设备中;GENERIC_WRITE表示读操作,允许从设备读取数据,这两个值可以合并起来使用 ◎ dwShareMode--指定设备是否可以被共享,0表示设备不能被共享,这样并发的访问会失败,直到句柄被关闭为止;要共享设备的话,可以指定下面的两个值:FILE_SHARE_READ表示可以并发地读取设备,FILE_SHARE_WRITE表示可以并发地写设备 ◎ lpSecurityAttributes--指向SECURITY_ATTRIBUTES结构的指针,在此无用,所以可以指定为NULL ◎ dwCreationDistribution--指明当文件存在或不存在时函数采取的动作,对于设备来说,这个参数应该使用OPEN_EXISTING ◎ dwFlagsAndAttributes--文件属性,在这里总是使用0 ◎ hTemplateFile--指定文件模板的句柄,在这里总是使用0
if psl^.Parameters.DeviceIoControl.IoControlCode = IOCTL_GET_PHYS_ADDRESS then begin if (psl^.Parameters.DeviceIoControl.OutputBufferLength >= DATA_SIZE) and (psl^.Parameters.DeviceIoControl.InputBufferLength >= DATA_SIZE) then begin pSystemBuffer := p_Irp^.AssociatedIrp.SystemBuffer; iCnt := 0; for iCnt := 1 to NUM_DATA_ENTRY do begin liPhysicalAddress := MmGetPhysicalAddress(PVOID(pSystemBuffer^)); pSystemBuffer^ := liPhysicalAddress.LowPart; inc(pSystemBuffer); end; dwBytesReturned := DATA_SIZE; status := STATUS_SUCCESS; end else begin status := STATUS_BUFFER_TOO_SMALL; end; end else begin status := STATUS_INVALID_DEVICE_REQUEST; end;
IofCompleteRequest(p_Irp, IO_NO_INCREMENT); result := status; end;
procedure DriverUnload(p_DriverObject:PDRIVER_OBJECT); stdcall; begin IoDeleteSymbolicLink(@g_usSymbolicLinkName); IoDeleteDevice(p_DriverObject^.DeviceObject); end;
function _DriverEntry(pDriverObject:PDRIVER_OBJECT; pusRegistryPath:PUNICODE_STRING): NTSTATUS; var status:NTSTATUS; pDeviceObject:TDeviceObject; begin status := STATUS_DEVICE_CONFIGURATION_ERROR; RtlInitUnicodeString(g_usDeviceName, '\Device\devVirtToPhys'); RtlInitUnicodeString(g_usSymbolicLinkName, '\??\slVirtToPhys');
if (IoCreateDevice(pDriverObject, 0, @g_usDeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, pDeviceObject) = STATUS_SUCCESS) then begin if (IoCreateSymbolicLink(@g_usSymbolicLinkName, @g_usDeviceName) = STATUS_SUCCESS) then begin pDriverObject^.MajorFunction[IRP_MJ_Create] := @DispatchCreateClose; pDriverObject^.MajorFunction[IRP_MJ_CLOSE] := @DispatchCreateClose; pDriverObject^.MajorFunction[IRP_MJ_DEVICE_CONTROL] := @DispatchControl; pDriverObject^.DriverUnload := @DriverUnload;
status := STATUS_SUCCESS; end else begin IoDeleteDevice(@pDeviceObject); end; end; result := status; end;