본문 바로가기

4-3. 2023-2 심화 스터디/윈도우 악성코드 분석

[2023.10.07] 인프런 윈도우 악성코드(malware) 분석 입문 과정 강의 수강 - 섹션 0, 섹션 1

인프런 - 윈도우 악성코드(malware) 분석 입문 과정 섹션 0의 1.6 ~ 1.8 강의와 섹션 1 강의를 수강하였다.


▶ 섹션 0 - 1.6 ~ 1.8

1. 올리디버거

  • 올리 유스척이 개발한 x86 디버거

 

1.1. CPU 인터페이스

  • 디스어셈블러 : 어셈블리어를 볼 수 있다.
  • 레지스터 : 레지스터의 내용을 볼 수 있다.
  • 덤프 윈도우 : 메모리에 저장된 값을 볼 수 있다.
  • 스택 : 스택의 상태를 볼 수 있다.

 

1.2. 메모리 맵

  • 프로그램의 배열 상태를 확인할 수 있다.

 

1.3. 스레드

  • View → Threads를 통해 현재 실행 스레드를 확인할 수 있다.
    • 각 스레드는 개별 스택을 가지고 있다.

 

2. 올리디버거 사용 방법

2.1. 올리디버거 기본 단축키

실행(Run/Play) Debug → Run F9
정지(Pause) Debug → Pause F12
선택까지 실행 Breakpoint → Run to Selection F4
리턴까지 실행 Debug → Execute till Return Ctrl + F9
사용자 코드 전까지 실행 Debug → Execute till User Code Alt + F9
싱글 스텝 / 스텝 인투 Debug → Step Into F7
스텝 오버 Debug → Step Over F8
함수 따라가기   Enter
뒤로 가기   -

 

2.2. 브레이크 포인트 단축키

소프트웨어 브레이크 포인트 Breakpoint → Toggle F2
조건 브레이크 포인트 Breakpoint → Conditional Shift + F2
하드웨어 브레이크 포인트 Breakpoint → Hardware, on Execution  
접근(읽기, 쓰기, 실행)에 대한    
메모리 브레이트 포인트 Breakpoint → Memory, on Access F2(메모리 선택)
쓰기에 대한 메모리 브레이크 포인트 Breakpoint → Memory, on Write  

 

3. 레나튜토리얼 1번 분석 및 해결 방법

  • 올리디버거에서 reverseMe.exe 파일을 실행한다.

 

  • 라이센스를 새로 구입하라는 팝업창이 뜨면서, 프로그램이 종료되는 것을 확인할 수 있다.

 

  • 가장 먼저, Keyfile.dat 파일이 존재하는지 확인한다.

 

  • Keyfile.dat 파일이 없으면, 라이센스를 새로 구입하라는 팝업창을 출력한다.

 

  • Keyfile.dat 파일이 존재하면 Keyfile.dat 파일을 읽어온 뒤, 다음 코드를 실행한다.

 

  • 메모장을 이용해 Keyfile.dat 파일을 생성한다.
  • 이때, 프로그램에서 keyfile.dat 파일의 내용을 읽어오므로 임의 값 aaaaa를 넣어준다.

 

  • 그리고, reverseMe.exe와 같은 경로에 해당 파일을 저장한다.

 

  • reverseMe.exe를 다시 실행해보면 팝업 문구가 달라진 것을 확인할 수 있다.
  • Keyfile.dat 파일의 내용이 올바르지 않다는 내용이 출력된다.

 

  • Keyfile.dat 파일을 정상적으로 읽으면, [402173] 주소에 저장된 값과 16진수 10을 비교한다.

 

  • [402173] 주소에 5가 저장 되어있는 것을 확인할 수 있다.
  • 새로 생성한 Keyfile.dat 파일에 a 5개를 저장했으므로 5가 저장된다.
  • 즉, [402173] 주소에는 Keyfile.dat 파일에서 읽어온 문자의 개수를 저장한다.

 

  • 그러나, [402173] 주소에 저장된 값과 16진수 10의 값이 달라 [004010F7] 주소로 점프하게 된다.

 

  • 그러므로, Keyfile.dat 파일에 a 16개를 넣어준다. (16진수 10 = 10진수 16)

 

  • 프로그램을 다시 실행하고, [402173] 주소에 저장된 값을 확인해보면 10이 저장되어 있다.

 

  • Keyfile.dat 파일에 저장된 문자열 개수가 16개 이상인 경우, [EAX+40211A] 주소에 저장된 값을 AL에 저장한다.

 

  • [40211A] 주소에 저장된 값을 확인해보니 Keyfile.dat의 내용이 저장되어 있다.

 

  • 프로그램을 실행하면 Keyfile.dat 파일의 내용이 올바르지 않다는 내용이 출력된다.

 

  • 다시 어셈블리를 해석해보면, EBX에는 Keyfile.dat 파일에 저장된 문자열에 접근하기 위한 인덱스 번호가 저장되고, ESI에는 Keyfile.dat 파일에 문자 G가 몇 개 저장되었는지 확인한다.
  • 즉, 반복문을 통해 Keyfile.dat 파일의 내용을 읽고, G의 개수가 몇 개인지 검사한다.
  • 따라서 Keyfile.dat 파일에 G를 8개 포함하고, 최소 16글자 이상 저장해야한다.

 

  • keyfile.dat에 G를 16개 저장한다.

 

  • 반복문이 끝나면, ESI가 10이 되면서 [004010F7] 주소가 아닌 [00401205] 주소로 점프하게 된다.

 

  • [00401205] 주소다.

 

  • 해당 명령어들을 실행하면, 축하 메세지가 출력된다.

 

▶ 섹션 1. PE 파일과 패커

1. PE 파일 개요

1.1. Portable Executable File Format : 파일(File)이 이식 가능한 다른 곳에 옮겨져도(Portable) 실행 가능하도록 (Executable) 만든 포맷(Format)

  • PE 포맷(위키피디아에서의 정의)
    • 윈도우에서 사용하는 실행 파일, DLL 파일 등을 위한 파일 형식
    • 윈도우 로더가 실행 가능한 코드를 관리하는데 필요한 정보를 캡슐화한 데이터 구 조체
    • 링킹을 위한 동적 라이브러리 참조, API 익스포트와 임포트 테이블, 자원 관리 데이 터 그리고 TLS 데이터를 포함

 

1.2. 실행 파일 컴파일 과정

  • C 코드 → 컴파일 → obj파일(시스템에서 인식 가능한 파일. 이 파일만으로는 호환 성을 제공하기 어려움) → 링킹 과정(링커) → exe 파일
    • obj: 시스템에서 인식 가능한 파일, 호환성 제공 어려움, h에 대한 내용만 가지고 있음
    • Link: 호환성을 연결해주기 위한 과정(Linking), DLL 리소스 데이터, Import, Export 테이블을 처리할 수 있는 정보를 윈도우에 약속된 규약 에 맞춰 파일 만듦
    • exe: Linker가 만드는 파일을 다 합한 것

 

1.3. PE 파일 분석에 사용되는 도구

  • PEview
  • Stud_PE
  • PEiD
  • exeinfo
  • pestudio
  • preframe.py

 

2. PE 파일 구조 이해

2.1. PE 파일 구조 주요 구조

  • IMAGE_DOS_HEADER
  • IMAGE_NT_HEADER
  • IMAGE_FILE_HEADER
  • IMAGE_OPTIONAL_HEADER
  • IMAGE_SECTION_HEADER
  • IMAGE_IMPORT_DESCRIPTOR
  • IMAGE_EXPORT_DIRECTORY
  • IMAGE_IMPORT_BY_NAME
  • IMAGE_THUNK_DATA32

 

  • IMAGE_DOS_HEADER
    • DOS 에서도 실행가능하도록 호환성을 제공하기 위한 헤더
    • MZ 헤더의 유무를 통해 바이너리가 PE 파일인지 검사
    • e_lfanew : MZ 헤더의 끝부분에 4바이트로 존재. PE 헤더의 위치를 알려주므로 중요.

 

  • IMAGE_NT_HEADER 1
    • Signature : PE|0|0, 4바잍, 바이러스에 자신의 시그니쳐를 심기도 함, 바이러스나 악성코드 감염 표식용으로 사용(지금은 x)

 

  • IMAGE_NT_HEADER 2
    • 나머지 두 개의 큰 구조체로 이루어짐
    • FileHeader, OptionalHeader
    • IMAGE_FILE_HEADER : WORD Machine(어떤 cpu에서 실행 가능한지 알림), WORD NumberOfsections(이 파일이 가진 세션의 개수를 알림, 일반적으로는 4개의 섹션이 존재), DWORD TimeDateStamp(obj→EXE 파일을 만든 시간을 알림), WORD SizeOfOptionalHeader(IMAGE_OPTIONAL_HEADER32의 구조체 크기를 알림), WORD Charcteristics(이 파일이 어떤 형식인지 알림)

 

  • IMAGE_NT_HEADER 3
  • IMAGE_OPTIONAL_HEADER : Standard Fields

 

  • IMAGE_FILE_HEADER
    • Machine : 어떤 CPU에서 실행 가능한지 알림
    • NumberOfSections : 이 파일이 가진 섹션의 개수를 알림
    • TimeDataStamp : obj → EXE 파일을 만든 시간 알림
    • SizeOfOptionalHeader : optional 헤더의 크기를 알림( PE를 로딩하 기 위한 굉장히 중요한 구조체를 담고 있음. 운영체제마다 크기가 다를 수 있어서 PE로더에서는 이 값을 먼저 확인)
    • Characteristics : 파일이 어떤 형식인지 알림

 

  • IMAGE_OPTIONAL_HEADER
    • Magic : 32비트인지 64비트인지 알려줌
    • MajorLinkerVersion , MinorLinkerVaersion : 사용한 컴파일러 버전을 알려줌
    • SizeOfCode : 코드 양의 전체 크기
      • 악성코드 : 이 값을 참고하여 자신의 코드를 복제할 위치 기준을 잡음
      • 솔루션 : 코드 섹션의 무결성 검사
    • AddressOfEntryPoint : 파일이 메모리에서 시작되는 지점
    • BaseOfCode : 실행 코드 위치
      • ImageBase와 BaseofCode를 더한 값부터 코드 시작.
    • ImageBase : 로드할 가상 메모리 주소
    • SectionAlignment, FileAlignment : 각 세션을 정렬하기 위한 정렬 단위(기본값 0x1000)
    • SizeOfImage: EXE,DLL이 메모리에 로딩됐을 때 전체크기
    • SizeOfHeaders : PE 헤더의 크기를 알림(기본값 0x1000)

 

  • IMAGE_DATA_DIRECTORY
    • VirtualAddress Size 필드, Export, Import, Rsrc 디렉터리와 IAT 등의 가상 주소와 크기 정보를 가짐.
    • 16가지의 데이터 디렉터리에 대한 정보를 가지고 있다.

 

  • 섹션(Section)
    • PE 파일에서 섹션은 프로그램의 실제 내용을 담고 있는 블록
    • PE가 가상 주소 공간에 로드된 후 섹션 내용이 참고되고 실행

 

  • IMAGE_SECTION_HEADER
    • 주로 각 세션에 대한 이름, 시작 주소, 사이즈 등의 정보를 관리하는 구조체

IMAGE_Section_Header의 구조체(왼쪽)와 해당 정보를 출력한 것(오른쪽)

 

  • IAT 호출 구조

 

2.2. PE 헤더 복구하기

  • 1번 notepad
    • 파일 실행이 안됨 → 원래 파일과 구조가 다름 → 정상적인 파일은 MZ로 시작
    • 하지만 1번 파일은 Boan Project….가 있음. 이를 제거하면 해결 가능
  • 2번 notepad 문제
    • Analysis > File-compare > compare 들어가서 2번 문제 파일과 원래 파일 선택 후 다른 부분을 찾아서 바꿔준다.
    • Analysis > File-compare > Next difference 들어가면 다음으로 차이가 나는 부분을 찾을 수 있다.
    • 이를 원래 파일과 똑같이 변경해주면 해결 가능

 

3. 패커 개요

3.1. 패커(Packer)

  • 실행 파일 압축기, 실행 파일 패킹
  • 사용 목적
    • (과거) PE 파일 크기 줄이고자하는 목적
    • (현재) PE 파일 내부 코드와 리소스(string, API 등)를 감추기 위한 목적
  • 패커의 흐름

패커의 흐름

  • A 패킹 후 B의 압축이 됨 → C는 압축을 해제해 줌 → 실행 -패킹하기 전 상태는 메모리 상태와 같다.

 

  • 메모리 내 파일 패킹 구조

EP가 .text section 에서 패킹 후 Unpacking stub으로 바뀜. 언패킹을 하고 난 뒤 OEP로 다시 점프

 

3.2. 백신 우회 방법

  • 시그니처 변경
    • 단순히 변수 및 개를 추가 및 함수 위치를 변경하여 리빌드
  • 쓰레기 코드를 통한 우회 방법
    • 네 줄이 수행된 경과를 보면 아무것도 것이 없음 (대칭 구조)
  • 헤더 변조
    • TimeDataStamp, Optional Header의 CheckSum, 메모리 속성 변조

 

3.3. Themida

  • 지상 최고의 패커라 불림
  • 안티 디버깅과 안티 분석, 언패킹 분석을 매우 어렵게 하는 안전한 패커
  • VMware, 디버거, 프로세스 모니터 분석을 방지하는 기능
  • 패킹된 실행 파일은 이례적으로 크기가 큼
  • 언패커가 존재하나 Themida 버전과 프로그램을 패킹할 때 사용한 설정에 따라 성공률이 다름

 

4. UPX 언패킹

4.1. 패킹

  • 원본 파일 자체를 변경

  • (바탕화면에서) start > Command Prompt(run(Window + R) > cmd 입력) > (Commad Prompt 창에서 입력) cd Desktop > upx.exe ori_notepad.exe > 압축이 됨

 

  • 언패킹

  • upx.exe ori_notepad.exe 사이의 -d 옵션을 입력하면 됨
    • → upx.exe -d ori_notepad.exe

 

  • 원본 파일 건들이지 않고 패킹 (새로운 파일 만들어서 패킹)

  • upx.exe ori_notepad.exe -o ori_notepad_upx.exe 입력하여 패킹

 

  • ori_notepad.exe와 ori_notepad_upx.exe 비교
    • *PEview.exe로 두 파일 열기
    • *구조가 바뀐 것을 확인할 수 있다.
    • SECTION.text, SECTION.data → SECTION UPX0, SECTION UPX1

  • 검정색 네모 박스에서 바뀐 부분 확인할 수 있다.
  • IMAGE_NT_HEADERS > Signature, IMAGE_FILE_HEADERS 그대로유지

 

  • IMAGE_OPTIONAL_HEADERS

  • 검정색 선 아래부터 Data 값이 변경된 것을 확인할 수 있다.

 

  • IMAGE_SECTION_HEADERS ~

  • 전체적인 사이즈와 권한이 변경되었고 ori_notepad_upx.exe에는 80000000 IMAGE_SCN_MEM_WRITE 이 새로생겼다.
  • 실제 파일 사이즈는 없고 가상 사이즈를 설정하여 입력을 받고 나중에 입력 받은 내용을 실행

 

4.2. UPX 언패킹

  • *패킹이 된 파일은 잘 분석이 안되기 때문에 열기 전 사전에 진짜로 패킹된 파일을 열려고 하는 건지 물어봄
  • *BP 걸거나 주석 달아도 나중에 다 날아감 → 언패킹하면 원래 파일에 메모리에 의 해서 작성한 메모리가 날아감
    • OllyDbg로 ori_notepad_upx.exe 열기
    • PUSHAD

  • EAX ~ EDI까지 데이터를 싹 다 넣음
  • 레지스터에 잠깐 보관하고 언패킹을 하고 레지스터 복구해서 정상적으로 프로그램을 실행하기 위해서 사용한다(+POPAD)

 

  • 언패킹
    • Debug > Animate over

 

  • 수동 언패킹 with Lena 21
    • 문제 풀기 전
    • UnPackme_UPX.exe 바탕화면에 옮기기
      • 필요한 파일 다운로드
      • 인터넷 > import rec 검색 > [Tool] ImportREC v1.7 Final ~ 클릭 > ImportREC 1.7c.rar 다운로드 > 압축 풀고 사용

 

  • 문제 풀기
    • PUSHAD F8로 실행
    • 덤프 창에 esp 검색 > 맨 앞 숫자에 마우스 오른쪽 클릭 Breakpoint > Hardware, on access (메모리에 접근할 때 BP를 걸겠다) > Byte (한 바이 트 BP 검)
    • BP 확인 방법: Debug > Hardware breakpoints

 

  • POPAD 끝난 이후
    • JMP 해서 원본 프로그램 실행
    • Piugins > OllyDump > Dump debugged process → Rebuild import 체크 해제 > Dump > Unpackme_UPX_dump.exe 저장

 

  • ImportREC
    • OllyDbg 종료하면 안됨 → 해당 import 내용을 Unpackme_UPX_dump.exe에 적용을 해줬기 때문에 종료하면 적용되지 않음
    • ImportREC 실행
      • unpackme_upx.exe 선택 > OEP 00001000 변경 후 AutoSearch, Size 00001000 변경 후 Get Imports > Fix Dump (Import 내용 dump에 적용할 때 클릭) > UnPackme_UPX_dump.exe 선택 후 OPEN 클릭