-
-
[转帖]CpuWhere
-
发表于:
2008-9-11 10:38
5963
-
CpuWhere
IA-32 CPU从P6开始便支持分支监视和记录机制。说白了这种机制就是记录下CPU曾经执行的分支。把这些分支信息串联起来便可以得到CPU的执行轨迹。这一机制的名称被称为BTS,Branch Tracing Store,它与Debug Store,简称DS有着紧密关系。
以下是使用BTS机制所编写的一个示例程序CpuWhere的工作画面。
窗口左侧是一系列控制按钮,编辑框用来指定BTS缓冲区可以容纳的BTS记录数,也就是SetupDSArea函数的参数。窗口右侧的列表框用来显示从驱动程序读取到的BTS记录。显示的顺序与栈回溯类似,最近发生的在上方。或者说,CPU的运行轨迹是从下到上。
在列表框中,每条BTS记录显示为两行,上面一行用来显示分支的目标地址(方括号中),地址前以>符号表示,地址后为这个地址所对应的符号;下面一行为分支的发起地址,地址前以<表示,大括号中是本条BTS记录的标志字段(dwFlags)。每一行的开头是以#开始的流水号。
以图中的第2行为例,#00004365 - [<0x80526bed]: nt!PsGetCurrentProcessId + d {flags 0x0}。其中,地址前的小于号代表这是一个BTS记录的发起行,0x80526bed是BtsRecord中的dwFrom字段的值,nt!PsGetCurrentProcessId + d是这个地址所对应的符号和位移(displacement)。
观察nt!PsGetCurrentProcessId函数的反汇编,可以看到地址0x80526bed是ret指令的下一条指令的地址,因此,CPU是在执行ret指令时产生这条BTS记录的。
lkd> u nt!PsGetCurrentProcessId
nt!PsGetCurrentProcessId:
80526be0 64a124010000 mov eax,dword ptr fs:[00000124h]
80526be6 8b80ec010000 mov eax,dword ptr [eax+1ECh]
80526bec c3 ret
80526bed cc int 3
观察第一行(#00004365 - [>0xbf801a73]: win32k!HmgLock + 2e),它是这个BTS记录的目标地址,于是,可以推测出这个BTS记录的记载的是从PsGetCurrentProcessId函数返回HmgLock这一事件。#00004365记载的是HmgLock函数调用PsGetCurrentProcessId时的分支。
在图中所示的列表框的下方,记录了调用系统服务时从用户态向内核态的转移过程。#00004365记载了是从用户态(#00004376 - [<0x7c90eb8f]: ntdll!KiFastSystemCallRet + 0 {flag 0x0})跳转到内核态(#00004376 - [>0x8053cad0]: nt!KiFastCallEntry + 0)的起始(0x7c90eb8f)和目标地址(0x8053cad0)。
CpuWhere.exe的大多数实现都是非常简单的。比较复杂的地方就是如何查找BTS记录所对应的符号。因为BTS记录中的地址有内核态的地址,也有用户态的地址,简单的使用DbgHelp库中的符号函数(SymFromAddr等)是不能满足我们的需要的。
实际上,这里使用的方法是使用WinDBG的调试引擎。通过调试引擎所输出的接口,我们启动了一个本地内核调试会话。然后调用调试引擎的服务来查找符号。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课