📄 windows内核调试器原理浅析.htm
字号:
//--></script><script type="text/javascript">/*<![CDATA[*/var RelatedDocData = null, GetAndEval = false;(function(){ var xhr = BdAjax.getXHR(); if(xhr == null){ RelatedDocData = -1; return; } xhr.open("GET", "/sys/search?type=8&word=Windows%C4%DA%BA%CB%B5%F7%CA%D4%C6%F7%D4%AD%C0%ED%C7%B3%CE%F6%28%D7%AA%D4%D8%29&item=17795518548f29b14bedbc39&t=" + new Date().getTime(), true); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if(xhr.status == 0 || xhr.status == 200){ if(GetAndEval){ eval(xhr.responseText); }else{ RelatedDocData = xhr.responseText; } } } } xhr.send(null);})();/*]]>*/</script></head><body onLoad="formatonlinpic();"><center><script type="text/javascript">
/*<![CDATA[*/
if(top.location != self.location){
top.location = self.location;
}
var myref = encodeURI("http://hi.baidu.com/showgood66/blog/item/17795518548f29b14bedbc39%2Ehtml");
/*]]>*/
</script>
<link rel="stylesheet" type="text/css" href="/ui/css/mods.css" />
<link rel="stylesheet" type="text/css" href="/showgood66/css/item/c81f4d2fe58e56381f30898d.css" />
<link rel="stylesheet" type="text/css" href="/space.css" />
<style type="text/css">
/*<![CDATA[*/
#usrbar{padding:4px 10px 3px 0;font-size:12px;height:19px;line-height:19px;color:#000000;font-family:Arial;text-align:right;background:#ffffff;filter:alpha(opacity=65);-moz-opacity:0.5;width:auto !important;width:100%;letter-spacing:normal}
#usrbar a,#usrbar a:link,#usrbar a:visited{color:#0000CC;text-decoration:underline}
#ft{clear:both;height:20px;line-height:20px;color:#666666;font-size:12px;font-family:Arial;text-align:center}
#ft a,#ft a:link,#ft a:visited{color:#7777CC;text-decoration:underline}
#usrbar,#usrbar a,#usrbar a:link,#usrbar a:visited,#ft,#ft a,#ft a:link,#ft a:visited{letter-spacing:normal}
/*]]>*/
</style>
<div id="usrbar"><nobr>
<a href="http://www.baidu.com/" target="_blank">百度首页</a>
| <a id="hi_index" href="http://hi.baidu.com" target="_blank">百度空间</a>
<script type="text/javascript">
document.write('| <a href="http://passport.baidu.com/?login&tpl=sp&tpl_reg=sp&u=http://hi.baidu.com' + encodeURI('/showgood66/blog/item/17795518548f29b14bedbc39%2Ehtml') + '">登录</a>');
</script>
</nobr></div>
<div id="main" align="left"><!--[if IE]>
<script>
var objmain = document.getElementById("main");
function updatesize(){ var bodyw = window.document.body.offsetWidth; if(bodyw <= 790) objmain.style.width="772px"; else if(bodyw >= 1016) objmain.style.width="996px"; else objmain.style.width="100%"; }
updatesize(); window.onresize = updatesize;
</script>
<![endif]--> <div id="header"> <div class="lc"><div class="rc"></div></div>
<div class="tit"><a href="/showgood66" class="titlink" title="showgood66的空间 http://hi.baidu.com/showgood66">纸上得来终觉浅绝知此事要躬行</a></div>
<div class="desc"></div>
<div id="tabline"> </div> <div id="tab"><a href="/showgood66">主页</a><a href="/showgood66/blog" class="on">博客</a><a href="/showgood66/album">相册</a><span>|</span><a href="/showgood66/profile">个人档案</a> <span>|</span><a href="/showgood66/friend">好友</a> </div></div><div class="stage"><div class="stagepad"><div style="width:100%"> <table width="100%" border="0" cellspacing="0" cellpadding="0" class="modth"> <tr><td class="modtl" width="7"> </td> <td class="modtc" nowrap><div class="modhead"><span class="modtit">查看文章</span></div></td> <td class="modtc" nowrap align="right"></td> <td class="modtr" width="7"> </td> </tr></table><div id="m_blog" class="modbox"><div class="tit">Windows内核调试器原理浅析(转载)</div><div class="date">2008-07-11 09:48</div><table style="table-layout:fixed"><tr><td><div id="blog_text" class="cnt">前段时间忽然对内核调试器实现原来发生了兴趣,于是简单分析了一下当前windows下主流内核调试器原理,并模仿原理自己也写了个极其简单的调试器:)<br><br> WinDBG<br> <br> WinDBG和用户调试器一点很大不同是内核调试器在一台机器上启动,通过串口调试另一个相联系的以Debug方式启动的系统,这个系统可以是虚拟机上的系统,也可以是另一台机器上的系统(这只是微软推荐和实现的方法,其实象SoftICE这类内核调试器可以实现单机调试)。很多人认为主要功能都是在WinDBG里实现,事实上并不是那么一回事,windows已经把内核调试的机制集成进了内核,WinDBG、kd之类的内核调试器要做的仅仅是通过串行发送特定格式数据包来进行联系,比如中断系统、下断点、显示内存数据等等。然后把收到的数据包经过WinDBG处理显示出来。 <br><br> 在进一步介绍WinDBG之前,先介绍两个函数:KdpTrace、KdpStub,我在《windows异常处理流程》一文里简单提过这两个函数。现在再提一下,当异常发生于内核态下,会调用KiDebugRoutine两次,异常发生于用户态下,会调用KiDebugRoutine一次,而且第一次调用都是刚开始处理异常的时候。<br><br> 当WinDBG未被加载时KiDebugRoutine为KdpStub,处理也很简单,主要是对由int 0x2d引起的异常如DbgPrint、DbgPrompt、加载卸载SYMBOLS(关于int 0x2d引起的异常将在后面详细介绍)等,把Context.Eip加1,跳过int 0x2d后面跟着的int 0x3指令。<br><br> 真正实现了WinDBG功能的函数是KdpTrap,它负责处理所有STATUS_BREAKPOINT和 STATUS_SINGLE_STEP(单步)异常。STATUS_BREAKPOINT的异常包括int 0x3、DbgPrint、DbgPrompt、加载卸载SYMBOLS。DbgPrint的处理最简单,KdpTrap直接向调试器发含有字符串的包。 DbgPrompt因为是要输出并接收字符串,所以先将含有字符串的包发送出去,再陷入循环等待接收来自调试器的含有回复字符串的包。SYMBOLS的加载和卸载通过调用KdpReportSymbolsStateChange,int 0x3断点异常和int 0x1单步异常(这两个异常基本上是内核调试器处理得最多的异常)通过调用KdpReportExceptionStateChange,这两个函数很相似,都是通过调用KdpSendWaitContinue函数。KdpSendWaitContinue可以说是内核调试器功能的大管家,负责各个功能的分派。这个函数向内核调试器发送要发送的信息,比如当前所有寄存器状态,每次单步后我们都可以发现寄存器的信息被更新,就是内核调试器接受它发出的包含最新机器状态的包;还有SYMBOLS的状态,这样加载和卸载了SYMBOLS我们都能在内核调试器里看到相应的反应。然后 KdpSendWaitContinue等待从内核调试器发来的包含命令的包,决定下一步该干什么。让我们来看看KdpSendWaitContinue 都能干些什么:<br><br> case DbgKdReadVirtualMemoryApi:<br> KdpReadVirtualMemory(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdReadVirtualMemory64Api:<br> KdpReadVirtualMemory64(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdWriteVirtualMemoryApi:<br> KdpWriteVirtualMemory(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdWriteVirtualMemory64Api:<br> KdpWriteVirtualMemory64(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdReadPhysicalMemoryApi:<br> KdpReadPhysicalMemory(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdWritePhysicalMemoryApi:<br> KdpWritePhysicalMemory(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdGetContextApi:<br> KdpGetContext(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdSetContextApi:<br> KdpSetContext(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdWriteBreakPointApi:<br> KdpWriteBreakpoint(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdRestoreBreakPointApi:<br> KdpRestoreBreakpoin(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdReadControlSpaceApi:<br> KdpReadControlSpace(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdWriteControlSpaceApi:<br> KdpWriteControlSpace(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdReadIoSpaceApi:<br> KdpReadIoSpace(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdWriteIoSpaceApi:<br> KdpWriteIoSpace(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdContinueApi:<br> if (NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus) != FALSE) {<br> return ContinueSuccess;<br> } else {<br> return ContinueError;<br> }<br> break;<br><br> case DbgKdContinueApi2:<br> if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus) != FALSE) {<br> KdpGetStateChange(&ManipulateState,ContextRecord);<br> return ContinueSuccess;<br> } else {<br> return ContinueError;<br> }<br> break;<br><br> case DbgKdRebootApi:<br> KdpReboot();<br> break;<br><br> case DbgKdReadMachineSpecificRegister:<br> KdpReadMachineSpecificRegister(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdWriteMachineSpecificRegister:<br> KdpWriteMachineSpecificRegister(&ManipulateState,&MessageData,ContextRecord);<br> break;<br><br> case DbgKdSetSpecialCallApi:<br> KdSetSpecialCall(&ManipulateState,ContextRecord);<br> break;<br><br> case DbgKdClearSpecialCallsApi:<br> KdClearSpecialCalls();<br> break;<br><br> case DbgKdSetInternalBreakPointApi:<br> KdSetInternalBreakpoint(&ManipulateState);<br> break;<br><br> case DbgKdGetInternalBreakPointApi:<br> KdGetInternalBreakpoint(&ManipulateState);<br> break;<br><br> case DbgKdGetVersionApi:<br> KdpGetVersion(&ManipulateState);<br> break;<br><br> case DbgKdCauseBugCheckApi:<br> KdpCauseBugCheck(&ManipulateState);<br> break;<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -