发新话题
打印

[原创]与 DriverStudio "过不去" 系列两篇(1和2)

[原创]与 DriverStudio "过不去" 系列两篇(1和2)

[backcolor=#000000]文章作者:侯佩|hopy[/backcolor]

            

           [原创]抢先DriverStudio夺取机器控制权



(这是以前早些时候研究ring0代码时随笔写的,现整理发表出来,请各位指教。)



  废话不谈,言归正传!



  大家都知道,装了DriverStudio软件(我使用的是v3.2版)的系统在

启动时会显示其配置画面,(如图0所示)





                                图 0



  这时操作系统的其他部件还没有运行。那么显示的原理是什么?

能不能早于DriverStudio而先执行其他代码呢?答案是肯定的。下面

先谈谈原理吧。

  原理比较简单,详细的大家可以看网文<<Inside NT boot>>,


我这里简单说说。当引导扇区被引导后,会查找NTLDR,NTLDR


做的一件非常重要的事就是将CPU从实模式转换到保护模式下。在加


载完NTDECT.COM后接下来就会将NT的核心装入内存, 它们是HAL.DLL


和NTOSKRNL.EXE,加载完毕后,NTLDR再加载所有引导必须的驱动程


序。接下来就是我们所关心的地方: 它会将HKLM\SYSTEM\Services


中值为 SERVICE_BOOT_START 的DRIVER装入,但此时不初始化。


(补充附注:

NtLdr第3步动作:扫描内存中SYSTEM注册表hive文件找到


所有引导设备驱动程序,这些Driver仔注册表中通过


SERVICE-BOOT-START启动值标记。

NtLdr第5步动作:加载引导驱动程序,在启动画面Starting Windows


下显示出不断更新的进度栏,该进度栏随每个驱动程序的加载而变化。

Kernel第23步动作:I/O管理器初始化……所有前面加载的


Boot-Start型驱动程序被调用以完成驱动程序相关初始化,这时才轮


到System-Start型的驱动程序被加载并初始化。

更详细的信息请参考<<Windows 2000 内部揭秘>>

)


  那么DriverStudio是不是也是使用了这个特性呢?我们运行


regedit.exe ,在Services目录中找到bootcfg这个注册项, 可以看


到它是一个内核驱动,并且Start类型为0。如图1所示:






                 图1



为了证实这个Driver就是提供DriverStudio开机时配置功能的驱动程


序,我用一个会引起系统崩溃驱动的名字来替换它,然后重新启动。


原本该显示配置画面的地方果然发生了系统崩溃。 (如图2所示)





图 2



既然知道了原理,再来看看操作。实际上windows自身提供了这个实现。


细心的朋友可能早就知道Win32 API CreateService的dwStartType


形参有个选项为:SERVICE_BOOT_START 说明如下:



[backcolor=#ffffcc]SERVICE_BOOT_START -- Specifies a device driver started by the

operating system loader. This value is valid only if the service
[/backcolor]

[backcolor=#ffffcc][/backcolor]

[backcolor=#ffffcc][/backcolor]

[backcolor=#ffffcc]type is [/backcolor][backcolor=#ffffcc]SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER.
[/backcolor]


好像看起来和普通的诸如SERVICE_DEMAND_START 的用法没什么不同嘛,


结果手动编制尝试结果返回非法参数。

  为什么会这样呢?经过一番thinking之后,我认为是由于使用了


SERVICE_BOOT_START 时,是在系统引导的早期发生load Driver事件,


这时可能除了少数几个OS必须的路径以外,还无法访问其他windows


目录。为了证实这点,我将自己的Driver文件拷贝到系统目录

%root%\system32\drivers\ 下,再次运行结果成功!

  下面再引出注册表中的一个与驱动程序加载相关的KEY:

ServiceGroupOrder ,如图3所示:





                 图3


这个KEY决定了所属改组的驱动程序的加载顺序。


再看一下图1中DriverStudio引导驱动的组名,是Boot Bus Extender,


它排在启动顺序的第2位。现在我新加一个Group名: hopy。同时还要


修改ServiceGroupOrder在其中添加新组hopy,要注意的是要以UNICODE


的格式添加字符串 "hopy". 如图4:




                图4


然后将代码改写如下:

复制内容到剪贴板
代码:
;BTmain.asm节选

.const

namesvr db &#39;TryBootSvr&#39;,0

notesvr db &#39;Test Drv Start at System Boot&#39;,0

namefile db &#39;BTdrv.sys&#39;,0

szLOG db &#39;hopy&#39;,0

szSSN db &#39;TBSvr2007&#39;,0 ;ServiceStartName

szpath db &#39;C:\WINNT\system32\drivers\BTdrv.sys&#39;,0



.code

invoke CreateService,hSCM,addr namesvr,addr notesvr,\

SERVICE_ALL_ACCESS,SERVICE_KERNEL_DRIVER,\

SERVICE_BOOT_START,SERVICE_ERROR_NORMAL,\

addr szpath,addr szLOG,addr tagid,NULL,\

NULL,NULL



驱动代码如下:

;BTdrv.asm节选

local status:NTSTATUS

local pDeviceObject:PVOID



mov status, STATUS_DEVICE_CONFIGURATION_ERROR

xor edi,edi

mov [edi],eax

jmp $

mov eax,status

ret



结果如我们所预料,该Driver抢在DriverStudio之前发生蓝屏,如果


将这个Driver换成带有特定功能的代码的驱动,则可以实现超前的目的。


这个留给大家去想象吧,呵呵。

(图看不完整的话可以点击察看完整视图)


(唉,格式怎么也弄不好,诸位抱歉啦。)





  再和DriverStudio"过不去"之加强版


(<<抢先DriverStudio夺取机器控制权>>系列2)



(测试平台 windows 2000 sp4 + masm32v9.0)






  上篇仅仅说到如何抢先DriverStudio,并在结尾留给大家一个遐想。


现在我进一步拓展这个遐想,从而给大家更多的遐想。: )


  那么现在我要给这个驱动增加新的功能,不但抢DriverStudio 启动,


而且给用户显示几行提示,并等待用户的输入,如果用户敲 B 键则发生


蓝屏,如果用户按任意其他键则继续往下执行,So DriverStudio 可以


正常执行下去。



要完成这个功能必须解决两个问题:


0 如何在系统引导时显示字符串;


1 如何捕获用户输入并延时等待。


  那么从哪入手呢?我首先想到直接写Video Buffer和直接捕获


键盘寄存器,但是这个方法可行吗?我们不妨先看一下DriverStudio


的 bootcfg.sys 是如何做的。照例用IDA载入bootcfg.sys,按照


DriverStudio初始化显示的字符串来到驱动的DriverEntry,如图0






图0




通过查找字符串的引用很快就找到对应的指令调用点,全文只有一个


引用,如图1所示:






图1



为了确认这一点,我将地址0x107dd - 0x107e6中的指令全部nop掉,






图2




这时原先应该显示"Press ESC ..."这段话的地方果然没有显示,



而是直接跳到 Config 对话框那里去了。既然找对了地方下一



步就好办了,通过进一步反汇编bootcfg.sys的代码片断,更加印证

了我先前的想法!



下面进一步谈谈DriverStudio是如何做的:



a. 使用 MmMapIoSpace 完成物理地址到虚拟地址的映射,



因为内核已经进入保护模式,并且开了分页。要想读写物



理地址必须做这样的映射(我的



Windows 核心编程研究系列之二:读取指定物理内存地址



中的内容一篇中有更为详细的说明)。




该函数原形如下:



PVOID
MmMapIoSpace(
IN PHYSICAL_ADDRESS PhysicalAddress,
IN ULONG NumberOfBytes,
IN MEMORY_CACHING_TYPE CacheType




参数含义都比较明显,其中CacheType我们选择NoCache类型。




b. 使用类似于bios字符中断显示的规则,一个字符占一



个word(16bit),低位为字符的ascii码,高位为显示属性。



我这里要显示闪烁的红色字体,所以属性为 84h。与bios



中断不同的是,我们直接写视频缓冲,而不是调用 int 10h。



视频缓冲的物理地址为 0b8000h 。我写了一个显示函数,



包含两个参数:




第一个是字符串地址,第二个是显示的位置。



为了美观,我将2行字符串显示在屏幕的倒数最后两行上:



Screen_W equ 50h



Screen_H equ 19h ;1ch



Show_Pos_Line0 equ (Screen_W * (Screen_H - 2) + 5) * 2



Show_Pos_Line1 equ (Screen_W * (Screen_H - 1) + 5) * 2




函数内容如下:

复制内容到剪贴板
代码:
[/size][/font][/align][align=left][font=宋体][size=1];******************************************************
[/size][/font][/align][align=left][font=宋体][size=1]_DisplayString proc _lpstr,_pos
[/size][/font][/align][align=left][font=宋体][size=1]local pa:qword
local lpvmem:dword

[/size][/font][/align][align=left][font=宋体][size=1]mov dword ptr [pa],Video_Addr
[/size][/font][/align][align=left][font=宋体][size=1]mov dword ptr [pa+4],0
[/size][/font][/align][align=left][font=宋体][size=1]push 0 ;MmNonCached
[/size][/font][/align][align=left][font=宋体][size=1]push 8000h ;NumberOfBytes
[/size][/font][/align][align=left][font=宋体][size=1]push dword ptr [pa+4]
[/size][/font][/align][align=left][font=宋体][size=1]push dword ptr [pa]
[/size][/font][/align][align=left][font=宋体][size=1]call MmMapIoSpace
[/size][/font][/align][align=left][font=宋体][size=1]mov lpvmem,eax
[/size][/font][/align][align=left][font=宋体][size=1]mov esi,_lpstr
[/size][/font][/align][align=left][font=宋体][size=1]mov edi,lpvmem
[/size][/font][/align][align=left][font=宋体][size=1]add edi,_pos
[/size][/font][/align][align=left][font=宋体][size=1]mov bh,84h ;char show_attribute
[/size][/font][/align][align=left][font=宋体][size=1].while TRUE
[/size][/font][/align][align=left][font=宋体][size=1].if byte ptr [esi] != 0
[/size][/font][/align][align=left][font=宋体][size=1]mov bl,byte ptr [esi]
[/size][/font][/align][align=left][font=宋体][size=1]mov word ptr [edi],bx
[/size][/font][/align][align=left][font=宋体][size=1]inc esi
[/size][/font][/align][align=left][font=宋体][size=1]inc edi
[/size][/font][/align][align=left][font=宋体][size=1]inc edi
[/size][/font][/align][align=left][font=宋体][size=1].else
[/size][/font][/align][align=left][font=宋体][size=1].break
[/size][/font][/align][align=left][font=宋体][size=1].endif
[/size][/font][/align][align=left][font=宋体][size=1].endw
[/size][/font][/align][align=left][font=宋体][size=1]invoke MmUnmapIoSpace,lpvmem,8000h
[/size][/font][/align][align=left][font=宋体][size=1]ret
[/size][/font][/align][align=left][font=宋体][size=1]_DisplayString endp[/size][/font][/align][align=left][font=宋体][size=1]

最后不要忘了用MmUnmapIoSpace取消映射。




c. 为了达到延时的效果需要调用ntoskrnl.exe中的api

KeDelayExecutionThread,其原形如下:



NTSTATUS
KeDelayExecutionThread(
IN KPROCESSOR_MODE WaitMode,
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Interval
);




其中 WaitMode选择KernelMode,将可报警置为FALSE.尤为值得



注意的是第3个参数Interval。这个参数说明如下:




Interval

Specifies the absolute or relative time, in units of 100 nanoseconds, for which the wait is to occur. A negative value indicates relative time. Absolute expiration times track any changes in system time; relative expiration times are not affected by system time changes.


我们最好使用相对时间的延时方式,这就需要写成负数的形式,而将

参数前缀位(byte)全部置1。为了达到捕获键盘输入,需要直接访问

IO端口64h和60h,这在ring0种都不成问题 。我同样写了一个子函数方

便调用,代码如下:



;************************************************************

_WaitForInput proc


local al_tmp:byte
local interval:LARGE_INTEGER
local turnsNow:dword

mov dword ptr [interval],0ffffe000h

mov dword ptr [interval+4],0ffffffffh

mov turnsNow,0

.while TRUE

.if turnsNow == Turns

.break

.else

inc turnsNow

in al,64h

test al,1 ;is anykey is pressed ?

jz Delay

in al,60h

mov al_tmp,al

movzx eax,al_tmp

cmp eax,1

jz ExitWhile

cmp eax,1eh

jz ExitWhile

cmp eax,0b0h

jz ExitWhile

cmp eax,1ch

jnz Delay


ExitWhile:

.break

Delay:

invoke KeDelayExecutionThread,0,0,addr interval

.endif

.endw

xor eax,eax

mov al,al_tmp

ret

_WaitForInput endp

;**********************************************************
[/code]



d. 剩下来做的事就是在Main中判断用户输入的键码:




invoke _DisplayString,addr szhopysay,Show_Pos_Line0

invoke _DisplayString,addr szchoose,Show_Pos_Line1

invoke _WaitForInput


.if al == 01h

;do nothing

.elseif al == 0b0h

invoke _TryBS

.else

;do nothing

.endif
[/code]


运行的效果如图3所示:





图3




  蓝屏的代码就不给出了,因为相信每个人都能写出N种来。写续


篇的原因是因为正好看到驱网(www.driverdevelop.com)的一篇逆向


的文章,想现学现卖一番,呵呵。


  暂时到这里吧(以前预告的第3篇文章因为要将原先结合VB的



界面变为C#而且又有了新的想法,所以还要等一段时间,呼呼),准



备去看女足啦,哇咔咔.......(无语了,这不是我...不是我....



不是我 ... ...)



(因为写得仓促,难免有不妥的地方,希望大家多多指出,谢谢)



(点击小图看大图)






侯佩|hopy



写于2007.09.18





[code]
[code]










                      hopy|侯佩

                      2007.09.16 整理于中国

                      女足惨败于巴西之后

TOP

这里提交也太恐怖了,浏览器占用99%的资源。

格式怎么也整理不好,晕

TOP

先贴到记事本
再复制到这里来吧
--->  伱 能 領 導 潮 流.  我 可 領 導 全 賕!  <---

TOP

引用:
引用第1楼hopy于2007-09-18 19:38发表的 :
这里提交也太恐怖了,浏览器占用99%的资源。

格式怎么也整理不好,晕
侯佩兄用什么浏览器啊?这里我的倒是没有问题,在CSDN 的新版上就卡得很了。
BLOG: http://blog.csdn.net/hkbyest

TOP

落叶树.....你..................

我用的是maxthon2

我嵌入的图片怎么只有连接?

TOP

呵呵,我的也是Maxthon,版本1.5.3 build18,我打过CPU占用高的补丁,刚才看了才发现官网现在没有下载了。
图片不显示可能是论坛后台限制,要不就是ssl的问题啦,要问管理员才清楚
BLOG: http://blog.csdn.net/hkbyest

TOP

为什么字体那么小! 有看到1楼字体非常小的吗 根本看不清
http://sb125.cn

TOP

我在maxthon下不小,楼上用什么浏览器?

TOP

我maxthon的,字体好小,根本看不清楚。估计ie会好点。等等换了看看。

TOP

换ie6也小,小的看不清楚,能不能调一下?

TOP

我用IE7也很小,滚轮+Ctrl放大看吧..
20字节够写什么?

TOP

发新话题