
Python 기반 리버스 엔지니어링 프레임워크
Miasm은 무료 오픈소스(GPLv2) 리버스 엔지니어링 프레임워크입니다. Miasm은 바이너리 프로그램을 분석/수정/생성하는 것을 목표로 합니다. 다음은 일부 기능 목록입니다:
더 많은 예제와 데모는 공식 블로그를 참조하세요.
Miasm x86 아키텍처 가져오기:```pycon
from miasm.arch.x86.arch import mn_x86 from miasm.core.locationdb import LocationDB
위치 db 가져오기:```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']
피연산자 수정:```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
`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)
중간 표현
---------------------------
명령어 생성:```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)
빈 ircfg 생성:```pycon
>>> ircfg = lifter.new_ircfg()
풀에 명령어를 추가하세요:```pycon
lifter.add_instr_to_ircfg(instr, ircfg)
현재 풀 출력:```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
Miasm IR에 대한 자세한 정보는 [해당 Jupyter Notebook](https://github.com/cea-sec/miasm/blob/master/doc/expression/expression.ipynb)을 참고하세요.
에뮬레이션
---------
쉘코드를 제공하는 경우:```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>
주소 `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()
임의의 메모리 위치에 셸코드를 추가합니다:```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)
센티넬을 생성하여 셸코드의 반환을 포착합니다:```Python def code_sentinelle(jitter): jitter.running = False jitter.pc = 0 return True
jitter.add_breakpoint(0x1337beef, code_sentinelle) jitter.push_uint32_t(0x1337beef)
활성 로그:```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
jitter와 상호 작용:```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)
기본 심볼 값으로 엔진 초기화:```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)
동일, 단계 로그 포함 (변경 사항만 표시됨):```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로 실행을 다시 시도하십시오. 여기서, 심볼릭/콘컬릭 실행은 셸코드의 끝에 도달합니다:```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
작동 방식
=================
Miasm은 자체 디스어셈블러, 중간 언어 및 명령어 의미론을 내장하고 있습니다. Python으로 작성되었습니다. 코드를 에뮬레이션하기 위해 LLVM, GCC, Clang 또는 Python을 사용하여 중간 표현을 JIT 컴파일합니다. 쉘코드와 바이너리의 전체 또는 일부를 에뮬레이션할 수 있습니다. 실행과 상호작용하기 위해 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 on GitHub](https://github.com/cea-sec/miasm/)
* [Docker Hub](https://registry.hub.docker.com/u/miasm/)에서 Docker 이미지를 가져오세요.
소프트웨어 요구 사항
---------------------
Miasm은 다음을 사용합니다:
* python-pyparsing
* python-dev
* 선택적으로 python-pycparser (버전 >= 2.17)
코드 JIT를 활성화하려면 다음 모듈 중 하나가 필수입니다:
* GCC
* Clang
* LLVM with Numba llvmlite, 아래 참조
'선택 사항' Miasm은 또한 다음을 사용할 수 있습니다:
* Z3, [정리 증명기](https://github.com/Z3Prover/z3)
설정
-------------
지터(jitter)를 사용하려면 GCC 또는 LLVM이 권장됩니다.
* GCC (모든 버전)
* Clang (모든 버전)
* 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
If something goes wrong during one of the jitter modules compilation, Miasm will skip the error and disable the corresponding module (see the compilation output).
Miasm의 IDA 플러그인 대부분은 Miasm 기능의 하위 집합을 사용합니다. 빠르게 작동하게 하는 방법은 다음을 추가하는 것입니다:
pyparsing.py to C:\...\IDA\python\ or pip install pyparsingmiasm/miasm directory to C:\...\IDA\python\JITter 관련 기능을 제외한 모든 기능을 사용할 수 있습니다. 보다 완전한 설치를 위해서는 위의 단락을 참조하십시오.
Miasm에는 회귀 테스트 세트가 포함되어 있습니다. 모두 실행하려면:```pycon cd miasm_directory/test
python test_all.py
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'
일부 옵션을 지정할 수 있습니다:
* 단일 스레드: `-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): 이더리움 EVM용 리버싱 도구 (해당 Miasm2 아키텍처 포함)
블로그 게시물 / 논문 / 컨퍼런스
---------------------------------
* [디오브퓨스케이션: OLLVM으로 보호된 프로그램 복구](http://blog.quarkslab.com/deobfuscation-recovering-an-ollvm-protected-program.html)
* [상징적 실행으로 난폭한 나노마이트 보호 MIPS 바이너리 길들이기: 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/)
* [Miasm을 이용한 빠른 DGA 생성](https://www.lexsi.com/securityhub/generation-rapide-de-dga-avec-miasm/): DGA 빠른 계산 (프랑스어 기사)
* [클라이언트 측 충돌 내성을 활성화하여 다양화 및 정보 은닉 극복](https://www.internetsociety.org/sites/default/files/blogs-media/enabling-client-side-crash-resistance-overcome-diversification-information-hiding.pdf): 방향 없는 호출 잠재 인자 탐지
* [Miasm: 리버스 엔지니어링 프레임워크](https://www.sstic.org/2012/presentation/miasm_framework_de_reverse_engineering/) (프랑스어)
* [Miasm 튜토리얼](https://www.sstic.org/2014/presentation/Tutorial_miasm/) (프랑스어 동영상)
* [의존성 그래프: Petit Poucet 스타일](https://www.sstic.org/2016/presentation/graphes_de_dpendances__petit_poucet_style/): DepGraph (프랑스어)
도서
-----
* [실전 리버스 엔지니어링: X86, X64, Arm, Windows 커널, 리버싱 도구 및 난독화](http://eu.wiley.com/WileyCDA/WileyTitle/productCd-1118787315,subjectCd-CSJ0.html): Miasm 소개 (5장 "난독화")
* [BlackHat Python - 부록](https://github.com/oreilly-japan/black-hat-python-jp-support/tree/master/appendix-A): 일본 보안 서적의 샘플