程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Win32調試API學習心得(二)

Win32調試API學習心得(二)

編輯:Delphi

 上一章講解了如何用調試API來打開一個被調試程序,並給出了一個簡單的例子,這一章將祥細
講解調試消息包含的內容.

  類似於消息處理中的消息結構TMessage一樣,調試事件也有自己特定的事件結構,那就是TDeb
ugEvent, TDebugEvent在Delphi中的定義為:
  TDebugEvent = _DEBUG_EVENT;
  _DEBUG_EVENT = record
    dwDebugEventCode: DWORD;
    dwProcessId: DWORD;
    dwThreadId: DWORD;
    case Integer of
      0: (Exception: TExceptionDebugInfo);
      1: (CreateThread: TCreateThreadDebugInfo);
      2: (CreateProcessInfo: TCreateProcessDebugInfo);
      3: (ExitThread: TExitThreadDebugInfo);
      4: (ExitProcess: TExitThreadDebugInfo);
      5: (LoadDll: TLoadDLLDebugInfo);
      6: (UnloadDll: TUnloadDLLDebugInfo);
      7: (DebugString: TOutputDebugStringInfo);
      8: (RipInfo: TRIPInfo);
  end;

  這個結構很復雜,包含了三個基本類型和一個聯合類型的數據.dwProcessId和dwThreadId指明
了產生調試事件的進程和線程的ID,dwDebugEventCode指明了產生了何種調試事件,可能的取值
如下表(摘自<<Win32匯編程序設計>>):
  1.CREATE_PROCESS_DEBUG_EVENT:進程被創建.當被調試進程剛被創建(還未運行) 或我們的程
序剛以DebugActiveProcess捆綁到一個運行中的進程時該事件發生. 這是我們的程序應該獲得
的第一個事件.
  2.EXIT_PROCESS_DEBUG_EVENT:被調試進程退出時產生此消息.
  3.CREATE_THEAD_DEBUG_EVENT:當一個新線程在被調試進程中創建或我們的程序首次捆綁到運
行中的進程時該事件發生.要注意的是當被調試進程的主線程被創建時不會收到該通知.  
  4.EXIT_THREAD_DEBUG_EVENT:被調試進程中的線程退出時事件發生.被調試進程的主線程退出
時不會收到該通知.我們可以認為被調試進程的主線程與被調試進程是同義詞. 因此, 當我們
的程序看到CREATE_PROCESS_DEBUG_EVENT標志時,對主線程來說,就是CREATE_THREAD_DEBUG_E
VENT標志.
  5.LOAD_DLL_DEBUG_EVENT:被調試進程裝入一個DLL.當PE裝載器第一次分解指向DLL的鏈接時
,我們將收到這一事件. (當調用CreateProcess裝入 被調試進程時)並且當被調試進程調用Lo
adLibrary時也會發生.
  6.UNLOAD_DLL_DEBUG_EVENT:一個DLL從被調試進程中卸載時此事件發生.  
  7.EXCEPTION_DEBUG_EVENT:在被調試進程中發生異常時事件發生.異常實際上是一個調試中斷
(int 3h).如果想恢復被調試進程事,以 DBG_CONTINUE 標志調用ContinueDebugEvent 函數.
不要使用DBG_EXCEPTION_NOT_HANDLED 標志否則被調試進程會在NT下拒絕運行(Win98下運行得
很好).
  8.OUTPUT_DEBUG_STRING_EVENT:當被調試進程調用DebugOutputString函數向我們的程序發送
消息字符串時該事件發生.  
  9.RIP_EVENT:系統調試發生錯誤.


  根據dwDebugEventCode的不同,應調用聯合中相應的結構來獲得相關的調試信息.例如我們有
個名為Debug的TDebguEvent的結構,在調用WaitForDebugEvent(Debug, INFINITE)後接收到調
試信息時,並且dwDebugEventCode的值為CREATE_PROCESS_DEBUG_EVENT,我們就可以通過仿問D
ebug.CreateProcessInfo.hProcess來獲得剛創建的被調試進程的進程句柄.

  下面將祥細講解TDebugEvent結構中可能包括的每個結構的含義.因為沒有相關的祥細資料,大
部分結果是靠測試所得,如有錯漏敬請指正.

  一.CreateProcessInfo結構: 對應的調試消息CREATE_PROCESS_DEBUG_EVENT.
CreateProcessInfo.hFile:被調試進程的EXE文件被映射到內存中的內存文件映射句柄,可以
通過打開這個句柄(用OpenFileMapping和MapViewOfFile)來讀取此EXE文件的相關信息.如引入
引出表等.
CreateProcessInfo.hProcess:被調試進程的進程句柄,如果要使用ReadProcessMemory和Wri
teProcessMemory等函數來修改被調試進程,就需要用到這個句柄,可以用一個變量保存起來供
以後使用.
CreateProcessInfo.hThread:主線程句柄.
CreateProcessInfo.lpBaseOfImage:可執行文件被裝載到虛似地址空間中的基址.
CreateProcessInfo.dwDebugInfoFileOffset:調試信息在可執行文件中的偏移地址(一般為0
,即沒有調試信息).
CreateProcessInfo.nDebugInfoSize:調試信息的長度.
CreateProcessInfo.lpThreadLocalBase:主線程基址.
CreateProcessInfo.lpStartAddress:主線程的線程函數地址.
CreateProcessInfo.lpImageName:文件映像名,注意這是一個RVA地址(相對虛擬地址).
CreateProcessInfo.fUnicode:如果此值大於0,則lpImageName指向的文件名為UNICODE碼.

  二.ExitProcess結構: 對應的調試消息EXIT_PROCESS_DEBUG_EVENT.
ExitProcess.dwExitCode:即被調試程序調用ExitProcess函數時傳入的退出代碼.

  三.CreateThread結構: 對應的調試消息CREATE_THEAD_DEBUG_EVENT.
CreateThread.hThread:新建線程的句柄.線程句柄,如果以後會涉及到對線程的操作,如掛起
線程等,則可以用一個TList來保存進程ID(TDebugEvent.dwThreadId)和相對應的句柄.再在其
它調試事件發生時,根據dwThreadId得到線程句柄.
CreateThread.lpThreadLocalBase:新線程的基址.
CreateThread.lpStartAddress:新線程的線程函數地址.

  四.ExitThread結構: 對應的調試消息EXIT_THREAD_DEBUG_EVENT.
ExitThread.dwExitCode:即退出的線程調用ExitThread函數時傳入的退出代碼.

  五.LoadDll結構: 對應的調試消息LOAD_DLL_DEBUG_EVENT.
LoadDll.hFile:被加載的DLL文件映射到內存中的內存文件映射句柄,可以通過打開這個句柄
來讀取此DLL文件的相關信息.
LoadDll.lpBaseOfDll:DLL文件被裝載到虛似地址空間中的基址.這個地址加上DLL文件引出的
函數的地址,就是這個函數在內存中的地址.
LoadDll.dwDebugInfoFileOffset:調試信息在DLL文件中的偏移地址.
LoadDll.nDebugInfoSize:調試信息的長度.
LoadDll.lpImageName:DLL文件名的地址,是一個RVA地.
LoadDll.fUnicode:如果此值大於0,則lpImageName指向的文件名為UNICODE碼.

  六.UnLoadDll結構: 對應的調試消息UNLOAD_DLL_DEBUG_EVENT.
UnloadDll.lpBaseOfDll:卸載的DLL文件的基址,可以通過在處理LOAD_DLL_DEBUG_EVENT消息
中保存DLL信息和對應的基址的方法,來得到卸載的DLL信息.

  七.Exception結構: 對應的調試消息EXCEPTION_DEBUG_EVENT.
Exception.ExceptionRecord: 這是一個TExceptionRecord結構,裡面包含了被調試程序產生
的中斷或異常的代碼,產生的中斷或異常的地址等信息.

  八.DebugString結構: 對應的調試消息OUTPUT_DEBUG_STRING_EVENT.
DebugString.lpDebugStringData:被調試進程調用DebugOutputString函數發送的消息字符串
的地址.
DebugString.nDebugStringLength:被調試進程調用DebugOutputString函數發送的消息字符
串的長度.
DebugString.fUnicode:如果此值大於0,則消息字符串為UNICODE碼.

  九.RipInfo結構: 對應的調試消息RIP_EVENT.
RipInfo.dwError:錯誤代碼.
RipInfo.dwType:錯誤類型.

  了解了以上的知識,我們就可以在調試器中監視這些調試消息,並獲得我們感興趣的信息.但這
僅僅實現了對被調試調試程序的監視.下一章將講解如何修改被調試程序.

  附:一個監視目標程序啟動,加載DLL,退出的例子,並演示了如何讀取RVA地址,獲得加載的DLL
文件名的方法.請到下面的地址下載.
http://qxccccc.8u8.com/debug.rar

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved