python灰帽子--进程调试基础2:将调试附加到进程

承接上一篇,进程调试基础1
第二种方法:将调试附加到一个正在运行的进程。

1 - 要附加到指定的进程,需要先获得他的句柄。这个任务由OpenProcess()完成,次函数由kernel32.dll库导出。原型如下

HANDLE WINAPI OpenProcess(
   	DWORD dwDesiredAccess,
   	BOOL bInheritHandle
   	DWORD dwProcessId
);

dwDesiredAccess:参数决定我们希望对将要打开的进程拥有什么样的权限
因为要执行调试,我们设置成PROCESS_ALL_ACCESS,即所有权限
bInheritHandle:参数设置成False
dwProcessId:参数设置成我们希望获得句柄的进程ID,即PID。

如果函数执行成功,将返回一个目标进程的句柄。

2 - 获得目标进程的句柄后,接着调用DebugActiveProcess()函数附加到目标进程:
函数原型:

BOOL WINAPI DebugActiveProcess(
	DWORD dwProcessId
)

注意,此处的参数仍为调试程序的PID,一旦系统认为我们有权限访问目标进程,目标进程就假定我们的调试器已经准备好处理调试事件,然后把进程的控制权转移给调试器。

3 - 调试器接着循环调用WaitDebugEvent()以便俘获调试事件。
函数原型:

BOOL WINAPI WaitForDebugEvent(
	LPDEBUG_EVENT lpDebugEvent,
	DWORD dwMilliseconds
);

lpDebugEvent:指向DEBUG_EVENT结构体,这个结构描述了一个调试事件。
dwMilliseconds:设置成INFINITE,表示无限等待,这样WaitForDebugEvent()就不用返回,一直等待直到一个事件产生。

调试器捕获的每一个事件都有相关联的事件处理函数,在程序继续执行前可以完成不同的操作。

4 - 当处理函数完成了操作,我们希望进程继续执行,这时候调用ContinueDebugEvent()
原型如下

BOOL WINAPI ContinueDebugEvent(
	DWORD dwProcessId,
	DWORD dwThreadId,
	DWORD dwContinueStatus
);

dwProcessIddwThreadId参数有DEBUG_EVENT结构里的数据填充。
当调试器捕捉到调试事件的时候,也就是WaitForDebugEvent()成功执行的时候,进程ID和线程ID就已经初始化好了。
dwContinueStatus:参数高速进城是继续执行(DBG_CONTINUE),还是产生异常(DBG_EXCEPTION_NOT_HANDLED)

5 - 调试结束后,我们需要把调试从进程中分离出来,也就是把进程ID传递给函数DebugActiveProcessStop()

程序创建

先说功能:
通过上面对附加进程原理的理解,我们要完成将调试附加和分离一个进程的功能。同时,加上打开一个进程和获取进程句柄的能力。最后我们在主循环里完成事件处理函数。

1 - 功能函数

#my_debugger.py 
from ctypes import *
from my_debugger_defines import *
kernel32 = windll.kernel32
class debugger()"
	def __init__(self):
		self.h_process = None
		self.pid = None
		self.debugger_active = None
	
	#打开进程
	def open_process(self,pid):
		h_process = kerne32.OpenProcess(PROCESS_ALL_ACCESS,pid,False)
		return h_prcess
	
	#附加到进程,同时获取进程句柄
	def attach(self,pid):
		self.h_process = self.open_process(pid)
		if kernel32.DebugActiveProcess(pid):
			self.debugger_active = True
			self.pid = int(pid)
			self.run()
		else:
			print"[*]Unable attach to the process"
	
	#捕获调试事件
	def run(self):
		while self.debugger_active == True:
			self.get_debug_event()
	
	def get_debug_event(self):
		debug_event = DEBUG_EVENT()
		continue_status = DBG_CONTINUE
		if kernel32.WaitForDebugEvent(byref(debug_event),INFINITE):
			raw_input('press a key to continue...')
			self.debugger_active = False
			kernel32.ContinueDebugEvent(
				debug_event.dwProcessId,
				debug_event.dwThreadId,
				continue_status)
	
	#将调试与进程分离
	def detach(self):
		if kernel32.DebugActiveProcessStop(self.pid):
			print"[*]Finished debugging.Exiting..."
			return True
		else:
			print "There was an error"
			return False

2 - 常量定义
常量和结构体定义在后续的文章中也都有用到,这里单用一片文章进行说明
详细定义参考my_debugger_defines.py

3 - 测试程序

#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))
debugger.detach()

windows按一下步骤进行测试:
(1)打开一个程序,如计算器
(2)通过任务管理器查看该程序的pid(任务管理器-详细信息标签栏可以看到PID)
(3)运行my_test.py
(4)在终端中输入pid
(5)当press a key to continue 打印在屏幕上时,试着操作计算器界面,这时应该是什么都按不了,因为进程被调试器挂起了。
(6)在Phont控制台里按任何键,脚本将输出别的信息,然后退出。
(7)这时计算器可以再次操作了。

测试正常后,把下面两行从 my_debugger.py 中注释掉,如果不注释掉会影响后续程序运行:

# raw_input("Press any key to continue...")
# self.debugger_active = False
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值