Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PythoNN: Василий Рябов – "Парсинг бинарных данн...

PythoNN: Василий Рябов – "Парсинг бинарных данных с помощью ctypes, или пишем на питоне как на Си"

Sobolev Nikita

July 22, 2023

Transcript

46 slides
  1. Парсинг бинарных данных, или пишем на Python как на C

    Василий Рябов, Huawei, Нижний Новгород PythoNN meetup #1 14 июля 2023
  2. С_одержимое • Как не надо делать! (а по рукам?) •

    Как надо/можно делать (сахарок) • чистый Python • Python зовёт C • Python зовёт C++ • Python берёт C++ к себе • Какое оно внутри?
  3. Примеры прикладных задач • Обновить прошивку на флешке устройства •

    прочитать, изменить некоторые поля, записать обратно • Распарсить сетевой пакет: TCP/IP стек или свой протокол • хотя есть scapy ☺ • Сериализация/десериализация при плотной упаковке бит • Реверс инжиниринг / security checkers
  4. Разбор ELF файла • ELF – Executable & Linkable Format

    (Linux) • .exe • .o • .so, .ko, .mod • core dump
  5. Разбор ELF файла # readelf -h /usr/bin/python3 ELF Header: Magic:

    7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Position-Independent Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 ...
  6. А по-русски? • Порядок байт: • little-endian • big-endian •

    сетевой – это какой из них? • ABI – Application Binary Interface (почти как API, только жёстче)
  7. Как надо/можно делать (чистый Python) magic = b'\x7fELF’ elf_class =

    2 endianness = little-endian (1) elf_version = 1 os_abi = UNIX System V ABI (0)
  8. Как надо/можно делать (чистый Python) magic = b'\x7fELF’ elf_class =

    2 endianness = little-endian (1) elf_version = 1 os_abi = UNIX System V ABI (0)
  9. Как надо/можно делать (чистый Python) • Плюсы: • отладка на

    чистом Python • не зависим от версии Python и внешних библиотек • нет магических чисел и букв • Минусы: • если есть готовый C код, нужно его переписать на Python • ctypes.LittleEndianStructure • ctypes.BigEndianStructure
  10. Python зовёт С • Зовём готовый C код из бинарной

    библиотеки (.dll, .so) <_FuncPtr object at 0x7f66834831c0>
  11. Python зовёт С • Зовём готовый C код из бинарной

    библиотеки (.dll, .so) <_FuncPtr object at 0x7f66834831c0> readelf -Ws /usr/lib/x86_64-linux-gnu/libelf-0.186.so
  12. Python зовёт С • Зовём готовый C код из бинарной

    библиотеки (.dll, .so) <_FuncPtr object at 0x7f66834831c0> readelf -Ws /usr/lib/x86_64-linux-gnu/libelf-0.186.so • Для Windows есть Dependency Walker
  13. Python зовёт С • Компилируем готовый C код, обёрнутый в

    PyObject*, и зовём • .pyd / .so --> импортим как обычный Python модуль
  14. Python зовёт С++ • pybind11 (в LLVM это 556 строк:

    4 класса, 11 type casters) • Boost-Python (Boost – слишком большой) • SWIG (.i или .swig --> .c) (в LLVM это ~2K+ строк) • Все требуют компиляции для нескольких версий Python • Желательно создание .whl файлов (колёс) для PyPI
  15. Python зовёт С++ (pybind11) #include <pybind11/pybind11.h> int add(int i, int

    j) { return i + j; } namespace py = pybind11; PYBIND11_MODULE(cmake_example, m) { m.doc() = R"pbdoc(Pybind11 example plugin)pbdoc"); m.def("add", &add, R"pbdoc(Add two numbers)pbdoc"); }
  16. Python берёт C++ к себе • cppyy (си-пи-пи вай-вай!) •

    pip install cppyy • cppyy <-- cling (just-in-time, JIT) <-- clang (ahead-of-time, AOT) <-- LLVM • Из чистого Python можно: • #include <elf.h> • загрузить .c / .cpp файл • выполнить произвольное С/С++ выражение • Результат можно использовать в чистом Python
  17. Python берёт C++ к себе • cppyy (си-пи-пи вай-вай!) •

    pip install cppyy • cppyy <-- cling (just-in-time, JIT) <-- clang (ahead-of-time, AOT) <-- LLVM • Из чистого Python можно: • #include <elf.h> • загрузить .c / .cpp файл • выполнить произвольное С/С++ выражение • Результат можно использовать в чистом Python
  18. cppyy (что он умеет?) • Видит: • typedef’ы • классы

    • структуры • enum’ы • namespace’ы • template’ы • функции и методы • Не видит: • ни один #define  весит порядка 150 Мб
  19. Разбор ELF файла через cppyy e_ehsize = 64 e_entry =

    2273792 e_flags = 0 e_ident = <cppyy.LowLevelView object at 0x7f727c9527b0> e_machine = 62 e_phentsize = 56 e_phnum = 13 e_phoff = 64 e_shentsize = 64 e_shnum = 34 e_shoff = 5910760 e_shstrndx = 33 e_type = 3 e_version = 1
  20. Какое оно внутри? • ctypes – это только преобразование типов

    • сигнатура функции • libffi : FFI == Foreign Function Interface (на чистом C) • конвенция вызовов (calling convention) в рантайме • __cdecl • __stdcall • __fastcall (MSVC != clang) • …
  21. Так вот ты какой, ABI… • список экспортированных функций в

    .so файле • сигнатуры функций • конвенция вызовов • С++ name mangling (правило обезображивания имён) • exception propagation

More Decks by Sobolev Nikita

Other Decks in Programming