ERESOURCE:和你玩躲猫猫

我是一直都知晓你的存在的,虽然你从未现身,任何时候都像操控着一切的隐形之手,但在我心里,你是世界的主宰,规则的制定者,高高在上的上帝。

我只是一个小螺丝钉,每天只是重复地做着我被要求的工作。关于我的出生,我并不清楚,因为我的创造者-“瓶瓶”老爷向来沉默寡言,从不多说话,并且一直都是忙忙碌碌。我也只能在他有空的时候,和他有一句没一句得聊聊天,这才从他口中得知关于我身世一星半点的信息。

听“瓶瓶”老爷说,他是最不愿意制造我们这些螺丝钉的。他说,每制造出一个,他的负担就会增加了一个,虽然我们都是他的长工,每时每刻不停得为他工作,但我们的衣食住行还是要“瓶瓶”老爷为我们打点才行,这也是忙碌的他在空闲时经常向我们发的牢骚。不过,尽管他爱发些不着边的牢骚,我们还是很喜欢他,毕竟他创造了并一直照顾着我们,我们真心地愿意为他打长工,哪怕是一辈子,只要这个世界存在并运转着。

但就在前些日子,世界不在像以前那么可靠了,原因是那只隐形的上帝之手在规则上所做的一个很小的改动,改动虽小,对我来说却是灾难,从此我的世界整个都变成瓦蓝瓦蓝的了(Blue Screen Of Death)。生活如此简单的我,与世无争,咱这井水犯不着任何一条河水,真想不到哎,躺着也会中枪。

我只是重复着做一丁点儿的事,说来也很简单:以Paging I/O的方式去从文件里读数据出来。至于为什么要以Paging I/O方式,我曾问过“瓶瓶”老爷,他说的话很长很长,很深奥很深奥,我只记住了一点点,希望我的复述你能听得明白:

我要读的文件是于用户层中打开的,而我却生活在内核里,我的另一个哥们会将用户层的HANDLE转成FileObject并交给我,之后用户层会将这个HANDLE释放掉(CloseHandle),这时候我虽然手上有Fileobject这把钥匙,但通向Cached I/O及Direct I/O的路全给封上了,只有Paging I/O这条黑路让我去走,我的职责如此,即便是刀山火海,也只能认了。但自从世界变成Win7之后,我总会遇到麻烦,连Paging I/O这条黑道有时也不让我走了,特别是看起来更炫的Win8世界,任何时候都是瓦蓝瓦蓝的。

当时我很伤心,世界一片惨蓝,我以为再也见不着太阳了。可“瓶瓶”老爷又让我重获新生。所以我更感激他了,我发誓愿意为他打二辈子长工,最多只能二辈子,不能再多了,因为我们所处的这个世界一直是很二很二的。

在世界又恢复至正常后,“瓶瓶”老爷曾对我说,或者是老爷他自言自语地说:Win7世界的NTFS动了点手脚,在获取文件ERESOURCE锁后,它会改变此ERESOURCE的Owner Thread’s Pointer(参见ExSetResourceOwnerPointer)!虽然我知道在Filter中是不应该操作此ERESOURCE锁的,但针对这种情况,也是不得已而为之,做个简单的Paging I/O也不是什么危险或惹事的操作。

“瓶瓶”老爷现在让我获取两次共享锁并在释放锁时多做个判断,你想看看我最得意时的状态吗?

0: kd> dt _ERESOURCE 0xfffffa80`02b62050; !locks -v 0xfffffa80`02b62050;
nt!_ERESOURCE
+0x000 SystemResourcesList : _LIST_ENTRY [ 0xfffffa80`02b620f8 - 0xfffffa80`029030d0 ]
+0x010 OwnerTable       : 0xfffffa80`03ba48c0 _OWNER_ENTRY
+0x018 ActiveCount      : 1
+0x01a Flag             : 0
+0x020 SharedWaiters    : (null)
+0x028 ExclusiveWaiters : (null)
+0x030 OwnerEntry       : _OWNER_ENTRY
+0x040 ActiveEntries    : 2
+0x044 ContentionCount  : 0
+0x048 NumberOfSharedWaiters : 0
+0x04c NumberOfExclusiveWaiters : 0
+0x050 Reserved2        : (null)
+0x058 Address          : (null)
+0x058 CreatorBackTraceIndex : 0
+0x060 SpinLock         : 0

Resource @ 0xfffffa8002b62050    Shared 2 owning threads
<strong>     Threads: fffffa800196ab53-01<*> *** Actual Thread fffffa800196ab50</strong>

THREAD fffffa800196ab50  Cid 1364.1368  Teb: 000007fffffde000 Win32Thread: fffff900c229fc20 RUNNING on processor 0
IRP List:
fffffa80042c2c40: (0006,0118) Flags: 00060043  Mdl: fffffa80045c7340
Not impersonating
DeviceMap                 fffff8a00256f460
Owning Process            fffffa80019b9b30       Image:         notepad.exe
Attached Process          N/A            Image:         N/A
Wait Start TickCount      8907           Ticks: 0
Context Switch Count      219                 LargeStack
UserTime                  00:00:00.000
KernelTime                00:00:00.592
Win32 Start Address 0x00000000ff383570
Stack Init fffff880171f1db0 Current fffff880171f0940
Base fffff880171f2000 Limit fffff880171e9000 Call 0
Priority 10 BasePriority 8 UnusualBoost 0 ForegroundBoost 2 IoPriority 2 PagePriority 5
Child-SP          RetAddr           Call Site
fffff880`171f17b0 fffff880`159d69de Foobar!FbDirectReadWriteSingle+0x2a1 [Foobar\read.c @ 332]
fffff880`171f1840 fffff880`159d73a8 Foobar!FbDirectReadWrite+0x85e [Foobar\read.c @ 628]
fffff880`171f1930 fffff800`01cbb1b5 Foobar!FbDispatchRead+0x18 [Foobar\read.c @ 1172]
fffff880`171f1960 fffff800`01cbac89 nt!IoPageRead+0x255
fffff880`171f19f0 fffff800`01ca165a nt!MiIssueHardFault+0x255
fffff880`171f1ac0 fffff800`01c920ee nt!MmAccessFault+0x146a
fffff880`171f1c20 00000000`ff384061 nt!KiPageFault+0x16e (TrapFrame @ fffff880`171f1c20)
00000000`000fde80 00000000`00000000 0xff384061

<strong>              fffffa800196ab50-01<*> </strong>

THREAD fffffa800196ab50  Cid 1364.1368  Teb: 000007fffffde000 Win32Thread: fffff900c229fc20
……

哈哈,不论你怎么躲,也躲不开我了,因为我知道了你所有的藏身之所。现在想改变规则了?你想怎么改呢?

我是个简单的小螺丝钉,我不惧怕任何权威,我吃苦耐劳,我要求很少,只要不让我的世界一片惨蓝,做再多的事我也愿意。

现在我的生命力更顽强了,我不仅会点自检,还会些自愈。面对这个美好的世界,只想说一句话,那就是:活着真好。

最后,我的id是“螺丝钉小P”。你的呢?我知道你有多个马甲的,嘿嘿!

摘自“螺丝钉小P”的日记(DEC/12/2012)

 

A Half Day

Pingping (瓶瓶) is a software engineer, as thousands of other software engineers, everyday he codes, everyday he gets bugs, so everyday he de-bugs.

Today is just a normal day that every normal software engineer would normally have.                                                  

This afternoon, when testing his software, trying to save something he randomly typed in windows notepad, he encountered an error. To confirm, he restarted a new instance of windows notepad, and got the same error.

It's an obvious bug.

So he debug.

Soon he was absorbed in his interesting enterprise of debugging. One round after another, every restart he typed something to verify, until the end of the bug.

It was already mid-night. On his computer's screen, was a long log in windows notepad.

I’m too somehow a night bird. When I occasionally saw it and thought it was interesting, then I made a copy, because I know, pingping is a guy who is always seeing forward, he would let it go and ghost his test system to a fresh, with all data destroyed.

So luck for you, here's the log, also for pingping if he isn't coding or debugging right now.

Round 1, 2012/12/07 13:06
Hi buggy, I'm waiting for you … 
   
Round 2, 2012/12/07 13:10
Now we are acquainted. But I still don’t know where you are from and when you arrive here. Tell me your story, let me know you, Pleaseeeee !

Round 3, 2012/12/07 13:17
You are really a hard nut, just my taste, I'm nailing up you.

Round 4, 2012/12/07 13:26
Huh, you are so deeply hid. But anyway, it's just a matter of time for me to get you, shorter or short, haha.

Round 5, 2012/12/07 13:39
What a doggy luck you have today ! But you are almost running out of it, I'm sure of that.

Round 6, 2012/12/07 14:02
Ok, fine, fine, you are good, really good. Unfortunately, I will NOT give up.

Round 7, 2012/12/07 14:30
Now I know you better, know you more. Don't bother to hide any more.

Round 8, 2012/12/07 14:37
You are good at hiding, but remember I'm damn good at seeking, top level in the world.

Round 9, 2012/12/07 14:52
Once i catch you, I'll screw your neck, and squeeze your head. So pray now before it's too late.

Round 10, 2012/12/07 15:09
pang !

Round 11, 2012/12/07 15:29
peng !

Round 12, 2012/12/07 15:40
bang !

Round 13, 2012/12/07 16:01
Yes, I'm still here, with full eyes on you. You, little damn buggy, show yourself !

Round 14, 2012/12/07 16:20
bang ……

Round 15, 2012/12/07 16:32
peng ……

Round 16, 2012/12/07 16:50
pang ……

Round 17, 2012/12/07 17:03
Ah, finally, I got you. now you know I'm a damn good seeker.

Round  18, 2012/12/07 17:09
Hurrah !

Round  19, 2012/12/07 17:16
Yippee, did one more test just to confrim. I'm quite satisfied of your disapperance.

…………

Round 20, 2012/12/07 18:00
I'm back, little buggy, are you there ?

Round 21, 2012/12/07 18:15
I'm back again, little buggy, can you hear me ?

Round 22, 2012/12/07 18:20
where are you ? playing with another software engineer ? is he cool ?

Round 23, 2012/12/07 18:25
???

Round 24, 2012/12/07 18:30
I know now, just because of the half day we stay together, a bug is not only a bug, but a present of a secret. Of all bugs, you are the secret of all secrets.

Round 25, 2012/12/07 18:40
I … I,  starts missing you.  

Round 26, 2012/12/07 19:00
Hi there, if you can hear me. I'm here to say goodbye. I must go now, another bug was just coming. For the first time of the life, I just feel so sad to leave. May I see you again ?

< Dec. 07 night, on the train from Beijing to Jining Shandong. >

离奇死亡事件薄之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个频道,只是所有频道上都是相同的节目,而且都是红歌大比拼。红歌声中,瓶瓶淡定地等待着下一件凶杀案的发生。他知道,用不着等太久 ……

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