已阅读5页,还剩42页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
标 题: 【原创】Delphi研究之驱动开发篇(一)作 者: mickeylan时 间: 2008-01-05,21:48链 接: /showthread.php?t=57762Delphi能不能开发Windows的驱动程序(这里的驱动程序当然不是指VxD了_)一直是广大Delphifans关注的问题。姑且先不说能或者不能,我们先来看看用Delphi开发驱动程序需要解决哪些技术上问题。Delphi的链接器是无法生成Windows内核模式程序的,因此用delphi无法直接生成驱动程序。M$的链接器是可以生成Windows内核模式程序的,那么是否可以用Delphi生成目标文件,然后用M$链接呢?要这么做必须要解决以下的问题:Delphi生成的目标文件是OMF格式的,而M$link虽然声称支持OMF格式的目标文件,但基本无用。最好能将OMF格式转换成COFF格式,EliCZ大侠的OMF2D正好可以解决这个问题。解决了目标格式的问题,一切都OK了吗?远没这么简单。继续之前,让我们先来看一下著名的DDDK吧。DDDK(DelphiDriverDevelopmentKit)是TheHackerDefenderProjectteam发布的一个用Delphi开发Windows驱动程序的工具包,目前最新版是0.0.4版。DDDK是将常用的驱动API用Delphi做了层包装放在DDDK单元中,就像下面这样:代码:unitDDDK;interfaceconstNtKernel=ntoskrnl.exe;procedureIoCompleteRequest(Irp:PIrp;PriorityBoost:Integer);stdcall;implementationprocedurekrnlIoCompleteRequest(Irp:PIrp;PriorityBoost:Integer);stdcall;externalNtKernelnameIoCompleteRequest;procedureIoCompleteRequest(Irp:PIrp;PriorityBoost:Integer);stdcall;beginkrnlIoCompleteRequest(Irp,PriorityBoost);end;然后在每次链接驱动文件之前,用omf2d对dddk.obj中需要引入的驱动API做以下的处理:omf2dincDDDK.obj/U-/CEIoCompleteRequest=_IoCompleteRequest82nul将DDDK.obj中的IoCompleteRequest改成_IoCompleteRequest8,为什么要这样做呢?那是因为诸如ntoskrnl.lib之类的导入库都是coff格式的,coff格式就是这样命名的。完成这步以后就可以调用m$link将目标文件链接成驱动文件了。这样做虽然可以生成正确的驱动文件,但缺点也是明显的。将驱动API用delphi包装,这些用delphi包装的函数不管是否使用都会被链接到最终生成的驱动文件中,这样会增加驱动文件的尺寸,而且通过delphi的封装函数再去调用驱动API效率也会受影响,还有就是每次链接前都要用omf2dincDDDK.obj/U-/CEIoCompleteRequest=_IoCompleteRequest8去转换delphi的目标文件,既麻烦又容易出错。有没有更好的办法呢?omf2d的工作就是将delphi的命名方法转换成coff的_xxxxxxxxx格式,默认omf2d会去掉前导下划线和xx后缀,可以用/U_*开关让omf2d不删除前导下划线,如果我们再有没有xx后缀的导入库,那问题就简单多了。但m$并没有提供没有xx后缀的导入库,那就让我们自己做一个吧_,其实很简单,比如我们要生成hal.dll的导入库,只需要编辑一个如下内容的hal.def文件:代码:LIBRARYHAL.DLLEXPORTSExAcquireFastMutexExReleaseFastMutexExTryToAcquireFastMutexHalAcquireDisplayOwnershipHalAdjustResourceListHalAllProcessorsStarted然后用LINK/LIB/MACHINE:IX86/DEF:hal.def/OUT:hal.lib命令就可以生成我们需要的没有xx后缀的导入库文件了。有了这个文件,事情就好办多了。下面就让我们开始用delphi来开发一个简单的驱动程序beeper吧。这个驱动程序是从Four-F的KmdKit里的beeper转换过来的,程序的目标就是通过访问端口让PC的扬声器发声,程序通过三种方法让扬声器发声,一种是直接访问端口,一种是调用hal.dll的READ_PORT_UCHAR和WRITE_PORT_UCHAR访问端口,第三种方法则是调用hal.dll的HalMakeBeep函数。代码:unitbeeper;interfaceuseswindows,DDDK,hal;function_DriverEntry(DriverObject:PDriverObject;RegistryPath:PUnicodeString):NTSTATUS;stdcall;implementationconstTIMER_FREQUENCY:DWORD=1193167;1,193,167HzOCTAVE:DWORD=2;octavemultiplierPITCH_C:DWORD=523;C-523,25HzPITCH_Cs:DWORD=554;C#-554,37HzPITCH_D:DWORD=587;D-587,33HzPITCH_Ds:DWORD=622;D#-622,25HzPITCH_E:DWORD=659;E-659,25HzPITCH_F:DWORD=698;F-698,46HzPITCH_Fs:DWORD=740;F#-739,99HzPITCH_G:DWORD=784;G-783,99HzPITCH_Gs:DWORD=831;G#-830,61HzPITCH_A:DWORD=880;A-880,00HzPITCH_As:DWORD=988;B-987,77HzPITCH_H:DWORD=1047;H-1046,50HzWearegoingtoplayc-majorchordDELAY:DWORD=$18000000;formy800mHzboxTONE_1:DWORD=1141;TONE_2:DWORD=905;TONE_3:DWORD=1568;forHalMakeBeepSTATUS_DEVICE_CONFIGURATION_ERROR:DWORD=$00C0000182;procedureMakeBeep1(dwPitch:DWORD);stdcall;assembler;asmclimoval,10110110bout43h,almoveax,dwPitchout42h,almoval,ahout42h,alTurnspeakerONinal,61horal,11bout61h,alstipusheaxmoveax,DELAY1:deceaxjnz1popeaxcliTurnspeakerOFFinal,61handal,11111100bout61h,alstiend;procedureMakeBeep2(dwPitch:DWORD);stdcall;vardwPort,i:DWORD;beginasmcli;end;WRITE_PORT_UCHAR(PUCHAR($43),$b6);WRITE_PORT_UCHAR(PUCHAR($42),dwPitchand$FF);WRITE_PORT_UCHAR(PUCHAR($42),(dwPitchshr8)and$FF);dwPort:=READ_PORT_UCHAR(PUCHAR($61);dwPort:=dwPortor3;WRITE_PORT_UCHAR(PUCHAR($61),dwPort);asmstiend;fori:=1toDELAYdobeginend;asmcliend;TurnspeakerOFFdwPort:=READ_PORT_UCHAR(PUCHAR($61);dwPort:=dwPortand$FC;WRITE_PORT_UCHAR(PUCHAR($61),dwPort);asmstiend;end;function_DriverEntry(DriverObject:PDriverObject;RegistryPath:PUnicodeString):NTSTATUS;stdcall;vari:integer;beginMakeBeep1(TONE_1);MakeBeep2(TONE_2);HalMakeBeep(TONE_3);fori:=1toDELAYdobeginend;HalMakeBeep(0);Result:=STATUS_DEVICE_CONFIGURATION_ERROR;end;end.代码:unithal;interfaceusesWindows;constNtHal=hal.dll;functionHalMakeBeep(Frequency:ULONG):BOOLEAN;stdcall;functionREAD_PORT_UCHAR(Port:PUCHAR):UCHAR;stdcall;procedureWRITE_PORT_UCHAR(Port:PUCHAR;Value:UCHAR);stdcall;implementationfunctionHalMakeBeep(Frequency:ULONG):BOOLEAN;stdcall;externalNtHalname_HalMakeBeep;functionREAD_PORT_UCHAR(Port:PUCHAR):UCHAR;stdcall;externalNtHalname_READ_PORT_UCHAR;procedureWRITE_PORT_UCHAR(Port:PUCHAR;Value:UCHAR);stdcall;externalNtHalname_WRITE_PORT_UCHAR;end.1.用dcc32U.include-B-CG-JP-$A-,C-,D-,G-,H-,I-,L-,P-,V-,W+,Y-beeper.pas生成目标文件(此处的.inc是我保存相关delphi单元文件的目录,你的可能不是这个目录哟)2.用omf2dbeeper.obj/U_*转换目标文件,使其能被m$link链接3.用link/NOLOGO/ALIGN:32/BASE:0x10000/SUBSYSTEM:NATIVE/DRIVER/FORCE:UNRESOLVED/FORCE:MULTIPLE/ENTRY:DriverEntry.libhal.libbeeper.obj/OUT:beeper.sys生成最终的驱动文件。(注意这里用/FORCE:UNRESOLVED是因为dcc32会在delphi的目标文件中加入一些单元的初始化及销毁代码,这些东东在驱动程序中是不需要的,所以强行忽略之,还会出现一堆链接警告,也不用理会)。执行完以上的步骤,在你的目录下就会生成一个beeper.sys文件了。把它拷贝到KmdKit的beeper目录中,用它的SCP文件加载,PC的喇叭果然发出的清脆的声音,证明我们的delphi驱动是正确的。用此种方法生成的beeper.sys只有1376字节,只比用KmdKit的汇编代码的beeper.sys大几百个字节,而用DDDK生成的beeper.sys则要超过3K。打完这么多字真不容易,这篇教程就到这里吧,下一篇我们再来用delphi做一个更有趣的东东。(谢谢捧场,我目前正在做一个基于Delphi的驱动开发工具包,我给它起了个名字叫KmdKit4D(KernelModeDriverKitforDelphi),目前已经完成了没有xx后缀的ntoskrnl.lib、hal.lib、win32k.lib、ntdll.lib导入库的创建以及一些常用C头文件转换成pascal声明的工作,适当的时候我会把它发布在论坛里(Delphi能开发驱动,BCB当然也能做_)标 题: 【原创】Delphi研究之驱动开发篇(二)作 者: mickeylan时 间: 2008-01-10,21:16链 接: /showthread.php?t=58070上篇教程主要是讲解了用Delphi开发Windows驱动程序需要解决的一些技术上的问题,虽然啰嗦了一大堆,也不知道讲清楚了没有_。本篇我们开始讲述用Delphi构建驱动开发环境。用Delphi开发驱动程序所必须的工具:lDcc32.exeDelphi编译器,我用的是Delphi2007的dcc32lOmf2d-Delphi目标文件转换工具lLink.exe-microsoft链接器,不要使用7.1xx版的,似乎有buglDDK相关结构、APIs的Delphi声明文件(我已经完成部分结构、APIs的声明转换,放在我的KmdKit4D工具包里)有上面的东东就可以开发Windows驱动程序了,下面就让我们来写一个最简单的驱动程序:代码:unitdriver;interfaceusesnt_status,ntoskrnl;function_DriverEntry(DriverObject:PDriverObject;RegistryPath:PUnicodeString):NTSTATUS;stdcall;implementationprocedureDriverUnload(DriverObject:PDriverObject);stdcall;beginDbgPrint(DriverUnload(DriverObject:0x%.8X),DriverObject);DbgPrint(DriverUnload(-),);end;function_DriverEntry(DriverObject:PDriverObject;RegistryPath:PUnicodeString):NTSTATUS;stdcall;beginDbgPrint(DriverEntry(DriverObject:0x%.8X;RegistryPath:0x%.8X),DriverObject,RegistryPath);DriverObject.DriverUnload:=DriverUnload;Result:=STATUS_SUCCESS;DbgPrint(DriverEntry(-):0x%.8X,Result);end;end.以上就是一个最简单的驱动程序,就像其他的可执行程序一样,每个驱动程序也有一个入口点,这是当驱动被装载到内存中时首先被调用的,驱动的入口点是DriverEntry过程(注:过程也就是子程序),DriverEntry这个名称只是一个标记而已,你可以把它命名为其他任何名字-只要它是入口点就行了。DriverEntry过程用来对驱动程序的一些数据结构进行初始化,它的函数原型定义如下: 代码:function_DriverEntry(DriverObject:PDriverObject;RegistryPath:PUnicodeString):NTSTATUS;stdcall;当然你也可以不用DriverEntry这个名字,任意的名字都可以,不过前面的下划线是必需的。nt_status和ntoskrnl两个单元包含了常用的数据结构和APIs的声明。由于我常开发Unix下的程序,所以我习惯使用make编译程序,个人感觉make比较智能和方便,因此在推荐大家使用make编译程序。我用的是borlandmake5.2版。Makefile的写法可以参考/showthread.php?t=56912,以下是编译这个程序的makefile:代码:NAME=driverDCC=dcc32INCLUDE=d:mickeylanKmdKit4DincludeLIB_PATH=d:mickeylanKmdKit4DlibDCCFLAGS=-U$(INCLUDE)-B-CG-JP-$A-,C-,D-,G-,H-,I-,L-,P-,V-,W+,Y-LIBS=ntoskrnl.libhal.libwin32k.libntdll.libLINKFLAGS=/NOLOGO/ALIGN:32/BASE:0x10000/SUBSYSTEM:NATIVE/DRIVER/LIBPATH:$(LIB_PATH)/FORCE:UNRESOLVED/FORCE:MULTIPLE/ENTRY:DriverEntryall:$(NAME).sys$(NAME).sys:$(NAME).objomf2d$(NAME).obj/U_*link$(LINKFLAGS)$(LIBS)/out:$(NAME).sys$(NAME).obj$(NAME).obj:$(NAME).pas$(DCC)$(DCCFLAGS)$(NAME).pasclean:del*.objdel*.dcudel*.sys在命令行下执行make即可编译生成驱动文件,是不是很简单_。此程序的源码放在KmdKit4D的samplebasic目录下,该目录下还有一个loaddriver.bat,执行此批处理文件即可加载驱动,并且可以在DbgView的窗口里看见驱动程序输出的调试信息。到这里,你应该对用Delphi开发驱动程序有了个大体的了解了,下面让我们再来写一个很有趣的驱动程序以加深了解。这个程序是从Four-F的KmdKit的giveio转换来的(我比较懒,不想写新的_),写个驱动程序让用户模式下的进程能通过读取端口来访问电脑的CMOS。大家都知道,端口是被Windows保护起来的,正常情况下,用户模式下的程序是无法直接操作端口的,通过我们的驱动程序修改I/O许可位图(I/Opermissionbitmap,IOPM),这样用户模式下的相应进程就被允许自由地存取I/O端口,这方面详细资料见/design/intarch/techinfo/pentium/PDF/inout.pdf。每个进程都有自己的I/O许可位图,每个单独的I/O端口的访问权限都可以对每个进程进行单独授权,如果相关的位被设置的话,对对应端口的访问就是被禁止的,如果相关的位被清除,那么进程就可以访问对应的端口。既然I/O地址空间由64K个可单独寻址的8位I/O端口组成,IOPM表的最大尺寸就是2000h字节(注:每个端口的权限用1个bit表示,64K个端口除以8得到的就是IOPM的字节数,也就是65536/88192字节2000h字节)。TSS的设计意图是为了在任务切换的时候保存处理器状态,从执行效率的考虑出发,WindowsNT并没有使用这个特征,它只维护一个TSS供多个进程共享,这就意味着IOPM也是共享的,因此某个进程改变了IOPM的话,造成的影响是系统范围的。ntoskrnl.exe中有些未公开的函数是用来维护IOPM的,它们是Ke386QueryIoAccessMap和Ke386SetIoAccessMap函数。代码:functionKe386QueryIoAccessMap(dwFlag:DWORD;pIopm:PVOID):NTSTATUS;stdcall;Ke386QueryIoAccessMap函数从TSS中拷贝2000h字节的当前IOPM到指定的内存缓冲区中,缓冲区指针由pIopm参数指定。各参数描述如下:dwFlag-0表示将全部缓冲区用0FFh填写,也就是所有的位都被设置,所有的端口都被禁止访问;1表示从TSS中将当前IOPM拷贝到缓冲区中pIopm-用来接收当前IOPM的缓冲区指针,注意缓冲区的大小不能小于2000h字节如果函数执行成功的话会在返回值的低8位返回非0值;如果执行失败则返回零。 代码:functionKe386SetIoAccessMap(dwFlag:DWORD;pIopm:PVOID):NTSTATUS;stdcall;Ke386SetIoAccessMap函数刚好相反,它从pIopm参数指定的缓冲区中拷贝2000h字节的IOPM到TSS中去。各参数描述如下:dwFlag-这个参数只能是1,其他任何值函数都会返回失败pIopm-指向包含IOPM数据的缓冲区,缓冲区的尺寸不能小于2000h字节如果函数执行成功的话会在返回值的低8位返回非0值;如果执行失败则返回零当IOPM拷贝到TSS后,IOPM的偏移指针必须被定位到新的数据中去,这可以通过Ke386IoSetAccessProcess函数来完成,这也是ntoskrnl.exe中的一个很有用的未公开函数。 代码:functionKe386IoSetAccessProcess(pProcess:PKPROCESS;dwFlag:DWORD):NTSTATUS;stdcall;Ke386IoSetAccessProcess允许或者禁止对进程使用IOPM。其参数说明如下:pProcess-指向KPROCESS结构dwFlag-0表示禁止对I/O端口进行存取,将IOPM的偏移指针指到TSS段外面;1表示允许存取I/O端口,将IOPM的偏移指针指到TSS段的88h中如果函数执行成功的话会在返回值的低8位返回非0值;如果执行失败则返回零顺便提一下,ntoskrnl中的所有函数都有前缀,通过这个前缀你就可以辨别该函数属于系统功能中的哪一类。不同的前缀表示不同的功能-如i前缀表示内部使用(internal)、p表示私有函数(private)、f表示fastcall。再如,Ke表示内核函数(kernel),Psp表示内部进程支持函数(internalprocesssupport),Mm表示内存管理函数(MemoryManager)等等。Ke386IoSetAccessProcess函数的第一个参数指向进程对象,也就是KPROCESS结构(在includent_status.dcu中定义),Ke386IoSetAccessProcess会将KPROCESS结构中IopmOffset字段的值设置为合适的值。代码:unitgiveio;interfaceusesnt_status,ntoskrnl,ntutils;constIOPM_SIZE=$2000;function_DriverEntry(DriverObject:PDriverObject;pusRegistryPath:PUnicodeString):NTSTATUS;stdcall;implementationfunction_DriverEntry(DriverObject:PDriverObject;pusRegistryPath:PUnicodeString):NTSTATUS;stdcall;varstatus:NTSTATUS;oa:OBJECT_ATTRIBUTES;hKey:HANDLE;kvpi:KEY_VALUE_PARTIAL_INFORMATION;pIopm:PVOID;pProcess:PVOID;iRet:NTSTATUS;resultLen:ULONG;KeyValue:TUnicodeString;beginDbgPrint(giveio:EnteringDriverEntry,);status:=STATUS_DEVICE_CONFIGURATION_ERROR;InitializeObjectAttributes(oa,pusRegistryPath,0,0,nil);iRet:=ZwOpenKey(hKey,KEY_READ,oa);ifiRet=STATUS_SUCCESSthenbeginRtlInitUnicodeString(KeyValue,ProcessId);if(ZwQueryValueKey(hKey,KeyValue,KeyValuePartialInformation,PVOID(kvpi),sizeof(kvpi),resultLen)STATUS_OBJECT_NAME_NOT_FOUND)and(resultLen0)thenbeginDbgPrint(giveio:ProcessID:%X,kvpi.dData);AllocateabufferfortheI/OpermissionmappIopm:=MmAllocateNonCachedMemory(IOPM_SIZE);ifpIopmnilthenbeginifPsLookupProcessByProcessId(kvpi.dData,pProcess)=STATUS_SUCCESSthenbeginDbgPrint(giveio:PTRKPROCESS:%08X,pProcess);iRet:=Ke386QueryIoAccessMap(0,pIopm);ifiRetand$ff0thenbeginI/Oaccessfor70hportasmpushadmovecx,pIopmaddecx,70h/8moveax,ecxbtreax,70hMOD8movecx,eaxI/Oaccessfor71hportmovecx,pIopmaddecx,71h/8moveax,ecxbtreax,71hMOD8movecx,eaxpopadend;iRet:=Ke386SetIoAccessMap(1,pIopm);ifiRetand$FF0thenbeginiRet:=Ke386IoSetAccessProcess(pProcess,1);ifiRetand$FF0thenbeginDbgPrint(giveio:I/Opermissionissuccessfullygiven,);endelsebeginDbgPrint(giveio:I/Opermissionisfailed,);status:=STATUS_IO_PRIVILEGE_FAILED;end;endelsebeginstatus:=STATUS_IO_PRIVILEGE_FAILED;end;endelsebeginstatus:=STATUS_IO_PRIVILEGE_FAILED;end;ObfDereferenceObject(pProcess);endelsebeginstatus:=STATUS_OBJECT_TYPE_MISMATCH;end;MmFreeNonCachedMemory(pIopm,IOPM_SIZE);endelsebeginDbgPrint(giveio:CalltoMmAllocateNonCachedMemoryfailed,);status:=STATUS_INSUFFICIENT_RESOURCES;end;end;ZwClose(hKey);end;DbgPrint(giveio:LeavingDriverEntry,);result:=status;end;end.以下是makefile:代码:NAME=giveioDCC=dcc32INCLUDE=e:mickeylanKmdKit4DincludeLIB_PATH=e:mickeylanKmdKit4DlibDCCFLAGS=-U$(INCLUDE)-B-CG-JP-$A-,C-,D-,G-,H-,I-,L-,P-,V-,W+,Y-LIBS=ntoskrnl.libhal.libwin32k.libntdll.libLINKFLAGS=/NOLOGO/ALIGN:32/BASE:0x10000/SUBSYSTEM:NATIVE/DRIVER/LIBPATH:$(LIB_PATH)/FORCE:UNRESOLVED/FORCE:MULTIPLE/ENTRY:DriverEntryall:$(NAME).sys$(NAME).sys:$(NAME).objomf2d$(NAME).obj/U_*link$(LINKFLAGS)$(LIBS)/out:$(NAME).sys$(NAME).objntutils.obj$(NAME).obj:$(NAME).pas$(DCC)$(DCCFLAGS)$(NAME).pasclean:del*.objdel*.dcudel*.sys通过上面的两个例子的学习,相信大家已经能用Delphi写些基本的驱动程序了。本教程的第二部分也就到此为止了,后面还会有更精彩的内容。PS:随本教程我发布了我的KmdKit4D0.01预览版,目前只完成了万里长征的第一步,后面的路还很长,希望有兴趣的朋友能和我一起努力来走完剩下的路_KmdKit4D.rar 标 题: 【原创】Delphi研究之驱动开发篇(三)作 者: mickeylan时 间: 2008-01-14,20:58链 接: /showthread.php?t=58301Delphi研究之驱动开发篇(三)(注:本篇的原理部分均摘自罗云彬大侠翻译的驱动开发教程)在前面的两篇教程中我们写了三个玩具驱动程序,为什么说是玩具驱动呢?因为它们确确实实是驱动程序,而且也能完成一些有趣的功能,但是它们都不完整,没有同用户交流的功能,这一篇就让我们来完成一个简单的全功能驱动程序。在写程序之前,我们有必要了解一些基础知识。在用户模式下,我们可以通过访问某个地址来直接调用dll中的函数,但是在内核模式下,从系统的稳定性考虑,这样做是非常危险的。所以,系统提供了和内核模式通讯的媒介-I/O管理器,它是I/O子系统的部件之一。I/O管理器将应用程序、系统部件和设备连接起来,并定义了一个架构来支持设备驱动程序。一般来说,用户模式的操作都被转换成了对具体硬件设备的I/O操作,仅对于某些设备,设备由驱动程序来创建和控制,这些设备就是虚拟设备。当然,创建这些设备并不意味着你创造了什么硬件,而仅仅是在内存中创建了一个新的对象而已。每个对象和一个物理设备或者逻辑设备对应,用于描述它们的特征。创建设备后,驱动程序告诉I/O管理器:“这里有个我控制的设备,如果你收到了操作这个设备的I/O请求的话,直接发给我好了,剩下的由我来搞定!”。驱动程序知道如何对自己管理的设备进行I/O操作,I/O管理器唯一的职责在于创建I/O请求并把它发送给适当的设备驱动程序。用户模式的代码不知道(也不必知道)其中的细节,也不用知道究竟是哪个驱动程序在管理哪个设备。下面先让我们来看一下用户模式下的控制程序:代码:programVirToPhys;$APPTYPECONSOLEusesSysUtils,Windows,WinSvc,Dialogs,nt_status;constNUM_DATA_ENTRY=4;DATA_SIZE=sizeof(DWORD)*NUM_DATA_ENTRY;_DELETE=$10000;varhSCManager:THANDLE;hService:THANDLE;acModulePath:array0.MAX_PATHofchar;_ss:SERVICE_STATUS;hDevice:THANDLE;adwInBuffer:array0.NUM_DATA_ENTRYofDWORD;adwOutBuffer:array0.NUM_DATA_ENTRYofDWORD;dwBytesReturned:DWORD;IOCTL_GET_PHYS_ADDRESS:DWORD;lpTemp:PChar;iRetValue:boolean;生成控制码functionCTL_CODE(DeviceType,Func,Method,Access:DWORD):DWORD;beginresult:=(DeviceType)SHL16)OR(Access)SHL14)OR(Func)SHL2)OR(Method);end;beginIOCTL_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);ifhSCManager0thenbeginGetFullPathName(PChar(VirtToPhys.sys),sizeof(acModulePath),acModulePath,lpTemp);hService:=CreateService(hSCManager,VirtToPhys,VirtualToPhysicalAddressCon
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二级建造师考试重点公路(实务)
- 四年级数学(简便运算)计算题专项练习与答案
- 终止推广合作协议书(2篇)
- 六年级上册《比的意义》说课稿9篇
- 南京航空航天大学《材料工程基础》2022-2023学年第一学期期末试卷
- 南京工业大学浦江学院《数据结构》2021-2022学年期末试卷
- 某供电公司综合工区门卫施工组织设计
- 南京工业大学浦江学院《酒店人力资源管理》2023-2024学年第一学期期末试卷
- 《小雨沙沙》说课稿
- 租聘挖机合同(2篇)
- 天然气管网安装工程施工过程岗位操作指南
- 船用甲板刷商业机会挖掘与战略布局策略研究报告
- 公司网络安全制度
- 跨学科主题学习- 探索外来食料作物传播史(课件)七年级地理上册同步高效备课课件(人教版2024)
- 学校编制外临时代课教师聘用管理办法
- 南京市江宁区2023-2024三年级数学上册期中试卷及答案
- GB/T 22838.7-2024卷烟和滤棒物理性能的测定第7部分:卷烟含末率
- 蚌埠医学院儿科学教案
- 第四单元认位置(单元测试)2024-2025学年一年级数学上册苏教版
- 个人加工厂转让协议书模板
- 沪教版 八年级(上)数学 正比例函数与反比例函数重点题型专项训练 (含解析)
评论
0/150
提交评论