第一部分:知识点
三种异常类型比较:错误异常、陷阱异常、中止异常
错误异常中断完成后,会回到错误的指令,继续执行它(例如:页错误,虚拟内存原理);
陷阱异常中断完成后,会回到错误指令的下一条,继续执行(例如:断点调试的原理);
中止异常,直接导致软件中止运行。
进程启动时最先加载的是EXE和NTDLL.DLL
NTDLL.DLL:是沟通用户空间和内核空间的桥梁,用户空间的代码通过这个DLL调用内核空间系统服务。它也是操作系统内核中用户模式下的代理,系统会在启动阶段把它加载到内存中,并把它映射到所有用户进程空间中的相同位置(虚拟地址)。当内核需要调用用户空间配合时,会使用这个DLL,因为只有这个DLL才存在于每个用户进程的用户空间固定位置上。
PEB和TEB
PEB:进程环境块,包含进程的大多数用户态信息(例如:执行映像(exe)基地址、进程堆)
TEB:线程的环境,包括栈边界等信息(可以通过!teb查看当前线程的TEB)
堆的释放:
堆管理器只有在以下两个条件都满足时才会立即释放堆内存:
(1)本次释放的堆块大小超过堆参数中设定的阈值
(2)累积起来的空闲堆空间超过堆参数中设定的阈值
否则,堆管理器会将这个堆块加入空闲列表,下次需要申请堆时先从空闲列表里面找到满足条件的堆,然后交给使用者。(这也是引起内存碎片的原因,因为空闲堆比申请的大小要大,于是留下一部分剩余,这部分剩余就成为内存碎片)
关于栈:
栈回溯信息:函数名后面+0x...,该地址就是函数起始地址和下一层函数返回地址之间的偏量
栈空间溢出:栈空间末尾有保护页面,访问该页面会触发异常;每个函数栈帧附近有安全Cookie,位于局部变量和栈帧指针之间,一旦Cookie被破坏说明函数内部有栈溢出。
手动生成Dump文件:
执行命令.dump c:\xx.dmp,可以生成一个mini dump,想生成full dump,就在文件名前面加上/f选项
第二部分:Windbg常用的指令
a命令:汇编
u命令:反汇编
b命令:设置软件断点
d命令:显示内存(dd:双字;df:浮点数;dv:局部变量;ds:字符串;dt:显示数据类型;)
k命令:栈回溯
lm:显示已经加载的模块信息
ln:查看地址附近的函数(例如:ln 0x...:显示内存地址附近的符号;ln eip:显示eip寄存器附近的符号)
| :显示和切换进程
~ :显示和切换线程
x:检查符号 (例如:x ntdll!dbg* 可以查看ntdll中所有以dbg开头的符号)
!:扩展命令
!handle:显示句柄
!address:显示内存的属性
!analyze -v:自动分析dump文件
!sym noisy:一般用在reload符号文件的时候,方便查看更多的信息
文件名!符号名 (例如:nt!PsGetCurrentProcessId,显示文件中某个符号)
!process 0 0 : 列出所有进程,只能在内核调试时使用
!process、!thread:显示进程、线程信息(例如:!process 0x987656,能够显示PDB等信息)
!teb:查看当前线程的TEB信息(通过teb结构可以看到栈等内存区域的边界,从而判断是否有越界)
!heap: 查看当前进程所有堆
.:元命令
.format:把指定的地址转换成二进制、十进制、16进制表示
.thread、.process:显示当前进程、线程的信息
.kill:杀死某个线程
.ecxr:显示异常信息,将转储文件的上下文设置到寄存器中
.frame:切换当前的栈帧,并查看栈帧相关信息
.reload:重新加载符号文件 /i 开关用来加载不完全匹配的符号文件,有时候找不到完全匹配的,而改动不大的时候可以用。
.detach: 分离调试目标