<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## 3.2獲得 CPU 寄存器狀態 一個調試器必須能夠在任何時候都搜集到 CPU 的各個寄存器的狀態。當異常發生的時 候這能讓我們確定棧的狀態,目前正在執行的指令是什么,以及其他一些非常有用的信息。 要實現這個目的,首先要獲取被調試目標內部的線程句柄,這個功能由 OpenThread()實現. 函數原型如下: ``` HANDLE WINAPI OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId ); ``` 這看起來非常像 OpenProcess()的姐妹函數,除了這次是用線程標識符(thread identifier TID) 提到了進程標識符(PID)。 我們必須先獲得一個執行著的程序內部所有線程的一個列表,然后選擇我們想要的,再 用 OpenThread() 獲 取 它 的 句 柄 。 讓 我 研 究 下 如 何 在 一 個 系 統 里 枚 舉 線 程 ( enumerate threads)。 ### 3.2.1 枚舉線程 為了得到一個進程里寄存器的狀態,我們必須枚舉進程內部所有正在運行的線程。線程 是進程中真正的執行體(大部分活都是線程干的),即使一個程序不是多線程的,它也至少 有一個線程,主線程。實現這一功能的是一個強大的函數 CreateToolhelp32Snapshot(),它由 kernel32.dll 導出。這個函數能枚舉出一個進程內部所有線程的列表,以加載的模塊(DLLs) 的列表,以及進程所擁有的堆的列表。函數原型如下: ``` HANDLE WINAPI CreateToolhelp32Snapshot( DWORD dwFlags, DWORD th32ProcessID ); ``` dwFlags 參數標志了我們需要收集的數據類型(線程,進程,模塊,或者堆 )。這里我 們把它設置成 TH32CS_SNAPTHREAD,也就是 0x00000004,表示我們要搜集快照 snapshot 中 所 有 已 經 注 冊 了 的 線 程 。 th32ProcessID 傳 入 我 們 要 快 照 的 進 程 , 不 過 它 只 對 TH32CS_SNAPMODULE, TH32CS_SNAPMODULE32, TH32CS_SNAPHEAPLIST, and TH32CS_SNAPALL 這幾個模塊有用,對 TH32CS_SNAPTHREAD 可是沒什么用的哦(后面 有說明)。當 CreateToolhelp32Snapshot()調用成功,就會返回一個快照對象的句柄,被接下 來的函數調以便搜集更多的數據。 一旦我們從快照中獲得了線程的列表,我們就能用 Thread32First()枚舉它們了。函數原型如下: ``` BOOL WINAPI Thread32First( HANDLE hSnapshot, LPTHREADENTRY32 lpte ); ``` hSnapshot 就 是 上 面 通 過 CreateToolhelp32Snapshot() 獲 得 鏡 像 句 柄 , lpte 指 向 一 個 THREADENTRY32 結構(必須初始化過)。這個結構在 Thread32First()在調用成功后自動填 充,其中包含了被發現的第一個線程的相關信息。結構定義如下: ``` typedef struct THREADENTRY32{ DWORD dwSize; DWORD cntUsage; DWORD th32ThreadID; DWORD th32OwnerProcessID; LONG tpBasePri; LONG tpDeltaPri; DWORD dwFlags; }; ``` 在這個結構中我們感興趣的是 dwSize, th32ThreadID, 和 th32OwnerProcessID 3 個參數。 dwSize 必須在 Thread32First()調用之前初始化,只要把值設置成 THREADENTRY32 結構的 大小就可以了。th32ThreadID 是我們當前發現的這個線程的 TID,這個參數可以被前面說過 的 OpenThread() 函數調用以打開此線程,進行別的操作。 th32OwnerProcessID 填充了當前 線 程 所 屬 進 程 的 PID 。 為 了 確 定 線 程 是 否 屬 于 我 們 調 試 的 目 標 進 程 , 需 要 將 th32OwnerProcessID 的值和目標進程對比,相等則說明這個線程是我們正在調試的。一旦我 們獲得了第一個線程的信息,我們就能通過調用 Thread32Next()獲取快照中的下一個線程條 目。它的參數和 Thread32First()一樣。循環調用 Thread32Next()直到列表的末端。 ### 3.2.2 把所有的組合起來 現在我們已經獲得了一個線程的有效句柄,最后一步就是獲取所有寄存器的值。這就需 要通過 GetThreadContext()來實現。同樣我們也能用 SetThreadContext()改變它們。 ``` BOOL WINAPI GetThreadContext( HANDLE hThread, LPCONTEXT lpContext ); BOOL WINAPI SetThreadContext( HANDLE hThread, LPCONTEXT lpContext ); ``` hThread 參數是從 OpenThread() 返回的線程句柄,lpContext 指向一個 CONTEXT 結構, 其中存儲了所有寄存器的值。CONTEXT 非常重要,定義如下: ``` typedef struct CONTEXT { DWORD ContextFlags; DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; FLOATING_SAVE_AREA FloatSave; DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; }; ``` 如你說見所有的寄存器都在這個列表中了,包括調試寄存器和段寄存器。在我們剩下的 工作中,將大量的使用到這個結構,所以盡快的實習起來。 讓我們回來看看我們的老朋友 my_debugger.py 繼續擴展它,增加枚舉線程和獲取寄存 器的功能。 ``` #my_debugger.py class debugger(): ... def open_thread (self, thread_id): h_thread = kernel32.OpenThread(THREAD_ALL_ACCESS, None, thread_id) if h_thread is not None: return h_thread else: print "[*] Could not obtain a valid thread handle." return False def enumerate_threads(self): thread_entry = THREADENTRY32() 36 Chapter 3 thread_list = [] snapshot = kernel32.CreateToolhelp32Snapshot(TH32CS _SNAPTHREAD, self.pid) if snapshot is not None: # You have to set the size of the struct # or the call will fail thread_entry.dwSize = sizeof(thread_entry) success = kernel32.Thread32First(snapshot, byref(thread_entry)) byref(thread_entry)) while success: if thread_entry.th32OwnerProcessID == self.pid: thread_list.append(thread_entry.th32ThreadID) success = kernel32.Thread32Next(snapshot, kernel32.CloseHandle(snapshot) return thread_list else: return False def get_thread_context (self, thread_id): context = CONTEXT() context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS # Obtain a handle to the thread h_thread = self.open_thread(thread_id) if kernel32.GetThreadContext(h_thread, byref(context)): kernel32.CloseHandle(h_thread) return context else: return False ``` 調試器已經擴展成功,讓我們更新測試模塊試驗下新功能。 ``` #my_test.py import my_debugger debugger = my_debugger.debugger() pid = raw_input("Enter the PID of the process to attach to: ") debugger.attach(int(pid)) list = debugger.enumerate_threads() # For each thread in the list we want to # grab the value of each of the registers Building a Windows Debugger 37 for thread in list: thread_context = debugger.get_thread_context(thread) # Now let's output the contents of some of the registers print "[*] Dumping registers for thread ID: 0x%08x" % thread print "[**] EIP: 0x%08x" % thread_context.Eip print "[**] ESP: 0x%08x" % thread_context.Esp print "[**] EBP: 0x%08x" % thread_context.Ebp print "[**] EAX: 0x%08x" % thread_context.Eax print "[**] EBX: 0x%08x" % thread_context.Ebx print "[**] ECX: 0x%08x" % thread_context.Ecx print "[**] EDX: 0x%08x" % thread_context.Edx print "[*] END DUMP" debugger.detach() ``` 當你運行測試代碼,你將看到如清單 3-1 顯示的數據。 ``` Enter the PID of the process to attach to: 4028 [*] Dumping registers for thread ID: 0x00000550 [**] EIP: 0x7c90eb94 [**] ESP: 0x0007fde0 [**] EBP: 0x0007fdfc [**] EAX: 0x006ee208 [**] EBX: 0x00000000 [**] ECX: 0x0007fdd8 [**] EDX: 0x7c90eb94 [*] END DUMP [*] Dumping registers for thread ID: 0x000005c0 [**] EIP: 0x7c95077b [**] ESP: 0x0094fff8 [**] EBP: 0x00000000 [**] EAX: 0x00000000 [**] EBX: 0x00000001 [**] ECX: 0x00000002 [**] EDX: 0x00000003 [*] END DUMP [*] Finished debugging. Exiting... ``` Listing 3-1:每個線程的 CPU 寄存器值 太酷了 ! 我們現在能夠在任何時候查詢所有寄存器的狀態了。試驗下不同的進程 ,看看能得到什么結果。到此為止我們已經完成了我們調試器的核心部分,是時間實現一些基礎 調試事件的處理函數了。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看