## 4.1擴展斷點處理
在前面的章節中我們講解了用事件處理函數處理調試事件的方法。用 PyDbg 可以很容 易的擴展這種功能,只需要構建一個用戶模式的回調函數。當收到一個調試事件的時候,回 調函數執行我們定義的操作。比如讀取特定地址的數據,設置更更多的斷點,操作內存。操 作完成后,再將權限交還給調試器,恢復被調試的進程。
PyDbg 設置函數的斷點原型如下:
```
bp_set(address, description="",restore=True,handler=None)
```
address 是要設置的斷點的地址,description 參數可選,用來給每個斷點設置唯一的名字。 restore 決定了是否要在斷點被觸發以后重新設置, handler 指向斷點觸發時候調用的回調函 數。斷點回調函數只接收一個參數,就是 pydbg()類的實例化對象。所有的上下文數據,線 程,進程信息都在回調函數被調用的時候,裝填在這個類中。
以 printf_loop.py 為測試目標,讓我們實現一個自定義的回調函數。這次我們在 printf() 函數上下斷點,以便讀取 printf()輸出時用到的參數 counter 變量,之后用一個 1 到 100 的隨 機數替換這個變量的值,最后再打印出來。記住,我們是在目標進程內處理,拷貝,操作這 些實時的斷點信息。這非常的強大!新建一個 printf_random.py 文件,鍵入下面的代碼。
```
#printf_random.py
from pydbg import *
from pydbg.defines import *
import struct
import random
# This is our user defined callback function
def printf_randomizer(dbg):
# Read in the value of the counter at ESP + 0x8 as a DWORD
parameter_addr = dbg.context.Esp + 0x8
counter = dbg.read_process_memory(parameter_addr,4)
# When we use read_process_memory, it returns a packed binary
# string. We must first unpack it before we can use it further.
counter = struct.unpack("L",counter)[0]
print "Counter: %d" % int(counter)
# Generate a random number and pack it into binary format
# so that it is written correctly back into the process
random_counter = random.randint(1,100)
random_counter = struct.pack("L",random_counter)[0]
# Now swap in our random number and resume the process
dbg.write_process_memory(parameter_addr,random_counter)
return DBG_CONTINUE
# Instantiate the pydbg class
dbg = pydbg()
# Now enter the PID of the printf_loop.py process
pid = raw_input("Enter the printf_loop.py PID: ")
# Attach the debugger to that process
dbg.attach(int(pid))
# Set the breakpoint with the printf_randomizer function
# defined as a callback
printf_address = dbg.func_resolve("msvcrt","printf")
dbg.bp_set(printf_address,description="printf_address",handler=printf_randomizer)
# Resume the process
dbg.run()
```
現在運行 printf_loop.py 和 printf_random.py 兩個文件。輸出結果將和表 4-1 相似。
Table 4-1:調試器和進程的輸出
| Output from Debugger | Output from Debugged Process |
| --- | --- |
| Enter the printf_loop.py PID: 3466 | Loop iteration 0! |
| … | Loop iteration 1! |
| … | Loop iteration 2! |
| … | Loop iteration 3! |
| Counter: 4 | Loop iteration 32! |
| Counter: 5 | Loop iteration 39! |
| Counter: 6 | Loop iteration 86! |
| Counter: 7 | Loop iteration 22! |
| Counter: 8 | Loop iteration 70! |
| Counter: 9 | Loop iteration 95! |
| Counter: 10 | Loop iteration 60! |
為了不把你搞混,讓我們看看 printf_loop.py 代碼。
```
from ctypes import *
import time
msvcrt = cdll.msvcrt
counter = 0
while 1:
msvcrt.printf("Loop iteration %d!\n" % counter)
time.sleep(2)
counter += 1
```
先搞明白一點,printf()接受的這個 counter 是主函數里 counter 的拷貝,就是說在 printf 函數內部,無論怎么修改都不會影響到外面的這個 counter(C 語言所說的只有傳遞指針才能真 正的改變值)。
你應該看到,調試器在 printf 循環到第 counter 變量為 4 的時候才設置了斷點。這是 因 為被 counter 被捕捉到的時候已經為 4 了(這是為了讓大家看到對比結果,不要認為調試器 傻了)。同樣你會看到 printf_loop.py 的輸出結果一直到 3 都是正常的。到 4 的時候,printf() 被中斷,內部的 counter 被隨即修改為 32!這個例子很簡單且強大,它告訴了你在調試事件 發生的時候如何構建回調函數完成自定義的操作。現在讓我們看一看 PyDbg 是如何處理應 用程序崩潰的。
- 序
- 1 搭建開發環境
- 1.1 操作系統準備
- 1.2 獲取和安裝 Python2.5
- 1.3 配置 Eclipse 和 PyDev
- 2 調試器設計
- 2.1 通用 CPU 寄存器
- 2.2 棧
- 2.3 調試事件
- 2.4 斷點
- 3 自己動手寫一個 windows 調試器
- 3.2 獲得 CPU 寄存器狀態
- 3.3 實現調試事件處理
- 3.4 全能的斷點
- 4 PyDBG---純 PYTHON 調試器
- 4.1 擴展斷點處理
- 4.2 處理訪問違例
- 4.3 進程快照
- 5 IMMUNITY----最好的調試器
- 5.1 安裝 Immunity 調試器
- 5.2 Immunity Debugger 101
- 5.3 Exploit 開發
- 5.4 搞定反調試機制
- 6 HOOKING
- 6.1 用 PyDbg 實現 Soft Hooking
- 6.2 Hard Hooking
- 7 Dll 和代碼注入
- 7.1 創建遠線程
- 7.2 邪惡的代碼
- 8 FUZZING
- 8.1 Bug 的分類
- 8.2 File Fuzzer
- 8.3 改進你的 Fuzzer
- 9 SULLEY
- 9.1 安裝 Sulley
- 9.2 Sulley primitives
- 9.3 獵殺 WarFTPD
- 10 Fuzzing Windows 驅動
- 10.1 驅動通信
- 10.2 用 Immunity fuzzing 驅動
- 10.4 構建 Driver Fuzzer
- 11 IDAPYTHON --- IDA 腳本
- 11.1 安裝 IDAPython
- 11.2 IDAPython 函數
- 11.3 腳本例子
- 12 PyEmu
- 12.1 安裝 PyEmu
- 12.2 PyEmu 一覽
- 12.3 IDAPyEmu