3편의
기초 구조 이해
내용의 다음으로 리버싱을 분석하는 절차와 흐름에 대해 정리하고 예시와 전략에 대해 작성함
코드 흐름 분석은 리버싱의 핵심 작업 중 하나로, 프로그램이 어떻게 실행되는지, 그리고 어떤 조건에서 어떤 동작을 하는지 파악하는 과정
이를 통해 프로그램히
- 어떤 조건에서 분기하며
- 어떤 함수를 호출하고
- 어떤 루틴이 반복 수행되는가
에 대해 정확하게 추적할 수 있음
Branch란 조건에 따라 실행 흐름이 바뀌는 구조로 어셈블리에서는
cmp
명령어로 값을 비교하고,je
,jne
,jg
,jl
등의 조건 점프(jump)명령으로 흐름이 갈라짐
명령어 | 의 미 | 예시 상황 |
---|---|---|
je / jz | Equal / Zero | [cmp eax, 1] → [eax == 1] |
jne / jnz | Not Equal / Not Zero | [eax != 1] |
jg | Greater than (signed) | [eax > ebx] |
jl | Less than (signed) | [eax < ebx] |
ja | Above (unsigned) | [eax > ebx] (unsigned 기준) |
jb | Below (unsigned) | [eax < ebx] (unsigned 기준) |
cmp eax, 0x5 ; EAX와 5 비교
je 0x401020 ; 같으면 0x401020으로 점프
jne 0x401030 ; 다르면 0x401030으로 점프
💡cmp
는 내부적으로 sub
와 비슷하게 작동하며, 연산 결과에 따라 ZF(Zero Flag)등 플래그가 바뀌고, 그걸 조건 점프가 확인함
반복문은 일반적으로 조건 분기 + 점프 조합으로 구현되어 있음
루프 구조는jmp
로 되돌아가면서 반복 수행되며,loop
,ecx
레지스터 기반 반복도 자주 등장함
mov ecx, 3 ; 반복 횟수
loop_start:
; ...코드...
loop loop_start ; ECX--, 0이 아니면 loop_start로 점프
또는
mov eax, 0
cmp eax, 5
jge end_loop
inc eax
jmp short loop_start
어셈블리에서 함수 호출은
call
, 함수 종료는ret
으로 표현됨
call 0x401000 ; 401000 주소의 함수 호출
call
실행 시, return 주소가 스택에 push됨ret
명령을 만나면, 스택에서 복귀 주소 pop하고 원래 위치로 돌아감push return_address ; call 명령으로 인해 자동으로 push 됨
jmp 함수주소 ; 내부적으로 jump와 동일
push 인자1
,push 인자2
,...)push 0x1234
pushs 0x5678
call MessageBoxA
💡API 호출을 분석할 때는 인자 순서와 개수를 정확히 파악해야 의미 있는 분석이 가능
x64dbg, IDA 등 기준
sub_401000
등)cmp
,test
와 jXX
조합 주목mov
,lea
,add
,xor
등 값 조작 주목esp
,ebp
,eax
,ecx
등 주요 레지스터 집중디버깅을 통해 프로그램의 실행을 멈추고, 레지스터∙메모리 값을 직접 조작하거나 흐름을 바꾸는 행위로 흔히
Dynamic Analysis
라 부르며, 정적 분석으로 파악하기 힘든 부분을 보완 함
Breakpoint[BP]
는 디버깅 시 특정 명령에서 실행을 멈추게 하는 일종의 중단점으로 함수 시작, 조건 분기 전, API 호출 전, 루프 시작 등에서 자주 사용됨
종 류 | 설 명 |
---|---|
코드 BP | [0x041000] 같은 주소나 함수 시작 위치 |
API BP | CreateFileA, MessageBoxA 같은 외부 함수 호출 시 |
조건 BP | 특정 레지스터 값일 때 멈춤 |
메모리 BP (H/W BP) | 특정 메모리 읽기/쓰기 발생 시 중단 (watchpoint) |
strcmp
,memcmp
,GetDlgItemTextA
등에 BP 걸기cmp
,test
전) 위치에 BP코드를 한 줄씩 실행하면서 동작을 확인할 수 있는 디버거의 핵심 기능
기 능 | 설 명 |
---|---|
Step Into (F7) | 함수 내부로 진입 |
Step Over | 함수 전체를 한 번에 실행하고 다음 줄로 이동 |
Run to Return | 현재 함수가 끝날 때까지 실행 후 복귀점에서 멈춤 |
Run Until Selection | 커서가 위치한 지점까지 실행 |
레지스터의 값을 직접 바꾸는 것이 바로 리버서의 무기 중 하나로 조건 분기 결과나 반환값 등을 조작하여 인위적으로 실행 흐름을 바꾸는 데 사용됨
cmp eax, 0x1
jne fail_branch
eax != 1
이면 fail_branch
로 가는 상황이라면 EAX
값을 디버거에서 0x1
로 변경하여 우회할 수 있음
응용 시나리오
디버깅 중 스택이나 메모리 값을 바꾸면 함수 동작이나 결과가 달라질 수 있음 특히 복호화 루틴, 포인터 체인, 문자열 처리 등에서 효과적임
ESP
나 EBP
의 값을 조작해서 리턴 주소 변경