Search

8장. 연습문제

1. 범용적인 디스어셈블 도구 기능 만들기

// Architecture type typedef enum cs_arch { CS_ARCH_ARM = 0, // ARM architecture (including Thumb, Thumb-2) CS_ARCH_ARM64, // ARM-64, also called AArch64 CS_ARCH_MIPS, // Mips architecture CS_ARCH_X86, // X86 architecture (including x86 & x86-64) CS_ARCH_PPC, // PowerPC architecture CS_ARCH_SPARC, // Sparc architecture CS_ARCH_SYSZ, // SystemZ architecture CS_ARCH_XCORE, // XCore architecture CS_ARCH_MAX, CS_ARCH_ALL = 0xFFFF, // All architectures - for cs_support() } cs_arch; // Mode type typedef enum cs_mode { CS_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode) CS_MODE_ARM = 0, // 32-bit ARM CS_MODE_16 = 1 << 1, // 16-bit mode (X86) CS_MODE_32 = 1 << 2, // 32-bit mode (X86) CS_MODE_64 = 1 << 3, // 64-bit mode (X86, PPC) CS_MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2 CS_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series CS_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM CS_MODE_MICRO = 1 << 4, // MicroMips mode (MIPS) CS_MODE_MIPS3 = 1 << 5, // Mips III ISA CS_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA CS_MODE_MIPSGP64 = 1 << 7, // General Purpose Registers are 64-bit wide (MIPS) CS_MODE_V9 = 1 << 4, // SparcV9 mode (Sparc) CS_MODE_BIG_ENDIAN = 1 << 31, // big-endian mode CS_MODE_MIPS32 = CS_MODE_32, // Mips32 ISA (Mips) CS_MODE_MIPS64 = CS_MODE_64, // Mips64 ISA (Mips) } cs_mode;
C
복사
1.
Disasm할 실행 파일 기준으로 정리
a.
load_binary 함수 내에서 파일 로드 시 자체적으로 아키텍쳐, 운영체제 비트를 체크함.
2.
캡스톤의 아키텍쳐, 모드 정의된 타입을 binary 객체에서도 동일하게 사용하여 중복 제거.
basic_capstone_linear.cc
// basic_capstone_linear /* Linearly disassemble a given binary using Capstone. */ #include <stdio.h> #include <string> //#include <capstone/capstone.h> #include "../inc/loader.h" // 캡스톤 해더를 로더 안에서 받아서 사용 int disasm(Binary *bin) { csh dis; cs_insn *insns; Section *text; size_t n; text = bin->get_text_section(); if(!text) { fprintf(stderr, "Nothing to disassemble\n"); return 0; } if(cs_open(bin->csarch, bin->csmode, &dis) != CS_ERR_OK) { // 변경 fprintf(stderr, "Failed to open Capstone\n"); return -1; }
C++
복사
loader.h
#ifndef LOADER_H #define LOADER_H #include <stdint.h> #include <string> #include <vector> #include <capstone/capstone.h> // 추가함 ... class Binary { public: enum BinaryType { BIN_TYPE_AUTO = 0, BIN_TYPE_ELF = 1, BIN_TYPE_PE = 2 }; // 기존의 arch, mode 타입을 삭제하고 capstone에서 사용하는 타입으로 통일 Binary() : type(BIN_TYPE_AUTO), csarch(CS_ARCH_ALL), csmode(CS_MODE_LITTLE_ENDIAN), entry(0) {} Section *get_text_section() { for(auto &s : sections) if(s.name == ".text") return &s; return NULL; } std::string filename; BinaryType type; std::string type_str; cs_arch csarch; std::string arch_str; cs_mode csmode; uint64_t entry; std::vector<Section> sections; std::vector<Symbol> symbols; };
C++
복사
loader.cc
static int load_binary_bfd(std::string &fname, Binary *bin, Binary::BinaryType type) { int ret; bfd *bfd_h; const bfd_arch_info_type *bfd_info; bfd_h = NULL; bfd_h = open_bfd(fname); if(!bfd_h) { goto fail; } bin->filename = std::string(fname); bin->entry = bfd_get_start_address(bfd_h); bin->type_str = std::string(bfd_h->xvec->name); switch(bfd_h->xvec->flavour) { case bfd_target_elf_flavour: 228,3 70% switch(bfd_h->xvec->flavour) { case bfd_target_elf_flavour: bin->type = Binary::BIN_TYPE_ELF; break; case bfd_target_coff_flavour: bin->type = Binary::BIN_TYPE_PE; break; case bfd_target_unknown_flavour: default: fprintf(stderr, "unsupported binary type (%s)\n", bfd_h->xvec->name); goto fail; } bfd_info = bfd_get_arch_info(bfd_h); bin->arch_str = std::string(bfd_info->printable_name); switch(bfd_info->mach) { case bfd_mach_i386_i386: bin->csarch = Binary::CS_ARCH_X86; bin->csmode = Binary::CS_MODE_32; break; case bfd_mach_x86_64: bin->csarch = Binary::CS_ARCH_X86; bin->csmode = Binary::CS_MODE_64; break; default: fprintf(stderr, "unsupported architecture (%s)\n", bfd_info->printable_name); goto fail; } /* Symbol handling is best-effort only (they may not even be present) */ load_symbols_bfd(bfd_h, bin); load_dynsym_bfd(bfd_h, bin); if(load_sections_bfd(bfd_h, bin) < 0) goto fail; ret = 0; goto cleanup; fail: ret = -1; cleanup: if(bfd_h) bfd_close(bfd_h); return ret; }
C++
복사

2. 코드 겹침 난독화 기법 탐지 기능 구현

예제의 선형 디스어셈블 도구는 코드 겹침 기법을 통한 난독화를 대응할 수 있음을 보였다.
그런데 코드 겹침 기법이 존재한다는 명시적인 안내 문구를 출력하지는 않는다.
해당 예제를 개선해, 만약 코드 겹침 난독화의 흔적이 발견됐다면 사용자가 참고할 수 있도록 경고 메시지 를 출력하라.
1.
선형 디스어셈블이 코드 겹침을 체크할 수 있다고...?
해당 논문 에 의하면 linear Disasmbler의 경우 Code coverage가 99%로 확인 되었음
실제로 코드 겹침에 의해 A행의 인스트럭션이 오류가 나더라도. A 행 및 A+1행이 오류, A+2부터는 다시 정상적으로 해석이 가능한 것으로 확인 됨.
2.
오피코드가 비정상적인 어셈블리부터 확인
a.
비정상적인 것을 어떻게 체크 할 것인가
i.
조건문 jump 구문(i)인 mnemonic 값을 찾는다
1.
i의 op_str이 0x로 시작되는 직접 점프(immidate jump)인지 확인
a.
op_str을 uint64_t로(점프 주소값) 변환하여 i+1의 address보다 작은지 비교
i.
i의 address가 점프 주소값보다 큰지 비교
1.
클 경우 찾은 i의 op_str에 warning Instruction Overlapping 문자열 추가
명령어 겹침(instruction overlapping) ≠ Break Alignment일 가능성이 있음
6장에서 사용했던 샘플을 이용하여 다시 테스트
원본
objdump -d ori_alignment 0000000000400526 <main>: 400526: 55 push %rbp 400527: 48 89 e5 mov %rsp,%rbp 40052a: bf d4 05 40 00 mov $0x4005d4,%edi 40052f: e8 cc fe ff ff callq 400400 <puts@plt> 400534: bf ec 05 40 00 mov $0x4005ec,%edi 400539: e8 c2 fe ff ff callq 400400 <puts@plt> 40053e: b8 00 00 00 00 mov $0x0,%eax 400543: 5d pop %rbp 400544: c3 retq 400545: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 40054c: 00 00 00 40054f: 90 nop
C++
복사
alignment 부순 샘플
./basic_capstone_linear a.out 0x0000000000400526: 55 push rbp 0x0000000000400527: 48 89 e5 mov rbp, rsp 0x000000000040052a: bf d4 05 40 00 mov edi, 0x4005d4 0x000000000040052f: e8 cc fe ff ff call 0x400400 0x0000000000400534: eb 01 jmp 0x400537 0x0000000000400536: e8 bf ec 05 40 call 0x4045f1fa // 처음 깨진 라인 A 0x000000000040053b: 00 e8 add al, ch // A2 0x000000000040053d: bf fe ff ff b8 mov edi, 0xb8fffffe // A3 0x0000000000400542: 00 00 add byte ptr [rax], al // A4 0x0000000000400544: 00 00 add byte ptr [rax], al // A5 0x0000000000400546: 5d pop rbp 0x0000000000400547: c3 ret
C
복사
책에서 말하는 코드 겹침(명령어 겹침)은 단순히 Break alignment 뿐만 아니라, 책의 overlapping 예시처럼 해당 분기문을 기점으로 또다른 명령을 수행하는 것을 원하는듯
0x00000000004005f6: 55 push rbp 0x00000000004005f7: 48 89 e5 mov rbp, rsp 0x00000000004005fa: 89 7d ec mov dword ptr [rbp - 0x14], edi 0x00000000004005fd: c7 45 fc 00 00 00 00 mov dword ptr [rbp - 4], 0 0x0000000000400604: 8b 45 ec mov eax, dword ptr [rbp - 0x14] 0x0000000000400607: 83 f8 00 cmp eax, 0 0x000000000040060a: 0f 85 02 00 00 00 jne 0x400612 0x0000000000400610: 83 f0 04 xor eax, 4 0x0000000000400613: 04 90 add al, 0x90 0x0000000000400615: 89 45 fc mov dword ptr [rbp - 4], eax 0x0000000000400618: 8b 45 fc mov eax, dword ptr [rbp - 4] 0x000000000040061b: 5d pop rbp 0x000000000040061c: c3 ret
C
복사
소스코드 작성 완료
int disasm(Binary *bin) { csh dis; cs_insn *insns; Section *text; size_t n; text = bin->get_text_section(); if(!text) { fprintf(stderr, "Nothing to disassemble\n"); return 0; } if(cs_open(bin->csarch, bin->csmode, &dis) != CS_ERR_OK) { fprintf(stderr, "Failed to open Capstone\n"); return -1; } n = cs_disasm(dis, text->bytes, text->size, text->vma, 0, &insns); if(n <= 0) { fprintf(stderr, "Disassembly error: %s\n", cs_strerror(cs_errno(dis))); return -1; } for(size_t i = 0; i < n; i++) { printf("0x%016jx: ", insns[i].address); for(size_t j = 0; j < 16; j++) { if(j < insns[i].size)printf("%02x ", insns[i].bytes[j]); else printf(" "); } printf("%-12s %s\n", insns[i].mnemonic, insns[i].op_str);// 해당 부분 밑으로 추가 if(insns[i].mnemonic[0] == 'j' && insns[i].mnemonic[1] != 'm') { if(insns[i].op_str[0] == '0' && insns[i].op_str[1] == 'x') { uint64_t addr = (uint64_t)strtol(insns[i].op_str,NULL,0); for(size_t fi = i; fi < n; fi++){ if(insns[fi+1].address > addr){ if(insns[fi].address < addr) { char wrongstring[45] = "\t[Instruction Overlapping Detection!]"; strcat(insns[fi].op_str,wrongstring); break; } } } } } } cs_free(insns, n); cs_close(&dis); return 0; } ./basic_capstone_linear overlapping_bb 0x00000000004005eb: 48 89 e5 mov rbp, rsp 0x00000000004005ee: ff d0 call rax 0x00000000004005f0: 5d pop rbp 0x00000000004005f1: e9 7a ff ff ff jmp 0x400570 0x00000000004005f6: 55 push rbp 0x00000000004005f7: 48 89 e5 mov rbp, rsp 0x00000000004005fa: 89 7d ec mov dword ptr [rbp - 0x14], edi 0x00000000004005fd: c7 45 fc 00 00 00 00 mov dword ptr [rbp - 4], 0 0x0000000000400604: 8b 45 ec mov eax, dword ptr [rbp - 0x14] 0x0000000000400607: 83 f8 00 cmp eax, 0 0x000000000040060a: 0f 85 02 00 00 00 jne 0x400612 0x0000000000400610: 83 f0 04 xor eax, 4 [Instruction Overlapping Detection!] 0x0000000000400613: 04 90 add al, 0x90 0x0000000000400615: 89 45 fc mov dword ptr [rbp - 4], eax 0x0000000000400618: 8b 45 fc mov eax, dword ptr [rbp - 4] 0x000000000040061b: 5d pop rbp 0x000000000040061c: c3 ret 0x000000000040061d: 55 push rbp 0x000000000040061e: 48 89 e5 mov rbp, rsp 0x0000000000400621: 48 83 ec 10 sub rsp, 0x10 0x0000000000400625: 89 7d fc mov dword ptr [rbp - 4], edi 0x0000000000400628: 48 89 75 f0 mov qword ptr [rbp - 0x10], rsi
C
복사
정렬이 조금 깨졌지만, 정상적으로 Instruction overlapping을 탐지하는 것을 확인할 수 있음.
Reference
sec16_paper_andriesse.pdf
420.8KB
PE Header Machine 값 (winnt.h)
#define IMAGE_FILE_MACHINE_UNKNOWN 0 #define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386. #define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian #define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian #define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2 #define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP #define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian #define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 #define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian #define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian #define IMAGE_FILE_MACHINE_SH5 0x01a8 // SH5 #define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian #define IMAGE_FILE_MACHINE_THUMB 0x01c2 #define IMAGE_FILE_MACHINE_AM33 0x01d3 #define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // IBM PowerPC Little-Endian #define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 #define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64 #define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS #define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64 #define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // MIPS #define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS #define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 #define IMAGE_FILE_MACHINE_TRICORE 0x0520 // Infineon #define IMAGE_FILE_MACHINE_CEF 0x0CEF #define IMAGE_FILE_MACHINE_EBC 0x0EBC // EFI Byte Code #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) #define IMAGE_FILE_MACHINE_M32R 0x9041 // M32R little-endian #define IMAGE_FILE_MACHINE_CEE 0xC0EE
JavaScript
복사
arm elf 파일 구조
DUI0101A_Elf.pdf
103.8KB