|
|
|
WMIACPI.SYS / `- I0 y5 F+ W( E- _
1. WMI Concept: y) A2 n, ?* d& o, f
! R7 @9 b" Q+ H+ ?" Q& Q$ u
WMI全称Windows Management Instrumentation是一种管理计算机系统的方式。它是微软基于WBEM的实现,WMI希望为系统管理以及分布式数据描述提供一种模型,并且允许使用基于COM的user mode API对系统部件进行访问、管理、控制。, m# p( y! \ F% R; q. T) v/ o
0 W7 U- ]0 N7 T- d' [% F, `
/ M$ C9 g) K& ]2 I; d* W! ~7 y2. WMIACPI.SYS
: a! w6 W* }. R! }
2 d" R4 S! P2 M) o2 W8 pWmiacpi.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达成的:
; e; T6 F' Z# M$ zA.Acpi.sys
8 u; m+ A- H5 i$ xB.Wmiacpi.sys
. ], `! ~) F, ~1 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获得。
9 w, b, y% a) i. cB).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:2 i9 E! {! u4 J4 F3 [
& j. T: b' ]. A: N9 M% Y* a! A2 G" ~0 j A; Q! ^
8 j1 B9 \! s9 m, N! h) @当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再返回具体信息然后逐级回送。7 G& j0 g& `' h
9 G+ ]$ R- d5 I3 n8 b3 D3. Under the hood
8 B! s# n1 ]5 J# ~ } H& Y6 O/ S* }4 w8 \3 [
前面都是原理的介绍,讲的我都快吐血了J,实践是检验理论的唯一标准。说不如做,随我揭开内幕一探究竟。WDK ver6000 src带了一个wmiacpi的samplecode,build之后会生成一只acpimof.dll,在BIOS里面将device.asl包进去然后再注册表中加入acpimof.dll的信息然后重启。讲到这里还要提到一个验证wmi的好工具叫做WMICodeCreator.exe微软的网站上有下载,下面我们就使用该tool验证前面的说法,下图2演示了我们定制wmiacpi之后的状况:
1 V. H* b0 m- M5 e+ j) J
7 A g$ Y) K, V* C8 ~% [' s1 r2 i- }/ N
4 _$ q- d) D; p$ z图 2
$ o! V& s6 T/ g. A图2红色方框标注的AcpiTest_**就是我们定制的WMI class。也就是OS Load wmiacpi.sys之后将其MOF档案解析出来并加入到WMI repository于是我们就看到了上图的信息。下面我们来跟踪一下访问具体的class的情况吧,祭出WinDbg,let’s go!首先查看一下wmiacpi.sys这支driver有没有被加载下图3表明该driver被正常加载了。
2 ]+ I: V% v0 x+ j; \- W* h6 j% l" ^* y$ w- h9 l( ^
5 y; {/ M0 b+ A
图3 6 E& D* F: ]/ S9 w0 G5 r% n
由图3显示与wmi相关的有两个driver:wmilib.sys和wmiacpi.sys,wmilib.sys是干嘛的呢?别急后续讲述wmi driver的文章会详细介绍它。既然被加载了那我们就要dump wmiacpi.sys的symbol看看有哪些有用的信息,这样我们才比较容易下手J。下图4显示了wmiacpi.sys的所有symbol。 n& R6 ?1 N: r
( D; g! t. F3 t
+ v* m; Q, I- b( n2 U/ u图4
. c, j4 r1 F+ T( C, U前面我们还讲到wmiacpi.sys最终会调用到acpi.sys访问asl code那我们再看一看acpi.sys有哪些symbol,下图5显示了acpi.sys的所有symbol:
+ L0 |( T- E0 S- T$ Z, d E1 H/ T! i" `6 A' S0 p8 Z
7 W2 d0 l* [3 H5 ~3 M E' N9 ^图5 # P( i. D/ h% u$ R, a9 {% l8 H. |
经过分析上述symbol我觉得下述函数很有作案嫌疑,所以将它们秘密监控J都给设上断点,被怀疑的对象如下图6所示:; A( w A& V2 `4 ?- |* I# p* Z
2 N7 |5 l7 t3 S2 \) H; h# c4 a
& m% L/ U8 j8 [' _( b4 a) }图6 , Q& s: [1 h' i' B% S
如图所示:
( b9 O7 \% D+ v$ k2 u6 t6 }( Q% }3 Y* Z6 T A/ x
wmiacpi!WmiAcpiSetWmiDataItem
6 |) \" @, s2 S i5 u: E
3 K( G" @* p c1 Vwmiacpi!WmiAcpiSetWmiDataBlock
s. z' b2 W3 a7 c+ P5 e8 T3 h3 t$ d: p' Z1 m& h
wmiacpi!WmiFireEvent& k4 I, r% q1 g% s X8 x
& s+ k- s( x( Y7 K5 c5 a
wmiacpi!WmiAcpiQueryWmiDataBlock
. W' k: N% f/ Q& t2 d- ~' j" N
& M m' j/ ]& z4 vwmiacpi!WmiAcpiSendAsyncDownStreamIrp3 F# @2 ?5 |; o
r) g0 o/ b8 w, j+ r0 Lwmiacpi!WmiSystemControl% U# s8 G4 Z# a9 U+ a
: I) h* f( d- z, ~3 `9 [8 G& S
wmiacpi!WmiAcpiSystemControlDispatch; y# W1 l+ t+ G+ _" R3 V: L
9 _5 J/ _. k( p8 \- A' J% N2 F7 \4 y
acpi!ACPIIoctlEvalControlMethod- O( j" C$ y" K" v7 \4 B
* o2 F; a3 l! Y/ |3 J# pacpi!ACPIIoctlAsyncEvalControlMethod, ?5 T4 }3 z- K" k1 }
; w- K* G. Y+ facpi!ACPIIoctlAsyncEvalControlMethodEx2 G8 I/ P! ]9 g2 u! X+ s
) l' E# K7 c7 y. k3 @$ Yacpi!ACPIIoctlEvalControlMethodEx
3 D) m: D1 H, V; c: a* ?4 T3 ]# K
" }& @/ P6 s8 a9 L, aacpi!ACPIButtonDeviceControl
9 N' h" L2 k( f: C9 k
8 I2 R2 m$ } C, v- u7 tacpi!ACPIEcInternalControl4 P9 F! ^6 C5 b$ q4 b" a7 B
6 B" S! x% d" @1 eacpi!AcpiEmbeddedControllerIrpDispatch
0 j% a! `' a0 O1 `7 e2 N0 n5 R$ G: O
acpi!ACPIIrpDispatchDeviceControl
+ V# @- d5 E. @$ }4 a; h; u/ N
% @" D/ S0 Q$ {- ?9 p* racpi!WmiSystemControl
8 ], X- g+ _* _7 O/ j, Z3 X6 H: W7 k. i) d$ @' a9 k
这些函数都被设置的断点,下面就我们读写一个class试试看了,图7证实了我之前的所说绝非空口无凭,我们读AcpiTest_MPackage class时发现先会call wmiacpi!WmiAcpiQueryWmiDataBlock,然后acpi!ACPIIrpDispatch DeviceControl会接手,当然后续还会有别的一些动作,但是上述行为就足以支撑我的论点了J。
. H: Q% c/ [* r& U
8 J3 T4 M( U6 i- |# q2 w8 ?; D; u( P7 z* ]6 T e
* u& Y; a2 r! U9 n1 K
( t; w4 q. E# `+ w# m图7
8 W. T6 x+ I- B w/ |9 f 图8演示了我们发一个event的状况,图中显示acpi.sys会接到该event然后透过wmiacpi!WmiFireEvent送给上层AP,上层AP再透过IRP下来qurey其它相关的具体信息。
/ K3 a" L! C; B) D* Z9 j
8 p: O" m8 S5 T2 e2 i& s( P2 t- A3 b" V3 ~7 M1 w# f' o% a5 i
& d) D' s l) C, A
图8 + u* e5 s* V* r& ?6 ]4 o1 d4 [
以上就是我费尽九牛二虎之力挖掘的wmiacpi.sys的秘密了,再附上一幅我的debug环境J。
* a3 e- Y3 F8 G+ J) K% q- @6 S
( t/ o7 [6 W6 t0 Q4 m h! i" J+ K
( y$ u# v7 A6 A& Y+ ~
图9
; ]9 X5 A& ]0 b5 K5 tThat’s all!' G8 p+ C" @* G/ |% b- ]
Peter
8 k5 Y, _; R U+ c+ R2 M
6 J6 o9 ^; K* T/ E& Q& A[ 本帖最后由 peterhu 于 2009-5-25 09:31 编辑 ] |
|