前言:近日阅读《Python灰帽子-黑客与逆向工程师的Python编程之道》看的我是云里雾里,单单这个调试器就各种Google资料,现在也是懂了点点,感觉做下笔记,以便后续继续学习
手写一个调试器有助于我们理解hook、进程注入等底层黑客技术具体实现,在编写过程中需要涉及大量Windows内核编程知识,因此手写调试器也可以作为启发式学习内核编程的任务驱动。要想调试一个程序, 就需要与目标程序建立某种联系, 为此, 我们的调试器应该具备两种基本能力:
1. 打开一个程序, 并使它以自身子进程的形式运行起来
2. 附加到一个正在进去的程序上
1.创建子进程
BOOL CreateProcess (
LPCTSTR lpApplicationName, // 程序路径
LPTSTR lpCommandLine, // 命令行参数
LPSECURITY_ATTRIBUTES lpProcessAttributes。
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags, // 创建的标志
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo, // 指向一个用于决定新进程的主窗体如何显示的 STARTUPINFO 结构体
LPPROCESS_INFORMATION lpProcessInformation // 指向一个用来接收新进程的识别信息的 PROCESS_INFORMATION 结构体
);
基本上, 我们只要关心 lpApplicationName、lpCommandLine、dwCreationFlags、lpStartupInfo 和 lpProcessInformation 这五个参数, 其它的设为 None即可.
2.调试器项目简介
调试器包括三个py文件,my_debugger.py 、my_debugger_defines.py 、my_test.py
my_debugger_defines.py : 保存的是程序常量及结构定义的地方
my_debugger.py : 是核心代码实现的地方
my_test.py : 运行文件
直接上示例代码:
my_debugger_defines.py
# coding=utf-8
from ctypes import *
# 为ctype变量创建符合匈牙利命名风格的匿名,这样可以使代码更接近Win32的风格
WORD = c_ushort
DWORD = c_ulong
LPBYTE = POINTER(c_ubyte)
LPTSTR = POINTER(c_char)
HANDLE = c_void_p
# 常值定义
DEBUG_RPOCESS = 0x00000001
CREATE_NEW_CONSOLE = 0x00000010
# 定义函数CreateProcessA()所需的结构体
class STARTUPINFO(Structure):
_fields_ = [
("cb", DWORD),
("lpReserved", LPTSTR),
("lpDesktop", LPTSTR),
("lpTitle", LPTSTR),
("dwX", DWORD),
("dwY", DWORD),
("dwXSize", DWORD),
("dwYSize", DWORD),
("dwXCountChars", DWORD),
("dwYCountChars", DWORD),
("dwFillAttribute", DWORD),
("dwFlags", DWORD),
("wShowWindow", WORD),
("cbReserved2", WORD),
("lpReserved2", LPBYTE),
("hStdInput", HANDLE),
("hStdOutput", HANDLE),
("hStdError", HANDLE),
]
class PROCESS_INFORMATION(Structure):
_fields_ = [
("hProcess", HANDLE),
("hThread", HANDLE),
("dwProcessId", DWORD),
("dwThreadId", DWORD),
]
my_debugger.py
# coding=utf-8
from ctypes import *
from my_debugger_defines import *
kernel32 = windll.kernel32