虚拟内存探究 -- 第二篇:Python 字节

http://blog.coderhuo.tech/2017/10/15/Virtual_Memory_python_bytes/是真看不懂哦

  

 翻译
 虚拟内存  翻译


这是虚拟内存系列文章的第二篇。
这次我们要做的事情和《虚拟内存探究 – 第一篇:C strings & /proc》类似,不同的是我们将访问Python 3 脚本的虚拟内存。这会比较费劲, 所以我们需要了解Pyhton3 内部的一些机制。

一、预备知识

本文基于上一篇文章《虚拟内存探究 – 第一篇:C strings & /proc》中所讲的知识, 所以,在继续阅读本文前,请确保阅读并理解上一篇文章。

为了方便理解本文,你需要具备以下知识:

  • C语言基础
  • 些许Python知识
  • 了解Linux的文件系统和shell命令
  • /proc文件系统的基本知识(可参阅《虚拟内存探究 – 第一篇:C strings & /proc》中的相关介绍)

二、实验环境

所有的脚本和程序都在下面的环境中测试过:

  • Ubuntu 14.04 LTS

    • Linux ubuntu 4.4.0-31-generic #50~14.04.1-Ubuntu SMP Wed Jul 13 01:07:32 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
  • gcc
    • gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
  • Python 3
    • Python 3.4.3 (default, Nov 17 2016, 01:08:31)
    • [GCC 4.8.4] on linux

三、剖析一个简单的Python脚本

下面是我们将要使用的Python脚本(main.py)。我们将尝试修改运行该脚本的进程虚拟内存中的“字符串” Holberton

#!/usr/bin/env python3
'''
Prints a b"string" (bytes object), reads a char from stdin
and prints the same (or not :)) string again
'''import syss = b"Holberton" print(s) sys.stdin.read(1) print(s) 

Python中的字节对象(bytes object)

字节和字符串(bytes vs str)

译者注:bytes在这里翻译成字节, 并非指单个字符。

如上面代码所示,我们使用一个字节对象(字符串Holberton前面的b说明这是个字节对象)来存储字符串Holberton。字节对象会把字符串中的字符以字节的形式(相对于每个字符占多个字节的字符串编码方式而言,也就是宽字符编码,具体可参阅unicodeobject.h)存下来。这样可以保证字符串在虚拟内存中是连续的ASCII码。

从技术上来讲, 上面代码中的s并不是一个Python字符串。如下所示, 它是一个字节对象(不过没关系, 这不影响我们的后续讨论):

julien@holberton:~/holberton/w/hackthevm1$ python3
Python 3.4.3 (default, Nov 17 2016, 01:08:31)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> s = "Betty"
>>> type(s)
<class 'str'>
>>> s = b"Betty"
>>> type(s)
<class 'bytes'>
>>> quit()

一切都是对象

Pyhton中的整数、字符串、字节、函数等等, 都是对象。所以, 语句s = b"Holberton"将创建一个字节对象,并将字符串存在内存中某处。字符串Holberton很可能在堆上,因为Python必须为字节对象s以及s指向的字符串分配内存(字符串可能直接存在对象s中,也可能s只维护了一个指向字符串的索引,目前我们并不确定具体的实现)。

对python脚本执行read_write_heap.py脚本

提示:read_write_heap.py是《虚拟内存探究 – 第一篇:C strings & /proc》中的脚本,用来查找并替换内存中的字符串。

我们首先执行前面的脚本main.py

julien@holberton:~/holberton/w/hackthevm1$ ./main.py
b'Holberton'

这时main.py阻塞在语句sys.stdin.read(1)上,一直在等待用户输入。

接下来我们用管理员权限执行脚本read_write_heap.py

julien@holberton:~/holberton/w/hackthevm1$ ps aux | grep main.py | grep -v grep
julien     3929  0.0  0.7  31412  7848 pts/0    S+   15:10   0:00 python3 ./main.py
julien@holberton:~/holberton/w/hackthevm1$ sudo ./read_write_heap.py 3929 Holberton "~ Betty ~"
[*] maps: /proc/3929/maps
[*] mem: /proc/3929/mem
[*] Found [heap]:pathname = [heap]addresses = 022dc000-023c6000permisions = rw-poffset = 00000000inode = 0Addr start [22dc000] | end [23c6000]
[*] Found 'Holberton' at 8e192
[*] Writing '~ Betty ~' at 236a192
julien@holberton:~/holberton/w/hackthevm1$

不出所料,我们在堆上找到了字符串Holberton并且将之替换成’~ Betty ~’。
现在我们按下回车键让脚本main.py继续执行,它应该会输出b'~ Betty ~'

b'Holberton'
julien@holberton:~/holberton/w/hackthevm1$

什么???

我们找到字符串Holberton并且替换了它,但是这不是我们要找的字符串?继续深入探究之前,我们需要再确认一件事情。我们的脚本read_write_heap.py在目标字符串首次出现之后就退出了,如果堆中有多个字符串Holberton呢?为了避免遗漏,我们将脚本read_write_heap.py执行多次。

还是先启动脚本main.py

julien@holberton:~/holberton/w/hackthevm1$ ./main.py
b'Holberton'

然后多次执行脚本read_write_heap.py

julien@holberton:~/holberton/w/hackthevm1$ ps aux | grep main.py | grep -v grep
julien     4051  0.1  0.7  31412  7832 pts/0    S+   15:53   0:00 python3 ./main.py
julien@holberton:~/holberton/w/hackthevm1$ sudo ./read_write_heap.py 4051 Holberton "~ Betty ~"
[*] maps: /proc/4051/maps
[*] mem: /proc/4051/mem
[*] Found [heap]:pathname = [heap]addresses = 00bf4000-00cde000permisions = rw-poffset = 00000000inode = 0Addr start [bf4000] | end [cde000]
[*] Found 'Holberton' at 8e162
[*] Writing '~ Betty ~' at c82162
julien@holberton:~/holberton/w/hackthevm1$ sudo ./read_write_heap.py 4051 Holberton "~ Betty ~"
[*] maps: /proc/4051/maps
[*] mem: /proc/4051/mem
[*] Found [heap]:pathname = [heap]addresses = 00bf4000-00cde000permisions = rw-poffset = 00000000inode = 0Addr start [bf4000] | end [cde000]
Can't find 'Holberton'
julien@holberton:~/holberton/w/hackthevm1$

字符串’Holberton’在堆上只出现了一次。那么脚本main.py所使用的字符串’Holberton’到底在哪里呢?Python的字节对象又是在内存的哪部分呢?有没有可能在栈上?我们可以把脚本read_write_heap.py中的[heap]改成[stack]试试看。

提示:文件/proc/[pid]/maps中标记为[stack]的部分就是栈, 具体可参阅上一篇文件《虚拟内存探究 – 第一篇:C strings & /proc》。

改写栈的脚本read_write_stack.py如下, 它所做的和之前的脚本read_write_heap.py一样,唯一的不同是它访问进程的栈:

#!/usr/bin/env python3
'''
Locates and replaces the first occurrence of a string in the stack
of a processUsage: ./read_write_stack.py PID search_string replace_by_string
Where:
- PID is the pid of the target process
- search_string is the ASCII string you are looking to overwrite
- replace_by_string is the ASCII string you want to replace
search_string with
'''import sysdef print_usage_and_exit(): print('Usage: {} pid search write'.format(sys.argv[0])) sys.exit(1) # check usage if len(sys.argv) != 4: print_usage_and_exit() # get the pid from args pid = int(sys.argv[1]) if pid <= 0: print_usage_and_exit() search_string = str(sys.argv[2]) if search_string == "": print_usage_and_exit() write_string = str(sys.argv[3]) if search_string == "": print_usage_and_exit() # open the maps and mem files of the process maps_filename = "/proc/{}/maps".format(pid) print("[*] maps: {}".format(maps_filename)) mem_filename = "/proc/{}/mem".format(pid) print("[*] mem: {}".format(mem_filename)) # try opening the maps file try: maps_file = open('/proc/{}/maps'.format(pid), 'r') except IOError as e: print("[ERROR] Can not open file {}:".format(maps_filename)) print(" I/O error({}): {}".format(e.errno, e.strerror)) sys.exit(1) for line in maps_file: sline = line.split(' ') # check if we found the stack if sline[-1][:-1] != "[stack]": continue print("[*] Found [stack]:") # parse line addr = sline[0] perm = sline[1] offset = sline[2] device = sline[3] inode = sline[4] pathname = sline[-1][:-1

转载于:https://www.cnblogs.com/jinanxiaolaohu/p/10917729.html

[转帖]虚拟内存探究 -- 第二篇:Python 字节相关推荐

  1. 九、给小白看的第二篇Python基础教程

    本文是第二篇 @Author:Runsen @Date:Writern By 2019/04/15 and supplied By 2020/3/31 @公众号:Python之王 本系列Python基 ...

  2. 第二篇python安装(1)

    python初学基础篇 1 嗨喽!各位观看我文章的大佬们,我是你们没事就喜欢折腾自己来玩的小可爱~~ 我又回来继续更新啦,虽然出了点小问题导致我周六周日没有更新,但是我坚挺的又出现在你们的面前,好啦, ...

  3. 第二篇 Python图片处理模块PIL(pillow)

    本篇包含:16.Point    17.Putalpha    18.Putdata    19.Putpalette    20.Putpixel      21.Quantize     22.R ...

  4. 第二篇 python基础知识总结:数据、运算符

    引子 我们跟任何人交流,说的每一句都是都一些文字组成,包含名词.动词.语句.标点符号等,组成我们说普通话构成的基本要素.同理我们学习python语言也要明白这些基本要素,也就是我们常说的基本语法,这是 ...

  5. 第二篇 Python数据类型、字符编码、文件处理

    一.引子 1.什么是数据? x=10,10是我们要存储的数据 2.为何数据要分不同的类型 数据是用来表示状态的,不同的状态就应该用不同的类型的数据去表示 3.数据类型的分类 数字(×××,长×××,浮 ...

  6. Python 学习笔记 第三篇 Python实现网易云评论网页爬虫+词云展示 (Pycharm+Mysql)

    初始条件,具体可见我的其他文章. 1.安装Python.Python 学习笔记 第一篇 Python的安装与配置 2.安装Pycharm,并导入第三方包.Python 学习笔记 第二篇 Python ...

  7. 初学Python——文件操作第二篇

    前言:为什么需要第二篇文件操作?因为第一篇的知识根本不足以支撑基本的需求.下面来一一分析. 一.Python文件操作的特点 首先来类比一下,作为高级编程语言的始祖,C语言如何对文件进行操作? 字符(串 ...

  8. Python开发【第二篇】:初识Python

    Python开发[第二篇]:初识Python Python简介 Python前世今生 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为 ...

  9. python定义一个整数变量a_第二篇.1、python基础之数据类型与变量

    一.变量 1 什么是变量之声明变量 #变量名=变量值 age=18 gender1='male' gender2='female' 2 为什么要有变量 变量作用:"变"=>变 ...

最新文章

  1. php mysql八大动态w...,PHP+MySQL八大动态Web应用实战
  2. java 快速io_java 最快的input (ACM) Java高效IO
  3. 【Win10 应用开发】扫描和连接Wi-fi网络
  4. [转载] PYTHON 字符串转换为二进制字符串,二进制字符串转换为字符串
  5. linux脚本定义量,Linux上增加自定义脚本的展现量
  6. 【语音编码】基于matlab LPC编解码【含Matlab源码 554期】
  7. webtrends 分析
  8. 计算机网络实验——ns3仿真最短路由选择算法
  9. 1MB是多少字节 ?是多少位?
  10. 以下sum函数用来求a,b两数的和,在主函数中输入两个数并调用sum函数求其和。
  11. linux下kegg注释软件,网页工具KOBAS进行KEGG富集分析
  12. C++ endian转换
  13. 如何用python爬取图片数据_python爬虫怎么实现爬取网站图片?
  14. 【题解】二进制优化的多重背包问题
  15. 飞秋下载 官方唯一的下载地址
  16. 驻点运维人员被客户投诉要求换人,换还是不换?
  17. m3u8转MP4 视频最最有效的办法!!!!!!!
  18. php mysql某小型汽车维修店信息管理系统zjyY3
  19. HDU - 1253 胜利大逃亡 BFS
  20. 从零开始的WordPress个人博客搭建

热门文章

  1. firefox设置代理服务器
  2. hadoop yarn的三种资源调度器详解
  3. Geospark从Shapefile中加载RDD
  4. Java IO模型:BIO NIO AIO及netty介绍
  5. session共享怎么做的(分布式如何实现session共享)?
  6. oracle数据库创建
  7. centos7.9更改root账号密码
  8. Vivado 自定义VHDL的IP核
  9. js实现按下删除键清空文本框内容
  10. 2.1.4 进程之间的通信(共享通信、消息传递、管道通信)