您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 资本运营 > 灰帽 Python之旅12
12PyEmuPyEmu由CodyPierce(TippingPointDVLabsteam)于2007在黑帽大会上首次公布。PyEmu是一个存Python实现的IA32仿真器,用于仿真CPU的各种行为以完成不同的任务。仿真器非常有用,比如在调试病毒的时候,我们就不用真正的运行它,而是通过仿真器欺骗它在我们的模拟环境中运行。PyEmu里有三个类:IDAPyEmu,PyDbgPyEmu和PEPyEmu。IDAPyEmu用于在IDAPro内完成各种仿真任务(由DAPython调用,详看第11章),PyDbgPyEmu类用于动态分析,同时它允许使用我们真正的内存和寄存器。PEPyEmu类是一个独立的静态分析库,不需要IDA就能完成反汇编任务。我们主要介绍IDAPyEmu和PEPyEm,剩下的PyDbgPyEmu留给大家自己去试验。下面先从PyEmu的安装开始,接着深入介绍仿真器的架构,为实际应用做好准备。安装PyEmu从下载作者打包好的文件,如果没有的同学去googlecode上下。文件下载好后,解压到C:\PyEmu。每次创建PyEmu脚本的时候,都要加入以下两行Python代码:sys.path.append(C:\PyEmu\)sys.path.append(C:\PyEmu\lib)接下来让我们输入了解下PyEmu的系统架构,方便后面的脚本编写。12.2PyEmu一览PyEmu被划分成三个重要的系统:PyCPU,PyMemory和PyEmu。与我们交互最多的就是PyEmu类,它再和PyCPU和PyMemoey交互完成底层的仿真工作。当我们测试驱动PyEmu执行一个指令的时候,它就调用PyCPU完成真正的指令操作。PyCPU在进行指令操作的时候,把需要的内存操作告诉PyEmu,由PyEmu继续调用PyMemory辅助完成整个指令的操作,最后由PyEmu将指令的结果返回给调用者。接下来,让我们简短的了解下各个子系统和他们的使用方法,以便更好的明白伟大的PyEmu替我们完成了什么,同时大家也能对实际应用有个初略的了解。12.2.1PyCPUPyCPU类是PyEmu的核心,它模拟成和真实的CPU一样。在仿真的过程中,它负责执行指令。当PyCPU处理一个指令的时候,会先检索指令指针(由负责静态分析的IDAPro/PEPyEmu或者负责动态调试的PyDbg获取),然后将指令传递给pydasm,由后者解码成操作码和操作对象。PyCPU提供的独立解码指令的能力使得PyEmu的跨平台变成了可能。每个PyEmu接收到的指令,都有一个相对应内部函数。举个例子,如果将指令CMPEAX,1传给PyCPU,接着PyCPU就会调用PyCPUCMP()函数执行真正的操作,并从内存中检索必要的值,之后设置CPU的标志位,告诉程序这次比较的结果。有兴趣的各位都可以看看PyCPU.py,所有的PyEmu支持的指令处理函数都在这里,通过研究它们可以明白CPU是如何完成那些神秘的底层操作的。别担心代码的可读性,Cody在这上面可没少花功夫。12.2.2PyMemoryPyMemor负责加载和储存执行指令的必要数据。同时也可以对可执行程序的代码和数据块进行映射,以便在仿真器中访问。在将借完两个主要类之后,让我们看看核心类PyEmu,以及相关的类方法。12.2.3PyEmuPyEmu负责驱动整个仿真器的运作。PyEmu类本身被设计的非常轻便和灵活,使得开发者能够很块的开发出强大的仿真器脚本,而不用关心底层操作。这一切都由PyEmu提供的帮助函数实现,使用它们能让我们的这个逆向工作变得更简单,无论是操作执行流程,改变寄存器值还是更新内存等等。下面就来卓一介绍它们。12.2.4执行操作PyEmu的执行过程由一个函数控制,execute()。原型如下:execute(steps=1,start=0x0,end=0x0)总共三个参数,如果一个都没有提供,就从PyEmu当前的地址开始执行。这个地址也许是PyDbg的EIP寄存器指向的位置,也许是PEPyEmu加载的可执行程序的入口地址,也许是IDAPro光标所处的位置。start为开始执行的地址,steps为执行的指令数量,end为结束的地址。12.2.5内存和寄存器操作修改和检索寄存器与内存的值在逆向的过程中特别重要。PyEmu将它们分成了4类:内存,栈变量(stackvariables),栈参数(stackarguments),寄存器。内存操作由get_memory()和set_memory()完成。get_memory(address,size)set_memory(address,value,size=0)get_memory()函数接收2个参数:address为要查询的地址,size为要获得数据的大小。set_memoey()负责写入数据,address为写入的地址,value为写入的值,size为写入数据的大小。另外两类基于栈操作的函数也差不多,主要负责栈框架中函数参数和本地变量的检索和修改。set_stack_argument(offset,value,name=)get_stack_argument(offset=0x0,name=)set_stack_variable(offset,value,name=)get_stack_variable(offset=0x0,name=)set_stack_argument()的offset相对与ESP,用于对传入函数的参数进行改变。在操作的过程中可以提供可以可选的名字。get_stack_argument()通过offset指定的相对于ESP的位移获得参数值,或者通过指定的name(前提是在set_stack_argument中提供了)获得。使用方式如下:set_stack_argument(0x8,0x12345678,name=arg_0)get_stack_argument(0x8)get_stack_argument(arg_0)set_stack_variable()和get_stack_variable()的操作也类似除了offset是相对于EBP(如果允许的话)以外,因为它们负责操作函数的局部变量。12.2.6处理函数处理函数提供了一种非常强大且灵活的回调结构,用于观察,设置或者修改程序的特定部分。PyEmu中有8个主要处理函数:register处理函数,library处理函数,exception处理函数,instruction处理函数,opcode处理函数,memory处理函数,high-levelmemory处理函数还有programcounter处理函数。让我们快速的了解下每一个函数,之后我们马上要在用到它们。12.2.6.1Register处理函数RegisterHandlers寄存器处理函数,用于监视任何寄存器的改变。只要有寄存器的遭到修改就将触发RegisterHandlers。安装方式如下:set_register_handler(register,register_handler_function)set_register_handler(eax,eax_register_handler)安装好之后,就需要定义处理函数了,原型如下:defregister_handler_function(emu,register,value,type):当处理函数被调用的时候,所有的参数都又PyEmu传入,第一个参数就是PyEmu实例首,接着是寄存器名,以及寄存器的值,type告诉我们这次操作是读还是写。时间久了你就会发现用这种方式观察寄存器是有多么强大且方便,如果需要你还能在处理函数里改变它们。12.2.6.2Library处理函数Libraryhandle库处理函数,能让我们捕捉所有的外部库调用,在它们被调用进程序之前就截获它们,这样就能很方便的修改外部库函数的调用方式以及返回值。安装方式如下:set_library_handler(function,library_handler_function)set_library_handler(CreateProcessA,create_process_handler)set_library_handler(LoadLibraryA,loadlibrary)库处理函数的原型如下:deflibrary_handler_function(emu,library,address):第一个参数就是PyEmu的实例。library为我们想要监视的函数,或者库,第三个是函数被映射在内存中的地址。12.2.6.3Exception处理函数ExceptionHandlers异常处理函数和第二章介绍的处理函数相似。PyEmu仿真器中的异常会触发ExceptionHandlers的调用。当前PyEmu支持通用保护错误,也就是说我们能够处理在模拟器中的任何内存访问违例。安装方式如下:set_exception_handler(GP,gp_exception_handler)Exception处理函数原型如下:defgp_exception_handler(emu,exception,address):同样,第一个参数是PyEmu实例,exception为异常代码,address为异常发生的地址。12.2.6.4Instruction处理函数InstructionHandlers指令处理函数,很强大,因为它能捕捉任何特定的指令。就像Cody在BlackHat说展示的那样,你能够通过安装一个CMP指令的处理函数,来监视整个程序流程的分支判断,并控制它们。set_instruction_handler(instruction,instruction_handler)set_instruction_handler(cmp,cmp_instruction_handler)Instruction处理函数原型如下:defcmp_instruction_handler(emu,instruction,op1,op2,op3):第一个参数照旧是PyEmu实例,instruction则为被执行的指令,另外三个都是可能的运算对象。12.2.6.5Opcode处理函数Opcodehandlers操作码处理函数和指令处理函数非常相似,任何一个特定的操作码被执行的时候,都会调用Opcodehandlers。这样我们对代码的控制就变得更精确了。每一个指令都有可能有不同的操作码这依赖于它们的运算对象,例如,PUSHEAX时操作码是0x50,而PUSH0x70时操作码是0x6A,合起来整个指令的操作码就是0x6A70,如下所示:50PUSHEAX6A70PUSH0x70它们的安装方法很简单:set_opcode_handler(opcode,opcode_handler)set_opcode_handler(0x50,my_push_eax_handler)set_opcode_handler(0x6A70,my_push_70_handler)第一个参数只要简单的设置成我们需要捕捉的操作码,第二个参数就是处理函数了。捕捉的范围不限于单个字节,而可以是多这个字节,就想第二个例子一样。处理函数原型如下:defopcode_handler(emu,opcode,op1,op2,op3):第一个PyEmu实例,后面不再累赘。opcode是捕捉到的操作码,剩下的三个就是指令可能使用到的计算对象。12.2.6.6Memory处理函数Memoryhandlers内存处理函数用于跟踪特定地址的数据访问。它能让我们很方便的跟踪缓冲区中感兴趣的数据以及全局变量的改变过程。安装过程如下:set_memory_handler(address,memory_handler)set_memory_handler(0x12345678,my_memory_handler)address简单传入我们想要观
本文标题:灰帽 Python之旅12
链接地址:https://www.777doc.com/doc-4870277 .html