Python打印环境变量内存地址

时间:2016-06-09 12:24:29

标签: python ruby memory environment-variables

是否可以打印我的环境变量内存地址?

使用gdb-peda我的内存地址看起来像0xbffffcd6 searchmem,我知道它是正确的形式。 (0xbfff????)但gdb使用其他一些环境变量移动了堆栈。

我想用我的python脚本获取这个地址然后做我的技巧并包含我的shellcode。

我试过(使用Python):

print hex(id(os.environ["ENVVAR"]))
print memoryview(os.environ["ENVVAR"])

# output :
# 0xb7b205c0L
# <memory at 0xb7b4dd9c>

使用Ruby:

puts (ENV['PATH'].object_id << 1).to_s(16)
# output :
# -4836c38c

如果有人有想法,可以使用python或ruby。

7 个答案:

答案 0 :(得分:4)

cpython内置函数id()为任何对象返回一个唯一的id,这不是它的内存地址,但是尽可能接近它。

例如,我们有变量x。 id(x)不返回变量x的内存地址,而是返回x指向的对象的内存地址。

&#39;变量&#39;之间存在严格的分离。和&#39;记忆对象&#39;。在标准实现中,python为虚拟机分配一组本地和一个堆栈以进行操作。所有本地插槽都是不相交的,因此如果您将一个对象从本地插槽x加载到堆栈并修改该对象,那么&#34; location&#34; x槽的变化并没有改变。

enter image description here http://docs.python.org/library/functions.html#id

答案 1 :(得分:3)

至少在python中,这似乎是一项不可能完成的任务。 从这个问题中可以考虑的事情很少:

  • ASLR会让这完全不可能
  • 每个二进制文件都有它自己的开销,不同的argv,所以,唯一可靠的选择是执行二进制文件并跟踪它的内存,直到我们找到我们正在寻找的环境变量。基本上,即使我们可以在python进程中找到环境地址,它也会在你试图利用的二进制文件中处于不同的位置。

最适合回答这个问题的方法是使用http://python3-pwntools.readthedocs.io/en/latest/elf.html来获取coredump文件,以便于查找地址。

答案 2 :(得分:3)

我想你可以使用ctypes模块直接调用本地getenv

import ctypes

libc = ctypes.CDLL("libc.so.6")

getenv = libc.getenv
getenv.restype = ctypes.c_voidp

print('%08x' % getenv('PATH'))

答案 3 :(得分:2)

请记住,系统环境变量不是您可以通过其内存地址访问的对象。每个进程,如运行脚本的Python或Ruby进程,都将获得自己的环境副本。这就是为什么Python和Ruby解释器返回的结果是如此不同。

如果要修改系统环境变量,则应使用编程语言提供的API。 有关Python解决方案,请参阅thisthat帖子。

答案 4 :(得分:1)

  

getenv()函数本质上不可重入,因为它返回一个指向静态数据的值。

     

实际上,为了提高getenv()的性能,实现还可以在数据结构中维护单独的环境副本,以便更快地搜索(例如索引哈希表或二叉树),并在调用setenv()或unsetenv()时更新它和environ中的线性列表。

因此getenv返回的地址不一定来自环境。

处理内存布局;

http://static.duartes.org/img/blogPosts/linuxFlexibleAddressSpaceLayout.png

http://d1gjlxt8vb0knt.cloudfront.net//wp-content/uploads/Memory-Layout-300x255.gif

记忆图

import os

def mem_map():
    path_hex = hex(id(os.getenv('PATH'))).rstrip('L')
    path_address = int(path_hex, 16)
    for line in open('/proc/self/maps'):
        if 'stack' in line:
            line = line.split()
            first, second = line[0].split('-')
            first, second = int(first, 16), int(second, 16)
            #stack grows towards lower memory address
            start, end = max(first, second), min(first, second)
            print('stack:\n\tstart:\t0x{}\n\tend:\t0x{}\n\tsize:\t{}'.format(start, end, start - end))
            if path_address in range(end, start+1):
                print('\tgetenv("PATH") ({}) is in the stack'.format(path_hex))
            else:
                print('\tgetenv("PATH") ({}) is not in the stack'.format(path_hex))
            if path_address > start:
                print('\tgetenv("PATH") ({}) is above the stack'.format(path_hex))
            else:
                print('\tgetenv("PATH") ({}) is not above the stack'.format(path_hex))
            print('')
            continue
        if 'heap' in line:
            line = line.split()
            first, second = line[0].split('-')
            first, second  = int(first, 16), int(second, 16)
            #heap grows towards higher memory address
            start, end = min(first, second), max(first, second)
            print('heap:\n\tstart:\t0x{}\n\tend:\t0x{}\n\tsize:\t{}'.format(start, end, end - start))
            if path_address in range(start, end+1):
                print('\tgetenv("PATH") ({}) in the heap'.format(path_hex))
            else:
                print('\tgetenv("PATH") ({}) is not in the heap'.format(path_hex))
            print('')

输出;

heap:
        start:  0x170364928
        end:    0x170930176
        size:   565248
        getenv("PATH") (0xb74d2330) is not in the heap

stack:
        start:  0x0xbffa8000L
        end:    0x0xbff86000L
        size:   139264
        getenv("PATH") (0xb74d2330) is not in the stack
        getenv("PATH") (0xb74d2330) is not above the stack

环境在堆栈之上。所以它的地址应该高于堆栈。但地址id显示不在堆栈中,不在堆中而不在堆栈上方。这真的是一个地址吗?或者我的计算错了!

这里是检查对象在内存中的位置的代码。

def where_in_mem(obj):
    maps = {}
    for line in open('/proc/self/maps'):
        line = line.split()
        start, end = line[0].split('-')

        key = line[-1] if line[-1] != '0' else 'anonymous'
        maps.setdefault(key, []).append((int(start, 16), int(end, 16)))

    for key, pair in maps.items():
        for start, end in pair:
            # stack starts at higher memory address and grows towards lower memory address
            if 'stack' in key:
                if start >= id(obj) >= end:
                    print('Object "{}" ({}) in the range {} - {}, mapped to {}'.format(obj, hex(id(obj)), hex(start), hex(end), key))
                    continue
            if start <= id(obj) <= end:
                print('Object "{}" ({}) in the range {} - {}, mapped to {}'.format(obj, hex(id(obj)), hex(start), hex(end), key))

where_in_mem(1)
where_in_mem(os.getenv('PATH'))

输出;

Object "1" (0xa17f8b0) in the range 0xa173000 - 0xa1fd000, mapped to [heap]
Object "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games" (0xb74a1330L) in the range 0xb7414000L - 0xb74d6000L, mapped to anonymous

上述输出中的匿名是什么?

  

还可以创建与任何文件不对应的匿名内存映射,而不是用于程序数据。在Linux中,如果通过malloc()请求大块内存,C库将创建这样的匿名映射,而不是使用堆内存。 “大”意味着大于MMAP_THRESHOLD字节,默认为128 kB,可通过mallopt()调整。

Anatomy of a Program in Memory

因此os.environ['PATH']位于malloc ed区域。

答案 5 :(得分:1)

感谢@ mickael9,我编写了一个函数来计算程序中环境变量的地址:

def getEnvAddr(envName, ELFfile):
  import ctypes
  libc = ctypes.CDLL('libc.so.6')
  getenv = libc.getenv
  getenv.restype = ctypes.c_voidp

  ptr = getenv(envName)
  ptr += (len('/usr/bin/python') - len(ELFfile)) * 2
  return ptr

例如:

user@host:~$ ./getenvaddr.elf PATH /bin/ls
PATH will be at 0xbfffff22 in /bin/ls
user@host:~$ python getenvaddr.py PATH /bin/ls
PATH will be at 0xbfffff22 in /bin/ls
user@host:~$

注意:此功能仅适用于Linux系统。

答案 6 :(得分:-1)

在红宝石中它是可能的 - 这篇文章涵盖了一般情况: Accessing objects memory address in ruby..?“你可以通过获取对象id来获取对象的实际指针值,然后按位向左移动”

puts (ENV['RAILS_ENV'].object_id << 1).to_s(16)
> 7f84598a8d58