您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 经营企划 > 内核态下基于动态感染技术的应用程序执行保护.
这一章我们用汇编语言编写一个最简单的内核程序,我们所要完成的所有功能以后都将在今天这个程序的基础上进行增加。也许有些人已经使用DDK作过Windows下内核程序的开发,使用DDK的确是比较好的做法,因为DDK的编译、连接选项都是专门针对内核程序,而且DDK中提供了许多宏,对内核函数的调用和其他代码作了很多安全性的保护,所以我还是建议大家没事不要随便用汇编语言进行内核程序的开发,除非你对汇编语言非常熟悉,而且有自信能驾驭它,否则你还是按部就班地用DDK吧。使用汇编语言开发内核程序,我们只需要安装MASM32V10和KmdKit开发包,不需要安装PlantformSDK和DDK。首先我们将MASM32V10开发包安装到C盘,当然你也可以安装到其它路径,只是后面的汇编和连接选项要作一些修改。将KmdKit开发包安装好,KmdKit的安装很简单,将include目录里的内容拷贝到MASM32的include目录中,将lib目录里的内容拷贝到MASM32的lib目录中,将macros目录中的内容拷贝到MASM32的macros目录中。启动MicrosoftVisualStudio2003,创建一个空白的Win32应用程序,添加DynamicHook.asm文件(这个项目和文件在命名时有点失误,不过名字而已,只不过是个符号,我姑且原谅自己的这个错误)。先把DynamicHook.asm的完整源代码贴出来:.386.modelflat,stdcalloptioncasemap:noneincludentddk.incincludentoskrnl.incincludestrings.mac.constCCOUNTED_UNICODE_STRING\\Device\\devDHDriver,g_usDeviceName,4CCOUNTED_UNICODE_STRING\\??\\slDHDriver,g_usSymbolicLinkName,4.code;DriverUnloadprocpDriverObject:PDRIVER_OBJECTinvokeDbgPrint,$CTA0(Driverunload)invokeIoDeleteSymbolicLink,addrg_usSymbolicLinkNamemoveax,pDriverObjectinvokeIoDeleteDevice,(DRIVER_OBJECTptr[eax]).DeviceObjectretDriverUnloadendp;DispatchCreateCloseprocpDeviceObject:PDEVICE_OBJECT,pIrp:PIRPmoveax,pIrpassumeeax:ptr_IRPmov[eax].IoStatus.Status,STATUS_SUCCESSmov[eax].IoStatus.Information,0assumeeax:nothinginvokeIoCompleteRequest,pIrp,IO_NO_INCREMENTmoveax,STATUS_SUCCESSretDispatchCreateCloseendp;.codeINITDriverEntryprocpDriverObject:PDRIVER_OBJECT,pusRegistryPath:PUNICODE_STRINGlocalstatus:NTSTATUSlocalpDeviceObject:PDEVICE_OBJECTmovstatus,STATUS_DEVICE_CONFIGURATION_ERRORinvokeIoCreateDevice,pDriverObject,0,addrg_usDeviceName,FILE_DEVICE_UNKNOWN,0,FALSE,addrpDeviceObject.ifeax==STATUS_SUCCESSinvokeIoCreateSymbolicLink,addrg_usSymbolicLinkName,addrg_usDeviceName.ifeax==STATUS_SUCCESSmoveax,pDriverObjectassumeeax:ptrDRIVER_OBJECTmov[eax].DriverUnload,offsetDriverUnloadmov[eax].MajorFunction[IRP_MJ_CREATE*(sizeofPVOID)],offsetDispatchCreateClosemov[eax].MajorFunction[IRP_MJ_CLOSE*(sizeofPVOID)],offsetDispatchCreateCloseinvokeDbgPrint,$CTA0(Driverentry)movstatus,STATUS_SUCCESSassumeeax:nothing.elseinvokeIoDeleteDevice,pDeviceObject.endif.endif@@:moveax,statusretDriverEntryendpENDDriverEntryCCOUNTED_UNICODE_STRING宏在汇编语言中定义一个类似DDK中的UNICODE_STRING的结构,定义在Strings.mac中,这是KmdKit作者Four-F的伟大贡献之一,Strings.mac包含了对大部分字符串的定义,ANSI字符串$CTA0(类似于char[]);Unicode字符串$CTW0(类似于w_char[])。在Strings.mac出现之前,在汇编中定义Unicode字符串是件相当麻烦的事情。DriverEntry是内核程序的入口点,当内核模块被加载时,程序从这里开始执行,类似于用户态程序的WinMain或main函数。其中的IoCreateDevice和IoCreateSymbolicLink创建设备名和创建符号连接。IoCreateDevice使用\Device\devDHDriver为名字来创建一个设备,你可以使用KmdKit中的SymLinks.exe这个工具来查看我们创建的符号和连接:同时你也可以在以后的用户态应用程序中以\\.\devDHDriver为文件名,用CreateFile来打开我们创建的内核对象。下面的代码为内核对象指定分派例程,例如:当使用CreateFile和CloseHndle打开或关闭对象的时候,我们的内核程序使用哪个函数处理(这里用DispatchCreateClose这一个函数来处理);当使用DeviceIoControl与内核对象交换数据时,应该用哪个函数来处理(我们的例子中没有添加对DeviceIoControl的支持);当内核对象被卸载时,应该用哪个函数来处理(这里是DriverUnload这个函数)。其实设备名称和连接符号不是内核态程序必须的,特别是一些不需要与用户态程序进行数据交互的内核程序,我们的程序就是这样,所以在我们的代码中完全不需要调用IoCreateDevice、IoCreateSymbolicLink,也不需要在分派例程中指定DispatchCreateClose这个函数,DispatchCreateClose也只是调用IoCompleteRequest直接向用户态程序返回操作成功。把这些写在这里的目的,只是让大家有所了解。后面的DbgPrint向内核调试器输出一串字符,类似于用户态的OutputDebugString函数。这个函数的调用也不是必须的,只方便我们检查用。DriverEntry应该返回STATUS_SUCCESS这样才能保证我们的内核程序被正常加载。看到这里,大家也许会发现其实DriverEntry这个函数只在系统加载内核模块时才被调用一次,其它时间永远不再调用了,如果在内核模块加载后仍将这份代码保存在内存中,真是一份不必要的内存开销(虽然我们的例子中这个开销非常小),所以我们将DriverEntry函数单独定义在.codeINIT节中,表示当内核加载完成后,这部分代码可以从内存中丢弃。再来看DriverUnload,刚才已经说了,我们将这个函数指定为内核模块的卸载例程,也就是当我们的内核模块被卸载时调用。它所作的工作刚好和DriverEntry相反:用IoDeleteSymbolicLink删除符号连接,用IoDeleteDevice删除设备。正如前面说的一样,如果你的内核程序并没有创建设备和符号连接,也就不需要调用这两和函数。好了,代码写完,我们来看内核程序的汇编和连接。在我的印象中MicrosoftVisualStudio2005及以上版本内置了对汇编语言的汇编支持,不幸这一次我安装的是2003版(我原以为2003也内置支持)。所以我们得手动地来调整。在DynamicHook.asm的“属性”à“自定义生成步骤”à“常规”中,设置命令行为:ml/c/coff/nologo/Fo$(IntDir)\$(InputFileName).obj/IC:\MASM32\include\w2k/IC:\MASM32\Macros$(InputFileName)(Debug版本可以加上/Zi参数)。ml各参数的含义你可以输入ml/?来查看,这里就不在敷述了。大家看到/I参数,指定了输入目录的位置,这就是我刚才讲如果你不将MASM32安装到C盘,这里你就要重新指定。设置输出为:$(IntDir)\$(InputFileName).obj,如图:当然,随着我们程序的进一步深入,DynamicHook.asm会include其它一些文件,你就需要在“附加依赖”里面指定这些文件,以保证当有文件修改时,VC会发现需要重新进行汇编。然后进入连接器选项,在“常规”选项卡中将输出文件修改为:$(OutDir)/DynamicHook.sys;“启用增量连接”选“否”;附加库目录中输入:C:\masm32\lib\w2k:“输入”选项卡中附加依赖项:ntoskrnl.libhal.lib;忽略所有默认库选“是”:“调试”选项卡中,生成调试信息选“是”(这个随便你,我见过很多人发行出来的exe仍包含有调试符号,逆向起来相当Happy)。“System”选项卡中子系统我们选“未设置”(VS2003相当不给力,只有CONSOLE、WINDOWS和未设置三个选项,VS2005中好像就有NATIVE,这个我们现在只有不设置,等会在命令行中手动设置):“高级”选项卡中,设置入口点为:DriverEntry(刚才我已经说了,这次我怕连接器不认识);设置校验和选“是”(内核程序的校验和都应该设置,虽然在用户态下,当启动进程时系统并不检查PE文件实际的校验和和PE文件结构中填写的校验和是否一致,但在对内核模块,系统却要严格检查,设置的校验和若与实际的校验和不一致,内核模块是不能被加载的);基址上填“0x10000”(我习惯用这个基址了,当然,若不设置,也没关系):最后在命令行中输入:/align:16/ignore:4078/section:CODE,REW/subsystem:native/driver:/align:16指定PE文件及内存映像按16字节对齐(通过我的经验来看,其实这个选项如何设置并不重要,但内核中内存是很宝贵的,还是弄小一点吧)。/ignore:4078若不设置,每次连接时会出现下面的warning:LINK:warningLNK4078:找到多个“I
本文标题:内核态下基于动态感染技术的应用程序执行保护.
链接地址:https://www.777doc.com/doc-2678113 .html