微信扫一扫

028-83195727 , 15928970361
business@forhy.com

Python灰帽子--黑客与逆向工程师的Python编程之道 笔记,过程问题解决

python,黑客,编程,逆向2016-08-15

跟着学习进度不断更新中。。。。

power by 《python灰帽子--黑客与逆向工程师的Python编程之道》


本文链接:http://blog.csdn.net/u012763794/article/details/52174275


自从上次读了python黑帽子(http://blog.csdn.net/u012763794/article/details/50612756),感觉作者写的书还不错,现在来读读python灰帽子吧(感谢翻译书的人,让我们有这么好的学习教材)


同理,我会根据学习进度不断更新, 也欢迎大家像python黑帽子一样,在下面评论给我以鼓励,我会带更多我的学习成果给大家


同样给书中全部代码链接(代码除了常量定义,都是手敲的,所以根据学习进度更新)(github):https://github.com/giantbranch/gray-hat-python-src


第一章 环境搭建


1.操作系统准备:

这个没什么好说的了,win+linux,最好的解决方案就是虚拟机了,如果你土豪就两台电脑也是挺好的

2.获取python:

作者是2.5太老了,我们尝试2.7吧,很多linux都是自带的了,在windows装去吧

3.配置编程环境开始编程吧

作者是eclipse和PyDev, 其实我喜欢用用sublime和pycharm

据说ctypes库是很多库的基础哦,什么python调用动态链接库,创建复杂的C数据类型和底层操作函数等


使用动态链接库


windows下:


linux下:



构造C数据类型


首先我们看看三者的对应关系


代码清单
# -*- coding: utf-8 -*-
# @Date    : 2016-08-10 20:30:23
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

from ctypes import *
c_int()
c_char_p('Hello world!')
c_ushort(65531)
c_short(-5)
seitz = c_char_p("loves the python")
print seitz
print seitz.value
exit()



定义结构体和联合体


结构体
//C语言
struct beer_recipe{
	int amt_barley;
	int amt_water;
};

#python
class beer_recipe(Structure):
	_fields_ = [
		("amt_barley", c_int),
		("amt_water", c_int),
	]

联合体
//C语言
union{
	long barley_long;
	int barley_int;
	char barley_char[8]
}barley_amount;

#python
class barley_amount(Union):
	_fields_ = [
		("barley_long", c_long),
		("barley_int", c_int),
		("barley_char", c_char*8),
	]

实践一下




第二章 调试器的设计


我去,一上来就搞这个, 既然来了,就坚持干下去


1.通用寄存器

2.栈

上面两个这些建议看其他书吧,什么加密与解密,反正逆向的书都有讲吧

3.调试事件

就是调试器捕捉到的事件,比如说什么断点触发,内存违例(也叫访问违例或者段错误),程序异常等
当调试器检测到这些事件,调用一个与之对应的处理函数

4.断点

就是想让程序在执行到什么时候,暂停下来,方便观察堆栈,寄存器和内存的数据, 破解明文比较的验证码就是这样的了

软件断点

这是一个使用最多的断点,od就是F2,本质就是一个单字节的指令,用于暂停被执行的程序,并将控制权转移给调试器的断点处理函数

这个单字节的操作码是3号中断指令(INT 3),转化成机器码(或者操作码)就是 0xCC
比如我们 要在 mov eax,ebx 处暂停,对应的机器码是 8BC3,那么下断后就变成 CCC3了

那么当我们按下分F2,调试器如何工作的呢? 首先读取目标地址的第一个字节的操作码,同时储存在内部的中断列表中,跟着就把那个字节改为CC,
当CPU执行到那,触发INT 3中断事件,调试器就捕捉到,判断这个地址(通过eip获取)是不是之前设置断点的地址,是的话就从内部的断点列表(跟上面的中断列表一个意思吧)找到这个地址,将之前储存的操作码写回该地址,

硬件断点


作用:有时候一些软件会做crc校验或其他校验,因为我们下断点改了指令,是校验值改变了,有些软件或者病毒什么的就直接退出了,

那么硬件断点就可以在 某个小区块设置断点,又不修改他们


硬件断点被设置在CPU级别,用的是特定的寄存器:调试寄存器,有8个哦(DR0-7)

0-3储存硬件断点地址,所以同一时间只能设置4个硬件断点

DR4,5保留,DR6是状态寄存器(说明了被断点触发的调试事件的类型)

DR7本质上是一个硬件断点的开关寄存器,同时储存了断点的不同类型

有以下3个类型



硬件断点是用INT 1中断(INT 1 负责硬件中断和步进事件)

由于硬件断点最多只能对4字节下断,如果要跟踪一大片区域就要用的内存断点了


内存断点

这个其实不是真的断点,其实是改变了某个块或者某个页的权限。

比如我们设置内存写入断点, 我就让这个区域没有写入权限,那么当执行到写入时,就会触发保护页异常,cpu就会暂停下来,就断下来了。


第三章 自己动手写一个windows调试器


我去,看这标题好像很高大上啊,坚持!!!

3.1 尝试用python创建要调试的程序的进程


那开始吧


下面这个是储存一些配置信息的
# -*- coding: utf-8 -*-
# @Date    : 2016-08-11 16:07:38
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

#把所有的结构体,联合体,常量等放这,方便以后维护

from ctypes import *

# 给ctypes类型重新命名,跟windows编程接轨吧
WORD	= c_ushort
DWORD	= c_ulong
LPBYTE	= POINTER(c_ubyte)
LPTSTR 	= POINTER(c_char)
HANDLE	= c_void_p

#常量
DEBUG_PROCESS = 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",	LPTSTR),
		("hStdInput",	DWORD),
		("hStdOutput",	DWORD),
		("hStdError",	DWORD),
	]

#进程的信息:进程线程的句柄,进程线程的id	
class PROCESS_INFORMATION(Structure):
	_fields_ = [
		("hProcess",	HANDLE),
		("hThread",		HANDLE),
		("dwProcessId",	DWORD),
		("dwThreadId",	DWORD),
	]
至于这两个数据结构可以查看msdn,下面给出STARTUPINFO截图




一个debuger类
# -*- coding: utf-8 -*-
# @Date    : 2016-08-11 16:48:16
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

from ctypes import *
from my_debugger_defines import *
kernel32 = windll.kernel32
class debugger():
	
	def __init__(self):
		pass
	def load(self, path_to_exe):
		creation_flags = DEBUG_PROCESS
		startupinfo = STARTUPINFO()
		process_information = PROCESS_INFORMATION()
		startupinfo.dwFlags = 0x1
		startupinfo.wShowWindow = 0x0
		startupinfo.cb = sizeof(startupinfo)
		if kernel32.CreateProcessA(path_to_exe,
									None,
									None,
									None,
									None,
									creation_flags,
									None,
									None,
									byref(startupinfo),
									byref(process_information)):
			print "[*] we have successfully launched the process!"
			print "[*] PID:%d" % process_information.dwProcessId
		else:
			print "[*] Error:0x%08x." % kernel32.GetLastError()

			
启动代码
# -*- coding: utf-8 -*-
# @Date    : 2016-08-12 14:18:10
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

import my_debugger
debugger = my_debugger.debugger()
debugger.load("C:\\WINDOWS\\system32\\calc.exe")

结果:可以看到启动计算器成功,还获取到了其pid,但是我们的任务管理器看不到,原来是因为进程没把解密绘画到屏幕上,他在等待调试器继续执行的命令,接下来我们就去干啦~~~~


继续出发,尝试实现附加到一个正在运行的程序上面进行附加

在debugger类中加入了以下的代码
# 获取进程的句柄,要调试当然要全不权限了		
	def open_process(self, pid):
		h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, pid, False)
		return h_process
			
	def attach(self, pid):
		self.h_process = self.open_process(pid)
		#尝试附加到某个pid的程序上
		if kernel32.DebugActiveProcess(pid):
			self.debugger_active = True
			self.pid = pid
			self.run()
		else:
			print "[*] Unable to 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
		#INFINITE表示无限等待
		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..."
		else:
			print "There was an error"
			return False

test.py也改一下
import my_debugger
debugger = my_debugger.debugger()
# debugger.load("C:\\WINDOWS\\system32\\calc.exe")
pid = raw_input("Enter the PID of the process to attach to:")
debugger.attach(int(pid))
debugger.detach()
常量也要加一下哦,放在报什么没定义的,将作者的代码一贴


不知道为啥附加不到计算器上 ,难道是权限问题?


附加到CTF的reverseme就可以,附加后,输入key回车后没反应,跟着我们任意按个键continue,那就从哪个进程分离了,就输出你输入的key是错误的



还发现下面两个参数调转都能运行,不过第二行的是跟windows多的一样的参数顺序


3.2 获得CPU寄存器状态


1. 枚举线程

CreateToolhelp32Snapshot可以获取线程,进程,模块,堆的信息,这里我们当然设置获取线程的信息
Thread32First枚举线程,看看他对应的进程是不是我们调试的进程
跟着就直接Thread32Next循环调用就可以了

2 .把所有的组合起来

可通过GetThreadContext获取寄存器的值,SetThreadContext可以改变他们哦

新增代码:
def open_thread(self, thread_id):
		h_thread = kernel32.OpenThread(THREAD_ALL_ACCESS, None, thread_id)
		if h_thread is not None:
			return h_thread
		else:
			print "[*] Could not obtain a valid thread handle."
			return False
	
	def enumerate_threads(self):
		thread_entry = THREADENTRY32()
		thread_list = []
		snapshot = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, self.pid)
		if snapshot is not None:
			thread_entry.dwSize = sizeof(thread_entry)
			success = kernel32.Thread32First(snapshot,  byref(thread_entry))
			while success:
				if thread_entry.th32OwnerProcessID == self.pid:
					thread_list.append(thread_entry.th32ThreadID)
				success = kernel32.Thread32Next(snapshot, byref(thread_entry))

			kernel32.CloseHandle(snapshot)
			return thread_list
		else:
			print "enumerate_threads fail."
			return False

	def get_thread_context(self, thread_id):
		context = CONTEXT()
		context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS
		h_thread = self.open_thread(thread_id)
		if kernel32.GetThreadContext(h_thread, byref(context)):
			kernel32.CloseHandle(h_thread)
			return context
		else:
			print "get_thread_context fail."
			return False
my_test
# -*- coding: utf-8 -*-
# @Date    : 2016-08-12 14:18:10
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

import my_debugger
debugger = my_debugger.debugger()
# debugger.load("C:\\WINDOWS\\system32\\calc.exe")
pid = raw_input("Enter the PID of the process to attach to:")
debugger.attach(int(pid))

threadList = debugger.enumerate_threads()
print threadList
for thread in threadList:
	thread_context = debugger.get_thread_context(thread)
	# %08x就是8位的十六进制,不够就0补充咯
	print "[*] Dumping registers for thread ID:0x%08x" % thread
	print "[**] EIP:0x%08x" % thread_context.Eip
	print "[**] ESP:0x%08x" % thread_context.Esp
	print "[**] EBP:0x%08x" % thread_context.Ebp
	print "[**] EAX:0x%08x" % thread_context.Eax
	print "[**] EBX:0x%08x" % thread_context.Ebx
	print "[**] ECX:0x%08x" % thread_context.Ecx
	print "[**] EDX:0x%08x" % thread_context.Edx
	print "[*] END DUMP"

debugger.detach()

日了dog,出来注释这个
# raw_input("Press a key to continue...")
			# self.debugger_active = False
还要把run注释掉


运行结果:可以看到我们也可以获取各个寄存器的值啦,同时这个进程有两个线程哦


3.3 实现调试事件的处理

新增了这个,mytest就看书吧


运行结果:可以获取到调试事件和线程id了(下面的get_thread_context fail.忽略,那个自己print出来的,作者那里有点问题,上面应该是传threadid的)


其中3是进程创建进程事件,6是load dll,2是创建新的线程,1是windows设置断点引发的吧,4就是线程结束自身了
# 调试事件常量
EXCEPTION_DEBUG_EVENT      =    0x1
CREATE_THREAD_DEBUG_EVENT  =    0x2
CREATE_PROCESS_DEBUG_EVENT =    0x3
EXIT_THREAD_DEBUG_EVENT    =    0x4
EXIT_PROCESS_DEBUG_EVENT   =    0x5
LOAD_DLL_DEBUG_EVENT       =    0x6
UNLOAD_DLL_DEBUG_EVENT     =    0x7
OUTPUT_DEBUG_STRING_EVENT  =    0x8
RIP_EVENT                  =    0x9

我们继续...,那个1号Code很重要,可能包括断点,访问异常或者内存访问错误。我们首先捕捉第一个windows设置的断点吧 


运行结果: 可以在1号code处输出信息啦



3.4 全能的断点


1.  软件断点

我们要将0xCC写入内存,原来的指令也要读取出来吧
用的两个API  ReadProcessMemory和WriteProcessMemory

加了这几个函数
def read_process_memory(self, address, length):
		data = ""
		read_buf = create_string_buffer(length)	
		count = c_ulong(0)
		if not kernel32.ReadProcessMemory(self.h_process, address, read_buf, length, byref(count)):
			return False
		else:
			data += read_buf.raw
			return data

	def write_process_memory(self, address, data):
		count = c_ulong(0)
		length = len(data)
		c_data = c_char_p(data[count.value:])
		if not kernel32.WriteProcessMemory(self.h_process, address, c_data, length, byref(count)):
			return False
		else:
			return True

	# 设置断点
	def bp_set(self, address):
		# 看看断点的字典里是不是已经存在这个断点的地址了
		if not self.breakpoints.has_key(address):
			try:
				# 先读取原来的一个字节,保存后再写入0xCC
				original_byte = self.read_process_memory(address, 1)
				self.write_process_memory(address, '\xCC')
				self.breakpoints[address] = (address, original_byte)
			except:
				return False
		return True

	# 获取某个模块(一般是dll)中的某个函数的地址
	def func_resolve(self, dll, function):
		handle = kernel32.GetModuleHandleA(dll)
		address = kernel32.GetProcAddress(handle, function)
		kernel32.CloseHandle(handle)
		return address



接下来是调试下面这个python程序


不知道为啥那个断点出不来


经过排查,原来是读写内存出了问题


通过GetLastError知道错误码为6,即无效的句柄

原来这个高清电子书里面的代码是错的,就说怎么跟windows的API的参数顺序不一样呢, 不过作者给的源码是没错的


运行结果:


怎么连续断了两次,
而且紧接着下面怎么无效出现内存访问XXXXX,而且速度很快,哎这个暂时搁着吧


2. 硬件断点


代码就不贴了,主要是这三个函数,


这次是比较成功的,代码看书吧


3. 内存断点


代码:


成功:


基本上这就开发了一个基于Windows的轻量级调试器。感觉实在用python来做Win32编程


第四章 PyDBG——纯PYTHON调试器


pydbg的安装可以参照这个http://blog.csdn.net/cheng_tian/article/details/7652058

1. 扩展断点处理

代码 ,另外还用到上次的printf_loop
# -*- coding: utf-8 -*-
# @Date    : 2016-08-14 10:04:29
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

from pydbg import *
from pydbg.defines import *
import struct
import random

# 这是我们定义的回调函数
def printf_randomizer(dbg):
	# 用esp索引count局部变量的值
	parameter_addr = dbg.context.Esp + 0x8
	counter = dbg.read_process_memory(parameter_addr, 4)

	print repr(counter) 
	# L表示unsigned long的意思
	# print struct.unpack("L", counter)
	counter = struct.unpack("L", counter)[0]
	print "Counter:%d" % int(counter)

	# 生成1到100的随机数,再转换成二进制格式的
	random_counter = random.randint(1, 100)
	random_counter = struct.pack("L", random_counter)[0]
	print repr(random_counter)

	dbg.write_process_memory(parameter_addr, random_counter)
	print GetLastError()
	return DBG_CONTINUE

dbg = pydbg()
pid = raw_input("Please Enter the printf_loop.py PID:")
# 附加
dbg.attach(int(pid))
printf_address = dbg.func_resolve("msvcrt", "printf")
# description为断点设置名字,handler设置回调函数
dbg.bp_set(printf_address, description="printf_address", handler=printf_randomizer)
# 启动起来
dbg.run()


struct.pack用于将Python的值根据格式符,转换为字符串(因为Python中没有字节(Byte)类型,可以把这里的字符串理解为字节流,或字节数组)。

struct.unpack做的工作刚好与struct.pack相反,用于将字节流转换成python数据类型。它的函数原型为:struct.unpack(fmt, string),该函数返回一个元组。

但运行结果出问题了,第一个读取的数据不对,第二个没有写入成功,但获取最后一次错误又没有错误


根据栈的结构应该是没错的

跟着我就用od找错误去了,直接输入断在printf上

但是这里默认使用的是msvcr90这个模块


第二个断点是下面的python代码从msvcrt找到的断点

跟od的不一样,我们再看看断在msvcrt的printf的断点时的栈的结构
好像都直接优化掉了还是怎么样


到这里我想解决方法有两个:
一个将msvcrt换成msvcr90试试
另外一个就是读出esp+4后,进一步再读那个地址里面的东西,再提取出数字,

先试试第一个:将msvcrt换成msvcr90,结果还是不行,我是不会那么容易被打败的,上神器od,不断地对那个变化的counter下硬件写入断点,就是图中的数字,终于找到了可能突破的点,发现调用的轨迹:
call python27.PyOS_snprintf ----> msvcr90._vsnprintf --> msvcr90.printf
而参数入栈在_vsnprintf 就已经搞定了,到后面的printf直接压字符串入栈就可以了,应该msvcrt也是一样的

那么我们改成_vsnprintf 看看,好像失败了,读出后不知如何再利用读出的地址再读

但发现有个更直接的


写入时成功写入了,但好像这断点用了两次


那么我们试试当Counter为那个数值的时候直接pass掉

哈哈,成功啦


具体为什么会这样,而作者会成功呢,难道是python版本的问题?这是一个值得思考的问题
解决这个问题不容易啊~,这个问题先记在这了, 知道的各位兄弟可以评论,或者私信给我,感谢~~~~

2. 处理访问违规


当程序没权限或者以不合法的方式访问内存的时候就是访问违规,如 内存溢出,不恰当处理空指针等

首先没有utils的安装一下,参考下面的链接 :
http://www.h4ck.org.cn/2012/06/pydbg安装(《python-灰帽子》)/

代码:
# -*- coding: utf-8 -*-
# @Date    : 2016-08-14 20:53:53
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

from ctypes import *
msvcrt = cdll.msvcrt
raw_input("Once the debugger is attached, press any key.")
# 定义一个缓冲区
buffer = c_char_p("AAAAA")
# 用于溢出的字符串
overflow = 'A' * 100
# 溢出
msvcrt.strcpy(buffer, overflow)
# -*- coding: utf-8 -*-
# @Date    : 2016-08-14 20:57:34
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

from pydbg import *
from pydbg.defines import *
import utils

def check_accessv(dbg):
	if  dbg.dbg.u.Exception.dwFirstChance:
		return DBG_EXCEPTION_NOT_HANDLED
	crash_bin = utils.crash_binning.crash_binning()
	crash_bin.record_crash(dbg)
	dbg.terminate_process()
	return DBG_EXCEPTION_NOT_HANDLED

pid = raw_input("Enter the Process ID:")
dbg = pydbg()
dbg.attach(int(pid))
dbg.set_callback(EXCEPTION_ACCESS_VIOLATION, check_accessv)
dbg.run()

怎么什么事都没发生,不科学


原来忘记打print了


运行结果:
第一个指出了那个指令引发的访问异常,及指令在那个块中
python27.dll:5c5aa6d0 mov ecx,[eax+0x10]
第二个有各个寄存器的信息,(框住的地方)

附近的汇编代码, 函数或者模块栈, 最后就是结构化异常处理程序列表


3. 进程快照


1. 获得进程快照



乱输入,再restore的时候出错了


暂时找不出原因

2.组合代码


直接给代码,但实际运行不起来啊
# -*- coding: utf-8 -*-
# @Date    : 2016-08-14 22:31:08
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

from pydbg import *
from pydbg.defines import *
import utils

# 设置我们要监视的代码的数量,就是内存访问违规后输出多少代码(指令)
MAX_INSTRUCTIONS = 10
# 一些危险的函数
dangerous_functions = {
	"strcpy":"msvcrt.dll",
	"strncpy":"msvcrt.dll",
	"sprintf":"msvcrt.dll",
	"vsprintf":"msvcrt.dll"
}
dangerous_functions_resolved = {}
crash_encountered = False
instruction_count = 0
def danger_handler(dbg):
	esp_offset = 0
	print "[*] Hit %s" % dangerous_functions_resolved[dbg.context.Eip]
	print "================================================================================"
	while esp_offset<=20:
		parameter = dbg.smart_dereference(dbg.context.Esp + esp_offset)
		print "[ESP + %d] => %s" % (esp_offset, parameter)
		esp_offset += 4
	print "================================================================================"
	dbg.suspend_all_threads()
	dbg.process_snapshot()
	dbg.resume_all_threads()
	return DBG_CONTINUE
def access_violation_handler(dbg):
	global crash_encountered

	if dbg.dbg.u.Exception.dwFirstChance:
		return DBG_EXCEPTION_NOT_HANDLED
	crash_bin = utils.crash_binning.crash_binning()
	crash_bin.record_crash(dbg)
	print crash_bin.crash_synopsis()

	if crash_encountered == False:
		dbg.suspend_all_threads()
		dbg.process_restore()
		crash_encountered = True

		for thread_id in dbg.enumerate_threads():
			print "[*] Setting single step for thread:0x%08x" % thread_id
			h_thread = dbg.open_thread(thread_id)
			dbg.single_step(True, h_thread)
			dbg.close_handle(h_thread)

		dbg.resume_all_threads()
		return DBG_CONTINUE
	else:
		dbg.terminate_process()
		return DBG_EXCEPTION_NOT_HANDLED

def single_step_handler(dbg):
	global instruction_count
	global crash_encountered
	if crash_encountered:
		if instruction_count == MAX_INSTRUCTIONS:
			dbg.single_step(False)
			return DBG_CONTINUE
		else:
			instruction = dbg.disasm(dbg.context.Eip)
			print "#%d\t0x%08x : %s" % (instruction_count, dbg.context.Eip, instruction)
			instruction_count += 1
			dbg.single_step(True)
	return DBG_CONTINUE

dbg = pydbg()
pid = int(raw_input("Enter the PID you wish to monitor:"))
dbg.attach(pid)
for func in dangerous_functions.keys():
	func_address = dbg.func_resolve(dangerous_functions[func], func)
	print "[*] Resolved breakpoint:%s -> 0x%08x" % (func, func_address)
	dbg.bp_set(func_address, handler=danger_handler)
	dangerous_functions_resolved[func_address] = func
	dbg.set_callback(EXCEPTION_ACCESS_VIOLATION, access_violation_handler)
	dbg.set_callback(EXCEPTION_SINGLE_STEP, single_step_handler)
	dbg.run()
断点设置不成功

第五章 IMMUNITY———最好的调试器


1.安装Immunity调试器

好像可能python版本过高,导致immunity调试器闪退

2.Immunity Debugger 101

界面就不用说了,跟OD一样

1.PyCommands

我们在调试器中执行python就是使用PyCommands

基础模型:
from immlib import *
def main(args):
	imm = Debugger()
	return "[*] PyCommand Executed!"
有两个必备条件:
一是main函数,只接收一个参数(由所有参数组成的python列表)
另一个是执行完成必须返回一个字符串

执行命令前在命令前加个叹号,如下

!<scriptname>

2.PyHooks


Immunity Debugger包含了13种不同类型的hook,每一种都能单独实现,或嵌入PyCommand

具体哪13种呢,下面的懒得打字了,截图吧






本文链接:http://blog.csdn.net/u012763794/article/details/52174275