Vista UAC 环境下如何早期加载调试器

来源:互联网 发布:文件读入列表 python 编辑:程序博客网 时间:2024/05/16 09:45

Vista UAC 环境下如何早期加载调试器

Vista UAC 环境下如何早期加载调试器
 
Vista UAC环境给调试带来些麻烦。不过要是问题太简单,怎么来快感阿
 
调试程序有两种加载调试器的方法。首先可以用调试器启动目标进程,在VS中摁F5就是这样。另外一种方法是用调试器加载到已有进程上,Windbg中摁F6,VS中选择Attach Process就是这种方法。
 
对于某些问题的调试,必须要让调试器尽早加载。比如:
 
1. 调试DLL的加载过程。如果等程序启动完毕再上调试器,DLL已经加载完毕,或者程序已经由于DLL加载错误退出了。
2. 设定断点。比如要在Main函数入口设断点。如果让程序开始运行后再上调试器,Main函数入口已经过了。
 
早期启动调试器一般有三种方法:
 
1. 用调试器直接启动进程
2. 使用File Execution Options注册表指定目标程序的默认调试器。目标进程启动的时候调试器会自动加载
3. 在目标进程启动以前,用调试器监视其父进程。用windbg的.childDBG命令监视并调试其子进程
 
Vista以前的环境中,上面的方法工作良好。但是Vista引入了UAC。如果需要调试的进在meataData里面说明了需要管理员权限,系统UAC激活的话,上面的方法就行不通了。
 
首先要弄明白UAC权限提升的流程。下面这篇文章说得很清楚:
http://www.codeproject.com/useritems/UAC__The_Definitive_Guide.asp?msg=2281654
 
不需要UAC权限提升的进程,启动流程跟原来一样,没有什么特别的。但是需要UAC权限提升的进程,在Vista上使用CreateProcess API无法创建出进程了。Vista使用新的Windows服务AppInfo来管理权限提升和进程创建。
 
如果目标进程需要权限提升,父进程不应该调用CreateProcess,而是应该使用ShellExecute类的API。ShellExecute的实现中,会跟AppInfo服务通信,让AppInfo做下面两件事情:

1. 弹出个框框让你确认权限提升,或者输入用户名
2. 得到确认后,用高权限方式启动目标进程
 
明白上面的流程后,就很容易理解为何以前的调试器加载方法现在行不通了
 
1. 如果在windbg中直接启动进程,windbg会使用CreateProcess。按照前面说的,进程都启不来,自然无法调试了。就算windbg用ShellExecute启动,那父进程是AppInfo服务,而不是windbg,windbg也无法监视进程的启动
2. File Execution Options注册表其实就是让调试器去启动目标进程的一个捷径。道理同上。
3. 由于父进程不是所监视的程序,而是AppInfo服务,所以用调试器监视父进程的办法也行不通了。
那具体该怎么弄了?其实问题的关键在于父进程角色的变化。既然真正启动进程的是AppInfo服务,那就在AppInfo上面下功夫了。

调试开始前,首先用Run as Administrator的方法启动一个cmd,凡是调试工具,比如windbg什么的,都在这里启动。否则没有足够的权限
 
AppInfo是运行在svchost.exe中的一个服务。系统中有很多svchost.exe进程,第一步自然是区分出哪一个svchost是AppInfo的宿主。在Debuggers目录中用tlist -v命令查看,很容易找出AppInfo的宿主


 
接下来就用windbg attach到宿主svchost了。输入下面的命令:
 
0:042> .childdbg 1
Processes created by the current process will be debugged
这个命令表示让windbg监视该svchost的所有子进程,同时自动调试其子进程。
接下来就g,然后去启动目标进程吧。双击目标进程后(mmc.exe),这边的windbg停下来了,看到:

0:042> g
ModLoad: 05d90000 05f48000   mmc.exe
ModLoad: 05d90000 05f48000   mmc.exe
ModLoad: 72720000 72731000   c:/windows/system32/mmcss.dll
ModLoad: 736f0000 736f7000   c:/windows/system32/AVRT.dll
ModLoad: 060b0000 06268000   mmc.exe
ModLoad: 73400000 7340e000   c:/windows/system32/sens.dll
Executable search path is:
DBGHELP: SharedUserData - virtual symbol module
ModLoad: 00800000 00817000   consent.exe
eax=0080314f ebx=7ffdd000 ecx=00000000 edx=00000000 esi=00000000 edi=00000000
eip=76f28348 esp=0014fda4 ebp=00000000 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000200
76f28348 89442404        mov     dword ptr [esp+4],eax ss:0023:0014fda8=00000000

1:049>
注意看,这里的windbg提示符从0:042变为了1:049。这前面的1,表示目标进程已经不是svhost了。查看一下:
 
1:049> |
   0 id: 9cc attach name: C:/Windows/system32/svchost.exe
.  1 id: 790 child name: consent.exe
 
这里的|命令用来查看当前被调试的进程立标。一个自然是svchost.exe,另外一个就是刚刚启动的子进程了,叫做consent.exe。
这里怎么不是mmc.exe呢?如果你仔细看了前面的链接,你就会知道consent.exe是用来提示你点确定,输入密码的UI进程。


接下来自然是g了.然后就可以看到让你输入用户名的UI弹出来了。这里输入密码后点确定。点了确定了,windbg又停下来了:
 
(790.248): Unknown exception - code 0000071a (first chance)
eax=0014fb20 ebx=00000000 ecx=00000004 edx=00000000 esi=00000001 edi=000e1b68
eip=76f28364 esp=0014fc3c ebp=0014fc4c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!KiFastSystemCallRet:
76f28364 c3              ret
 
看看是不是MMC起来了?
 
1:049> |
   0 id: 9cc attach name: C:/Windows/system32/svchost.exe
.  1 id: 790 exited name: consent.exe
 
1:049> kL
ChildEBP RetAddr 
0014fc38 76f27a1c ntdll!KiFastSystemCallRet
0014fc3c 76eff96a ntdll!ZwTerminateProcess+0xc
0014fc4c 77077f47 ntdll!RtlExitUserProcess+0x7a
0014fc60 76b72a2d kernel32!ExitProcess+0x12
0014fc60 76b72a2d msvcrt!__crtExitProcess+0x17
0014fc6c 76b72977 msvcrt!__crtExitProcess+0x17
0014fca4 76b72a0c msvcrt!doexit+0xac
0014fcb8 00801eae msvcrt!exit+0x11
0014fd3c 77091cc2 consent!__mainCRTStartup+0x154
0014fd48 76f08785 kernel32!BaseThreadInitThunk+0xe
0014fd88 76f08758 ntdll!__RtlUserThreadStart+0x23
0014fda0 00000000 ntdll!_RtlUserThreadStart+0x1b
 
原来不是MMC起来了,而是consent.exe的退出事件。那就继续g:

1:049> g
ModLoad: 009e0000 00b98000   mmc.exe
eax=00a3ea2f ebx=7ffdf000 ecx=00000000 edx=00000000 esi=00000000 edi=00000000
eip=76f28348 esp=0010fc10 ebp=00000000 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000200
76f28348 89442404        mov     dword ptr [esp+4],eax ss:0023:0010fc14=00000000
 
哈哈!这下次抓到mmc.exe了,看看:
 
1:028> |
   0 id: 9cc attach name: C:/Windows/system32/svchost.exe
.  1 id: dc0 child name: mmc.exe

1:028> lmf
start    end        module name
009e0000 00b98000   mmc      mmc.exe 
 
成功了!这样我们就在mmc.exe启动的最开始阶段把它给断下来了。接下来69 3p爱怎么玩就怎么玩了

当然,有的同学肯定还是觉得在一个windbg中调试两个进程不爽。这个很简单的,直接切换到svchost,然后detach就可以只留下mmc

1:028> |0s
eax=767eaafb ebx=00000000 ecx=00000000 edx=00000000 esi=00000000 edi=00007530
eip=76f28364 esp=030efbcc ebp=030efbf8 iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000297
ntdll!KiFastSystemCallRet:
76f28364 c3              ret
0:023> .detach
eax=00a3ea2f ebx=7ffdf000 ecx=00000000 edx=00000000 esi=00000000 edi=00000000
eip=76f28348 esp=0010fc10 ebp=00000000 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000200
76f28348 89442404        mov     dword ptr [esp+4],eax ss:0023:0010fc14=00000000
Detached
1:028> |
.  1 id: dc0 child name: mmc.exe
 
这样就只剩下一个mmc.exe了
如果有同学觉得还是启动一个单独的windbg来调试,那办法也很多的。比如可以首先用~n命令把mmc的主线程挂起来,然后detach,然后再启动一个新的windbg去attach MMC,然后再用~m命令恢复MMC的执行。
 
http://eparg.spaces.live.com/blog/cns!59BFC22C0E7E1A76!2694.entry
  
原创粉丝点击