Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
miasm — Фреймворк для реверс-инжиниринга на Python | Kitploit
Инструменты/GitHubGitHub/cea-sec/miasm
Статический анализДинамический анализ (песочница)Обратная инженерияОтладчикиФаззингАнализ Бинарных Файлов
GitHubcea-sec/miasm

miasm

Фреймворк для реверс-инжиниринга на Python

Репозиторий
3.9k48910 дней назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
Сайт

Статус сборки Статус сборки Тесты Miasm Качество кода Присоединиться к чату на https://gitter.im/cea-sec/miasm

Что такое Miasm?

Miasm — это свободный фреймворк для обратной разработки с открытым исходным кодом (GPLv2). Miasm предназначен для анализа / модификации / генерации бинарных программ. Вот неисчерпывающий список возможностей:

  • Открытие / изменение / генерация PE / ELF 32 / 64 LE / BE
  • Ассемблирование / дизассемблирование X86 / ARM / MIPS / SH4 / MSP430
  • Представление семантики ассемблера с помощью промежуточного языка
  • Эмуляция с использованием JIT (динамический анализ кода, распаковка и т.д.)
  • Упрощение выражений для автоматической деобфускации
  • ...

Смотрите официальный блог для дополнительных примеров и демонстраций.

Содержание

  • Что такое Miasm?
  • Базовые примеры
    • Ассемблирование / Дизассемблирование
    • Промежуточное представление
    • Эмуляция
    • Символическое выполнение
  • Как это работает?
  • Документация
  • Получение Miasm
    • Системные требования
    • Конфигурация
    • Windows и IDA
  • Тестирование
  • Они уже используют Miasm
  • Разное

Базовые примеры

Ассемблирование / Дизассемблирование

Импорт архитектуры Miasm x86:```pycon

from miasm.arch.x86.arch import mn_x86 from miasm.core.locationdb import LocationDB

root@kitploit:~
Получить базу данных местоположений:```pycon
>>> loc_db = LocationDB()

Соберите строку:```pycon

l = mn_x86.fromstring('XOR ECX, ECX', loc_db, 32) print(l) XOR ECX, ECX mn_x86.asm(l) ['1\xc9', '3\xc9', 'g1\xc9', 'g3\xc9']

root@kitploit:~
Изменить операнд:```pycon
>>> l.args[0] = mn_x86.regs.EAX
>>> print(l)
XOR        EAX, ECX
>>> a = mn_x86.asm(l)
>>> print(a)
['1\xc8', '3\xc1', 'g1\xc8', 'g3\xc1']

Дизассемблировать результат:```pycon

print(mn_x86.dis(a[0], 32)) XOR EAX, ECX

root@kitploit:~
Использование абстракции `Machine`:```pycon
>>> from miasm.analysis.machine import Machine
>>> mn = Machine('x86_32').mn
>>> print(mn.dis('\x33\x30', 32))
XOR        ESI, DWORD PTR [EAX]

Для MIPS:```pycon

mn = Machine('mips32b').mn print(mn.dis(b'\x97\xa3\x00 ', "b")) LHU V1, 0x20(SP)

root@kitploit:~
Промежуточное представление
---------------------------

Создайте инструкцию:```pycon
>>> machine = Machine('arml')
>>> instr = machine.mn.dis('\x00 \x88\xe0', 'l')
>>> print(instr)
ADD        R2, R8, R0

Создать объект промежуточного представления:```pycon

lifter = machine.lifter_model_call(loc_db)

root@kitploit:~
Создать пустой ircfg:```pycon
>>> ircfg = lifter.new_ircfg()

Добавить инструкцию в пул:```pycon

lifter.add_instr_to_ircfg(instr, ircfg)

root@kitploit:~
Вывести текущий пул:```pycon
>>> for lbl, irblock in ircfg.blocks.items():
...     print(irblock)
loc_0:
R2 = R8 + R0

IRDst = loc_4

Работа с IR, например, путем получения побочных эффектов:```pycon

for lbl, irblock in ircfg.blocks.items(): ... for assignblk in irblock: ... rw = assignblk.get_rw() ... for dst, reads in rw.items(): ... print('read: ', [str(x) for x in reads]) ... print('written:', dst) ... print() ... read: ['R8', 'R0'] written: R2

read: [] written: IRDst

root@kitploit:~
Более подробная информация о Miasm IR находится в [соответствующем Jupyter Notebook](https://github.com/cea-sec/miasm/blob/master/doc/expression/expression.ipynb).

Эмуляция
---------

Предоставляя shellcode:```pycon
00000000 8d4904      lea    ecx, [ecx+0x4]
00000003 8d5b01      lea    ebx, [ebx+0x1]
00000006 80f901      cmp    cl, 0x1
00000009 7405        jz     0x10
0000000b 8d5bff      lea    ebx, [ebx-1]
0000000e eb03        jmp    0x13
00000010 8d5b01      lea    ebx, [ebx+0x1]
00000013 89d8        mov    eax, ebx
00000015 c3          ret
>>> s = b'\x8dI\x04\x8d[\x01\x80\xf9\x01t\x05\x8d[\xff\xeb\x03\x8d[\x01\x89\xd8\xc3'

Импортируйте шеллкод с помощью абстракции Container:```pycon

from miasm.analysis.binary import Container c = Container.from_string(s, loc_db) c <miasm.analysis.binary.ContainerUnknown object at 0x7f34cefe6090>

root@kitploit:~
Дизассемблирование shellcode по адресу `0`:```pycon
>>> from miasm.analysis.machine import Machine
>>> machine = Machine('x86_32')
>>> mdis = machine.dis_engine(c.bin_stream, loc_db=loc_db)
>>> asmcfg = mdis.dis_multiblock(0)
>>> for block in asmcfg.blocks:
...  print(block)
...
loc_0
LEA        ECX, DWORD PTR [ECX + 0x4]
LEA        EBX, DWORD PTR [EBX + 0x1]
CMP        CL, 0x1
JZ         loc_10
->      c_next:loc_b    c_to:loc_10
loc_10
LEA        EBX, DWORD PTR [EBX + 0x1]
->      c_next:loc_13
loc_b
LEA        EBX, DWORD PTR [EBX + 0xFFFFFFFF]
JMP        loc_13
->      c_to:loc_13
loc_13
MOV        EAX, EBX
RET

Инициализация JIT-движка со стеком:```pycon

jitter = machine.jitter(loc_db, jit_type='python') jitter.init_stack()

root@kitploit:~
Добавьте шелл-код в произвольное место в памяти:```pycon
>>> run_addr = 0x40000000
>>> from miasm.jitter.csts import PAGE_READ, PAGE_WRITE
>>> jitter.vm.add_memory_page(run_addr, PAGE_READ | PAGE_WRITE, s)

Создайте sentinelle для перехвата возврата shellcode:```Python def code_sentinelle(jitter): jitter.running = False jitter.pc = 0 return True

jitter.add_breakpoint(0x1337beef, code_sentinelle) jitter.push_uint32_t(0x1337beef)

root@kitploit:~
Активные логи:```pycon
>>> jitter.set_trace_log()

Запуск по произвольному адресу:```pycon

jitter.init_run(run_addr) jitter.continue_run() RAX 0000000000000000 RBX 0000000000000000 RCX 0000000000000000 RDX 0000000000000000 RSI 0000000000000000 RDI 0000000000000000 RSP 000000000123FFF8 RBP 0000000000000000 zf 0000000000000000 nf 0000000000000000 of 0000000000000000 cf 0000000000000000 RIP 0000000040000000 40000000 LEA ECX, DWORD PTR [ECX+0x4] RAX 0000000000000000 RBX 0000000000000000 RCX 0000000000000004 RDX 0000000000000000 RSI 0000000000000000 RDI 0000000000000000 RSP 000000000123FFF8 RBP 0000000000000000 zf 0000000000000000 nf 0000000000000000 of 0000000000000000 cf 0000000000000000 .... 4000000e JMP loc_0000000040000013:0x40000013 RAX 0000000000000000 RBX 0000000000000000 RCX 0000000000000004 RDX 0000000000000000 RSI 0000000000000000 RDI 0000000000000000 RSP 000000000123FFF8 RBP 0000000000000000 zf 0000000000000000 nf 0000000000000000 of 0000000000000000 cf 0000000000000000 RIP 0000000040000013 40000013 MOV EAX, EBX RAX 0000000000000000 RBX 0000000000000000 RCX 0000000000000004 RDX 0000000000000000 RSI 0000000000000000 RDI 0000000000000000 RSP 000000000123FFF8 RBP 0000000000000000 zf 0000000000000000 nf 0000000000000000 of 0000000000000000 cf 0000000000000000 RIP 0000000040000013 40000015 RET

root@kitploit:~
Взаимодействие с джиттером:```pycon
>>> jitter.vm
ad 1230000 size 10000 RW_ hpad 0x2854b40
ad 40000000 size 16 RW_ hpad 0x25e0ed0

>>> hex(jitter.cpu.EAX)
'0x0L'
>>> jitter.cpu.ESI = 12

Символическое выполнение

Инициализация пула IR:```pycon

lifter = machine.lifter_model_call(loc_db) ircfg = lifter.new_ircfg_from_asmcfg(asmcfg)

root@kitploit:~
Инициализация движка с символическими значениями по умолчанию:```pycon
>>> from miasm.ir.symbexec import SymbolicExecutionEngine
>>> sb = SymbolicExecutionEngine(lifter)

Запуск выполнения:```pycon

symbolic_pc = sb.run_at(ircfg, 0) print(symbolic_pc) ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10)

root@kitploit:~
То же самое, с пошаговыми логами (отображаются только изменения):```pycon
>>> sb = SymbolicExecutionEngine(lifter, machine.mn.regs.regs_init)
>>> symbolic_pc = sb.run_at(ircfg, 0, step=True)
Instr LEA        ECX, DWORD PTR [ECX + 0x4]
Assignblk:
ECX = ECX + 0x4
________________________________________________________________________________
ECX                = ECX + 0x4
________________________________________________________________________________
Instr LEA        EBX, DWORD PTR [EBX + 0x1]
Assignblk:
EBX = EBX + 0x1
________________________________________________________________________________
EBX                = EBX + 0x1
ECX                = ECX + 0x4
________________________________________________________________________________
Instr CMP        CL, 0x1
Assignblk:
zf = (ECX[0:8] + -0x1)?(0x0,0x1)
nf = (ECX[0:8] + -0x1)[7:8]
pf = parity((ECX[0:8] + -0x1) & 0xFF)
of = ((ECX[0:8] ^ (ECX[0:8] + -0x1)) & (ECX[0:8] ^ 0x1))[7:8]
cf = (((ECX[0:8] ^ 0x1) ^ (ECX[0:8] + -0x1)) ^ ((ECX[0:8] ^ (ECX[0:8] + -0x1)) & (ECX[0:8] ^ 0x1)))[7:8]
af = ((ECX[0:8] ^ 0x1) ^ (ECX[0:8] + -0x1))[4:5]
________________________________________________________________________________
af                 = (((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[4:5]
pf                 = parity((ECX + 0x4)[0:8] + 0xFF)
zf                 = ((ECX + 0x4)[0:8] + 0xFF)?(0x0,0x1)
ECX                = ECX + 0x4
of                 = ((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1))[7:8]
nf                 = ((ECX + 0x4)[0:8] + 0xFF)[7:8]
cf                 = (((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1)) ^ ((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[7:8]
EBX                = EBX + 0x1
________________________________________________________________________________
Instr JZ         loc_key_1
Assignblk:
IRDst = zf?(loc_key_1,loc_key_2)
EIP = zf?(loc_key_1,loc_key_2)
________________________________________________________________________________
af                 = (((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[4:5]
EIP                = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10)
pf                 = parity((ECX + 0x4)[0:8] + 0xFF)
IRDst              = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10)
zf                 = ((ECX + 0x4)[0:8] + 0xFF)?(0x0,0x1)
ECX                = ECX + 0x4
of                 = ((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1))[7:8]
nf                 = ((ECX + 0x4)[0:8] + 0xFF)[7:8]
cf                 = (((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1)) ^ ((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[7:8]
EBX                = EBX + 0x1
________________________________________________________________________________
>>>

Повторите выполнение с конкретным ECX. Здесь символическое / конколическое выполнение достигает конца shellcode:```pycon

from miasm.expression.expression import ExprInt sb.symbols[machine.mn.regs.ECX] = ExprInt(-3, 32) symbolic_pc = sb.run_at(ircfg, 0, step=True) Instr LEA ECX, DWORD PTR [ECX + 0x4] Assignblk: ECX = ECX + 0x4


af = (((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[4:5] EIP = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10) pf = parity((ECX + 0x4)[0:8] + 0xFF) IRDst = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10) zf = ((ECX + 0x4)[0:8] + 0xFF)?(0x0,0x1) ECX = 0x1 of = ((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1))[7:8] nf = ((ECX + 0x4)[0:8] + 0xFF)[7:8] cf = (((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1)) ^ ((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[7:8] EBX = EBX + 0x1


Instr LEA EBX, DWORD PTR [EBX + 0x1] Assignblk: EBX = EBX + 0x1


af = (((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[4:5] EIP = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10) pf = parity((ECX + 0x4)[0:8] + 0xFF) IRDst = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10) zf = ((ECX + 0x4)[0:8] + 0xFF)?(0x0,0x1) ECX = 0x1 of = ((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1))[7:8] nf = ((ECX + 0x4)[0:8] + 0xFF)[7:8] cf = (((((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8]) & ((ECX + 0x4)[0:8] ^ 0x1)) ^ ((ECX + 0x4)[0:8] + 0xFF) ^ (ECX + 0x4)[0:8] ^ 0x1)[7:8] EBX = EBX + 0x2


Instr CMP CL, 0x1 Assignblk: zf = (ECX[0:8] + -0x1)?(0x0,0x1) nf = (ECX[0:8] + -0x1)[7:8] pf = parity((ECX[0:8] + -0x1) & 0xFF) of = ((ECX[0:8] ^ (ECX[0:8] + -0x1)) & (ECX[0:8] ^ 0x1))[7:8] cf = (((ECX[0:8] ^ 0x1) ^ (ECX[0:8] + -0x1)) ^ ((ECX[0:8] ^ (ECX[0:8] + -0x1)) & (ECX[0:8] ^ 0x1)))[7:8] af = ((ECX[0:8] ^ 0x1) ^ (ECX[0:8] + -0x1))[4:5]


af = 0x0 EIP = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10) pf = 0x1 IRDst = ((ECX + 0x4)[0:8] + 0xFF)?(0xB,0x10) zf = 0x1 ECX = 0x1 of = 0x0 nf = 0x0 cf = 0x0 EBX = EBX + 0x2


Instr JZ loc_key_1 Assignblk: IRDst = zf?(loc_key_1,loc_key_2) EIP = zf?(loc_key_1,loc_key_2)


af = 0x0 EIP = 0x10 pf = 0x1 IRDst = 0x10 zf = 0x1 ECX = 0x1 of = 0x0 nf = 0x0 cf = 0x0 EBX = EBX + 0x2


Instr LEA EBX, DWORD PTR [EBX + 0x1] Assignblk: EBX = EBX + 0x1


af = 0x0 EIP = 0x10 pf = 0x1 IRDst = 0x10 zf = 0x1 ECX = 0x1 of = 0x0 nf = 0x0 cf = 0x0 EBX = EBX + 0x3


Instr LEA EBX, DWORD PTR [EBX + 0x1] Assignblk: IRDst = loc_key_3


af = 0x0 EIP = 0x10 pf = 0x1 IRDst = 0x13 zf = 0x1 ECX = 0x1 of = 0x0 nf = 0x0 cf = 0x0 EBX = EBX + 0x3


Instr MOV EAX, EBX Assignblk: EAX = EBX


af = 0x0 EIP = 0x10 pf = 0x1 IRDst = 0x13 zf = 0x1 ECX = 0x1 of = 0x0 nf = 0x0 cf = 0x0 EBX = EBX + 0x3 EAX = EBX + 0x3


Instr RET Assignblk: IRDst = @32[ESP[0:32]] ESP = {ESP[0:32] + 0x4 0 32} EIP = @32[ESP[0:32]]


af = 0x0 EIP = @32[ESP] pf = 0x1 IRDst = @32[ESP] zf = 0x1 ECX = 0x1 of = 0x0 nf = 0x0 cf = 0x0 EBX = EBX + 0x3 ESP = ESP + 0x4 EAX = EBX + 0x3


root@kitploit:~
Как это работает?
=================

Miasm включает собственный дизассемблер, промежуточный язык и семантику инструкций. Он написан на Python.

Для эмуляции кода он использует LLVM, GCC, Clang или Python для JIT-компиляции промежуточного представления. Он может эмулировать шелл-коды и целиком или частично бинарные файлы. Для взаимодействия с выполнением могут выполняться callback-функции Python, например, для эмуляции эффектов библиотечных функций.

Документация
=============

Некоторые ресурсы документации доступны в папке [doc](https://github.com/cea-sec/miasm/blob/HEAD/doc).

Доступна автосгенерированная документация:
* [Doxygen](http://miasm.re/miasm_doxygen)
* [pdoc](http://miasm.re/miasm_pdoc)

Получение Miasm
===============

* Клонируйте репозиторий: [Miasm на GitHub](https://github.com/cea-sec/miasm/)
* Получите один из образов Docker на [Docker Hub](https://registry.hub.docker.com/u/miasm/)

Требования к программному обеспечению
---------------------

Miasm использует:

* python-pyparsing
* python-dev
* опционально python-pycparser (версия >= 2.17)

Для включения JIT-компиляции кода обязателен один из следующих модулей:
* GCC
* Clang
* LLVM с Numba llvmlite, см. ниже

'Опционально' Miasm также может использовать:
* Z3, [доказатель теорем](https://github.com/Z3Prover/z3)

Конфигурация
-------------

Для использования JIT-компилятора рекомендуется GCC или LLVM
* GCC (any version)
* Clang (any version)
* LLVM
  * Debian (testing/unstable): Не тестировалось
  * Debian stable/Ubuntu/Kali/и т.д.: `pip install llvmlite` или установите из [llvmlite](https://github.com/numba/llvmlite)
  * Windows: Не тестировалось
* Соберите и установите Miasm:```pycon
$ cd miasm_directory
$ python setup.py build
$ sudo python setup.py install

Если во время компиляции одного из модулей jitter возникает ошибка, Miasm пропустит ошибку и отключит соответствующий модуль (см. вывод компиляции).

Windows & IDA

Большинство плагинов IDA для Miasm используют подмножество функциональности Miasm. Быстрый способ заставить их работать — добавить:

  • pyparsing.py в C:\...\IDA\python\ или pip install pyparsing
  • каталог miasm/miasm в C:\...\IDA\python\

Все функции, кроме связанных с JITter, будут доступны. Для более полной установки обратитесь к приведенным выше абзацам.

Тестирование

Miasm поставляется с набором регрессионных тестов. Чтобы запустить их все:```pycon cd miasm_directory/test

Run tests using our own test runner

python test_all.py

Run tests using standard frameworks (slower, require 'parameterized')

python -m unittest test_all.py # sequential, requires 'unittest' python -m pytest test_all.py # sequential, requires 'pytest' python -m pytest -n auto test_all.py # parallel, requires 'pytest' and 'pytest-xdist'

root@kitploit:~
Некоторые опции могут быть заданы:

* Однопоточный режим: `-m`
* Инструментирование покрытия кода: `-c`
* Только быстрые тесты: `-t long` (исключает длительные тесты)

Они уже используют Miasm
========================

Инструменты
-----------

* [Sibyl](https://github.com/cea-sec/Sibyl): Инструмент для дивинации функций
* [R2M2](https://github.com/guedou/r2m2): Использование miasm в качестве плагина radare2
* [CGrex](https://github.com/mechaphish/cgrex): Таргетный патчер для CGC-бинарных файлов
* [ethRE](https://github.com/jbcayrou/ethRE): Инструмент реверс-инжиниринга для Ethereum EVM (с соответствующей архитектурой Miasm2)

Посты в блогах / статьи / конференции
-------------------------------------

* [Deobfuscation: recovering an OLLVM-protected program](http://blog.quarkslab.com/deobfuscation-recovering-an-ollvm-protected-program.html)
* [Taming a Wild Nanomite-protected MIPS Binary With Symbolic Execution: No Such Crackme](https://doar-e.github.io/blog/2014/10/11/taiming-a-wild-nanomite-protected-mips-binary-with-symbolic-execution-no-such-crackme/)
* [Génération rapide de DGA avec Miasm](https://www.lexsi.com/securityhub/generation-rapide-de-dga-avec-miasm/): Быстрое вычисление DGA (статья на французском)
* [Enabling Client-Side Crash-Resistance to Overcome Diversification and Information Hiding](https://www.internetsociety.org/sites/default/files/blogs-media/enabling-client-side-crash-resistance-overcome-diversification-information-hiding.pdf): Обнаружение потенциальных аргументов неориентированных вызовов
* [Miasm: Framework de reverse engineering](https://www.sstic.org/2012/presentation/miasm_framework_de_reverse_engineering/) (на французском)
* [Tutorial miasm](https://www.sstic.org/2014/presentation/Tutorial_miasm/) (французское видео)
* [Graphes de dépendances : Petit Poucet style](https://www.sstic.org/2016/presentation/graphes_de_dpendances__petit_poucet_style/): DepGraph (на французском)

Книги
-----

* [Practical Reverse Engineering: X86, X64, Arm, Windows Kernel, Reversing Tools, and Obfuscation](http://eu.wiley.com/WileyCDA/WileyTitle/productCd-1118787315,subjectCd-CSJ0.html): Введение в Miasm (Глава 5 "Обфускация")
* [BlackHat Python - Appendix](https://github.com/oreilly-japan/black-hat-python-jp-support/tree/master/appendix-A): Примеры из японской книги по безопасности
Скачать инструмент