스크립트 확장자는 .ahk이고, 설치하면 Compiler 폴더의 Ahk2Exe를 사용하여 ahk를 exe로 컴파일 가능
→ AutoHotKey 프로그램에 비밀번호를 설정한 후, 입력 값 일치하면 프로그램을 실행할 수 있도록 하는 기능
따라서 ahk.exe 파일에 입력해야 하는 비밀번호가 decript's key가 됨
Exe2Aut.exe 디컴파일러
ank의 password: decript's key
ahk.exe 파일 확인
입력 창에 임의의 문자를 입력한 후, OK 버튼을 누르면 프로그램이 종료
패킹된 파일을 그대로 디버거로 로드하면, 함수나 문자열 등 제대로 확인하기 어려움
파일을 제대로 분석하기 위해서는, 디버깅 상태에서 다음과 같은 명령어를 확인해야 함
F2: 브레이크 포인트 설정
F7: 디버깅 중 프로그램을 한 줄 실행시킴
F8: 디버깅 중 프로그램을 한 줄 실행시킴(call 명령어가 있을 경우에는 해당 함수로 들어가지 않음)
UPX(Ultimate Packer for eXecutables): 여러 운영체제에서 수많은 파일 포맷을 지원하는 오픈 소스 실행 파일 압축 프로그램
exe 파일이 압축되어 있어서 내부 구조 확인하기 어려움
(패킹: -o, 언패킹: -d 옵션)
다시 exe 파일 실행 시 출력 화면이 다음과 같이 변경
파일 검증하는 CRC 체크 부분에서, 위와 같은 EXE corrupted 문구 출력
컴파일 후 변조가 되면 해당 문자열 출력
HS_EXEArc_Read::Open 함수에서 체크하여, 이후 어떤 분기문으로 이동할 지 스크립트를 실행시킴
→ UPX 언패킹한 바이너리 분석 시 CRC 체크 영역에 걸려서 에러
오토핫키 프로그램은 컴파일 시 자동으로 UPX 패커를 적용시키기 때문에 언패킹을 한 이후 분석을 하면 DecryptKey를 찾을 수 없음(디컴파일 시 필요한 비밀번호이므로)
+ 알고리즘을 숨기고 복원하는 과정에서 힌트를 얻고 디컴파일을 수행할 수 있겠지만, 해당 프로그램 특성 상 언패킹 시 분기문에서 탈락하도록 설정했으므로 의미 없음
하단의 >AUTOHOTKEY SCRIPT< , >AHK WITH ICON<
특정 함수의 반환값을 조건으로 "EXE corrupted" 메시지 박스를 띄우고 종료하는 분기
">AUTOHOTKEY SCRIPT<" 문자열을 사용하는 함수를 호출하는 분기
2. OllyDbg 디버깅
OllyDbg: 바이너리 코드 분석을 위한 x86 디버거(소스 코드가 없을 때 주로 사용)
- 레지스터 추적, 함수/API 호출, 문자열 인식, 오브젝트 파일과 라이브러리 내 루틴 위치 검색
바로 Debug Run할 경우, (or F9 단축키)
Options > Debugging options (or) Alt + O > Events 버튼 클릭하여 Make first pause at: Entry point of main module 체크
* 제어가 운영 체제에서 컴퓨터 프로그램으로 이동하는 것 → 패킹된 파일의 실제 프로그램 시작 부분
OllyDbg 활용 OEP 확인
OEP란? unpacking에서 가장 중요한 부분(Original Entry Point)
packing되기 전으로 돌아간 곳, 덤프를 통해 packing 해제된 파일을 만듦
UPX로 압축하면 PUSHAD와 POPAD 어셈블리어는 필수적으로 생성
PUSHAD 실행 이후 맨 위의 스택 주소를 덤프하여 BYTE H/W BreakPoint를 지정하고 실행해서 POPAD 다음에서 멈추도록 함
JMP 명령어를 통해 OEP로 이동
* 스택에서 레지스터들이 POP이 되는 순간을 캐치하면 OEP로 진입할 수 있는 힌트를 찾아낼 수 있을 것
Entry point breakpoint
PUSHAD로 시작하는 첫번째 instruction 조회
PUSHAD 명령어: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI 모든 레지스터를 stack에 PUSH하는 역할
일반적인 packer는 특정 위치의 레지스터들의 백업을 만들어 놓기 위해 처음에 PUSH 명령을 이용하여 저장
(∵ 패킹된 파일이 루프를 돌면서 연산을 하게 됨, 기존 레지스터가 수정될 수 있기 때문에 저장, 루틴이 모두 끝나고 정상 코드를 실행시킬 때 이 레지스터들을 돌려 받기 위함)
→ 파일 메인 프로그램이 실행되기 전에 POP instruction으로 레지스터를 복귀
(참고) System breakpoint 설정했을 경우
2사분면(Code Window) 왼쪽: 주소 창(명령어가 실행되는 주소)
2사분면(Code Window) 가운데: 기계어(OP 코드 창)
2사분면(Code Window) 오른쪽: 어셈블리어(디스어셈블리 창)
1사분면(Register Window): 레지스터 값 표시
3사분면(Dump Window): 메모리 덤프 창 - 특정 시점에 작업 중이던 메모리 상태(주소, Hex dump, hex to ASCII 해석 내용) 기록
4사분면(Stack Window): 스택 주소 값, comment 순으로 출력
PUSHAD 위아래 추가 설명
POPAD 명령어 실행 전 루프문들이, 압축된 코드를 해제하는 과정
Dump Window의 Ctrl+G > (Enter expression to follow in Dump:) ESP 입력 후 확인
* 스택 프레임의 끝지점 주소가 저장되는 최상단 구간(ESP)
Hex dump 부분 우클릭 > Breakpoint > Hardware, on access > Byte
다시 Run하면 하드웨어 브레이트 특성 상 Breakpoint 설정 명령어 이후 제어가 멈추므로 0x00471BCC에서 Paused됨
아래로 스크롤하다 보면 거의 마지막 코드에 POPAD
JMP 명령어 뒤에 오는 주소가 OEP임(ahk.00442B4F)
해당 주소로 점프(Ctrl+G)하여 조회
Ctrl+A: 코드 분석(다시 읽기)
Ctrl+F: POPAD 찾기
Compressed code? Quick statistical test of module 'ahk' reports that its code section is either compressed, encrypted, or contains large amount of embedded data. Results of code analysis can be very unreliable or simply wrong. Do you want to continue analysis?
AutoHotKey의 패킹된 바이너리를 실행해서 OEP까지 간 다음 CRC 체크를 통해 에러가 발생했을 때 출력되는 문자열 영역을 기준으로,
우클릭 > 더 많은 옵션 표시 or Shift+F10 단축키 클릭하여 Edit Script
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. ; #Warn ; Enable warnings to assist with detecting common errors. SendMode Input ; Recommended for new scripts due to its superior speed and reliability. SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
본래 내용을 지우고 다음과 같이, F1버튼을 눌렀을 때 hello라는 메시지 창이 나오도록 코드 작성
이후 저장하고 창 닫기
.ahk 파일 우클릭하여 Compile Script 하면 .exe 파일이 생성
.exe 파일을 관리자 권한으로 실행하여 하단 바에 AutoHotKey icon 생성
F1 단축키 클릭 시 다음과 같은 화면 출력
4. 오토핫키 취약점
CVE-2020-18174 취약점
AutoHotkey 1.1.32.00의 setup.exe에 있는 프로세스 주입 취약점으로 인해 공격자가 권한을 상승시킬 수 있음
목차 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 확인
개요 * Easy_KeygenMe.exe 파일 실습 1. 레지스터 활용 분석 - 메모리 주소 및 스택 프레임의 이해 - ESP(스택 포인터), EBP(프레임 포인터), EIP 등 개념 정리 2. 어셈블리 명령어 이해 및 알고리즘 분석 - Pseudo code 기반 소스코드 작성
목차 0. 파일 버전 확인(32bit, 64bit) 1. 정의된 데이터(db) 2. 어셈블리어: CMP, LEA, TEST, XOR, MOV, MOVZX, MOVSX 3. 메모리의 구조 1) 코드 영역 2) 데이터 영역 3) 힙 영역 4) 스택 영역 - 레지스터: ESP, EBP, EIP, ECX, EAX 4. IDA 메모리 주소 표시 차이
개요 * Easy_CrackMe.exe 실습 리뷰 및 Easy_KeygenMe.exe 파일 실습 1. 디스어셈블리 상세 기능 - 스택 프레임 및 함수 호출 규약의 이해 - 동적 디버깅 사용 및 코드 실행 - 데이터 타입과 데이터 구조 - 기본 데이터/코드 변환 2. 스택/힙 할당 배열 및 구조체 접근
Byte 단위로 각각 스택에 넣어줌, 사용자가 입력한 문자열을 첫번째 글자부터 순서대로 Byte 단위로 레지스터에 넣음
CMP
esi가 3 이상이면 0으로 초기화
XOR
두 입력 신호가 서로 같으면 0, 다르면 1, 동일한 두 값 → 초기화
MOVZX
소스의 내용을 목적지로 복사, 목적지의 나머지 부분을 0 padding
(목적지에 32bit register → 소스에 16bit register)
MOVSX
소스의 내용을 목적지로 복사, 목적지의 나머지 부분을 소스의 맨 처음 bit로 채움
(목적지에 32bit register → 소스에 16bit register)
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(⊕) 연산의 결합법칙
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='')
개요 * Easy_CrackMe.exe 실습 리뷰 및 Easy_KeygenMe.exe 파일 실습 1. 디스어셈블리 상세 기능 - 스택 프레임 및 함수 호출 규약의 이해 - 동적 디버깅 사용 및 코드 실행 - 데이터 타입과 데이터 구조 - 기본 데이터/코드 변환 2. 스택/힙 할당 배열 및 구조체 접근
1) 함수 호출자가 파라미터 형태로 정보를 넘겨줄 때 어딘가에 저장되고, 호출된 함수가 정보를 찾게 해야 한다.
2) 함수의 작업을 위한 임시 저장소가 필요하다.
* 스택: 제한적으로 접근할 수 있는 자료 구조(LIFO, Last In First Out)
* 임시 저장소: 주로 지역 변수가 사용, 함수가 종료되면 더 이상 접근 불가
2. 레지스터: ESP, EBP, EIP, ECX, EAX
예제
32비트 x86 기반 컴퓨터의 컴파일된 함수 코드
void bar(int j, int k); // 호출할 함수
void demo_stackframe(int a, int b, int c) {
int x;
char buffer[64];
int y;
int z;
// 스택 프레임 테스트 용도 외에는 다른 목적이 없는 함수
bar(z, y);
}
지역 변수에 최소 76바이트(3개의 4바이트 정수, 64바이트 버퍼)가 필요
변수
오프셋
ESP 기반 스택 프레임
z
[esp]
지역 변수
y
[esp+4]
buffer
[esp+8]
x
[esp+72]
저장된 eip
[esp+76]
a
[esp+80]
파라미터
b
[esp+84]
c
[esp+88]
모든 오프셋은 ESP가 바뀜에 따라 다시 조절
변수
오프셋
EBP 기반 스택 프레임
z
[ebp-76]
지역 변수
y
[ebp-72]
buffer
[ebp-68]
x
[ebp-4]
저장된 ebp
[ebp]
저장된 레지스터
저장된 eip
[ebp+4]
a
[ebp+8]
파라미터
b
[ebp+12]
c
[ebp+16]
개념 정리
* E: Extended(16bit → 32bit system), 64bit에서는 R로 표현
ESP(stack pointer register)
: 현재의 스택 지점(stack의 가장 아래 부분), 스택의 크기를 조정할 때 사용
- 스택에 값을 넣을 때마다 ESP가 4만큼 줄어듦
EBP(base pointer)
: 프레임 포인터를 사용하는 함수를 가리킴(함수가 프레임 포인터를 쓰는지 여부의 분석이 필요할 때, 이 속성을 이용해 수작업으로 지정 가능 - 레지스터의 크기 보정 필요)
- 스택의 가장 윗 부분, 스택 프레임 형태로 저장된 함수의 지역 변수나 전달인자를 참조/변경시 사용하는 레지스터
- 고정적, 코드 유지에 용이(스택프레임 생성시)
EIP(instruction pointer)
: 실행할 명령의 주소
3. 어셈블리어: CMP, LEA, TEST
1) .text:004010B0
디스어셈블리 코드
설명
.text:00401080 var_63
스택 프레임에서 바로 참조할 수 있는 모든 변수의 목록을 변수 크기와 프레임 포인터에서 떨어진 거리와 함께 요약해 보여줌
1. IDA 파일 정보 확인 - IDA 로딩 파일(.idb), 데이터베이스 파일(.id0, .id1, .nam, .til) 2. IDA 툴 기능의 이해 - IDA 데스크탑/그래프 뷰 등 화면 동작/기능 파악 - 데이터 타입/코드 변환 등 설정 대화상자 기능 파악 - pseudo code 조회, 다른 함수로 변환 등 3. 코드 표기 이해(헥사 뷰, 디스어셈블리 뷰 동기화 등)