Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

PE File Format and Packer - Inc0gnito 2016

PE File Format and Packer - Inc0gnito 2016

Incognito Conference 5회에서 발표했던 자료입니다.
PE File 구조에 대한 이해와, 이를 바탕으로 PE Packer를 분석해 보았습니다.

  • Inicia sesión para ver los comentarios

PE File Format and Packer - Inc0gnito 2016

  1. 1. 2016년 8월 16일 PE File Format & Packer KUICS 장하진
  2. 2. 2 Who am I?  고려대학교 정보보호동아리 KUICS 12대 회장 (2015.12 ~ 현재)  차세대 보안리더 양성프로그램 BoB 4기 수료생  https://joveler.kr  https://ied206.github.io  https://github.com/ied206  http://www.slideshare.net/ied206 KUICS
  3. 3. PE File Format exe 파일의 정체는?
  4. 4. 4 PE File이란?  Windows에서 사용하는 실행 파일 포맷  Portable Executable의 약자  대표적인 PE File Format - exe (실행 파일) - dll (동적 링크 라이브러리) - sys (드라이버) KUICS
  5. 5. 5 PE File 구조  다음과 같은 구조로 이루어져 있다.  DOS Header  DOS Stub  COFF File Header  Optional Header  Section Header  Sections - .text, .data 등 KUICS
  6. 6. 6 PE File 구조 – 1) DOS Header & Stub  PE File은 DOS의 MZ 실행 파일 규격에 대한 하위 호환성을 지닌다.  MS-DOS에서 Windows의 exe 파일을 실행할 경우 다음과 같은 문구를 볼 수 있 다.  동일 exe 파일은 Windows에서 다음과 같이 실행된다.  즉, 하나의 파일이 운영체제에 따라 다르게 실행된다. KUICS
  7. 7. 7 PE File 구조 – 1) DOS Header & Stub  이러한 구조가 가능한 이유?  PE File은 DOS MZ 규격을 확장한 형태이다.  DOS Header  DOS Stub  DOS에서 PE File을 실행하면 DOS Stub을 실행하고 종료한다.  Windows에서 PE File을 실행할 때, 이 DOS 관련 부분을 곧바로 건너뛴다. KUICS
  8. 8. 8 PE File 구조 – 2) COFF File Header  PE File은 MZ 포맷의 확장이기도 하지만 COFF 포맷의 확장이기도 하다.  대표적으로 다음과 같은 값을 지닌다.  Machine  SizeOfOptionalHeader  Characteristics KUICS
  9. 9. 9 PE File 구조 – 3) Optional File Header  PE File이 메모리에 로드되기 위해 필요한 정보들이 이곳에 담겨 있다.  AddressOfEntryPoint  ImageBase  SectionAlignment  FileAlignment  SizeOfImage  SizeOfHeader  Subsystem  NumberOfRavAndSizes  DataDirectory KUICS
  10. 10. 10 PE File 구조 – 3) Optional File Header  AddressOfEntryPoint - 처음 실행될 때 어디부터 시작할지 결정  ImageBase - 가상 메모리 주소에서 PE File이 로드되는 기준 위치  FileAlignment & SectionAlignment - Section의 크기는 반드시 특정 값의 배수여야 한다. - 파일 상태 : FileAlignment의 배수 - 메모리 : SectionAlignment의 배수  SizeOfImage - PE 파일이 메모리에 로드되었을 때 차지하는 크기  Subsystem - PE 파일이 실행될 때 사용하는 Windows의 Subsystem KUICS
  11. 11. 11 PE File 구조 – 4) Section  실행 파일은 크게 기계어와 기계어가 사용하는 데이터로 이루어져 있다.  PE File은 이들을 별도의 영역에 분리해 보관한다.  .text - 기계어 코드  .data - 데이터 (전역변수, 상수 등)  .rsrc - 아이콘 등의 리소스 KUICS
  12. 12. 12 PE File 구조 – 4) Section  각각의 Section은 별도의 권한을 가진다.  Ex) Read, Write, Execute  .text - Read, Execute  .data - Read, Write  .rsrc - Read, Write KUICS
  13. 13. 13 PE File 구조 – 4) Section  Section Header - 각 섹션에 대한 정보가 담겨 있다.  VirtualSize  VirtualAddress (VirtualOffset) - 섹션이 메모리에 로딩되었을 상태의 크기와 시작 위치 - VirtualAddress는 SectionAlignment의 배수  SizeOfRawData (RawSize)  PointerToRawData (RawOffset) - 파일 상태일때의 섹션의 크기와 시작 위치 - PointerToRawData는 FileAlignment의 배수  Characteristics - 섹션의 속성 (Ex 권한) KUICS
  14. 14. 14 PE File 구조 – 4) Section PE (File) .text .data .rsrc KUICS PE (Memory) .text .data .rsrc
  15. 15. 15 VA & RVA  하나의 exe 파일이 실행될 때는 다음 과 같이 메모리 구역을 용도에 맞게 나눠 사용한다.  다양한 dll도 함께 로드된다. KUICS
  16. 16. 16 VA & RVA  Virtual Memory (VA) - 가상 메모리의 절대주소  Relative Virtual Memory (RVA) - Base Address부터의 상대주소  PE File 내부의 메모리 주소는 RVA로 표현되어 있다.  PE File이 메모리에 올라갈 때 RVA 주소값은 절대주소인 VA로 변환된다.  RVA로 메모리 주소를 표현한 이유는 Base Address는 로드시마다 다르게 바뀔 수 있기 때문이다.  PE 파일을 조작하고 분석하기 위해선 RVA와 RAW의 관계를 잘 알아야 한다. KUICS
  17. 17. 17 VA & RVA  다음 이유들로 인해 메모리와 파일 형태에 차이가 생긴다. - FileAlignment와 SectionAlignment의 차이 - RVA의 사용  메모리 형태에서 본 주소를 PE 파일과 매핑하려면, VA와 RVA 사이의 관계를 알아 야 한다.  VA = BaseAddress + RVA  RAW – PointerToRawData = RVA – VirtualAddress  PointerToRawData : 파일에서 RVA가 속해 있는 섹션의 시작 위치  VirtualAddress : 메모리에서 RVA가 속해 있는 섹션의 시작 위치 KUICS
  18. 18. 18 PE File 구조 – 4) Section PE (File) .text .data .rsrc KUICS PE (Memory) .text .data .rsrc
  19. 19. 19 IAT  Import Address Table - dll에서 불러 사용하는 함수의 주소값을 보관할 영역  dll에서 불러 사용하는 함수의 주소는 PE 파일의 상태에 따라 다르다. - 파일 형태에서는 RVA로 표현되어 있다. - 메모리에 로드되면 이 RVA가 VA값으로 바뀐다. KUICS
  20. 20. 20 IAT  CloseHandle의 주소가 0x400000 + 0x122B8로 표기되어 있다.  0x4122B8를 통해 0x73BB9660에 있는 Kernel32.dll의 CloseHandle로 간다.  dll에 있는 함수를 호출하는 경우, 이와 같이 IAT를 활용한 간접 호출을 한다. KUICS
  21. 21. 21 IAT  실행파일 내부에서 API를 호출할 때 다음과 같은 과정을 거친다. - 코드 -> API (X) - 코드 -> IAT -> API (O)  후자는 속도가 더 느려지지 않을까?  DLL이 메모리에 로드될 때 ImageBase 값이 변경될 수 있다.  VA는 ImageBase 값에 따라 변동된다.  이러한 특징 때문에 API의 주소를 VA로 하드코딩할 수 없다.  따라서, API의 주소는 dll에 대한 RVA로 적혀 있으며 dll이 로딩되는 시점에 VA로 변환된다. KUICS
  22. 22. PE Packer 분석 UPX와 UPack의 세계로! KUICS
  23. 23. 23 PE Packer  Packer의 종류  Compressor - 실행 프로그램의 용량을 줄인다. Ex) UPX  Protector - 실행 프로그램의 역공학을 방해한다. - 상용프로그램의 경우, 핵심 알고리즘의 역공학을 막기 위해 사용 Ex) Themida - 악성코드는 백신 탐지를 어렵게 할 목적으로 사용 Ex) UPack KUICS
  24. 24. 24 Compressor : UPX  실행 압축계의 No1 패커 - http://upx.sourceforge.net/  다양한 운영체제와 아키텍쳐를 지원한다. - OS : Windows, macOS, Linux, FreeBSD, OpenBSD, NetBSD, MS-DOS 등 - Arch : amd64, i386, arm, mips, powerpc 등  압축해제 속도가 매우 빠른 UCL 라이브러리를 사용 - 실행 압축 특성상 압축해제가 빨라야 한다.  작동 방법 - 1) SFX 형태로 임시 폴더에 압축을 해제하여 실행 (extract to temp file) - 2) 실행되는 시점에 메모리에 압축 해제를 하고 실행 (in-place) - 대부분 2번 in-place 방법을 사용 KUICS
  25. 25. 25 Compressor : UPX  구조를 알아보기 위해 한 실행 프로그램을 패킹하고, 분석해보자.  패킹 전 - 다양한 섹션이 존재하는 것을 확인할 수 있다. - 섹션의 용도에 맞는 권한들을 가지고 있다. KUICS
  26. 26. 26 Compressor : UPX  패킹 중  212KB가 175KB로 줄어들었다 KUICS
  27. 27. 27 Compressor : UPX  패킹 후 - rsrc 섹션을 제외한 나머지 섹션들이 사라졌다. - UPX0, UPX1 모두 Read/Write/Execute 권한을 가지고 있다. - UPX0의 RawSize는 0이다 (파일 상태에서는 존재하지 않는다). - UPX0의 VirtualSize는 원본 파일의 섹션의 크기를 다 더한 것보다 크다. - UPX1은 RawSize를 가지고 있으며 VirtualSize의 크기와 같다. - UPX1에 EntryPoint가 존재한다.  이것들이 의미하는 바는? KUICS
  28. 28. 28 Compressor : UPX  패킹 후  가정 - UPX1 섹션에 EP가 존재하므로, 압축해제 코드가 존재하리라 알 수 있다. - UPX0 섹션의 RawSize가 0이지만 VirtualSize는 값이 크다는 점에서, 이 프로그램이 실행되는 시점에 원래의 데이터가 UPX0에 압축해제됨을 추측할 수 있다. - rsrc 섹션의 크기는 거의 똑같으므로, 압축된 데이터는 UPX1 섹션에 존재할 것이다. - UPX0 섹션은 Read/Write/Execute 권한을 모두 가지고 있으므로, code 섹션 (Read/Execute)과 data 섹션 (Read/Write)의 역할을 모두 할 것이다. KUICS
  29. 29. 29 Compressor : UPX  패킹 후  섹션 Offset (ImageAddress + VirtualOffset) - UPX0 = 0x400000 + 0x01000 = 0x401000 (~0x436FFFF) - UPX1 = 0x400000 + 0x37000 = 0x437000 (~0x43CFFFF)  EntryPoint - EP = 0x400000 + 0x3CC50 = 0x43CC50 - EP는 UPX1 섹션에 존재한다. KUICS
  30. 30. 30 Compressor : UPX  UPX의 압축 해제 코드를 분석해보자.  IDA로 패킹된 프로그램을 열 경우 IAT가 깨져있다는 경고가 나타난다.  -> UPX는 압축시 IAT를 건드린다는 점을 알 수 있다. KUICS
  31. 31. 31 Compressor : UPX  패킹 전의 IAT KUICS
  32. 32. 32 Compressor : UPX  패킹 후의 IAT  압축 해제에 필수적인 API만 제대로 표시되고 있다. KUICS
  33. 33. 33 Compressor : UPX  패킹된 파일은 단 두개의 함수만을 가지고 있다.  start 함수가 압축해제 코드일 가능성이 높다. KUICS
  34. 34. 34 Compressor : UPX  start 함수는 PUSHA로 시작하여 POPA ~ JMP 문으로 끝난다. KUICS
  35. 35. 35 Compressor : UPX  첫 부분에서 ESI와 EDI를 세팅하고 있다.  어셈블리어에서 ESI와 EDI가 쓰일 경우 관용적으로 다음을 가리킨다. - ESI : Source, 데이터를 읽어올 주소 - EDI : Destination, 데이터를 쓸 주소  즉, 다음 가능성이 높다. - ESI : 압축된 데이터의 주소 - EDI : 원본 데이터가 들어가야 할 위치 KUICS
  36. 36. 36 Compressor : UPX  첫 부분에서 ESI와 EDI를 세팅하고 있다.  세팅되는 값을 살펴보자. - ESI = 0x437015 - EDI = 0x401000  즉, ESI는 UPX1 섹션, EDI는 UPX0 섹션을 가리키고 있다. - UPX0 = 0x401000 ~ 0x436FFFF - UPX1 = 0x437000 ~ 0x43CFFFF KUICS
  37. 37. 37 Compressor : UPX  [EDI]에 쓰기를 하는 코드가 있는 곳이 패킹된 파일을 원래 상태로 복구하는 핵심 부분이다. KUICS
  38. 38. 38 Compressor : UPX  CALL을 만났다.  뭐하는 녀석이지? KUICS
  39. 39. 39 Compressor : UPX  더 진행하면 CALL로 함수를 호출하는 부분이 존재한다. KUICS
  40. 40. 40 Compressor : UPX  동적 분석 결과, LoadLibrary와 GetProcAddress를 호출하고 있음을 알 수 있다. KUICS
  41. 41. 41 Compressor : UPX  UPX로 패킹된 프로그램은 IAT Table에 함수의 RVA가 없어 불완전하다.  LoadLibrary로 dll을 로드하고 그 주소를 EBP에 저장한다.  dll 명단은 IAT에서 직접 가져온다. KUICS
  42. 42. 42  UPX로 패킹된 프로그램은 IAT Table에 함수의 RVA가 없어 불완전하다.  GetProcAddress을 dll 주소 (EBP), 함수 이름(EDI)을 인자로 주고 호출한다.  API의 주소(VA)를 얻어 (EAX) EBX가 가리키는 곳에 복사한다. Compressor : UPX KUICS
  43. 43. 43 Compressor : UPX  마무리로, 메모리 특정 구역의 권한을 설정한다. KUICS
  44. 44. 44 Compressor : UPX  동적 분석 결과, 다음과 같은 작업을 한다.  VirtualProtect(0x400000, 0x1000, PAGE_READWRITE, &지역변수);  VirtualProtect(0x400000, 0x1000, PAGE_READONLY, &지역변수);  TlsCallback(…); KUICS
  45. 45. 45 Compressor : UPX  마지막 단계  POPA 명령으로 레지스터를 복구한다.  그 뒤 원래의 EP로 JMP한다. KUICS
  46. 46. 46 Compressor : UPX  패킹 전 원본 파일의 EP KUICS
  47. 47. 47 Compressor : UPX  패킹된 프로그램의 압축해제 전 (원본의 EP)  NULL Padding만 존재한다. KUICS
  48. 48. 48 Compressor : UPX  패킹된 프로그램의 압축해제 후 (원본의 EP)  원본과 같은 코드가 나타난 것을 볼 수 있다. KUICS
  49. 49. 49 Compressor : UPX  UPX 압축해제가 정상적으로 끝난 상태에서 F9를 눌러주면?  원본이 실행되듯이 정상적으로 잘 실행된다. KUICS
  50. 50. 50 Compressor : UPX  결론  UPX의 압축 해제는 다음과 같은 순서로 진행된다.  UCL 알고리즘으로 압축된 PE 섹션의 압축 해제 -> IAT 복구 KUICS
  51. 51. 51 Compressor : UPX  사족 : 디버거의 빼애애액  패커가 적용되었을 때 디버거에서 BP를 걸면 다음과 같은 경고 메시지가 뜬다.  디버거는 EP를 보고 어떤 섹션이 code 섹션인지 구분한다.  패커가 EP를 다른 섹션으로 바꿔버렸기 때문에 디버거에 혼동이 온 것. KUICS
  52. 52. 52 Protector : UPack  PE 파일을 난독화시키는 패커이다.  헤더를 꼬아 파일의 구조를 완벽하게 바꿔 버리기에 리버싱에 큰 지장이 온다.  Windows의 PE 로더가 PE 표준 규격보다 너그럽게 구현된 것을 악용한다. KUICS
  53. 53. 53 Protector : UPack  원본 PE 파일 헤더 구조 - 헤더들이 순서대로 붙어 있다. KUICS DOS MZ Header COFF Header DOS Stub Optional Header
  54. 54. 54 Protector : UPack  UPack으로 패킹한 후의 PE 헤더 - 헤더들이 이리저리 꼬여 있다. KUICS DOS MZ Header COFF Header Optional Header
  55. 55. 55 Protector : UPack 헤더 겹치기  Windows는 DOS Stub을 전혀 참고하지 않으며, MZ Header의 맨 마지막 값, e_lfnew 값을 보고 PE 헤더의 시작점을 찾는다.  PE 규격에 COFF Header의 시작 오프셋은 정해져 있지 않다.  MZ Header의 e_lfnew 값을 MZ Header의 바깥이 아닌, 안을 향하게 만들어 서 헤더를 겹치게 만든다. KUICS DOS MZ Header COFF Header Optional Header
  56. 56. 56 Protector : UPack Section 겹치기 + Alignment 꼬기  섹션의 메모리상 Offset (ImageAddress + VirtualOffset) - Sec01 = 0x400000 + 0x01000 = 0x401000 (~0x43BFFFF) - Sec02 = 0x400000 + 0x3C000 = 0x43C000 (~0x46DFFFF) - Sec03 = 0x400000 + 0x6E000 = 0x46E000 (~0x46EFFFF)  섹션의 파일상 Offset (PointerToRawData) - Sec01 = 0x000010 ~ 0x0001FF - Sec02 = 0x000200 ~ 0x02AAB7 - Sec03 = 0x000010 ~ 0x0001FF  파일상 Offset이 이상하다? KUICS
  57. 57. 57 Protector : UPack Section 겹치기 + Alignment 꼬기  섹션의 파일상 Offset (PointerToRawData) - Sec01 = 0x000010 ~ 0x0001FF - Sec02 = 0x000200 ~ 0x02AAB7 - Sec03 = 0x000010 ~ 0x0001FF  파일상 Offset이 이상하다? - 파일상의 Offset은 반드시 FileAlignment의 배수여야 한다. - 일반적으로 FlieAlignment는 0x200 (512)의 값을 가진다. - 그런데 0x10은 0x200의 배수가 아니다.  Windows의 PE Loader는 이 경우 강제로 배수에 맞춘다. KUICS
  58. 58. 58 Protector : UPack Section 겹치기 + Alignment 꼬기  즉 여기서 0x10의 RawOffset은 0x0 또는 0x200으로 교정된다. - 테스트 결과 0x00으로 계산됨  실제 파일상 Offset (PointerToRawData) - Sec01 = 0x000000 ~ 0x0001EF - Sec02 = 0x000200 ~ 0x02AAB7 - Sec03 = 0x000000 ~ 0x0001EF  RAW to RVA를 계산할 때도 이 점에 유의해야 한다. KUICS
  59. 59. 59 Protector : UPack Section 겹치기 + Alignment 꼬기  EntryPoint (RAW)를 계산해보자.  헤더에 따르면, EntryPoint (RVA)는 0x00001018이다.  이 RAW 주소는 Sec01 및 Sec03에 속한다.  RAW = RVA–VirtualOffset + RawOffset  EP (RAW) = 0x1018 – 0x1000 + 0x10 = 0x28 (X)  그러나 RawOffset이 0x10으로, 0x200의 배수가 아니므로 0x0으로 교정한다.  EP (RAW) = 0x1018 – 0x1000 + 0x0 = 0x18(O) KUICS
  60. 60. 60 Protector : UPack  x64dbg의 경우, Sec01에 진입을 시도할 시 크래시가 발생한다. KUICS
  61. 61. 61 Protector : UPack  Immunity Debugger  패킹된 프로그램의 EP로 접근하지 못한다. KUICS
  62. 62. 62 Protector : UPack  UPack이 RAW to RVA 변환법을 꼬아놓기에 Immunity Debugger가 EP를 제 대로 계산하지 못해 발생하는 문제이다.  EP를 강제로 지정해야 디버깅이 가능하다.  EP = ImageBase + EntryPoint (RVA)  EP = 0x400000 + 0x001018 = 0x401018 KUICS
  63. 63. 63 Protector : UPack  EP를 강제로 지정해야 디버깅이 가능하다.  Ctrl + G -> 00401018 (EP) 입력  New origin here로 EP 강제 지정. KUICS
  64. 64. 64 Protector : UPack  정상적인 PE 파일이 아니기에 Ctrl + G를 통해 00401018로 직접 이동하지 않으 면 어셈블리 코드가 비정상적으로 표기된다.  정상  디버거의 표시 KUICS
  65. 65. 65 Protector : UPack  IDA Pro는?  경고 5관왕 달성! KUICS
  66. 66. 66 Protector : UPack  4) Section 겹치기 + Alignment 꼬기  섹션의 파일상 Offset (PointerToRawData) - Sec01 = 0x000010 ~ 0x0001FF - Sec02 = 0x000200 ~ 0x02AAB7 - Sec03 = 0x000010 ~ 0x0001FF  파일상 Offset이 이상하다? - 파일상의 Offset은 반드시 FileAlignment의 배수여야 한다. - 일반적으로 FlieAlignment는 0x200 (512)의 값을 가진다. - 그런데 0x10은 0x200의 배수가 아니다.  Windows의 PE Loader는 이 경우 강제로 배수에 맞춘다. KUICS
  67. 67. 67 Protector : UPack  가정  Sec01은 파일 상태의 크기는 작으나, 메모리 상태의 크기는 크다.  Sec02는 파일 상태의 크기와 메모리 상태의 크기가 모두 크다.  Sec03은 파일 상태의 크기와 메모리 상태의 크기가 모두 작다.  용량으로 보아 Sec02에 압축된 원본 데이터가 존재하리라 추측할 수 있다.  Sec01이 Sec02보다 메모리 상태의 크기가 더 크다.  이를 통해 Sec01에 원본 데이터가 압축해제 된다는 점을 추측할 수 있다. KUICS
  68. 68. 68 Protector : UPack  EP에서 몇가지 연산을 수행한 이후 0x004667A3 으로 JMP한다. KUICS
  69. 69. 69 Protector : UPack  0x4667A3 이후부터는 CALL DWORD PTR [ESI] 구문이 자주 등장한다. KUICS
  70. 70. 70 Protector : UPack  CALL DWORD PTR DS:[ESI] 실행시 0x46675B 함수를 호출한다.  인자를 EAX와 EDX로 받는다.  자주 호출되는 것을 보아 압축 해제를 담당하는 코드일 가능성이 높다. KUICS
  71. 71. 71 Protector : UPack  [ESI] 뿐만 아니라 [ESI+54], [ESI+50]도 호출하고 있다. KUICS
  72. 72. 72 Protector : UPack  BP를 걸고 F9를 계속 눌러보자. KUICS
  73. 73. 73 Protector : UPack  원본 프로그램의 .text 섹션  패킹된 프로그램 디버깅 중 살펴본 동일 영역 KUICS 압축 해제가 이루어지고 있다.
  74. 74. 74 Protector : UPack  이 시점에서 다시 IAT를 살펴보자.  IAT를 복구할 때 필요한 두 API만 여기에 존재한다.  원래의 IAT 명단을 복구해야 하므로, IAT를 복구하는 코드가 존재할 것이다. KUICS
  75. 75. 75 Protector : UPack  그런데 이 주소를 직접 부르고 있지 않아 정적 분석으로는 추적이 불가능하다!  동적 분석 중 0x4011E8나 0x4011EC를 CALL하는 부분을 찾자.  모든 CALL에 BP를 걸고 진행하며 찾다보면 나오지 않을까? KUICS
  76. 76. 76 Protector : UPack  0x466923  LoadLibraryA("GDI32.DLL"); KUICS
  77. 77. 77 Protector : UPack  0x46693A  GetProcAddress([HANDLE of GDI32.DLL], "BitBlt"); KUICS
  78. 78. 78 Protector : UPack  EAX에 BitBlt 값이 반환되고, STOS를 통해 EAX의 값을 [EDI]에 복사한다. KUICS
  79. 79. 79 Protector : UPack  F9를 반복해서 눌러 상황을 보자.  IAT가 복구되고 있다. KUICS
  80. 80. 80 Protector : UPack  IAT를 복구한 뒤 원래의 EP로 JMP한다. KUICS 패킹 전 원본 파일 패킹 복구 후
  81. 81. 81 Protector : UPack  결론  UPack도 UPX와 마찬가지로 실행시 압축 해제 -> IAT 복구 순서를 거친다.  용량을 줄이기 위해 압축만 하는 UPX와는 달리, UPack은 PE 헤더의 값을 꼬아 분 석의 난이도를 높인다.  결과적으로 리버싱과 같은 바이너리 분석을 크게 방해한다. KUICS
  82. 82. Q&A KUICS
  83. 83. 2016-08-19 동아리이름

×