Python ctypes и вызовы функции

Просмотрите Class.contextType для доступа к контексту в методах класса.

7
задан Cheery 9 November 2008 в 08:56
поделиться

5 ответов

Как vincent упомянутый, это происходит из-за выделенной страницы, отмечаемой как не исполняемый файл. Более новые процессоры поддерживают эту функциональность и ее используемые в качестве добавленного уровня безопасности ОС, которые поддерживают его. Идея состоит в том, чтобы защитить от определенных атак переполнения буфера. Например, общее нападение должно переполнить переменной стека, переписывание обратного адреса для указания для кодирования Вас вставило. С неисполняемым стеком это теперь только производит segfault, а не управление процесса. Подобные нападения также существуют для памяти "кучи".

Для обхождения его необходимо изменить защиту. Это может только быть выполнено на выровненной памяти страницы, таким образом, необходимо будет, вероятно, изменить код на что-то как ниже:

libc = CDLL('libc.so')

# Some constants
PROT_READ = 1
PROT_WRITE = 2
PROT_EXEC = 4

def executable_code(buffer):
    """Return a pointer to a page-aligned executable buffer filled in with the data of the string provided.
    The pointer should be freed with libc.free() when finished"""

    buf = c_char_p(buffer)
    size = len(buffer)
    # Need to align to a page boundary, so use valloc
    addr = libc.valloc(size)
    addr = c_void_p(addr)

    if 0 == addr:  
        raise Exception("Failed to allocate memory")

    memmove(addr, buf, size)
    if 0 != libc.mprotect(addr, len(buffer), PROT_READ | PROT_WRITE | PROT_EXEC):
        raise Exception("Failed to set protection on buffer")
    return addr

code_ptr = executable_code(buffer)
fptr = cast(code_ptr, CFUNCTYPE(c_long, c_long))
print fptr(1234)
libc.free(code_ptr)

Примечание: Это может быть хорошая идея сбросить исполняемый флаг прежде, чем освободить страницу. Библиотеки Most C на самом деле не возвращают память ОС при выполнении но сохраните ее в их собственном пуле. Это могло означать, что они снова используют страницу в другом месте, не очищая ИСПОЛНИТЕЛЬНЫЙ бит, обходя преимущество безопасности.

Также обратите внимание, что это довольно непортативно. Я протестировал его на Linux, но не на любой другой ОС. Это не будет работать над окнами, покупка может сделать на другом unixes (BSD, OsX?).

8
ответ дан 6 December 2019 в 10:04
поделиться

Проведенный некоторое исследование с моим другом и узнанный это - конкретный вопрос платформы. Мы подозреваем, что на некоторых платформах malloc mmaps память без PROT_EXEC и на других это делает.

Поэтому необходимо изменить уровень защиты с mprotect впоследствии.

Хромая вещь, требовал времени для обнаружения, что сделать.

from ctypes import (
    cast, CFUNCTYPE, c_long, sizeof, addressof, create_string_buffer, pythonapi
)

PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC = 0, 1, 2, 4
mprotect = pythonapi.mprotect

buffer = ''.join(map(chr, [ #0000000000000000 <add>:
    0x55,                     # push   %rbp
    0x48, 0x89, 0xe5,         # mov    %rsp,%rbp
    0x48, 0x89, 0x7d, 0xf8,   # mov    %rdi,-0x8(%rbp)
    0x48, 0x8b, 0x45, 0xf8,   # mov    -0x8(%rbp),%rax
    0x48, 0x83, 0xc0, 0x0a,   # add    $0xa,%rax
    0xc9,                     # leaveq 
    0xc3,                     # retq
]))

pagesize = pythonapi.getpagesize()
cbuffer = create_string_buffer(buffer)#c_char_p(buffer)
addr = addressof(cbuffer)
size = sizeof(cbuffer)
mask = pagesize - 1
if mprotect(~mask&addr, mask&addr + size, PROT_READ|PROT_WRITE|PROT_EXEC) < 0:
    print "mprotect failed?"
else:
    fptr = cast(cbuffer, CFUNCTYPE(c_long, c_long))
    print repr(fptr(1234))
7
ответ дан 6 December 2019 в 10:04
поделиться

Я думаю, что Вы не можете свободно выполнить выделенную память без первой установки его как исполняемый файл. Я никогда не судил меня, но Вы могли бы хотеть проверить функцию Unix mprotect:

http://linux.about.com/library/cmd/blcmdl2_mprotect.htm

VirtualProtect кажется, делает то же самое на окнах:

http://msdn.microsoft.com/en-us/library/aa366898 (По сравнению с 85) .aspx

4
ответ дан 6 December 2019 в 10:04
поделиться

Python даже позволяет такое использование? Я должен изучить это затем...

Я думаю, что интерпретатор не ожидает, что любой регистр будет изменен. Попытайтесь сохранить регистры, которые Вы используете в функции, если Вы планируете использовать свой ассемблерный вывод как это.

Btw, звоните, конвенция x86_64 отличается, чем регулярный x86. Можно испытать затруднения, если Вы теряете выравнивание указателя вершины стека и смешиваете внешние объекты, сгенерированные с другими инструментами.

0
ответ дан 6 December 2019 в 10:04
поделиться

Я придумал только более простой подход, но недавно он не включает mprotect. Просто mmap исполняемое пространство для программы напрямую. В наши дни у python есть модуль для этого, хотя я не нашел способа получить адрес кода. Короче говоря, вы должны выделить память, вызывая mmap, вместо использования строковых буферов и косвенной установки флага выполнения. Это проще и безопаснее, вы можете быть уверены, что только ваш код может быть выполнен сейчас.

0
ответ дан 6 December 2019 в 10:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: