python逆向入门教程


Posted in Python onJanuary 15, 2018

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/#section=windows

2、ctypes

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

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网络编程学习笔记(九):数据库客户端 DB-API
Jun 09 Python
基于python实现的抓取腾讯视频所有电影的爬虫
Apr 22 Python
Python 高级专用类方法的实例详解
Sep 11 Python
Python中 传递值 和 传递引用 的区别解析
Feb 22 Python
详解PyCharm配置Anaconda的艰难心路历程
Aug 13 Python
python卸载后再次安装遇到的问题解决
Jul 10 Python
浅谈Python3实现两个矩形的交并比(IoU)
Jan 18 Python
解决tensorflow读取本地MNITS_data失败的原因
Jun 22 Python
Python APScheduler执行使用方法详解
Dec 10 Python
Pytorch如何切换 cpu和gpu的使用详解
Mar 01 Python
python plt.plot bar 如何设置绘图尺寸大小
Jun 01 Python
Python实现8种常用抽样方法
Jun 27 Python
Python3一行代码实现图片文字识别的示例
Jan 15 #Python
Python编程二分法实现冒泡算法+快速排序代码示例
Jan 15 #Python
selenium python浏览器多窗口处理代码示例
Jan 15 #Python
100行python代码实现跳一跳辅助程序
Jan 15 #Python
tornado 多进程模式解析
Jan 15 #Python
200 行python 代码实现 2048 游戏
Jan 12 #Python
一篇文章快速了解Python的GIL
Jan 12 #Python
You might like
php 之 没有mysql支持时的替代方案
2006/10/09 PHP
强烈声明: 不要使用(include/require)_once
2013/06/06 PHP
thinkPHP基于ajax实现的菜单与分页示例
2016/07/12 PHP
PHP去除字符串最后一个字符的三种方法实例
2017/03/01 PHP
PHP命令空间namespace及use的用法小结
2017/11/27 PHP
Javascript(AJAX)解析XML的代码(兼容FIREFOX/IE)
2010/07/11 Javascript
查找页面中所有类为test的结点的方法
2014/03/28 Javascript
window.open()详解及浏览器兼容性问题示例探讨
2014/05/29 Javascript
JavaScript实现关键字高亮功能
2014/11/12 Javascript
js小数运算出现多位小数如何解决
2015/10/08 Javascript
使用jQuery中的wrap()函数操作HTML元素的教程
2016/05/24 Javascript
ui组件之input多选下拉实现方法(带有搜索功能)
2016/07/14 Javascript
jQuery插入节点和移动节点用法示例(insertAfter、insertBefore方法)
2016/09/08 Javascript
移动适配的几种方案(三种方案)
2016/11/25 Javascript
Angular.js中处理页面闪烁的方法详解
2017/03/09 Javascript
老生常谈javascript中逻辑运算符&&和||的返回值问题
2017/04/13 Javascript
Vue2.0子同级组件之间数据交互方法
2018/02/28 Javascript
mpvue 如何使用腾讯视频插件的方法
2018/07/16 Javascript
bootstrap实现点击删除按钮弹出确认框的实例代码
2018/08/16 Javascript
基于JS实现一个随机生成验证码功能
2019/05/29 Javascript
[01:03:09]完美世界DOTA2联赛PWL S2 Forest vs SZ 第二场 11.25
2020/11/26 DOTA
在Python程序中实现分布式进程的教程
2015/04/28 Python
python 随机数使用方法,推导以及字符串,双色球小程序实例
2017/09/12 Python
基于python 二维数组及画图的实例详解
2018/04/03 Python
Python之使用adb shell命令启动应用的方法详解
2019/01/07 Python
对python中的*args与**kwgs的含义与作用详解
2019/08/28 Python
python3常用的数据清洗方法(小结)
2019/10/31 Python
关于tf.matmul() 和tf.multiply() 的区别说明
2020/06/18 Python
Ubuntu20.04环境安装tensorflow2的方法步骤
2021/01/29 Python
Django视图类型总结
2021/02/17 Python
使用CSS禁止textarea调整大小功能的方法
2015/03/13 HTML / CSS
酒店个人求职信范文
2014/01/25 职场文书
廉洁校园实施方案
2014/05/25 职场文书
长城英文导游词
2015/01/30 职场文书
Redis分布式锁Redlock的实现
2021/08/07 Redis
springboot 全局异常处理和统一响应对象的处理方式
2022/06/28 Java/Android