-
-
调试器原理分析
-
发表于: 2020-9-24 12:51 3685
-
记录一下自己的学习历程
启动windbg(A实例)和windbg(B实例),将windbg(B)附加到windbg(A)上,在windbg(B)上执行命令bp ntdll!NtDebugContinue ".printf\"continue=%p\",poi(@esp+c);.echo n;g"命令打印出windbg(A)返回给系统的调试信息,返回给系统的值有DBG_EXCEPTION_NOT_HANDLED(0x80010001)
DBG_CONTINUE(0x00010002)
DBG_EXCEPTION_HANDLED(0x00010001)
windbg(B)再执行bp ntdll!NtWaitForDebugEvent "$$><D:/windbgcmd/bp32.txt",记录收到的异常,此时操作Windbg(A),打开程序test.exe,test代码如下
long WINAPI FilterFunc(DWORD dwExceptionCode)
{
printf("3333\n");
OutputDebugStringA("FilterFunc");
return (dwExceptionCode ==
STATUS_INTEGER_DIVIDE_BY_ZERO+1) ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
}
int a = 10;
int _tmain(int argc, _TCHAR argv[])
{
__try
{
printf("11111\n");
getchar();
printf("2222\n");
int b = (int*)a;
}
__except (FilterFunc(GetExceptionCode()))
{
a = 11;
}
return 0;
}
运行程序命令行窗口输入一个字符,脚本中判断了调试器收到异常事件类型为EXCEPTION_DEBUG_EVENT断到调试器B,断点位置为调用NtWaitForDebugEvent 指令的下一条指令,此时windbg(B)首先收到异常并打印系统发过来的第一次异常,使用dd $t3可以查看异常的信息
exception=00000000eax=00000000 ebx=06a97228 ecx=77720000 edx=00000000 esi=77033ad0 edi=0c88f560
eip=7935e511 esp=0c88f490 ebp=0c88f514 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
dbgeng!Ordinal332+0x261881:
7935e511 8bf0 mov esi,eax
0:010> dd $t3
0c88f4a8 00000006 000033f8 00006744 c0000005
0c88f4b8 00000000 00000000 00685551 00000002
0c88f4c8 00000000 0000000a 00000000 00000000
0c88f4d8 00000000 00000000 00000000 00000000
0c88f4e8 00000000 00000000 00000000 00000000
0c88f4f8 00000000 00000000 00000000 00000001
0c88f508 00770000 c0fe6e2e 00000000 0c88f678
0c88f518 7917fea9 06a97228 000003e8 0c88f560
00000006 是调试事件类型,6为异常事件
000033f8 是进程ID
00006744 是线程ID
C0000005是程序的异常
00685551是异常地址
....
查看Windbg(A)可以看到程序断到了00685551地址int b = (int)a;
windbg(A)使用G命令让test程序继续运行,windbg(B)打印了g命令之后调用NtDebugContinue返回给系统的数据是0x00010001,说明第一次异常调试器会返回给系统DBG_EXCEPTION_NOT_HANDLED,告诉系统异常未处理
此时windbg(B)会收到两条异常,第一条异常如下:
eip=7935e511 esp=0e36fb20 ebp=0e36fba4 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
dbgeng!Ordinal332+0x261881:
7935e511 8bf0 mov esi,eax
0:021> dd $t3
0e36fb38 00000006 00006694 0000645c 40010006
0e36fb48 00000000 00000000 75f544c2 00000002
0e36fb58 0000000b 0041ca5c 00000000 00000000
0e36fb68 00000000 00000000 00000000 00000000
0e36fb78 00000000 00000000 00000000 00000000
0e36fb88 00000000 00000000 00000000 00000001
0e36fb98 00770000 c240619e 00000000 0e36fd08
0e36fba8 7917fea9 0e8f7ab0 000003e8 0e36fbf0
75f544c2 是异常地址,调试器A使用U 75f544c2查看是软件异常函数RaiseException
0:000> u 75f544c2
KERNELBASE!RaiseException+0x62:
40010006表示是一个消息输出异常
分析程序得出40010006是OutputDebugStringA产生的一个异常
第二条异常也是一个C0000005异常
eip=7935e511 esp=0c88f490 ebp=0c88f514 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
dbgeng!Ordinal332+0x261881:
7935e511 8bf0 mov esi,eax
0:010> dd $t3
0c88f4a8 00000006 000033f8 00006744 c0000005
0c88f4b8 00000000 00000000 00685551 00000002
0c88f4c8 00000000 0000000a 00000000 00000000
0c88f4d8 00000000 00000000 00000000 00000000
0c88f4e8 00000000 00000000 00000000 00000000
0c88f4f8 00000000 00000000 00000000 00000000
0c88f508 00770000 c0fe6e2e 00000000 0c88f678
0c88f518 7917fea9 06a97228 000003e8 0c88f560
和第一以收到的异常一样
windbg打印了NtDebugContinue返回给调试器的数据是0x00010002,说明第二次异常调试器会返回给系统DBG_CONTINUE,告诉系统异常已经处理,此时会重新执行异常的函数int b = (int)a;
bp32.txt文件
r $t0 = poi(@esp+4)
r $t1 = poi(@esp+8)
r $t2 = poi(@esp+c)
r $t3 = poi(@esp+10)
bp poi(@esp) "$$><d:/windbgcmd/prt32.txt"
g
prt32.txt文件
$$t0是第一个参数
$$t1是第二个参数
$$t2是第三个参数
$$t3是第四个参数
bc 2
.echo n;
.if(poi($t3)=6)
{
.printf"exception=%p",poi($t3+28)
}
.else
{
g
}
赞赏
- [原创]windows堆内存管理及调试技巧 15100
- [原创]cpu任务段任务门 15470
- [原创]关于X64程序中RUNTIME_FUNCTION,UNWIND_INFO,UNWIND_CODE结构理解 6743
- 调试器原理分析 3686