下面的信息是使用Windbg准备启动一个进程之前,Windbg输出的信息,下面我用红色字体来解释输出里面的重要信息。
Windbg信息 |
# Windbg的版本号,还有一个重要的信息是最后的x86字样,因为它告诉你他是一个32位 # 的调试器,所以不能调试64位的程序。然而64位的Windbg可以调试32位和64位的用 # 户模式下面的进程 Microsoft (R) Windows Debugger Version 6.10.0003.233 X86 Copyright (c) Microsoft Corporation. All rights reserved. # 显示命令行输入和参数,这里你可以验证你在使用Windbg的时候,被调试进程的参数是 # 否正确。 CommandLine: "C:/Documents and Settings/Administrator/桌面/我的征途/我的征途/MyLegend/Debug/MyLegend.exe" # 显示当前Windbg的符号文件加载设置,下面的符号文件说明我们在采用微软的公开符号 # 文件服务器,两个星号之间的D:/symbols是本地符号文件缓存文件夹的路径。 Symbol search path is: SRV*D:/symbols*http://msdl.microsoft.com/download/symbols # .exe、.dll和.sys后缀名的文件都叫做可执行文件(executable file),Executable search path # 是指调试器在加载进程所需的可执行文件时候,用来查找这些文件的路径,一般的情况下 # 调试器知道如何找到进程所需的可执行文件,因此你不需要去设置这个变量。但是如果你 # 是在调试用户模式的minidump文件,由于这种dump文件没有保存程序的信息,例如进 # 程的程序指令,没有这些指令,你甚至连堆栈(call stack)都不能打印出来,因此你需要 # 指定这个路径,让Windbg在分析minidump可以找到可执行文件并且执行相关的操作。
# 你可以通过Windbg的-i选项、或者.exepath命令,或者设置_NT_EXECUTABLE_IMAGE_PATH # 来设置可执行文件搜索路径 Executable search path is: # 列出进程MyLegend加载进内存中的依赖项,Windows操作系统采取延迟加载可执行文件 # 依赖项的方法,用来加快进程加载的速度。就是说Windows只在第一次用到该依赖项的 # 时候才加载相应的可执行文件到内存里面来。
# 另外,你可能会好奇,有些DLL是所有Windows程序都依赖的,例如ntdll.dll和kernel32.dll, # 为什么Windows不只在内存里面保留一份这些通用dll的备份呢?实际上,Windows在加 # 载一个程序的时候,是会将通用的DLL加载进进程的地址空间里面去的。但是这样不是会 # 造成内存浪费了吗? # 不会的 # 32位Windows之后,所有的进程访问到的都是虚拟内存,从进程的角度来看,它可以访 # 问到所有4G的内存,即0x00000000到0xFFFFFFFF都可以访问到。别急,操作系统会在 # 程序访问每个虚拟地址的时候将该地址转换或者说映射到物理内存地址。因此操作系统完 # 全可以在物理内存中只加载一份DLL备份,然后将所有进程的加载该DLL 的地址(虚拟 # 内存地址)映射到那唯一一份DLL备份加载的物理内存地址上。 # 这是所有的故事吗? # 当然不是 # 因为DLL除了包含可以被其他程序调用的代码以外,还定义了很多的全局变量,这些全局 # 变量如果只有一个备份的话,那么所有使用这个DLL的进程岂不是会乱套。这就是为什么 # 我们的Windows可执行文件是有固定的格式的,这个格式将可执行文件中的代码和数据 # 分离开了,比如说代码就放在一个.text的段(section)里面,而数据就放在其他段里面, # 这样Windows可以通过虚拟地址映射功能将代码和数据做分别的处理。 # 为了简便可执行文件操作,每一个可执行文件都指定了它希望加载到内存中的位置—不要 # 忘记我们的进程可以访问到整个4G的地址空间,这就是下面第二列数字的意思(可执行 # 文件加载进内存的起始地址),第三列就是可执行文件在内存中的结束地址。当然会有两 # 个不同的DLL指定相同的首地址,这种情况下Windows会做其他相应的处理—这是我后 # 面将要讲到的技术。 ModLoad: 00400000 004a6000 MyLegend.exe ModLoad: 7c930000 7ca00000 ntdll.dll ModLoad: 7c800000 7c92b000 C:/WINDOWS/system32/kernel32.dll ModLoad: 77e10000 77ea0000 C:/WINDOWS/system32/USER32.dll ModLoad: 77bd0000 77c19000 C:/WINDOWS/system32/GDI32.dll ModLoad: 77f30000 77fdb000 C:/WINDOWS/system32/ADVAPI32.dll ModLoad: 77c20000 77cbf000 C:/WINDOWS/system32/RPCRT4.dll ModLoad: 76eb0000 76ec3000 C:/WINDOWS/system32/Secur32.dll # 这里Windbg列出了进程被中断执行的原因,下面说明了程序被中断的原因是因为碰到断 # 点了,断点的异常代码是80000003,这个代码和后面的first chance将会在后面的SHE里 # 面讲到。 (b28.b2c): Break instruction exception - code 80000003 (first chance) # 列出了当前CPU各个寄存器的值 eax=76f00000 ebx=7ffd5000 ecx=00000006 edx=00000040 esi=7c9b77f4 edi=0062d080 eip=7c94a3e1 esp=0012fb70 ebp=0012fcb4 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 # 进程中断时,当前线程正在执行的函数名,感叹号前面是函数所在的可执行文件名称,后# 面就是函数名啦,这里我们可以看出,Windows使用DbgBreakPoint函数在进程里面设置 # 断点。 ntdll!DbgBreakPoint: # 进程中断时,当前正在执行的程序指令,第一列是程序指令在内存中的地址,第二列是程 # 序指令的二进制表现形式,而后面的则是程序指令的反汇编。INT 3是Intel兼容的CPU中 # 断程序执行的特殊指令,实际上在Intel兼容的CPU上,所有的断点都是用下面这个指令 # 实现的。 7c94a3e1 cc int 3 |