蓝屏,谁之过?

Bug总能在你意想不到的地方给你个措手不及,只是它所带来并不是惊喜,而是Blue Screen Of Death !

既如此,只能兵来将挡。

先介绍一下程序的大体流程:

NTSTATUS XXXProcessDirents(…) {

do {

KeEnterCriticalRegion(); ExAcquireResourceSharedLite(&fcb->Resource, TRUE);

/ access several members of fcb structure /

ExReleaseResourceLite(&fcb->Resource); KeLeaveCriticalRegion();

        XXXXProcessDirent(…);

} while (list_is_not_empty(….));

return status; }

NTSTATUS XXXXProcessDirent(…) { HANDLE handle = NULL; XXXX_FILE_HEADE fileHead; ……

/ open file / status = ZwCreateFile(&handle, GENERIC_READ, &oa, &iosb, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, 0, NULL, 0);

/ read file header/ status = ZwReadFile(handle, ioevent, NULL, NULL, &iosb, (PVOID)&fileHead, sizeof(XXXX_FILE_HEADE), &offset, NULL);

/ check whether file is interesting to us / if (status == STATUS_SUCCESS && iosb.Information == sizeof(……)) { / it’s my taste, haha / }

/ close file, not interested in it any more /

if (handle){ ZwClose(handle); }

return status; }

过程比较简单,XXXProcessDirents()会循环调用XXXProcessDirent(),直至列表中所有项全检查完毕。

下面再来看windbg分析吧:

1: kd> !analyze -v


                                                                                                     Bugcheck Analysis                                                                                                                


IRQL_NOT_LESS_OR_EQUAL (a) An attempt was made to access a pageable (or completely invalid) address at an interrupt request level (IRQL) that is too high.  This is usually caused by drivers using improper addresses. If a kernel debugger is available get the stack backtrace. Arguments: Arg1: 0abc9867, memory referenced Arg2: 00000002, IRQL Arg3: 00000001, bitfield : bit 0 : value 0 = read operation, 1 = write operation bit 3 : value 0 = not an execute operation, 1 = execute operation (only on chips which support this level of status) Arg4: 806e7a2a, address which referenced memory

Debugging Details:

WRITE_ADDRESS:  0abc9867

CURRENT_IRQL:  2

FAULTING_IP: hal!KeAcquireInStackQueuedSpinLock+3a 806e7a2a 8902            mov     dword ptr [edx],eax

DEFAULT_BUCKET_ID:  DRIVER_FAULT

BUGCHECK_STR:  0xA

PROCESS_NAME:  System

TRAP_FRAME:  b9019bbc -- (.trap 0xffffffffb9019bbc) ErrCode = 00000002 eax=b9019c40 ebx=00000000 ecx=c0000211 edx=0abc9867 esi=c0000128 edi=8842d268 eip=806e7a2a esp=b9019c30 ebp=b9019c68 iopl=0         nv up ei ng nz na pe nc cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010286 hal!KeAcquireInStackQueuedSpinLock+0x3a: 806e7a2a 8902            mov     dword ptr [edx],eax  ds:0023:0abc9867=???????? Resetting default scope

LAST_CONTROL_TRANSFER:  from 806e7a2a to 80544768

STACK_TEXT: b9019bbc 806e7a2a badb0d00 0abc9867 804f4e77 nt!KiTrap0E+0x238 b9019c68 806e7ef2 00000000 00000000 b9019c80 hal!KeAcquireInStackQueuedSpinLock+0x3a b9019c68 b9019d24 00000000 00000000 b9019c80 hal!HalpApcInterrupt+0xc6 WARNING: Frame IP not in any known module. Following frames may be wrong. b9019cf0 80535873 00000000 8896fb20 00000000 0xb9019d24 b9019d10 b79d87ff ba668a30 8859b7e8 00000440 nt!ExReleaseResourceLite+0x8d b9019d2c b79d8a5c 8a3ff2f0 00000003 ba6685f0 XXXXX!XXXProcessDirents+0xef b9019d88 b79e163a e2f6b170 00000001 00000001 XXXXX!XXXKernelQueryDirectory+0x20c b9019ddc 8054616e b79e1530 88a8ae00 00000000 nt!PspSystemThreadStartup+0x34 00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16

问题出在系统函数ExReleaseResourceLite()及KeAcquireInStackQueuedSpinLock()上,且程序要写的地址为0abc9867 ,明显不对,所以此处可做栈损坏推断。

第一嫌疑要考虑的是,XXXProcessDirents()中有锁保护的部分,此部分是果真是最容易造成栈损坏buffer复制操作。但经过仔细检查及测试,便排除了此部分出错的可能。

在排除第一嫌疑后,就没有明显目标了。只好再接着看windbg log:

貌似KeAcquireInStackQueuedSpinLock()要写的地址是LockHandle的LockQueue->Next,而LockHandle一般都在从当前堆栈分配的,由此可肯定之前对于栈损坏的推断。可问题是,是谁导致的栈损坏。

Stack中有hal!HalpApcInterrupt()调用记录,它是处理APC的软中断。hal!HalpApcInterrupt()会一般会调用nt!KiDeliverApc()来处理线程的APC队列。但当ExReleaseResourceLite()调用的时候,线程还处于临界区内(Critical Section),此时User mode APC及Kernel mode normal APC都会被禁止的,但Kernel mode special APC不会。

Kernel Special APC最常见的情况便是由IoCompleteRequest()添加的:在APC Level中调用IopCompleteRequest()以处理Irp的Stage 2的清理工作。

至此,问题终于有些眉目了。分析代码中唯一有可能导致APC添加的地方就在函数XXXXProcessDirent()中的ZwReadFile()调用,而且fileHead正是于堆栈中分配的。

想到此处,此bug的根据原因便付出水面:

XXXXProcessDirent()没有处理ZwReadFile()返回STATUS_PENDING的情况,此情形下,XXXXProcessDirent()退出并继续执行,而之前的ZwReadFile()的IRP完成操作也在同时进行(还没有完成),并且此完成操作所要写的fileHead地址,正是早已被回收并加以重用的当前栈。

搞清楚之后,便在调用ZwReadFile()后,特别针对STATUS_PENING的情况来调用ZwWaitForSingleObject()以确保读操作全部完成后,再进行下一步操作。

到此,问题解决!

一个蓝屏的问题,竟然如此之绕,不禁让我想起刘震云的《一句顶一万句》,只是这能顶一万句的一句到底是哪句呢?

<下一步打算写写APC相关的东西,操作系统将APC隐藏得太深,总让人捉摸不定!>

Continue reading » · Rating: · Written on: 09-11-12 · 14 Comments »

Win7调试模式问题一例

BootMgr的引入,虽然增加了操作及维护的复杂度,但相应带来的好处也不少,就比如我曾做过的一次操作:将Win7系统从第一分区移动至第三分区。这样的操作在XP时代,是不太可能的,因为这就意味着盘符的改变,系统内部配置都是以盘符来确定的,而Win7始终将系统盘加载至C:上。

将Win7移动后,修改BootMgr记录中的device及osdevice项后,Win7系统便能正常启动,相应命令如下:

bcdedit /set {uuid} device=partitioin=X: bcdedit /set {uuid} osdevice=partitioin=X:

然后将debug模式打开:

bcdedit /debug {uuid} on

然后再设置dbgsettings为1394,而不是默认的com串口:

C:\>bcdedit /dbgsettings An error occurred while attempting to access the boot configuration data. The system cannot find the file specified.

系统中竟没有dbgsettings,那就自己创建好了:

C:\>bcdedit /create {dbgsettings} The entry {dbgsettings} was successfully created. C:\>bcdedit /dbgsettings There are no debugger settings present. The operation completed successfully. C:\>bcdedit /dbgsettings 1394 channel:11 The operation completed successfully. C:\>bcdedit /dbgsettings debugtype               1394 channel                 11 The operation completed successfully.

设置好生重启系统,但wndbg死活就是连不上。但同样的硬件,用XP启动windbg确实能正常,所以排除了线材、硬件问题,还是要从Win7系统着手。

经过详细对比正常系统的BootMgr设置后,发现是dbgsettings虽设好了,但并没有关联到Win7启动项上。那就做一下关联试试:

C:\>bcdedit /create {globalsettings} The entry {globalsettings} was successfully created. C:\>bcdedit /set {globalsettings}  inherit {dbgsettings} The operation completed successfully. C:\>bcdedit /set {current} inherit {globalsettings} The operation completed successfully.

重启系统后,windbg便能正常连接了。

挺简单的事,非要搞得这么复杂!难怪简单的苹果产品却赢得了如此多用户的芳心!?

Continue reading » · Rating: · Written on: 09-05-12 · No Comments »

离奇死亡事件薄之CoCreate篇

“周节棍的双杰伦,砌里侉叉 …”

一阵吵杂的手机铃声将正在发呆的瓶瓶吵醒,他呆滞的眼神中蓦地闪出亮光,心想:大买卖又来了?

果不其然,又是一桩离奇案件:CoCreate在密镇莫名死亡,临终前嘴里还含糊地说了句“The file xxx failed to load. could not unpack the file xxx. Either this file is invalid, you do not have sufficient memory, or no space is left. (Error 398)” ,然后便咽气了。

密镇是凶杀案频发的地方,因其本身治案环境不好,很多案件都成了无头案。这也是为什么作为私家侦探的瓶瓶会被委托查找真凶的原因。

瓶瓶深思了一会,便开始着手重构死亡现场。这里还要多说一句,随着科技的进步,新时代的侦探们也有了更高效的破案方式方法,虽然原始的从验尸(Postmortem,Crash dump analysis)开始的福氏方式依然盛行,但越来越多的人都开始采用这种重建虚拟现场的方式,毕竟新的方法可以让你一遍一遍地推演,并在推演中不断地发现新的线索,直到真相大白。

重构虚拟现场需要相关的工具和设备才行。每位侦探都有自己偏爱的工具组合,当然也逃不脱其时代的限制与烙印。比如两位同姓宋的侦探前辈:宋慈因处宋朝,手中也只有手术刀之类的工具,纵使锋利,但作用毕竟有限;再看19世纪英国的宋戴克,他的方形绿皮箱里可谓是包罗万象,从放大镜,显微镜,到酒精灯,试剂等一应俱全,俨然福尔摩斯的化学实验室了。

但对于21世纪像瓶瓶一样的侦探们来说,一切又化繁为简,一般一台电脑足矣,有时也需要多台并加上若干互联设备。瓶瓶的书房便是充斥着各色各样的电子设备,相互间连接着的五颜六色的电缆全绞缠在一起。

瓶瓶最得心应手的工具包还是windbg,外加一根1394线,便足以对付大多数棘手的凶案。从业之初,瓶瓶用得可是debug工具包,后来经过softice,最后才用上windbg,前几年还是windbg第五代,当时用得还是串口线,现在已升级至第六代了。

不到一个小时,瓶瓶便已连接好所有设备,并设定妥了虚拟现场环境。随着“滴”的一声响,模拟系统开始启动,windbg上开始显现一串串的字符。此时,瓶瓶圆睁的双眼透过厚厚的近似镜片直盯盯地注视着快速翻滚的屏幕,生怕错过每一个细节。同时又暗自庆幸,CoCreate并没有进行反模拟手术,否则,如果像3ds max那样完全依赖log来分析地话苦头可就大了。

忽然“铛”地一声响,屏幕跳出了CoCreate的临终遗言。此次模拟相当成功,但在细致分析windbg记录之前还没找到任何明显线索,在浏览了所有记录后,也未能找到什么重要的线索。不得不又架设好procmon工具,重新又模拟了一次。procmon工具可以协助记录CoCreate死亡前的所有活动记录,及所有与他接触的相关人员等等。在procmon记录中,发现最后一个与死者接触的人是unzip。

“CoCreate死前找unzip干什么呢?”,瓶瓶陷入深思,忽然间,他想到了死者的遗言中有说 "unpack”,“难道真和unzip有关”,瓶瓶一边思考着一边努力寻找着证据。

瓶瓶打开了死者临死前正翻阅的文件,题为xxx。这是一个加密的文件,密镇定了法律为了保护所有信息,必须对各种重要文件进行加密,否则不能随便交换或传阅。瓶瓶当然知道怎么将此加密文件解密成明文,毕竟如果没有点关系,还真干不成侦探这个行当。

刚打开明文文件,瓶瓶就发现文件头竟赫然是 “504B0304”, ”504B”正是zip压缩法发明者Phil Katz的名字缩写: PK。基本可以肯定xxx文件为zip文件格式,所以CoCreate死前才会去见unzip。若如此地话,那unzip倒底做了些什么呢?

瓶瓶大感意外的是:等找到unzip时,发现unzip也离奇死亡了。难道是…连环谋杀?看来此案件内情确实不简单,搞不好会惹火上身!想到此,瓶瓶不禁觉得背后发寒。

但事已至此,由不得自己了。瓶瓶先勘察了unzip的死亡现场,但另他失望的是,unzip临死留下的遗言更让人摸不着头脑:  ”End-of-central-directory signature not found. Either this file is not a zipfile, or it constitutes one disk of a multi-part archive…”。这倒底什么意思?进行了一番搜索后,瓶瓶发现如此死亡的案件竟有很多,只是,众多老案件至今还未结案。

多次探索均无功而返,瓶瓶决定先从模拟unzip死亡现场开始。好在unzip也是位名人,有关他的材料可谓是汗牛充栋,特别是有关他的生平传记(unzip60.zip),更是给现场模拟提供了最好的背景材料。

模拟中果然有新的发现,unzip在通过公开渠道获取的加密文件信息竟是错的。此公开渠道是_stat64调用:

int _stat64( const char path, struct __stat64 buffer );

_stat64会返回文件大小、时间戳等信息。关键的地方是:_stat64获取这些信息的方法不是通过GetFileInformationByHandle (IRP_MJ_QUERY_INFORMATION/FileStandardInformation),而是通过FindFirstFileEx (即IRP_MJ_DIRECTORY_CONTROL/IRP_MN_QUERY_DIRECTORY)得来的。这样操作如果在平时是没有问题的,但在密镇却会出错。

密镇会对所有文件进行过滤并加密,即便是授权的用户在用第二种办法查询文件时,所返回的文件大小与实际大小也是不相符的,因为密镇的所有文件都要附载加密信息而被增厚了。故unzip用错误的文件页码信息来校验文件时,必然会发生了意外。

这个问题当然是出在密镇身上,但令人可气的是,unzip在调用_stat64后又调用了GetFileTime (IRP_MJ_QUERY_INFORMATION/FileBasicInformation),既然都动用私人关系了,为什么不一次性到位,直接将文件大小也一并取了呢?!

案件侦测至此,案情已基本大白。只是善后工作该怎样去做,真是个让瓶瓶头痛的事情:

最彻底的办法,当然是改良密镇,虽然此方案涉及面太广。瓶瓶经过好一番努力,透过多个渠道才将此事办妥,本以为可以长舒一口气的当口,黑老大M$的代表Office Word发飙了,无论如何都反对。此事竟然黑老大也参与其中?这让瓶瓶不得其解,在没有搞清楚其中奥妙之前,也只能放弃此番所有努力而另辟奇径了,毕竟太岁头上的土动不得。

既然unzip已经死亡,那就不妨再推出个新个unzip吧。让新的unzip用新的私人渠道来获取加密文件的信息不就完了呗。

说到便做到,等将新的unzip装上设备,又进行新的一轮模拟,一切正常了。

连日的探查已让瓶瓶厚厚的镜片蒙上了一层灰尘,正好遮挡住了他更加疲惫的眼神。但无论如何,最后还是以最小的代价将善后工作完成了,瓶瓶终于能够安坐在弹簧椅上,惬意地随着电视哼起了 《游击队歌》。

密镇的电视共有200个频道,只是所有频道上都是相同的节目,而且都是红歌大比拼。红歌声中,瓶瓶淡定地等待着下一件凶杀案的发生。他知道,用不着等太久 ……

(本故事部分纯属虚构,请勿胡乱对号入座)

Continue reading » · Rating: · Written on: 12-30-11 · 7 Comments »

_snwprintf_s的潜规则

在程序中为了构造文件全路径时,使用了函数_snwprintf_s。结果在释放buffer时运行时库(runtime library)报错,提示buffer已被破坏了。再次审视代码,看不出有什么毛病,只得动手调试,然后便定位问题出在了_snwprintf_s的调用上。

_snwprintf_s函数的原型定义如下:

int _snwprintf_s( wchar_t *buffer, size_t sizeOfBuffer, size_t count, const wchar_t *format [, argument] ... );

在细致地阅读了MSDN中关于它的说明后才发现问题原因:

此函数第二个参数(size_t sizeOfBuffer)是以word (双字节)为单位的,而不是byte。问题找到,更改传入参数后,buffer corruption的问题消失。

但是,还有个奇怪的问题,也许你已注意到,如果第二个参数是以word为单位的,那第三个参数呢?不应该也是以word为单位吗?

可惜,不是。第三个参数依然还是以byte为单位,否则你的程序又不能工作了,只是这次错误将会更加地隐蔽。

你只能感叹:同样都是count,咋相差这么大呢!

这里再说说_XXX_printf_X等一系列相关的函数,如果你看了MSDN中关于snprintf的说明,你这定会惊讶于它众多的兄弟姐妹,个个相像,可绝对又各不相同:如_snprintf, _snwprintf, _snwprintf_s, _snwprintf_s_l:

  • sprintf是ANSI C所定义的函数之一,应该是最古老的一个,当然也是最容易受缓存区溢出攻击的一个
  • _snprintf: 多了一个“n”表示是多了一个描述buffer长度的参数,如果输入字串过长将被截断,毫不留情。
  • _snwprintf: 多了个“w”表示是字串为双字节字串,如unicode
  • _snwprintf_s:又多了个”s”后缀,表示是“Security Enhancement”。为了应对缓存区溢出攻击,而对函数进行改进以对输入参数进行多项检查。更多信息见于:MSDN
  • _snwprintf_s_l: 更进一步,又多了个“l”后辍,表示此函数支持字符集指定,而不是默认使用当前字符集。
  • _snwprintf_s_l_? : 不久的将来又将怎样演化呢 ?我且拭目以待。
Continue reading » · Rating: · Written on: 12-19-11 · No Comments »

Windbg指令体系

Windbg,作为Windows御用的调试工具,功能异常强大,其指令亦是相当繁杂。我是从01年开始使用,至今为止所掌握的指令还是最常用的一些,如果做点稍复杂的工作,必须求助于Windbg帮助手册,查手册寻找指令或确认指令语法格式已是经常之事。

倒是被Windbg所替代的一代神器Softice,以其界面和指令的简洁、易用,曾给几代程序人留下深刻印象。我大约是从96年开始使用Softice,至01年完全转移到Windbg上来,但很多Softice的指令还是犹如历历在目,看来“先入者为王”对习惯的养成来说同样是条不二准则。

言归正传,Windbg的指令分为三种:

  • 1)Debugger commands,或 regular commands

    如 u: 反汇编指令;db: 以16进制及字节方式打印数据;t: 单步执行 …

    regular commands 一般是面向于被调试程序或目标系统的,即可以显示被调试程序相关的信息或控制目标程序的的执行等。

  • 2)Meta commands

    如 .reload: 加载符号表;.cls: 清除command窗口所显示的信息;.thread: 挂接并显示指定线线程的上下文(context) …

    meta commands 一般指控制windbg本身的一些指令,所有指令以”.”为开始,如符号表管理相关的指令。

    其实有一些指令功能上与regular command相混淆,如:

    .restart: 重启被调试机器或程序,呵呵,没有比这个对被调试对象更大的控制操作了;
    .writemem: 将指定内存区域写入文件;
    ……

    此外,还有些莫名的指令也归入这一类,如.dbgdbg指令,它会启动调试器来调试当前的调试器,够绕吧!

  • 3)Debugger extension commands

    如 !process:显示当前进程信息;!analyze: 著名的BSOD分析命令…

    这类指令属于windbg的扩展指令,所有指令均以”!”为前缀,指令的实现不在debugger程序体中,而是相关的DLL文件。windbg的扩展组件,有标准的格式,开发者可以根据需要为协助自己程序的调试定制自己的扩展组件。windbg程序包已为不同的应用环境提供了不同的扩展组件:如应用程,内核层,NDIS驱动,GDI图形类驱动……

除了Windbg的帮助手册之外,还有几本书对Windbg的使用很有帮助:

1, Dmitry Vostokov, Memory Dump Analysis Anthology, Volume 1 & 2
    结合实例介绍Windbg的使用技巧,共两本
2, Mario Hewardt & Daniel Pravat, Advanced Windows Debugging
    此书有中译本。主要还是面向Windows内核调试的。
3, 熊力,Windows用户态程序高效排错
    主要面向于用户态及.NET程序的调试。

Continue reading » · Rating: · Written on: 11-16-11 · No Comments »

慎用MmSetAddressRangeModified

MmSetAddressRangeModified用来设置PFN为dirty/modified,并将PTE的dirty位清除。但除此之外,还有个不明显的副作用,看下面的分析:

1: kd> !pte 0xfffff880`0c9e6000
                                 VA fffff8800c9e6000
PXE @ FFFFF6FB7DBEDF88     PPE at FFFFF6FB7DBF1000    PDE at FFFFF6FB7E200320    PTE at FFFFF6FC40064F30
contains 000000003FE84863  contains 000000003FE83863  contains 0000000014516863  contains 000000000FAD7963
pfn 3fe84      ---DA--KWEV  pfn 3fe83      ---DA--KWEV  pfn 14516      ---DA--KWEV  pfn fad7       -G-DA--KWEV

PTE entry 状态为dirty,并且是可写的(writable)。 再看调用MmSetAddressRangeModified后的状态:

1: kd> !pte 0xfffff880`0c9e6000
                                 VA fffff8800c9e6000
PXE @ FFFFF6FB7DBEDF88     PPE at FFFFF6FB7DBF1000    PDE at FFFFF6FB7E200320    PTE at FFFFF6FC40064F30
contains 000000003FE84863  contains 000000003FE83863  contains 0000000014516863  contains 000000000FAD7921
pfn 3fe84      ---DA--KWEV  pfn 3fe83      ---DA--KWEV  pfn 14516      ---DA--KWEV  pfn fad7       -G--A--KREV

PTE entry的dirty位已被清除,但是此pte已被设成了readonly状态了。所以如果再有写操作,必然会导致page fault发生。

这就是我曾遇到的一个Ext2Fsd的bug:Ext2Fsd为了将page cache锁定,创建了MDL并重新映射到系统空间(调用MmMapLockedPagesSpecifyCache)。新映射的va具有dirty及writable属性,故此va在spinlock (DISPATCH_LEVEL)下进行写操作不会导致任何异常。但在提交改动过程中,Ext2Fsd调用了MmSetAddressRangeModified,调用后MmSetAddressRangeModified会将此pte设置为readonly,如果下一次的写操作正好在spinlock下(DISPATCH_LEVEL),将会导致BSOD: DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1),如果在获取spinlock前曾执行过写操作(IRQL < DISPATCH_LEVEL),则会正常触发page fault,然后MmAccessFault会重置pte为writeable,并设置dirty位,此后如果再进入DISPATCH_LEVEL,对此va进行写操作便不会触发page fault了。这就构成了一定的随机性和隐蔽性,给调试带来了很大的麻烦。

明白了问题所在,不妨再做个实验:如果手工将此pte设为writeable的,再进行写操作,cpu应该直接置pte为dirty,而不必调用OS(即page fault)。

对va 0xfffffa60`04ae7000 调用MmSetAddressRangeModified后,

1: kd> !pte 0xfffffa60`04ae7000
                                 VA fffffa6004ae7000
PXE @ FFFFF6FB7DBEDFA0     PPE at FFFFF6FB7DBF4C00    PDE at FFFFF6FB7E980128    PTE at FFFFF6FD30025738
contains 000000007FFC4863  contains 000000007FFC3863  contains 00000000539A2863  contains 00000000149AD921
pfn 7ffc4      ---DA--KWEV  pfn 7ffc3      ---DA--KWEV  pfn 539a2      ---DA--KWEV  pfn 149ad      -G--A—KREV

手工修改 0xfffffa60`04ae7000为writeable,不必置dirty标志:
1: kd> dq FFFFF6FD30025738 l1
fffff6fd`30025738  00000000`149ad921

1: kd> eb FFFFF6FD30025738 23
1: kd> !pte 0xfffffa60`04ae7000
                                 VA fffffa6004ae7000
PXE @ FFFFF6FB7DBEDFA0     PPE at FFFFF6FB7DBF4C00    PDE at FFFFF6FB7E980128    PTE at FFFFF6FD30025738
contains 000000007FFC4863  contains 000000007FFC3863  contains 00000000539A2863  contains 00000000149AD923
pfn 7ffc4      ---DA--KWEV  pfn 7ffc3      ---DA--KWEV  pfn 539a2      ---DA--KWEV  pfn 149ad      -G--A--KWEV

在进行写操作前可以对KiPageFault或MmAccessFault设置断点,然后进行实验。看断点会不会触发,操作后再检查一下pte的dirty标志是不是已经设置了。具体实验结果,就留给读者自己去验证了。

在DISPATCH_LEVEL中操作paged va无论是已将其page锁定还是重新映射过,都有点如履薄冰的感觉,特别是对file cache,Cache Manager的不少内部操作都会更改pte的属性或调用MmSetAddressRangeModified,到处都可能有陷阱。所以最保险的方式还是不用spinlock 微笑

Continue reading » · Rating: · Written on: 02-09-11 · No Comments »