从 python 中读取存储在绝对内存地址中的值
Reading value stored in absolute memory address from python
我用作弊器找了一个绝对地址(见下图)
Memory address
现在我想知道如何从地址“0x14340A654”读取值“1”
我试着在 Whosebug 上找到相同的东西,这就是我能收集到的。
from ctypes import string_at
from sys import getsizeof
from binascii import hexlify
a = 0x14340A654
print(hexlify(string_at(id(a), getsizeof(a))))
但是这个returns有些乱七八糟的
b'030000000000000010bcabf2f87f0000020000000000000054a6400305000000'
code.py:
#!/usr/bin/env python3
import sys
import ctypes
def get_long_data(long_obj):
py_obj_header_size = sys.getsizeof(0)
number_size = sys.getsizeof(long_obj) - py_obj_header_size
number_address = id(long_obj) + py_obj_header_size
return number_address, number_size, long_obj < 0
def hex_repr(number, size=0):
format_base = "0x{{:0{:d}X}}".format(size)
if number < 0:
return ("-" + format_base).format(-number)
else:
return format_base.format(number)
def main():
numbers = [0x00,
0x01,
-0x01,
0xFF,
0xFFFF,
0x00FFFFFF,
0x12345678,
0x3FFFFFFF,
0x40000000,
0x1111111111
]
for number in numbers:
address, size, negative = get_long_data(number)
print("Number: {:s}".format(hex_repr(number, size), size, negative))
buf = ctypes.string_at(address, size)
print(" Address: {:s}, Size: {:d}, Negative: {:},\n Data: {:}".format(hex_repr(address, size=16), size, negative, buf))
print(" ({:d}).to_bytes(): {:}".format(number, number.to_bytes(size, sys.byteorder, signed=(number < 0))))
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
备注:
- get_long_data 是完成工作的函数(其他一切仅用于显示/测试目的)
- 单独的地址有点无用(如果想要能够重建数字),这就是返回大小(以字节为单位)和数字符号的原因
代码依赖[Python 3]: PyLongObject's structure (most of int functionality is located in [GitHub]: python/cpython - (master) cpython/Objects/longobject.c)。下面是它的定义:
struct _longobject {
PyObject_VAR_HEAD
digit ob_digit[1];
};
- 末尾的数组保存实际数值(这就是为什么 Python 中的数字可以变得如此之大)
- 仅适用于0,
sys.getsizeof
returnsPyObject_VAR_HEAD的大小,用于获取结构体内部的数组偏移
- [Python 3]: int.to_bytes(length, byteorder, *, signed=False) 用于验证,但请注意它会匹配我们的输出 只有当 :
0 <= n < 2 ** 30
(该方法对数组内容做了一些处理,并没有直接将原始数据存储到返回的字节流中)
- 可见字节在输出缓冲区(0x12345678[=54]中颠倒了(4byte) =] 是最 eloquent 的例子),与数字的 hex 表示法相比;这是因为 little endianness(可以查看 [SO]: Python struct.pack() behavior (@CristiFati's answer) 了解更多详情)
输出:
(py35x64_test) e:\Work\Dev\Whosebug\q053657865>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py
Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32
Number: 0x0
Address: 0x0000000074C55318, Size: 0, Negative: False,
Data: b''
(0).to_bytes(): b''
Number: 0x0001
Address: 0x0000000074C55338, Size: 4, Negative: False,
Data: b'\x01\x00\x00\x00'
(1).to_bytes(): b'\x01\x00\x00\x00'
Number: -0x0001
Address: 0x0000000074C552F8, Size: 4, Negative: True,
Data: b'\x01\x00\x00\x00'
(-1).to_bytes(): b'\xff\xff\xff\xff'
Number: 0x00FF
Address: 0x0000000074C572F8, Size: 4, Negative: False,
Data: b'\xff\x00\x00\x00'
(255).to_bytes(): b'\xff\x00\x00\x00'
Number: 0xFFFF
Address: 0x0000023286E3A6C8, Size: 4, Negative: False,
Data: b'\xff\xff\x00\x00'
(65535).to_bytes(): b'\xff\xff\x00\x00'
Number: 0xFFFFFF
Address: 0x0000023286C14FA8, Size: 4, Negative: False,
Data: b'\xff\xff\xff\x00'
(16777215).to_bytes(): b'\xff\xff\xff\x00'
Number: 0x12345678
Address: 0x0000023286DE4E88, Size: 4, Negative: False,
Data: b'xV4\x12'
(305419896).to_bytes(): b'xV4\x12'
Number: 0x3FFFFFFF
Address: 0x000002328710C128, Size: 4, Negative: False,
Data: b'\xff\xff\xff?'
(1073741823).to_bytes(): b'\xff\xff\xff?'
Number: 0x40000000
Address: 0x000002328710C108, Size: 8, Negative: False,
Data: b'\x00\x00\x00\x00\x01\x00\x00\x00'
(1073741824).to_bytes(): b'\x00\x00\x00@\x00\x00\x00\x00'
Number: 0x1111111111
Address: 0x000002328710C148, Size: 8, Negative: False,
Data: b'\x11\x11\x11\x11D\x00\x00\x00'
(73300775185).to_bytes(): b'\x11\x11\x11\x11\x11\x00\x00\x00'
我用作弊器找了一个绝对地址(见下图) Memory address
现在我想知道如何从地址“0x14340A654”读取值“1”
我试着在 Whosebug 上找到相同的东西,这就是我能收集到的。
from ctypes import string_at
from sys import getsizeof
from binascii import hexlify
a = 0x14340A654
print(hexlify(string_at(id(a), getsizeof(a))))
但是这个returns有些乱七八糟的
b'030000000000000010bcabf2f87f0000020000000000000054a6400305000000'
code.py:
#!/usr/bin/env python3
import sys
import ctypes
def get_long_data(long_obj):
py_obj_header_size = sys.getsizeof(0)
number_size = sys.getsizeof(long_obj) - py_obj_header_size
number_address = id(long_obj) + py_obj_header_size
return number_address, number_size, long_obj < 0
def hex_repr(number, size=0):
format_base = "0x{{:0{:d}X}}".format(size)
if number < 0:
return ("-" + format_base).format(-number)
else:
return format_base.format(number)
def main():
numbers = [0x00,
0x01,
-0x01,
0xFF,
0xFFFF,
0x00FFFFFF,
0x12345678,
0x3FFFFFFF,
0x40000000,
0x1111111111
]
for number in numbers:
address, size, negative = get_long_data(number)
print("Number: {:s}".format(hex_repr(number, size), size, negative))
buf = ctypes.string_at(address, size)
print(" Address: {:s}, Size: {:d}, Negative: {:},\n Data: {:}".format(hex_repr(address, size=16), size, negative, buf))
print(" ({:d}).to_bytes(): {:}".format(number, number.to_bytes(size, sys.byteorder, signed=(number < 0))))
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
备注:
- get_long_data 是完成工作的函数(其他一切仅用于显示/测试目的)
- 单独的地址有点无用(如果想要能够重建数字),这就是返回大小(以字节为单位)和数字符号的原因
代码依赖[Python 3]: PyLongObject's structure (most of int functionality is located in [GitHub]: python/cpython - (master) cpython/Objects/longobject.c)。下面是它的定义:
struct _longobject { PyObject_VAR_HEAD digit ob_digit[1]; };
- 末尾的数组保存实际数值(这就是为什么 Python 中的数字可以变得如此之大)
- 仅适用于0,
sys.getsizeof
returnsPyObject_VAR_HEAD的大小,用于获取结构体内部的数组偏移
- [Python 3]: int.to_bytes(length, byteorder, *, signed=False) 用于验证,但请注意它会匹配我们的输出 只有当 :
0 <= n < 2 ** 30
(该方法对数组内容做了一些处理,并没有直接将原始数据存储到返回的字节流中) - 可见字节在输出缓冲区(0x12345678[=54]中颠倒了(4byte) =] 是最 eloquent 的例子),与数字的 hex 表示法相比;这是因为 little endianness(可以查看 [SO]: Python struct.pack() behavior (@CristiFati's answer) 了解更多详情)
输出:
(py35x64_test) e:\Work\Dev\Whosebug\q053657865>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32 Number: 0x0 Address: 0x0000000074C55318, Size: 0, Negative: False, Data: b'' (0).to_bytes(): b'' Number: 0x0001 Address: 0x0000000074C55338, Size: 4, Negative: False, Data: b'\x01\x00\x00\x00' (1).to_bytes(): b'\x01\x00\x00\x00' Number: -0x0001 Address: 0x0000000074C552F8, Size: 4, Negative: True, Data: b'\x01\x00\x00\x00' (-1).to_bytes(): b'\xff\xff\xff\xff' Number: 0x00FF Address: 0x0000000074C572F8, Size: 4, Negative: False, Data: b'\xff\x00\x00\x00' (255).to_bytes(): b'\xff\x00\x00\x00' Number: 0xFFFF Address: 0x0000023286E3A6C8, Size: 4, Negative: False, Data: b'\xff\xff\x00\x00' (65535).to_bytes(): b'\xff\xff\x00\x00' Number: 0xFFFFFF Address: 0x0000023286C14FA8, Size: 4, Negative: False, Data: b'\xff\xff\xff\x00' (16777215).to_bytes(): b'\xff\xff\xff\x00' Number: 0x12345678 Address: 0x0000023286DE4E88, Size: 4, Negative: False, Data: b'xV4\x12' (305419896).to_bytes(): b'xV4\x12' Number: 0x3FFFFFFF Address: 0x000002328710C128, Size: 4, Negative: False, Data: b'\xff\xff\xff?' (1073741823).to_bytes(): b'\xff\xff\xff?' Number: 0x40000000 Address: 0x000002328710C108, Size: 8, Negative: False, Data: b'\x00\x00\x00\x00\x01\x00\x00\x00' (1073741824).to_bytes(): b'\x00\x00\x00@\x00\x00\x00\x00' Number: 0x1111111111 Address: 0x000002328710C148, Size: 8, Negative: False, Data: b'\x11\x11\x11\x11D\x00\x00\x00' (73300775185).to_bytes(): b'\x11\x11\x11\x11\x11\x00\x00\x00'