找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3730|回复: 2

windows用户态调试学习(一)

[复制链接]
发表于 2015-7-6 00:02:30 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
本帖最后由 元始天尊 于 2015-7-6 00:47 编辑

windows用户态调试学习
一 基础知识
msdn上的介绍:https://msdn.microsoft.com/en-us/library/ms679304(v=vs.85).aspx
》调试事件及调试结构

调试事件:
WaitForDebugEvent在接收到内核传递的调试信息后会由阻塞态转为激活态,内核会挂起所有线程,直到ContinueDebugEvent执行
CREATE_PROCESS_DEBUG_EVENT 创建进程事件 CREATE_PROCESS_DEBUG_INFO
CREATE_THREAD_DEBUG_EVENT 创建线程事件 CREATE_THREAD_DEBUG_INFO
EXCEPTION_DEBUG_EVENT 发生异常 EXCEPTION_DEBUG_INFO
EXIT_PROCESS_DEBUG_EVENT 进程退出 EXIT_PROCESS_DEBUG_INFO
EXIT_THREAD_DEBUG_EVENT 线程退出 EXIT_THREAD_DEBUG_INFO
LOAD_DLL_DEBUG_EVENT 加载DLL LOAD_DLL_DEBUG_INFO
OUTPUT_DEBUG_STRING_EVENT 输出调试字符串 OUTPUT_DEBUG_STRING_INFO
UNLOAD_DLL_DEBUG_EVENT 卸载DLL UNLOAD_DLL_DEBUG_INFO
RIP_EVENT 进程不受系统调试器控制的结束 RIP_INFO

调试结构:
CONTEXT :ring3下不能直接读写寄存器,而间接通过设置context结构完成
DEBUG_EVENT:接受的调试事件结构
LDT_ENTRY:用于获得描述符表

》调试函数
CheckRemoteDebuggerPresent  检查debug port是否存在
ContinueDebugEvent  继续执行由调试事件打断的线程.
DebugActiveProcess  附加调试
DebugActiveProcessStop  停止附加调试
DebugBreak  在当前进程中产生断点
DebugBreakProcess  在指定进程中产生断点(远程线程注入)
DebugSetProcessKillOnExit  调试器退出时结束进程
FatalExit  退出进程并将执行权交给调试器
FlushInstructionCache  刷新指令缓存(在修改内存指令后使用)
GetThreadContext  获取线程上下文
GetThreadSelectorEntry  获取线程的选择子的描述符表
IsDebuggerPresent  用调试标志检查用户态调试器是否存在
OutputDebugString  输出调试信息给调试器
SetThreadContext  设置线程上下文
WaitForDebugEvent  等待调试事件

二 用户态调试模型及相关代码
windows用户态调试器是基于事件模式的,由内核做中介的被调试进程和调试器进程的交互,也就是说被调试者和调试器处于不同进程(见《软件调试》),流程如下:
void main()
{
        (OpenProcess);
        DebugActiveProcess;
        while(Alive)
        {
                WaitForDebugEvent;
                switch(DebugEvent.dwDebugEventCode)
                {
                        ....
       
                }
                ContinueDebugEvent;
        }
}

无疑这里最重要的函数就是DebugActiveProcess和ContinueDebugEvent,是调试器最表层的接口,而调试器源码位于ntos/dbgk文件夹下,
dbgkobj.c dbgkp.h dbgkport.c dbgkproc.c

DebugActiveProcess->NtDebugActiveProcess->DbgkpPostFakeProcessCreateMessages DbgkpSetProcessDebugObject
ContinueDebugEvent->NtDebugContinue->DbgkpWakeTarget->DbgkpFreeDebugEvent

DbgkpPostFakeProcessCreateMessages->DbgkpPostFakeThreadMessages DbgkpPostFakeModuleMessages


DbgkpSendApiMessage 调试消息函数,在某些内核api操作中会将调试事件添加到队列中
DbgkpSuspendProcess 挂起进程
DbgkpResumeProcess 恢复线程

未完待续。。。。。。。。


    默认下windows只能支持一个调试器,绑定到进程peb的debugport成员中,由于内核代码已经写死了,因此想支持多个调试器同时调试一个进程,只能另寻办法,我的构想是将调试器和内核之间的通信,中间插入一个中介调试器进行协调,同时一个调试器的行为生效则刷新到所有调试器,这样就需要中介调试器hook一些调试api,并完成和这些调试器的通信,而中介调试器直接接收内核发出的调试信息。正在深入研究调试源码并完善设计思路。
回复

使用道具 举报

 楼主| 发表于 2015-7-6 22:51:38 | 显示全部楼层

  1. //DbgSsReserved[0]->PDBGSS_THREAD_DATA*
  2. //DbgSsReserved[1]->DebugObjectHandle
  3. BOOL WINAPI ContinueDebugEvent(DWORD dwProcessId, DWORD dwThreadId, DWORD dwContinueStatus)
  4. {
  5.         ClientId.UniqueProcess = (HANDLE)dwProcessId;
  6.         ClientId.UniqueThread = (HANDLE)dwThreadId;
  7.         ZwDebugContinue(NtCurrentTeb()->DbgSsReserved[1], ClientId, dwContinueStatus);
  8.         //移除进程线程句柄
  9.         ThreadData = (PDBGSS_THREAD_DATA*)NtCurrentTeb()->DbgSsReserved;
  10.         ThisData = *ThreadData;
  11.         while(ThisData)
  12.         {
  13.                 if ((ThisData->HandleMarked) && ((ThisData->ProcessId == dwProcessId) || (ThisData->ThreadId == dwThreadId)))
  14.                 {
  15.                         if (ThisData->ThreadHandle) CloseHandle(ThisData->ThreadHandle);
  16.                         if (ThisData->ProcessHandle) CloseHandle(ThisData->ProcessHandle);
  17.                         *ThreadData = ThisData->Next;
  18.                         RtlFreeHeap(RtlGetProcessHeap(), 0, ThisData);
  19.                 }
  20.                 else
  21.                 {
  22.                         ThreadData = &ThisData->Next;
  23.                 }
  24.                 ThisData = *ThreadData;
  25.         }
  26. }

  27. BOOL WINAPI DebugActiveProcess(DWORD dwProcessId)
  28. {
  29.         //创建调试对象
  30.         InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, 0);
  31.         Status = ZwCreateDebugObject(&NtCurrentTeb()->DbgSsReserved[1], DEBUG_OBJECT_ALL_ACCESS, &ObjectAttributes, DBGK_KILL_PROCESS_ON_EXIT);
  32.         //OpenProcess获取进程句柄
  33.         ClientId.UniqueThread = NULL;
  34.         ClientId.UniqueProcess = UlongToHandle(dwProcessId);
  35.         InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
  36.         Status = NtOpenProcess(&Handle, PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ
  37.                 | PROCESS_SUSPEND_RESUME | PROCESS_QUERY_INFORMATION, &ObjectAttributes, &ClientId);
  38.         Status = NtDebugActiveProcess(Process, NtCurrentTeb()->DbgSsReserved[1]);
  39.         //注入并设置int 3
  40.         NtClose(Handle);
  41. }

  42. BOOL WINAPI DebugActiveProcessStop(DWORD dwProcessId)
  43. {
  44.         //OpenProcess获取进程句柄
  45.         ClientId.UniqueThread = NULL;
  46.         ClientId.UniqueProcess = UlongToHandle(dwProcessId);
  47.         InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
  48.         Status = NtOpenProcess(&Handle, PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ
  49.                 | PROCESS_SUSPEND_RESUME | PROCESS_QUERY_INFORMATION, &ObjectAttributes, &ClientId);
  50.         //关闭所有进程句柄
  51.         ThreadData = (PDBGSS_THREAD_DATA*)NtCurrentTeb()->DbgSsReserved;
  52.         ThisData = *ThreadData;
  53.         while(ThisData)
  54.         {
  55.                 if (ThisData->ProcessId == dwProcessId)
  56.                 {
  57.                         if (ThisData->ThreadHandle) CloseHandle(ThisData->ThreadHandle);
  58.                         if (ThisData->ProcessHandle) CloseHandle(ThisData->ProcessHandle);
  59.                         *ThreadData = ThisData->Next;
  60.                         RtlFreeHeap(RtlGetProcessHeap(), 0, ThisData);
  61.                 }
  62.                 else
  63.                 {
  64.                         ThreadData = &ThisData->Next;
  65.                 }
  66.                 ThisData = *ThreadData;
  67.         }
  68.         Status = NtRemoveProcessDebug(Process, NtCurrentTeb()->DbgSsReserved[1]);
  69.         NtClose(Handle);
  70. }

  71. BOOL WINAPI DebugSetProcessKillOnExit(BOOL KillOnExit)
  72. {
  73.         STATE = KillOnExit != 0;
  74.         Handle = NtCurrentTeb()->DbgSsReserved[1];
  75.         Status = NtSetInformationDebugObject(Handle, DebugObjectKillProcessOnExitInformation, &State, sizeof(State), NULL);
  76. }

  77. BOOL WINAPI WaitForDebugEvent(LPDEBUG_EVENT lpDebugEvent, DWORD dwMilliseconds)
  78. {
  79.         do
  80.         {
  81.                 Status = NtWaitForDebugEvent(NtCurrentTeb()->DbgSsReserved[1], TRUE, TimeOut, &WaitStateChange);
  82.         } while ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC));

  83.         lpDebugEvent->dwProcessId = (DWORD)WaitStateChange->AppClientId.UniqueProcess;
  84.         lpDebugEvent->dwThreadId = (DWORD)WaitStateChange->AppClientId.UniqueThread;

  85.         switch (WaitStateChange->NewState)
  86.         {
  87.         case DbgCreateThreadStateChange:
  88.                 DebugEvent->dwDebugEventCode = CREATE_THREAD_DEBUG_EVENT;
  89.                 DebugEvent->u.CreateThread.hThread = WaitStateChange->StateInfo.CreateThread.HandleToThread;
  90.                 DebugEvent->u.CreateThread.lpStartAddress = WaitStateChange->StateInfo.CreateThread.NewThread.StartAddress;
  91.                 Status = NtQueryInformationThread(WaitStateChange->StateInfo.CreateThread.HandleToThread, ThreadBasicInformation, &ThreadBasicInfo, sizeof(ThreadBasicInfo), NULL);
  92.                 DebugEvent->u.CreateThread.lpThreadLocalBase = ThreadBasicInfo.TebBaseAddress;
  93.                 break;

  94.         case DbgCreateProcessStateChange:
  95.                 DebugEvent->dwDebugEventCode = CREATE_PROCESS_DEBUG_EVENT;
  96.                 DebugEvent->u.CreateProcessInfo.hProcess = WaitStateChange->StateInfo.CreateProcessInfo.HandleToProcess;
  97.                 DebugEvent->u.CreateProcessInfo.hThread = WaitStateChange->StateInfo.CreateProcessInfo.HandleToThread;
  98.                 DebugEvent->u.CreateProcessInfo.hFile = WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.FileHandle;
  99.                 DebugEvent->u.CreateProcessInfo.lpBaseOfImage = WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.BaseOfImage;
  100.                 DebugEvent->u.CreateProcessInfo.dwDebugInfoFileOffset = WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.DebugInfoFileOffset;
  101.                 DebugEvent->u.CreateProcessInfo.nDebugInfoSize = WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.DebugInfoSize;
  102.                 DebugEvent->u.CreateProcessInfo.lpStartAddress = WaitStateChange->StateInfo.CreateProcessInfo.NewProcess.InitialThread.StartAddress;
  103.                 Status = NtQueryInformationThread(WaitStateChange->StateInfo.CreateProcessInfo.HandleToThread, ThreadBasicInformation,
  104.                         &ThreadBasicInfo, sizeof(ThreadBasicInfo), NULL);
  105.                 DebugEvent->u.CreateProcessInfo.lpThreadLocalBase = ThreadBasicInfo.TebBaseAddress;
  106.                 DebugEvent->u.CreateProcessInfo.lpImageName = NULL;
  107.                 DebugEvent->u.CreateProcessInfo.fUnicode = TRUE;
  108.                 break;

  109.         case DbgExitThreadStateChange:
  110.                 DebugEvent->dwDebugEventCode = EXIT_THREAD_DEBUG_EVENT;
  111.                 DebugEvent->u.ExitThread.dwExitCode = WaitStateChange->StateInfo.ExitThread.ExitStatus;
  112.                 break;

  113.         case DbgExitProcessStateChange:
  114.                 DebugEvent->dwDebugEventCode = EXIT_PROCESS_DEBUG_EVENT;
  115.                 DebugEvent->u.ExitProcess.dwExitCode = WaitStateChange->StateInfo.ExitProcess.ExitStatus;
  116.                 break;

  117.         case DbgExceptionStateChange:
  118.         case DbgBreakpointStateChange:
  119.         case DbgSingleStepStateChange:
  120.                 if (WaitStateChange->StateInfo.Exception.ExceptionRecord.ExceptionCode == DBG_PRINTEXCEPTION_C)
  121.                 {
  122.                         DebugEvent->dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT;
  123.                         DebugEvent->u.DebugString.lpDebugStringData = (PVOID)WaitStateChange->StateInfo.Exception.ExceptionRecord.ExceptionInformation[1];
  124.                         DebugEvent->u.DebugString.nDebugStringLength = WaitStateChange->StateInfo.Exception.ExceptionRecord.ExceptionInformation[0];
  125.                         DebugEvent->u.DebugString.fUnicode = FALSE;
  126.                 }
  127.                 else if (WaitStateChange->StateInfo.Exception.ExceptionRecord.ExceptionCode == DBG_RIPEXCEPTION)
  128.                 {
  129.                         DebugEvent->dwDebugEventCode = RIP_EVENT;
  130.                         DebugEvent->u.RipInfo.dwType = WaitStateChange->StateInfo.Exception.ExceptionRecord.ExceptionInformation[1];
  131.                         DebugEvent->u.RipInfo.dwError = WaitStateChange->StateInfo.Exception.ExceptionRecord.ExceptionInformation[0];
  132.                 }
  133.                 else
  134.                 {
  135.                         DebugEvent->dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
  136.                         DebugEvent->u.Exception.ExceptionRecord = WaitStateChange->StateInfo.Exception.ExceptionRecord;
  137.                         DebugEvent->u.Exception.dwFirstChance = WaitStateChange->StateInfo.Exception.FirstChance;
  138.                 }
  139.                 break;

  140.         case DbgLoadDllStateChange:
  141.                 DebugEvent->dwDebugEventCode = LOAD_DLL_DEBUG_EVENT;
  142.                 DebugEvent->u.LoadDll.lpBaseOfDll = WaitStateChange->StateInfo.LoadDll.BaseOfDll;
  143.                 DebugEvent->u.LoadDll.hFile = WaitStateChange->StateInfo.LoadDll.FileHandle;
  144.                 DebugEvent->u.LoadDll.dwDebugInfoFileOffset = WaitStateChange->StateInfo.LoadDll.DebugInfoFileOffset;
  145.                 DebugEvent->u.LoadDll.nDebugInfoSize = WaitStateChange->StateInfo.LoadDll.DebugInfoSize;
  146.                 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
  147.                 Status = NtOpenThread(&ThreadHandle, THREAD_QUERY_INFORMATION, &ObjectAttributes, &WaitStateChange->AppClientId);
  148.                 Status = NtQueryInformationThread(ThreadHandle, ThreadBasicInformation, &ThreadBasicInfo, sizeof(ThreadBasicInfo), NULL);
  149.                 NtClose(ThreadHandle);
  150.                 DebugEvent->u.LoadDll.lpImageName = ((PTEB)ThreadBasicInfo.TebBaseAddress)->NtTib.ArbitraryUserPointer;
  151.                 DebugEvent->u.LoadDll.fUnicode = TRUE;
  152.                 break;

  153.         case DbgUnloadDllStateChange:
  154.                 DebugEvent->dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT;
  155.                 DebugEvent->u.UnloadDll.lpBaseOfDll = WaitStateChange->StateInfo.UnloadDll.BaseAddress;
  156.                 break;

  157.         default:
  158.                 return STATUS_UNSUCCESSFUL;
  159.         }

  160.         switch (lpDebugEvent->dwDebugEventCode)
  161.         {
  162.         case CREATE_THREAD_DEBUG_EVENT:
  163.                 SaveThreadHandle(lpDebugEvent->dwProcessId, lpDebugEvent->dwThreadId, lpDebugEvent->u.CreateThread.hThread);
  164.                 break;
  165.         case CREATE_PROCESS_DEBUG_EVENT:
  166.                 SaveProcessHandle(lpDebugEvent->dwProcessId, lpDebugEvent->u.CreateProcessInfo.hProcess);
  167.                 SaveThreadHandle(lpDebugEvent->dwProcessId, lpDebugEvent->dwThreadId, lpDebugEvent->u.CreateProcessInfo.hThread);
  168.                 break;
  169.         case EXIT_PROCESS_DEBUG_EVENT:
  170.                 MarkProcessHandle(lpDebugEvent->dwProcessId);
  171.         case EXIT_THREAD_DEBUG_EVENT:
  172.                 MarkThreadHandle(lpDebugEvent->dwThreadId);
  173.                 break;
  174.         case EXCEPTION_DEBUG_EVENT:
  175.         case LOAD_DLL_DEBUG_EVENT:
  176.         case UNLOAD_DLL_DEBUG_EVENT:
  177.         case OUTPUT_DEBUG_STRING_EVENT:
  178.         case RIP_EVENT:
  179.                 break;
  180.         default:
  181.                 return FALSE;
  182.         }
  183. }
复制代码
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2015-7-6 23:00:33 | 显示全部楼层
  1. #define DbgSsSetThreadData(d) NtCurrentTeb()->DbgSsReserved[0] = d
  2. #define DbgSsGetThreadData() ((PDBGSS_THREAD_DATA)NtCurrentTeb()->DbgSsReserved[0])

  3. VOID WINAPI SaveThreadHandle(DWORD dwProcessId, DWORD dwThreadId, HANDLE hThread)
  4. {
  5.         PDBGSS_THREAD_DATA ThreadData;
  6.         ThreadData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DBGSS_THREAD_DATA));
  7.         ThreadData->ThreadHandle = hThread;
  8.         ThreadData->ProcessId = dwProcessId;
  9.         ThreadData->ThreadId = dwThreadId;
  10.         ThreadData->ProcessHandle = NULL;
  11.         ThreadData->HandleMarked = FALSE;
  12.         ThreadData->Next = DbgSsGetThreadData();
  13.         DbgSsSetThreadData(ThreadData);
  14. }

  15. VOID WINAPI SaveProcessHandle(DWORD dwProcessId, HANDLE hProcess)
  16. {
  17.         PDBGSS_THREAD_DATA ThreadData;
  18.         ThreadData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DBGSS_THREAD_DATA));
  19.         ThreadData->ProcessHandle = hProcess;
  20.         ThreadData->ProcessId = dwProcessId;
  21.         ThreadData->ThreadId = 0;
  22.         ThreadData->ThreadHandle = NULL;
  23.         ThreadData->HandleMarked = FALSE;
  24.         ThreadData->Next = DbgSsGetThreadData();
  25.         DbgSsSetThreadData(ThreadData);
  26. }

  27. VOID WINAPI MarkProcessHandle(DWORD dwProcessId)
  28. {
  29.         PDBGSS_THREAD_DATA ThreadData;
  30.         for (ThreadData = DbgSsGetThreadData(); ThreadData; ThreadData = ThreadData->Next)
  31.         {
  32.                 if ((ThreadData->ProcessId == dwProcessId) && !(ThreadData->ThreadId))
  33.                 {
  34.                         ThreadData->HandleMarked = TRUE;
  35.                         break;
  36.                 }
  37.         }
  38. }

  39. VOID WINAPI MarkThreadHandle(DWORD dwThreadId)
  40. {
  41.         PDBGSS_THREAD_DATA ThreadData;
  42.         for (ThreadData = DbgSsGetThreadData(); ThreadData; ThreadData = ThreadData->Next)
  43.         {
  44.                 if (ThreadData->ThreadId == dwThreadId)
  45.                 {
  46.                         ThreadData->HandleMarked = TRUE;
  47.                         break;
  48.                 }
  49.         }
  50. }
复制代码


可见作为内核接口的api有:
ZwDebugContinue
ZwCreateDebugObject
NtDebugActiveProcess
NtRemoveProcessDebug
NtSetInformationDebugObject
NtWaitForDebugEvent





回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-12-23 02:13 , Processed in 0.032527 second(s), 21 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表