python逆向入门教程

yipeiwu_com5年前Python基础

1、开发环境

我们在Windows 10上开始python逆向之旅,首先开始搭建开发环境,python解释器使用最新的3.6.1,IDE使用PyCharm社区版2017.1.3,下载地址如下所示,下载完成后直接双击安装包安装即可,随后设置PyCharm的Project Interpreter为刚才安装的Python解释器就可以了。

【Python】https://www.python.org/downloads/
【PyCharm】http://www.jetbrains.com/pycharm/download/

2、ctypes

首先介绍一下ctypes,它是一个用于Python的外部函数库,提供了与C语言兼容的数据类型,允许调用动态链接库或共享库中的函数,还可以包装这些库。下面是ctypes中的数据类型与C语言、Python中的数据类型的对应关系。

ctypes中的数据类型全部通过class来实现,在Python中加载C库涉及如下几个类。

  1. class ctypes.CDLL 加载共享库,使用标准C函数调用惯例即cdecl,返回类型为int。
  2. class ctypes.OleDLL 加载共享库,只用于Windows平台,使用stdcall函数调用惯例,返回类型为HRESULT。
  3. class ctypes.WinDLL 加载共享库,只用于Windows平台,使用stdcall函数调用惯例,返回类型为int。
  4. class ctypes.PyDLL 类似于CDLL,与前面三个不同的是,在函数调用期间不会释放GIL,Global Interpreter Lock。
  5. class ctypes.LibraryLoader(dlltype) dlltype为CDLL、OleDLL、WinDLL、PyDLL,这个类有一个加载共享库的函数LoadLibrary。

加载C库更简单的方法是使用如下几个预先创建的类实例。

ctypes.cdll
ctypes.oledll
ctypes.windll
ctypes.pydll
ctypes.pythonapi

上面提到了函数调用惯例cdecl和stdcall,cdecl的意思是函数的参数从右往左依次压入栈内,函数的调用者在函数执行完成之后负责函数的平衡,常用于X86架构的C语言里,返回值存储在EAX寄存器中,从汇编代码的角度来看,函数参数从右往左依次压栈,然后调用函数,最后修改栈指针ESP为原来的位置。stdcall,参数传递的顺序也是从右到左,不过栈的平衡处理由函数自己完成,而不是调用者,返回值同样存储在EAX中,也就是说,函数参数压栈、函数调用之后没有像cdecl一样的栈指针ESP移动。

下面的例子在Python中调用C的printf函数,printf属于“C:\Windows\System32\msvcrt.dll”,也就是Linux上的“libc.so”。

from ctypes import *

msvcrt = cdll.msvcrt
message = b"Hello World\n"
msvcrt.printf(b"Message is %s", message)

上面的代码输出“Message is Hello World”。另外,ctypes还允许在Python中定义结构和联合等其它高级功能,详细介绍请参考https://docs.python.org/3.6/library/ctypes.html?highlight=ctypes#。

3、调试原理

使用调试器,能够对程序进行动态跟踪和分析,特别是涉及到exploit、fuzzer和病毒分析的时候,动态分析程序的能力就显得非常重要了。调试程序时,如果可以获得源代码,调试起来就容易一些,也就是透明的白盒测试,如果没有源代码,也就是黑盒测试,想要得到理想的结果,那就必须拥有高超的逆向技术和逆向工具的帮助。黑盒测试包括用户模式与内核模式两种情况,两者有不同的权限。

CPU的寄存器能够对少量的数据进行快速的存取访问,在X86指令集里,一个CPU有八个通用寄存器:EAX、EDX、ECX、ESI、EDI、EBP、ESP和EBX,以及其它的寄存器,下面逐个介绍。
EAX:累加寄存器,除了用于存储函数的返回值外也用于执行计算的操作,许多优化的X86指令集都专门设计了针对EAX寄存器的读写和计算指令。

EDX:数据寄存器,本质上是EAX寄存器的延伸,辅助EAX寄存器完成更多复杂的计算操作。
ECX:计数寄存器,用于循环操作,计算是向下而不是向上的,由大减到小。
ESI:Source Index,源操作数指针,存储着输入的数据流的位置,用于读,高效地处理循环操作的数据。
EDI:Destination Index,目的操作数指针,存储了计算结果存储的位置,用于写,高效地处理循环操作的数据。
ESP:Stack Pointer,栈指针,负责函数的调用和栈的操作,函数调用时压栈参数和返回地址,指向栈顶即返回地址。
EBP:Base Pointer,基指针,负责函数的调用和栈的操作,函数调用时压栈参数和返回地址,指向栈底。
EBX:唯一一个没有特殊用途的寄存器,作为额外的数据存储器。
EIP:Instruction Pointer,指令指针,总是指向马上要执行的指令。

熟悉调试器的朋友们都知道断点,断点其实就是一个调试事件,其它事件如经典的段错误(Segment Fault)等。断点包括软件断点、硬件断点和内存断点,用于暂停被执行程序。

软件断点:一个单字节的指令,将控制权转移给调试器的断点处理函数。汇编指令是CPU执行的指令的高级表示方法,如下面的汇编指令MOV EAX, EBX,告诉CPU把存储在EBX寄存器里的东西放到EAX寄存器,然而CPU并不明白这个汇编指令,必须转化为能够让CPU识别的操作码8BC3,假设这一操作发生在地址0x44332211,为了在这个地址设置断点,暂停CPU,需要从2个字节的操作码8BC3中换出一个单字节的操作码,这个单字节的操作码也就是3号中断指令,INT3,一条能让CPU暂停的指令,对应的操作码为0xCC,具体如下面的代码片段所示。当调试器被告知在目标地址设置一个断点时,它首先读取目标地址的第一个字节的操作码然后保存起来,同时把地址存储在内部的中断列表中,接着,调试器把3号中断指令对应的操作码0xCC写到刚才的地址,当CPU执行到替换后的操作码的时候,CPU暂停,并触发一个INT3事件,此时调试器就能捕捉到这个事件,然后调试器通过EIP判断这个中断地址是否是我们设置的断点,如果是,就把对应的操作码写回以恢复程序的正常运行。软件断点包括一次性断点和持续性断点,前者生效一次,后者一直生效,不生效后将其从中断列表移除。需要注意的是,当我们改变了被调试程序的内存数据时,同时改变了运行时软件的CRC即循环冗余代码校验和,CRC是一种校验数据是否被改变的机制,广泛应用于文件、内存、文本、网络数据包等任何想监视数据的地方,它将一定范围内的数据进行hash计算,然后将hash值同此前的hash值进行比较,判断数据是否改变,为了在这种特殊的情况下也能调试程序,就要使用下面介绍的硬件断点了。

地址: 操作码 汇编指令
0x44332211: 8BC3 MOV EAX, EBX
0x44332211: CCC3 MOV EAX, EBX

硬件断点:在小块区域内设置断点,属于CPU级别,使用了DR0到DR7共八个特殊的调试寄存器,这些寄存器专门用于管理硬件断点。DR0到DR3存储硬件断点地址,意味着同一时间内最多只能有4个硬件断点,DR4和DR5保留,DR6是状态寄存器,说明被断点触发的调试事件的类型,DR7是开关寄存器,同时也存储了断点的不同类型,包括指令执行时中断、数据可以写入时中断、有数据读或者写但不执行时中断。硬件断点使用1号中断指令INT1,负责硬件中断和步进事件。硬件断点的特点是同一时间只能设置四个断点,而且断点起作用的区域只有四个字节,如果想要跟踪一大块内存数据,请使用下面介绍的内存断点。

内存断点:用于大块区域,不是真正的断点,而是改变了内存中某个块或者页的权限。一个内存页是操作系统处理的最小的内存单位,一个内存页被申请成功后,就拥有了一个权限集,如可执行页、可读页、可写页,这些决定了内存该如何被访问,任何对保护页的访问都会引发异常,之后页面恢复访问前的状态。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持【听图阁-专注于Python设计】。

相关文章

python argparser的具体使用

一.正常运行: 咱们随便写个文件: # test.py import argparse ap = argparse.ArgumentParser() ap.add_argumen...

从头学Python之编写可执行的.py文件

Python可是真强大。但他具体是怎么强大的,让我们一点一点来了解吧(小编每天晚上下班回家会抽时间看看教程,多充实下自己也是好的)。 废话不多说,就讲一下这个背景吧: 事情是这个样子的~...

Python实现类的创建与使用方法示例

Python实现类的创建与使用方法示例

本文实例讲述了Python实现类的创建与使用方法。分享给大家供大家参考,具体如下: #coding=utf8 #为了使除法总是会返回真实的商,不管操作数是整形还是浮点型。 from...

Python+OpenCV实现旋转文本校正方式

Python+OpenCV实现旋转文本校正方式

假设我们有一幅图像,图像中的文本被旋转了一个未知的角度。为了对文字进行角度的校正,我们需要完成如下几个步骤: 1、检测出图中的文本范围 2、计算出文本被旋转的角度 3、将图像旋转特定的角...

Python Socket编程之多线程聊天室

Python Socket编程之多线程聊天室

本文为大家分享了Python多线程聊天室,是一个Socket,两个线程,一个是服务器,一个是客户端。 最近公司培训,要写个大富翁的小程序,准备做个服务器版的,先练练手。 代码: #...