728x90
반응형
목차
0. Ransomware 파일 내부
  1) file 정보

  2) readme.txt 파일
  3) run.exe 파일
1. run.exe 파일 실행
  1) Exeinfo.exe 설치
  2) HxD 설치
  3) UPX 설치
  4) OllyDbg 설치
  5) WOW64 설치
2. IDA run.exe 파일 분석
3. OllyDbg run.exe 파일 분석
4. Key값 구하기
5. 소스코드 정리 및 연산 수행
6. 최종 실행 및 Flag 확인

[Review] (5주차) 실습

2022.08.06 - [Security & Analysis/IDA Pro] - [IDA Pro] 악성코드 정적분석 툴 사용법&이론 - week.05(Easy ELF)

 

[IDA Pro] 악성코드 정적분석 툴 사용법&이론 - week.05(Easy ELF)

목차 1. Easy ELF 실습 - 실습을 위한 사전 단계(Linux 파일 실행) 2. 분기문 분석 3. byte 및 배열 정리 4. 소스코드 작성(어셈블리어 기반) [Review] (4주차) 이론 - 총정리 2022.07.19 - [Security & Analysis/..

sarahee.tistory.com


0. Ransomware 파일 내부

랜섬웨어 암호화 file 및 txt, exe 파일

zip 파일의 압축을 풀면 다음과 같이 file 및 txt, exe 총 3개의 파일 생성

file에 파일 확장자가 없기 때문에 바이너리 형식으로 암호화되었다고 판단

따라서 16진 편집기인 HxD 사용 예정

1) file 정보

2) readme.txt 파일

file 확장자가 exe

ui 파일을 .py로 변경(Pyutic)

3) run.exe 파일


1. run.exe 파일 실행

IAT: Import Address Table, 프로그램이 어떤 라이브러리에서 어떤 함수를 쓰는지 기술한 테이블

프로그램이 특정 API를 실행하고자 할 때 IAT를 불러옴

압축되어 있어서 확인 불가

해당 파일이 압축되어 있어서, 내부 정보 확인이 불가

1) Exeinfo PE 파일 다운로드하여 정보 확인

https://exeinfo-pe.kr.uptodown.com/windows

 

Exeinfo PE (Windows)

Exeinfo PE을 위한 Windows을 무료로 다운로드하세요. .exe 파일 확인하기. Exeinfo PE는 여러분이 .exe 파일들을 확인하여 그 속성을 살펴볼 수 있는 프로그램입니다. 또한, 해당 파일의 이름을 변경하고

exeinfo-pe.kr.uptodown.com

파일이 UPX로 패킹되어 있음

(언패킹된 프로그램을 출력 시 컴파일된 언어 등 조회 가능)

2) HxD 설치

Window 용 16진 편집기, 디스크/메모리 편집기, 프로세스 실행에 사용되는 메모리를 표시하고 편집할 수 있음

https://mh-nexus.de/en/downloads.php?product=HxD20 

3) UPX 설치

하단 Unpack info

Big sec. 2 [ UPX1 ] , unpack "upx.exe -d"  from  http://upx.github.io or any UPX/Generic unpacker

해당 사이트에 접속하여 설치 진행

UPX란?

the Ultimate Packer for eXecutables, 오픈 소스 실행 파일 압축 프로그램

Download latest release > upx-3.96-win64.zip
다운로드 받은 upx.exe 파일을 unpacking하고자 하는 exe 파일에 위치

upx.exe -d run.exe

Not packed, 내부 정보 확인 가능

4) OllyDbg 설치

https://www.ollydbg.de/download.htm

5) WOW64 설치

운영체제의 하위 시스템, 32비트 윈도우와 64비트 윈도우의 차이 보완

모든 64비트 버전의 마이크로소프트 윈도우에서 32비트 응용 프로그램들이 돌아가도록 도와줌

https://ko.dll-files.com/wow64.dll.html

zip 파일 압축 해제 후, regsvr32 wow64.dll


2. IDA run.exe 파일 분석

cmd 명령어에서 확인한 Key 문자열 검색하여 알고리즘 확인

Key의 입력값이 byte_44D370에 저장

call [접근할 함수 주소]

file 문자열 확인

StartAddress Functions 내부 file open

함수 시작 부분에 코드 반복 ← 파일 크기 키우고, 분석에 어려움을 주기 위함

 

rb는 file을 읽는 형식

read binary, 즉 바이너리 형식으로 파일을 읽겠다는 의미

 

좌측 printf: '파일을 찾을수 없다!' 문자열 출력 구문

 

하단 Stream

* Stream: 컴퓨터 처리 환경에서, 시간이 지남에 따라 사용할 수 있게 되는 일련의 데이터 요소

fseek: fopen으로 호출된 파일의 위치 변경

ftell: 스트림 위치 지정자의 현재 위치(파일 포인터)

feof: stream(FILE)의 파일 끝 플래그가 설정되었는지 여부 표시, 파일의 끝 위치 확인

fgetc: 파일에서 글자를 하나씩 읽는 함수

→ feof를 이용해 파일의 끝에 도달할 때까지 fgetc 함수를 통해 1byte씩 file 파일로부터 읽어들임

wb, binary 형식으로 file을 쓰겠다는 의미

  • 좌측 하단 printf: '파일을 복구했다! ~' 문자열 출력
  • 우측에 핵심 부분으로 복호화를 수행하는 loop 존재

알고리즘 loop

1) xor edx, edx - ebp+Stream 등.. 의미 없음(모두 0이 되므로, 초기화하는 과정)

2) div [ebp+var_C] - 입력한 key가 DIV 연산에 의해 끝 byte에 도달했을 때, 처음 byte로 돌아감

3) xor ecx, edx - input으로 입력한 key 중 한 byte와 XOR 연산 수행(ecx: 입력값(반복 카운터), edx: key값)

4) xor edx, 0FFh - 위의 결과와 0xFF XOR 연산 수행

 

XOR 연산의 성질에 의해, Key를 찾기 위해 file 파일과 0xFF를 XOR

Original File을 바이트 단위로 XOR

Original File은? readme.exe 파일의 hint에 의해 복호화된 파일은 exe 파일(PE구조)이라는 것을 판단

 


3. OllyDbg run.exe 파일 분석

run.exe file open


4. Key값 구하기

file이 exe 포맷이므로, header 구조는 다른 exe 파일과 동일할 것

upx.exe, run.exe

00000000 ~ 00000070까지 대부분 동일한 헤더값을 가지며,(00000030의 F0, 80 차이)

키 값을 모르기 때문에 0x20 크기 복호화

  • 복호화 되어야 할 값:
  • 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00
4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00
B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 F0 00 00 00
0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68
69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F
74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20
6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00

 

file

  • 암호화된 값: 
  • DE C0 1B 8C 8C 93 9E 86 98 97 9A 8C 73 6C 9A 8B 34 8F 93 9E 86 9C 97 9A CC 8C 93 9A 8B 8C 8F 93
DE C0 1B 8C 8C 93 9E 86 98 97 9A 8C 73 6C 9A 8B
34 8F 93 9E 86 9C 97 9A CC 8C 93 9A 8B 8C 8F 93
9E 86 9C 97 9A 8C 8C 93 9A 8B 8C 8F 93 9E 86 9C
97 9A 8C 8C 93 9A 8B 8C 8F 93 9E 86 6C 97 9A 8C
82 8C 20 85 8C 3B 9A 53 A7 24 96 D6 41 AD C7 F2
E2 FF AF E3 EC E9 FB E5 FB E1 AC F0 FB E5 E2 E0
E7 BE E4 F9 B7 E8 F9 E2 B3 F3 E5 AC CB DC CD A6
F1 F8 FE E9 A2 9E 97 81 A8 8F 93 9E 86 9C 97 9A

5. 소스 코드 정리 및 연산 수행

해당 파일이 최종 구현된 소스코드

key = input('Key : ').encode()

f = open('./ransomware/file', 'rb')
enc_content = f.read()
f.close()

dec_content = []
for i in range(len(enc_content)):
    dec_content.append(enc_content[i] ^ key[i % len(key)] ^ 0xFF)
dec_content = bytes(dec_content)

f = open('file', 'wb')
f.write(dec_content)
f.close()

 

de_file[i] = en_file[i] ^ key[i] ^ 0xFF → key[i] = en_file[i] ^ de_file[i] ^ 0xFF

원본 데이터가 반복이라면, key 값만 달라지기 때문에 key의 길이만큼 동일 데이터가 반복될 것

 

# sol1

# 20 bytes
# 암호화된 값 : DE C0 1B 8C 8C 93 9E 86 98 97 9A 8C 73 6C 9A 8B 34 8F 93 9E 86 9C 97 9A CC 8C 93 9A 8B 8C 8F 93
# 복호화 되어야 할 값: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00

enc_content = [0xDE, 0xC0, 0x1B, 0x8C, 0x8C, 0x93, 0x9E, 0x86, 0x98, 0x97, 0x9A, 0x8C, 0x73, 0x6C, 0x9A, 0x8B, 0x34, 0x8F, 0x93, 0x9E, 0x86, 0x9C, 0x97, 0x9A, 0xCC, 0x8C, 0x93, 0x9A, 0x8B, 0x8C, 0x8F, 0x93]
dec_content = [0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

key = ''
for i in range(len(enc_content)):
    key += chr(dec_content[i] ^ enc_content[i] ^ 0xFF)
print(key)

# sol2

enc_content = "DE C0 1B 8C 8C 93 9E 86 98 97 9A 8C 73 6C 9A 8B 34 8F 93 9E 86 9C 97 9A CC 8C 93 9A 8B 8C 8F 93".split(' ')
dec_content = "4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00".split(' ')

for i in range(len(enc_content)):
    enc_content[i] = int(enc_content[i], 16)
    dec_content[i] = int(dec_content[i], 16)
    enc_content[i] = enc_content[i] ^ 0xFF
    enc_content[i] = enc_content[i] ^ dec_content[i]
    print(chr(enc_content[i]), end="")

결과값: letsplaychess 반복


6. 최종 실행 및 Flag 확인

기존의 file을 확장자 변경(exe) 후 실행하면, 다음과 같이 실행 불가

run.exe 파일 실행 후 결과값(Key : letplaychess) 입력

 

 

728x90
728x90
728x90
반응형
목차
1. Easy ELF 실습
  - 실습을 위한 사전 단계(Linux 파일 실행)
2. 분기문 분석
3. byte 및 배열 정리
4. 소스코드 작성(어셈블리어 기반)

[Review] (4주차) 이론 - 총정리

2022.07.19 - [Security & Analysis/IDA Pro] - [IDA Pro] 악성코드 정적분석 툴 사용법&이론 - week.04(전 과정 Review)

 

[IDA Pro] 악성코드 정적분석 툴 사용법&이론 - week.04(전 과정 Review)

개요 * Easy_KeygenMe.exe 파일 실습 1. 레지스터 활용 분석 - 메모리 주소 및 스택 프레임의 이해 - ESP(스택 포인터), EBP(프레임 포인터), EIP 등 개념 정리 2. 어셈블리 명령어 이해 및 알고리즘 분석 - Pse

sarahee.tistory.com


1. Easy ELF 실습

ELF 파일은 리눅스의 실행파일이므로, 실행시킨 후 랜덤 문자를 입력

Wrong 출력

파일 확장자를 모든 파일(All Files (*))로 변경

2. 분기문 분석

실행 후 View > Open subviews > Strings (or Shift + F12)

문자열 검색

리눅스 실행 시 조회된 문자열(Reversing.Kr Easy ELF, Wrong) 및 정답 출력 예상(Correct) 조회

Wrong 해당 그래프 모드 확인

Wrong graph

cmp를 통해 분기문 이동

jump if not zero(not equal) → eax가 1이라면(빨간색 화살표), Correct 연결

레지스터나 메모리 값을 변경하지 않고, 플래그 레지스터에만 영향을 줌

* flag register: 상태 레지스터

Correct graph

분기문 지나기 전 call 링크 두개

sub_8048434

sub_8048451

eax가 1이 되기 위해서는, 모든 분기문에서 조건 점프(초록색 화살표 이동)하여, 우측 하단으로 차례 이동

3. byte 및 배열 정리

첫 번째 조건문

byte_804A021의 값과 31h 비교

 

두 번째 조건문

byte_804A020을 eax에 저장하여,

첫 번째 문자(eax 내)와 0x34 XOR 연산

 

세 번째 문자(byte_804A022)와 0x32 XOR 연산

네 번째 문자(byte_804A023)와 0x0FFFFFF88 XOR 연산

다섯 번째 문자(byte_804A024)와 0x58 값이 같은지 비교

 

네 번째 조건문

테스트

 

네 번째 조건문

세번째 문자(byte_804A022)와 0x7C 비교

 

다섯 번째 조건문

첫번째 문자(byte_804A020)와 0x78 비교

 

여섯 번째 조건문

네번째 문자(byte_804A023)와 0x0DD 비교

No. CODE XREF 어셈블리어 10진수 to 문자(ASCII) 순서
1 sub_804851B+2A↓p cmp     al, 31h 0x31 = 49, chr(49) = 1 byte_804A021
2 sub_8048451+C↑j
loc_8048469
xor     eax, 34h
xor     eax, 32h
xor     eax, 0FFFFFF88h
cmp     al, 58h
0x34 = 52, chr(52) = 4
0x32 = 50, chr(50) = 2
0x88 = 136, chr(136) = (enter)
0x58 = 88, chr(88) = X
byte_804A020
byte_804A022
byte_804A023
byte_804A024
3 sub_8048451+4E↑j
loc_80484A8
test     al, al    
4 sub_8048451+60↑j
loc_80484BA
cmp     al, 7Ch 0x7C = 124, chr(124) = | byte_804A022
5 sub_8048451+72↑j
loc_80484CC
cmp     al, 78h 0x78 = 120, chr(120) = x byte_804A020
6 sub_8048451+84↑j
loc_80484DE
cmp     al, 0DDh 0xDD = 221, chr(221) = Ý byte_804A023

 

정리해보면, input 문자열은 다음과 같이 구성 (^: XOR)

input[0] ^ 34h = 78h

input[1] = 31h

input[2] ^ 32h = 7Ch

input[3] ^ 88h = DDh (byte이므로 88 앞의 FFFFFF는 무시)

input[4] = 58h

input[5]는 test(세 번째 조건문)

4. 소스코드 작성(어셈블리어 기반)

// string
ans = ""

ans += chr(0x34 ^ 0x78)
ans += chr(0x31)
ans += chr(0x32 ^ 0x7C)
ans += chr(0x88 ^ 0xDD)
ans += chr(0x58)

print(ans)

 

출력: L1NUX

Correct! 정답 출력

 

 

728x90
728x90
728x90
반응형
개요
* Easy_CrackMe.exe 실습 리뷰 및 Easy_KeygenMe.exe 파일 실습
1. 디스어셈블리 상세 기능
- 스택 프레임 및 함수 호출 규약의 이해
- 동적 디버깅 사용 및 코드 실행
- 데이터 타입과 데이터 구조
- 기본 데이터/코드 변환
2. 스택/힙 할당 배열 및 구조체 접근

목차
0. Easy KeygenMe 실습
1. 어셈블리어: MOV, CMP, XOR, MOVZX, MOVSX
2. 알고리즘 분석
3. XOR(⊕) 연산의 결합법칙
4. 소스코드 작성(pseudo code 기반)

[Review] (3주차) 실습

2022.07.04 - [IDA Pro] - IDA Pro 악성코드 정적분석 툴 사용법&실습 - week.03(Easy_CrackMe) (2)

 

IDA Pro 악성코드 정적분석 툴 사용법&실습 - week.03(Easy_CrackMe) (2)

개요 * Easy_CrackMe.exe 실습 리뷰 및 Easy_KeygenMe.exe 파일 실습 1. 디스어셈블리 상세 기능 - 스택 프레임 및 함수 호출 규약의 이해 - 동적 디버깅 사용 및 코드 실행 - 데이터 타입과 데이터 구조 - 기

sarahee.tistory.com


0. Easy KeygenMe 실습

Intro

Find the Name when the Serial is 5B134977135E7D13

Name을 사용해서 시리얼 값 생성, 역으로 시리얼 값을 통해 해당 Name을 찾아내는 문제

초기 디스어셈블리 창
debug Running page
Input Name, Input Serial

시리얼 생성 알고리즘과 관련된 문제 풀이

1) 어셈블리어로 전체적인 구조 파악

2) Hex-rays로 세부 알고리즘 파악

rep stosd: 저장소 문자열 명령

stosb: AL로부터 byte를 읽어 들임, stosw: AX로부터 word를 읽어 들임 - 정수값을 메모리에 복사


1. 어셈블리어: MOV, CMP, XOR, MOVZX, MOVSX

MOV

데이터 복사 명령어

0x10: [esp+140h+var_130]

0x20: [esp+140h+var_12F]

0x30: [esp+140h+var_12E]

Byte 단위로 각각 스택에 넣어줌, 사용자가 입력한 문자열을 첫번째 글자부터 순서대로 Byte 단위로 레지스터에 넣음

CMP

esi가 3 이상이면 0으로 초기화

XOR

두 입력 신호가 서로 같으면 0, 다르면 1, 동일한 두 값초기화

MOVZX

소스의 내용을 목적지로 복사, 목적지의 나머지 부분을 0 padding

(목적지에 32bit register 소스에 16bit register) 

MOVSX

소스의 내용을 목적지로 복사, 목적지의 나머지 부분을 소스의 맨 처음 bit로 채움

(목적지에 32bit register → 소스에 16bit register)

loc_40107E: pseudocode


2. 알고리즘 분석

1) v3이 v8의 strlen이 클 때 까지 반복하고, i가 3 이상이면 0으로 초기화

2) sprintf를 통해 Buffer에 생성된 serial 저장

3) "%s%02X"를 통해 기존 Buffer 내용과 v8 포인터 입력값을 한글자씩 가져옴

4) xor 연산을 한 값을 sprintf 함수를 통해 serial이 저장되는 Buffer에 저장

5) serial을 계산하여 scanf로 입력받은 후, strcmp 함수로 동일한지 비교

- if 0일 때 거짓, 0이 아닐 때 참으로 동작하므로, strcmp 내 0일 경우(문자열이 같을 경우) Correct 출력

 

v6에는 16 16 = 0x10

v7[i - 1]가 될 수 있는 값은, v7[0], v7[1], v7[2]의 반복

qmemcpy: sizeof(v7)만큼 " 0" 영역의 값을 v7로 복사

첫번째 인자(v7): 복사받을 메모리를 가리킴

두번째 인자(" 0"): 복사할 메모리를 가리킴

세번째 인자(sizeof(v7)): 복사할 데이터(값)의 길이(바이트 단위)

 

16진수이므로 두자리씩 끊어서 총 8자리


3. XOR(⊕) 연산의 결합법칙

^: XOR 연산자

p q p ⊕ q (p ⊕ q) ⊕ q
T T F T
T F T T
F T T F
F F F F

(p ⊕ q) ⊕ q ≡ p ⊕ (q ⊕ q) ≡ p ⊕ F ≡ p

 

0x5b^0x10

0x13^0x20

0x49^0x30

0x77^0x10

0x13^0x20

0x5E^0x30

0x7D^0x10

0x13^0x20


4. 소스코드 작성(pseudo code 기반)

# sol1

serial = [0x5B, 0x13, 0x49, 0x77, 0x13, 0x5E, 0x7D, 0x13]
xor = [0x10, 0x20, 0x30]
ans = []

i_xor = 0
for i_ser in range(len(serial)):
    if i_xor >= 3:
        i_xor = 0
    ans.append(serial[i_ser]^xor[i_xor])
    i_xor += 1
    print(chr(ans[i_ser]), end='')

# sol2

serial = [0x5B, 0x13, 0x49, 0x77, 0x13, 0x5E, 0x7D, 0x13]
xor = [0x10, 0x20, 0x30]
ans = []

for i in range(len(serial)):
    ans.append(serial[i]^xor[i%3])
    print(chr(ans[i]), end='')

출력: K3yg3nm3

75 51 121 103 51 110 109 51

Name: K3yg3nm3 / Serial: 5B134977135E7D13

결과값 출력도 전에 창이 닫혀서, cmd로 다시..

Correct!


[Next] (4주차) 이론

2022.07.19 - [Security & Analysis/IDA Pro] - IDA Pro 악성코드 정적분석 툴 사용법&이론 - week.04(전 과정 Review)

 

IDA Pro 악성코드 정적분석 툴 사용법&이론 - week.04(전 과정 Review)

개요 * Easy_KeygenMe.exe 파일 실습 1. 레지스터 활용 분석 - 메모리 주소 및 스택 프레임의 이해 - ESP(스택 포인터), EBP(프레임 포인터), EIP 등 개념 정리 2. 어셈블리 명령어 이해 및 알고리즘 분석 - Pse

sarahee.tistory.com

 

728x90
728x90

+ Recent posts