## 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