Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
metasm — 이것은 Ruby로 작성된 무료 어셈블러/디스어셈블러/컴파일러인 metasm의 메인 저장소입니다. | Kitploit
도구/GitHubGitHub/jjyg/metasm
Code AnalysisReverse EngineeringShellcodeDebuggersBinary Analysis
GitHubjjyg/metasm

metasm

이것은 Ruby로 작성된 무료 어셈블러/디스어셈블러/컴파일러인 metasm의 메인 저장소입니다.

저장소 보기
4758215개월 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
웹사이트

Metasm, Ruby 어셈블리 조작 스위트

  • 샘플 스크립트는 samples/ 에 있습니다 -- 파일 시작 부분의 주석을 읽으세요
  • 모든 파일은 LGPL 조건에 따라 라이선스가 부여됩니다.

저자: Yoann Guillot

기본 개요:

Metasm을 사용하면 실행 파일 형식(ExeFormat)과 상호작용할 수 있습니다: PE, ELF, Mach-O, Shellcode 등. ExeFormat을 다루는 방법에는 세 가지가 있습니다:

  • 처음부터 하나를 컴파일하기
  • 기존 형식을 디컴파일하기
  • 파일 구조를 조작하기

바로 사용할 수 있는 스크립트는 samples/ 하위 디렉터리에서 찾을 수 있습니다. 스크립트 헤더의 주석을 확인하세요. 운이 좋다면 --help 인자도 시도해 볼 수 있습니다.

자세한 내용은 doc/ 하위 디렉터리를 확인하세요. 텍스트 파일은 misc/txt2html.rb 스크립트를 사용하여 html로 컴파일할 수 있습니다.

다음은 Metasm 내부 구조에 대한 간략한 개요입니다.

어셈블리:

컴파일할 때 구문 분석되는 소스 텍스트(ruby String, 대부분 명령어/데이터/패딩 지시어의 연속으로 구성됨)에서 시작합니다.

이 문자열은 Preprocessor 인스턴스에 전달됩니다(#if, #ifdef, #include, #define, /* */ 등을 처리하며, gcc -E와 100% 호환되어야 합니다). 이 Preprocessor는 어셈블러 소스용 AsmPreprocessor로 캡슐화됩니다(asm 매크로 정의, 'equ' 및 asm ';' 주석 처리용). 그렇게 하는 인터페이스는 ExeFormat#parse(text[, filename, lineno]) 또는 ExeFormat.assemble입니다(.new, #parse 및 #assemble을 호출).

(Asm)Preprocessor는 토큰을 ExeFormat에 반환하며, ExeFormat은 이를 Data, Padding, Labels 또는 파서 지시어로 구문 분석합니다. 파서 지시어는 항상 점으로 시작합니다. 이는 일반적인(.pad, .offset...) 것일 수도 있고 ExeFormat 특화(.section, .import, .entrypoint...) 것일 수도 있습니다. 이들은 #parse_parser_instruction()에 의해 처리됩니다. ExeFormat이 단어를 인식하지 못하면 해당 CPU 인스턴스로 전달되며, CPU 인스턴스는 명령어를 구문 분석하거나 예외를 발생시킵니다. 이 모든 토큰은 ExeFormat의 @source 속성에 있는 하나 이상의 배열에 저장됩니다. (Shellcode의 @source는 Array이고, PE/ELF의 경우 [섹션 이름] => [구문 분석된 데이터의 Array] 해시입니다) 모든 즉시 값은 임의의 Expression일 수 있습니다(나중에 참조).

그런 다음 ExeFormat#assemble을 사용하여 소스를 바이너리 섹션으로 어셈블할 수 있습니다.

섹션 바이너리가 준비되면 전체 바이너리 실행 파일을 ExeFormat#encode_file(filename[, format])을 사용하여 디스크에 쓸 수 있습니다.

PE와 ELF에는 알려진 OS별 함수에 대한 import 관련 데이터를 자동으로 생성하는 autoimport 기능이 포함되어 있습니다. (예: 'strcpy'에 대한 확인되지 않은 호출은 런타임에 바이너리가 libc 라이브러리와 링크되도록 데이터를 생성합니다).

samples/{exe,pe,elf}encode.rb는 asm 소스 파일을 인자로 받아 작동하는 실행 파일로 컴파일할 수 있습니다.

CPU 클래스는 개별 명령어를 구문 분석하고 인코딩하는 역할을 담당합니다. 현재 Ia32 파서는 Intel 구문을 사용합니다(예: mov eax, 42). 일반 파서는 줄 시작 부분에 콜론이 뒤따르는 문자열을 레이블로 인식합니다 (예: 'some_label:'). GCC 스타일 로컬 레이블을 사용할 수 있습니다 (예: '1:'은 '1b'(뒤로) 또는 '1f'(앞으로)로 참조하며, 필요에 따라 여러 번 재정의할 수 있습니다.) 데이터는 'db' 스타일 표기법으로 지정합니다(예: 'dd 42h', 'db "blabla", 0') samples/asmsyntax.rb를 참조하세요.

EncodedData:

Metasm에서 모든 바이너리 데이터는 EncodedData로 저장됩니다. EncodedData에는 3가지 주요 속성이 있습니다:

  • #data: 원시 바이너리 데이터를 보유합니다(일반적으로 ruby String이지만 VirtualString 참조)
  • #export: 내보내기 이름(레이블 이름)을 #data 내의 오프셋에 연결하는 해시입니다
  • #reloc: 키가 #data 내의 오프셋이고 값이 Relocation 객체인 해시입니다. Relocation 객체에는 엔디언(:little/:big), 유형(:u32는 부호 없는 32비트) 및 대상(여기에 저장하려는 값)이 있습니다. 대상은 임의의 산술/논리 Expression입니다.

EncodedData에는 #virtsize(예: .bss 섹션용)와 #ptr(디코딩 시 사용되는 내부 오프셋)도 있습니다.

EncodedData는 Hash 변수 이름 => 값으로 fixup할 수 있습니다(값은 Expression 또는 숫자 값이어야 합니다). 이렇게 하면 각 relocation의 대상이 바인딩을 사용하여 바인딩되고, 결과를 계산할 수 있다면(Expression에 외부 변수 이름이 없음), relocation의 크기/부호/엔디언 정보를 사용하여 결과가 인코딩됩니다. 오버플로가 발생하면(8비트 부호 있는 relocation에 128을 저장하려는 경우) EncodeError 예외가 발생합니다. :a32 유형을 사용하면 오버플로를 조용히 잘라낼 수 있습니다. relocation의 대상이 숫자가 아닌 경우 EncodedData#fixup을 사용하면 대상은 그대로 유지되고, #fixup! 을 사용하면 바인딩된 대상으로 대체됩니다.

디스어셈블리:

이 코드는 Disassembler 클래스를 정의하는 metasm/decode.rb 소스 파일에 있습니다.

디스어셈블러는 디코딩된 ExeFormat(어떤 데이터가 어떤 가상 주소에 있는지 알 수 있어야 함)과 진입점(가상 주소 또는 내보내기 이름)이 필요합니다. 그런 다음 명령어 디스어셈블을 시작할 수 있습니다. :setip으로 표시된 Opcode를 만나면 CPU에 점프 대상(레지스터 값을 포함할 수 있는 Expression, 예: jmp eax)을 묻고, 숫자 값을 찾을 때까지 명령어를 역추적합니다.

디코딩 시 Disassembler는 주소(식/정수 #normalize()d)를 DecodedInstruction에 연결하는 #decoded 해시를 유지합니다.

디스어셈블리는 InstructionBlock 그래프를 생성합니다. 각 블록은 DecodedInstruction 목록과 다음/이전 블록에 대한 포인터(주소 기준)를 보유합니다.

디스어셈블러는 또한 명령어의 데이터 접근을 추적하고 이에 대한 Xrefs를 저장합니다. 역추적 매개변수를 조정할 수 있으며, :r/:w 역추적(명령어 메모리 xrefs)에 대해 고려할 최대 깊이를 특별히 변경할 수 있습니다. #backtrace_maxblocks_data를 사용합니다. Expression이 역추적될 때, 통과한 각 블록은 루프가 감지되도록 표시되고, 기존 블록에 대한 새 코드 경로가 발견되면 이 새 경로를 사용하여 역추적을 재개할 수 있습니다.

디스어셈블러는 가정을 거의 하지 않으며, 특히 함수가 반환될 것이라고 가정하지 않습니다. 'ret' 명령어의 역추적이 확정적일 때만 반환됩니다. 이것은 매우 강력하지만, 역추적 과정의 오류가 완전한 중단으로 이어질 수 있음을 의미하며, 또한 디스어셈블러가 상당히 느리다는 것을 의미합니다.

코드가 올바르게 구성된 것으로 알려진 경우(즉, 모든 호출이 반환된다고 가정) 특수 메서드 #disassemble_fast를 사용하여 이 문제를 해결할 수 있습니다.

하위 함수가 발견되면 함수의 효과 요약을 보유하는 특수 DecodedFunction이 생성됩니다 (강화된 DecodedInstruction과 같음). 이를 통해 역추적기가 하위 함수를 '건너뛸' 수 있어 속도가 크게 향상됩니다. DecodedFunctions는 콜백 기반일 수 있어 매우 동적인 동작을 허용합니다. 외부 함수 호출은 일부 API 정보(예: 스택 fixup 정보, 기본 매개변수 접근 등)를 보유하는 전용 DecodedFunctions를 생성합니다. 이 정보는 미리 구문 분석된 C 헤더에서 파생될 수 있습니다. C 함수 프로토타입을 사용할 수 없으면 함수가 표준 ABI를 갖는다고 가정하는 특수 'default' 항목이 사용됩니다.

Ia32는 마지막 'call' 명령어가 반환된다고 가정하여 자동 스택 fixup 해석을 처리하는 특정 :default 항목을 구현합니다. 이로 인해 예기치 못한 결과가 발생할 수 있습니다. 최대 정확도를 위해 모든 외부 함수에 대한 정보를 담은 C 헤더가 권장됩니다 (전체 Visual Studio 설치와 대상 바이너리에서 이러한 헤더를 생성하는 스크립트는 samples/factorize-headers-peimports를 참조하세요).

Ia32는 또한 특정 GetProcAddress/dlsym 콜백을 구현하며, 매개변수를 역추적할 수 있으면 올바른 반환 값을 제공합니다.

전체 디스어셈블러를 구현하는 스크립트는 samples/disassemble{-gui}.rb입니다. GUI 키 바인딩은 주석을 참조하세요.

ExeFormat 조작:

ExeFormat을 인코딩/디코딩할 수 있습니다(즉, 섹션, 임포트, 헤더 등 디코딩).

생성자: ExeFormat.decode_file(str), ExeFormat.decode_file_header(str) 메서드: ExeFormat#encode_file(filename), ExeFormat#encode_string

PE 및 ELF 파일에는 해당 형식의 메모리 mmap 버전으로 작업할 수 있는 LoadedPE/LoadedELF 대응물이 있습니다(예: 실행 중인 프로세스를 디버깅하려는 경우).

VirtualString:

VirtualString은 String과 유사한 객체입니다. 슬라이스를 읽거나 다시 쓸 수 있습니다. EncodedData#data로 사용될 수 있으므로 대부분의 Metasm 알고리즘을 가상화할 수 있습니다. VirtualString의 길이는 변경할 수 없습니다. VirtualString의 슬라이스를 가져오면 String(작은 크기의 경우) 또는 다른 VirtualString(다른 것의 '창')이 반환됩니다. #dup(offset, length) 메서드를 사용하여 작은 VirtualString을 강제로 얻을 수 있습니다. 호출된 구현되지 않은 메서드는 VirtualString의 전체 복사본인 frozen String으로 전달됩니다. (가능하면 피해야 합니다. 기본 문자열이 매우 크고 접근 속도가 느릴 수 있습니다.)

현재 구현된 VirtualString은 3가지입니다:

  • VirtualFile: 요청 시 파일을 페이지 크기 청크 단위로 로드합니다.
  • WindowsRemoteString: 다른 프로세스의 가상 메모리를 매핑합니다(WinDbgAPI를 통해 Windows 디버그 API 사용).
  • LinuxRemoteString: 다른 프로세스의 가상 메모리를 매핑합니다(ptrace 권한 필요, 메모리 읽기는 /proc/pid/mem을 사용하여 수행).

Win/Lin 버전은 매우 강력하며, LoadedPE/LoadedELF를 ExeFormat으로 사용하여 라이브 프로세스 디스어셈블/패칭을 쉽게 할 수 있습니다.

디버깅:

Metasm에는 디버깅을 처리하기 위한 몇 가지 인터페이스가 포함되어 있습니다. WinOS 및 LinOS 클래스는 기본 OS 프로세스에 대한 접근을 제공합니다(예: OS.current.find_process('foobar')는 파일 이름에 foobar가 포함된 실행 중인 프로세스를 찾으며, 그런 다음 process.mem을 사용하여 해당 메모리에 접근할 수 있습니다.)

Windows 및 Linux 저수준 디버깅 API에는 기본 ruby 인터페이스(PTrace 및 WinAPI)가 있으며, 이 인터페이스는 통합 하이엔드 Debugger 클래스에서 사용됩니다. 원격 디버깅은 GDB 서버 와이어 프로토콜을 통해 지원됩니다.

하이레벨 디버거는 다음 ruby 줄로 생성할 수 있습니다: Metasm::OS.current.create_debugger('foo')

한 번에 한 종류의 호스트 디버거 클래스만 존재할 수 있습니다. 여러 프로세스를 디버깅하려면 기존 클래스를 사용하여 다른 프로세스에 연결하세요. 이는 Windows와 Linux에서 OS 디버깅 API가 작동하는 방식 때문입니다.

저수준 백엔드는 os/ 하위 디렉터리에 정의되고, 프런트엔드는 debug.rb에 정의됩니다.

Linux 콘솔 디버깅 인터페이스는 samples/lindebug.rb에서 사용할 수 있습니다. 이 인터페이스는 (단순화된) SoftICE와 유사한 모양과 느낌을 사용합니다. gdb-server 소켓과 통신할 수 있습니다. [udp:]host:port 대상을 사용하세요.

disassembler-gui 샘플은 'live:'을 대상으로 사용할 때 라이브 프로세스와 상호작용할 수 있습니다.

C 파서:

Metasm에는 직접 작성된 C 파서가 포함되어 있습니다. 16진수 부동소수점을 제외하고 제가 알고 있는 모든 구문을 처리합니다:

  • static const L"bla"
  • 가변 인자
  • 불완전한 타입
  • attributes(()), __declspec()
  • #pragma once
  • #pragma pack()
  • C99 declarators - type bla = { [ 2 ... 14 ].toto = 28 };
  • 중첩 함수
  • __int8 등의 네이티브 타입
  • 레이블 주소 (&&label) 또한 이러한 모든 것이 구문 분석되지만, 대부분은 Ia32/X64 백엔드(현재까지 구현된 유일한 백엔드)에서 컴파일되지 않을 수 있습니다.

C 파일 구문 분석은 기존 ExeFormat과 parse_c_file 메서드를 사용하여 수행해야 합니다. 이렇게 하면 형식별 매크로/ABI가 올바르게 정의됩니다 (예: 'long' 타입의 크기, 함수에 매개변수를 전달하는 ABI 등).

C::Parser.parse(text)를 사용하여 C String을 구문 분석하면 Parser 객체를 받습니다. 이 객체는 #structs, #symbols 및 #statements를 보유하는 C::Block인 #toplevel 필드를 가집니다. 최상위 함수는 #symbol 해시에서 찾을 수 있으며, 키는 함수를 보유하는 C::Variable 객체에 연결된 심볼 이름입니다. 함수 매개변수/속성은 func.type을 통해 접근할 수 있고, 코드는 그 자체로 C::Block인 func.initializer에 있습니다. 그 아래에는 C::Statements(If, While, Asm, CExpressions...)의 트리 구조가 있습니다.

C::Parser는 #precompiled되어 컴파일하기 더 쉬운 단순화된 버전으로 변환될 수 있습니다: typedef가 제거되고, 제어 시퀀스는 'if (XX) goto YY;' 등으로 변환됩니다.

C 프로그램을 컴파일하려면 PE/ELF.compile_c를 사용하세요. 이는 exe별 매크로(예: PE 또는 ELF)가 정의된 C::Parser를 생성합니다.

공급업체별 헤더는 #pragma prepare_visualstudio(Microsoft Visual Studio 헤더를 구문 분석하려는 경우) 또는 prepare_gcc(gcc용)를 사용해야 할 수 있으며, 후자는 자동 감지될 수도 있고 아닐 수도 있습니다. 테스트된 공급업체 헤더는 VS2003(DDK 포함) 및 gcc4입니다. 결과는 다를 수 있습니다.

현재 C 코드의 CPU#compilation은 asm 소스(텍스트)를 생성하며, 이 소스는 이후 구문 분석 및 어셈블되어 바이너리 코드가 될 수 있습니다.

ExeFormat#compile_c 및 samples/exeencode.rb를 참조하세요.

도구 다운로드