|
|
|
WMIACPI.SYS
7 }( F3 c- J1 g" R( G, q4 m1. WMI Concept
! h6 W) B7 i3 v7 }. L# E2 ^
& S4 f' t) P: Y; Z. V3 HWMI全称Windows Management Instrumentation是一种管理计算机系统的方式。它是微软基于WBEM的实现,WMI希望为系统管理以及分布式数据描述提供一种模型,并且允许使用基于COM的user mode API对系统部件进行访问、管理、控制。' {3 H, Y1 `$ q, q
8 W3 w5 H2 T2 W( L5 a# Q
5 i( @& l) G# C4 `' P2. WMIACPI.SYS2 |4 m9 t* F6 E5 k: u6 Z# n1 U( ?: ]
9 @+ K5 J- B; Y" P( }. x b0 h2 hWmiacpi.sys 是微软提供的一只generic mapping driver它的Plug and Play ID为 PNP0c14.,ACPI包含丰富的系统信息,OEM厂商可以利用这支mapping driver定制平台相关的功能而且允许使用WMI获取,如此便可以在单机或者在网络环境中获得平台的特定信息。关于如何在BIOS、OS中定制wmiacpi,bini已经给出了非常详细的讲解,有兴趣可以参考bini的文章。在这里我会讲解一下原理部分。ACPI-to-WMI mapping function是通过下述两只driver达成的:
2 Y2 O* f: g) b( N8 I( A+ RA.Acpi.sys
0 q4 E$ c. C: Y9 ^ D# TB.Wmiacpi.sys
( y8 ?2 A! p7 {. R9 \' I4 XA).Acpi.sys的一个主要功能是解释和执行aml,而aml就是asl code的机器码,所以ACPI asl code真正的执行是由acpi.sys触发的,而不是BIOS主动执行的。它的另一个功能就是查找ACPI spec定义的device Plug and Play ID,并据此创建相应的software device后续OS会为这些device加载对应driver。如power button driver,battery driver,lid driver,fan driver等等。Device 对应的Plug and Play ID可以查阅ACPI spec获得。
( [/ J& X; T; \6 ?8 H% d" Y1 |B).Wmiacpi.sys它的Plug and Play ID为PNP0c14,一旦BIOS 在asl code给出定义,acpi.sys就会创建这个pseudo device,OS就会load wmiacpi.sys作为该device的driver。当然仅仅加载这支driver还是不够的,为了能够使用WMI访问该software device包含的具体信息我们还需要一个供BIOS使用的asl文件以及与asl code对应的MOF文件而微软并没有提供Wmiacpi.sys相关的MOF文件。那么MOF文件到底有什么作用呢?要搞明白这一点我们来研究一下WMI的工作原理了,下图1展示了WMI Architecture:7 @6 z1 N% ]6 J" x+ u! y/ }
7 G, f4 n$ z2 F% N) Q
2 c6 Z5 j; v) b% F: ?* B; U: B9 G
, R2 K% F3 ~$ n0 j
当user使用API访问WMI信息时,WMI CORE会查看repository中已知的scheme定义,然后将希望获得的信息通过IRP的形式送给Providers这些Providers通常都是WMI Driver,它们处理IRP并将所需信息送给上层。那么也就是说必须要将MOF scheme加到WMI repository之中,consumer 才可能透过WMI COM API访问到。完整的过程是这样的OS在加载WMI驱动程序的时候会查看驱动程序的MOF scheme,如果驱动程序MOF scheme 部分正确无误,那么OS会将MOF scheme提取出来并自动加入到repository之中。所以OS仅仅加载wmiacpi.sys并不行,我们还需要给出与ACPI asl code对应的MOF scheme,并且通过在WMIACPI service key 下面建立一个key MofImagePath它的value指向MOF档的路径。如此在OS加载wmiacpi.sys时就会将对应的MOF scheme加入到repository之中,后续consumer访问时WMI CORE就会检索到scheme信息,然后下IRP给wmiacpi.sys。讲到这里原理应该差不多了但还要注意的是wmiacpi.sys并不会去执行asl code,最终执行动作还是会由acpi.sys发动。driver是层次结构的,acpi.sys是wmiacpi.sys的lower driver,wmiacpi.sys会将上层对asl的访问转化为low level IRP 送给acpi.sys,acpi.sys再返回具体信息然后逐级回送。
6 D) M4 w: w, d5 e A5 h
5 A1 @& L% {& v0 A$ k3. Under the hood
& i# y# L. M) U* b" U$ F: Z; }
% u* O5 R' s1 F前面都是原理的介绍,讲的我都快吐血了J,实践是检验理论的唯一标准。说不如做,随我揭开内幕一探究竟。WDK ver6000 src带了一个wmiacpi的samplecode,build之后会生成一只acpimof.dll,在BIOS里面将device.asl包进去然后再注册表中加入acpimof.dll的信息然后重启。讲到这里还要提到一个验证wmi的好工具叫做WMICodeCreator.exe微软的网站上有下载,下面我们就使用该tool验证前面的说法,下图2演示了我们定制wmiacpi之后的状况:
8 ?1 [0 s1 z5 i& z7 D- \% s' J. J; e- P6 C3 d
# m1 r! k& y( S" Q- ]
9 V0 d: i- \# `3 [: p: e图 2 9 }/ b( ~6 `" v8 l' X( ^" c
图2红色方框标注的AcpiTest_**就是我们定制的WMI class。也就是OS Load wmiacpi.sys之后将其MOF档案解析出来并加入到WMI repository于是我们就看到了上图的信息。下面我们来跟踪一下访问具体的class的情况吧,祭出WinDbg,let’s go!首先查看一下wmiacpi.sys这支driver有没有被加载下图3表明该driver被正常加载了。, V$ E p0 \* G' F# T: N
/ O" q9 v: Q5 j4 ]* G
+ ~8 Y! L' A, p8 b" M, a5 f图3
! n5 H, m1 J2 U; R3 P由图3显示与wmi相关的有两个driver:wmilib.sys和wmiacpi.sys,wmilib.sys是干嘛的呢?别急后续讲述wmi driver的文章会详细介绍它。既然被加载了那我们就要dump wmiacpi.sys的symbol看看有哪些有用的信息,这样我们才比较容易下手J。下图4显示了wmiacpi.sys的所有symbol。7 Z+ [2 l2 F! O8 q+ Q( K
9 ~+ k/ w/ q- h' Y) }
& ^5 i5 E/ `* i0 ]. G+ {1 U图4 9 `* }- T o0 ^
前面我们还讲到wmiacpi.sys最终会调用到acpi.sys访问asl code那我们再看一看acpi.sys有哪些symbol,下图5显示了acpi.sys的所有symbol:; E3 f# S& V( b
4 N6 S5 ^. V* P+ c
7 ?3 C) ]1 Q8 L6 L$ ~6 q
图5
# i8 I' w Q b5 a经过分析上述symbol我觉得下述函数很有作案嫌疑,所以将它们秘密监控J都给设上断点,被怀疑的对象如下图6所示: R9 o9 X6 Z! i1 d% r
* g; ]. y7 [( P; {7 ^5 W
: }/ F9 @ D/ Y1 @
图6
+ w% {( Q! n6 }; @( r. R如图所示:
" t: S' Y4 n; k$ z# _5 q
( p. |$ ~- M; ?4 f+ \wmiacpi!WmiAcpiSetWmiDataItem
+ {* d( S$ g6 _1 h
k5 M( c! l/ K) jwmiacpi!WmiAcpiSetWmiDataBlock
3 K" `; {6 i9 K% Q l& x3 d( R, ]6 v* c6 c& E& [
wmiacpi!WmiFireEvent, e; g' L! L0 T+ O6 i' }
0 x( {: |4 W' a& k& o8 L6 Ywmiacpi!WmiAcpiQueryWmiDataBlock# {& U) X, w, e$ q8 n% K
: m1 @+ P* U' D1 qwmiacpi!WmiAcpiSendAsyncDownStreamIrp' ~8 j* M( V& {" ?7 T' ], e+ |/ B5 N! S
& ?6 K* E- R: {6 m5 |! m+ S% swmiacpi!WmiSystemControl4 T( f6 B" d0 q% S ^. A; e @- X" M
+ r: r0 n/ ]- h. F' nwmiacpi!WmiAcpiSystemControlDispatch9 {2 p" f" g: {! `* b
. M; H! `. h" `
acpi!ACPIIoctlEvalControlMethod9 a; [3 f7 U4 X# A8 G
* j; C( R+ m2 I2 H+ K5 B# |
acpi!ACPIIoctlAsyncEvalControlMethod7 d$ U; V$ _2 p& E& ]- _
4 ?, D- E V+ Y( D- E
acpi!ACPIIoctlAsyncEvalControlMethodEx) d6 X; F, }9 }; T. h5 x
0 H' B6 N1 p3 G) j* y4 u5 Yacpi!ACPIIoctlEvalControlMethodEx
/ [& D: z; v6 n1 R" }8 I# W; \7 \9 D4 ?- g8 A
acpi!ACPIButtonDeviceControl
3 a4 G3 w' r& _' C4 X: L
$ b4 W; E. F x& lacpi!ACPIEcInternalControl
; D+ C7 I, W/ @/ ]8 X8 ?7 z0 G& B$ f! j
acpi!AcpiEmbeddedControllerIrpDispatch$ l* M+ S! l& W$ ~$ x9 `: P
- M9 C5 Q& g" Facpi!ACPIIrpDispatchDeviceControl
' H% S# k. Q6 q. ^
* H% F7 y* E& t }3 [7 H! ^8 f9 Aacpi!WmiSystemControl2 X+ E! f0 _/ ^6 v
/ x" r, I9 i7 Q) {- B( l) I" K这些函数都被设置的断点,下面就我们读写一个class试试看了,图7证实了我之前的所说绝非空口无凭,我们读AcpiTest_MPackage class时发现先会call wmiacpi!WmiAcpiQueryWmiDataBlock,然后acpi!ACPIIrpDispatch DeviceControl会接手,当然后续还会有别的一些动作,但是上述行为就足以支撑我的论点了J。 v$ b+ [& k/ m: S
! d/ u- }, _; I( k- h- {
0 D2 k; ]! k2 Y, U
: v/ |# T8 J& w+ Z- p
$ a/ n/ ?9 M6 k. E图7
8 _: ]% ^$ S0 Z6 S4 `3 \ 图8演示了我们发一个event的状况,图中显示acpi.sys会接到该event然后透过wmiacpi!WmiFireEvent送给上层AP,上层AP再透过IRP下来qurey其它相关的具体信息。
' j/ R* V) a* A% j* A; @* F( z2 Y- M( w
" D( c0 c L5 z& N. d
* @" x0 @/ A3 [ D! e图8 ' ] b) D$ T2 `$ W5 b: P( {
以上就是我费尽九牛二虎之力挖掘的wmiacpi.sys的秘密了,再附上一幅我的debug环境J。
& S! c6 C& a3 r% ~1 K% z
1 }6 {; V5 C) T7 j" u+ I+ Y/ k# v' [, P6 Q3 e4 f+ o
# W, F: \9 }# `3 g" r
图9 # ]- K7 E# ]$ c$ \2 p; u5 V) O! Y
That’s all! S" w9 M* n, J# O) G
Peter 8 D9 Y, I; {0 {7 a$ ~6 o
. J( ?- U/ E0 r! b# G8 x; Y6 k[ 本帖最后由 peterhu 于 2009-5-25 09:31 编辑 ] |
|