2주차 스터디에서는 유튜브 강의를 통해 리버싱 기초 지식을 학습했다.
4-7강을 듣고 내용을 정리한 뒤, 실습에서 해결되지 않았던 부분들을 공유하며 해결하는 시간을 가졌다.
https://youtu.be/mJCzHwBH2HQ?si=0CeZOsEWrNH4yXnx
- CPU 레지스터
CPU 내부에 있는 저장공간.
CPU 내부에 있기때문에 데이터 연산속도가 매우 빠르지만, 용량이 매우 작다.
- 범용 레지스터(General Register)
레지스터의 한 종류로, 막 쓰는 레지스터이다.
32비트 아키텍처 레지스터에 포함됨.
reg size(IA-32 32bit) = 4byte
- 범용 레지스터의 종류
산술 명령어에서 상수/변수 값이 저장되는 용도
- EAX : 결과값을 저장하거나 오퍼랜드(피연산자, x+y=z에서 x와y)를 저장한다.
- EBX
- ECX : while, for문 같은 반복문을 사용할 때 ECX에서 loop count -1씩 감소한다.
- EDX
메모리 주소를 저장하는 포인터로 사용되는 용도
- ESI
- EDI
- EBP : ESP 값을 저장
- ESP : 스택 메모리 주소, 스택 포인터
EIP : CPU가 다음에 처리할 명령어 주소
ex) 0x123 mov eax, 1(16진수) ; 1이라는 값을 eax에 옮겨라
EIP = 0x123이면 다음 명령어가 실행될 때 0x123의 명령어가 실행 됨
- 바이트 수
- EAX = 4byte
- AX = 2byte
- AH(High) = 1byte
- AL(Low) = 1byte
* EAX를 분해하면 AX, AH, AL이다.
마찬가지로 EBX=4, BX=2, BH=1, BL=1...
- 플래그 레지스터(Flag Register)
명령어가 실행되기 위한 조건.
명령어 수행에 따라 True(1), False(0)로 세팅되며 32개 존재한다.
Zero Flag(ZF)
연산 명령 후에 결과 값이 0이 되면 ZF가 1(True)로 세팅. cmp와도 관련이 있다.
ex)
mov eax, 1 // eax에 1을 넣고
mov ebx, 1 // ebx에 1을 넣음
sub eax, ebx // 1-1=0이므로 r=0(결과값이 0)이 됨. → ZF=1로 세팅됨
Overflow Flag(OF)
부호가 있는 수(Signed integer)의 오버플로우가 발생했을 때 1로 세팅된다.
MSB(최상위 비트)가 변경되었을 때 1로 세팅된다.
Carry Flag(CF)
부호가 없는 수(Unsigned integer)의 오버플로우가 발생했을 때 1로 세팅된다.
- 스택(Stack)
메모리 안에 존재한다.
스택을 배워야 하는 이유
1. 함수 내의 변수가 임시저장된다.
2. 함수 호출시 매개변수(파라미터)가 전달된다.
3. 복귀 주소가 저장된다.
스택의 특징
FILO(First In Last Out)구조를 가짐
스택에서 ESP(스택포인터)는 유동적이고, EBP는 고정적(버팀목 같은 존재로 움직이지 않음)이다.
- PUSH = 스택에 값을 넣음
- POP = 스택의 값을 뺌
- 스택 프레임(Stack Frame)
ESP가 아닌 EBP를 이용하여 스택 내의 변수 파라미터 복귀주소에 접근하는 기법
ex) Assembly code // 어셈블리에서 ;는 주석처리를 뜻한다.
PUSH EBP ; 함수시작, EBP값을 스택에 백업
MOV EBP, ESP ; ESP값을 EBP에 백업. 즉,c언어에서 EBP=ESP;
. ; 함수 로직 실행
. ; 여기서 ESP가 변경되어도 괜찮다. → EBP는 스택에 백업되어있고, ESP는 EBP에 저장되어있기 때문에
.
MOV ESP, EBP ; ESP 복원
POP EBP ; EBP 복원
RETN ; 함수 종료
위 코드를 보면 ESP값이 아무리 변해도 EBP를 기준으로 안전하게 해당 변수나 파라미터, 복귀주소에 접근이 가능한 것을 알 수 있다.
다만 스택에 값이 저장된다는 점에서 취약할 수 있다.
- CodeEngn - Basic RCE L01 실습
CodeEngn에서 Basic RCE L01 문제 파일을 다운받고, 압축을 해제해 exe파일을 실행한다.
실행을 하자 다음과 같은 메세지 박스가 뜬다.
x32dbg에서 exe파일을 열어서 EP로 들어가면
cmp분기문(주어진 조건의 흐름을 바꿀 수 있는 구문)과 에러 구문, 성공 구문이 있는 것을 확인할 수 있다.
HDD를 CD-ROM으로 인식시켜야 문제를 해결할 수 있으므로,
에러구문이 아닌 성공구문으로 갈 수 있도록 메모리를 변조해야한다.
Cheat Engine을 실행하고, Process List(모니터에 돋보기 아이콘)를 누르고 exe를 열어준다.
F5 = 브레이크 포인트 설정 Ctrl+B = 설정한 브레이크 포인트 리스트 |
Cheat Engine 단축키
cmp에서 값을 비교한 뒤 에러구문과 성공구문으로 나뉘므로, cmp에 중단점을 설정(F5)한다.
실행시켜주면 ZF가 0인 것을 볼 수 있다. (=cmp 결과값이 0이 아니었음)
따라서 점프가 일어나지 않고, 에러구문으로 향하게 된다.
* cmp결과값 = 0 → ZF=1 → JE는 주어진 주소로 점프 cmp결과값 ≠ 0 → ZF=0 → JE는 주어진 주소로 점프x |
반면 JE가 점프할 경우, 성공구문으로 점프하는 것을 확인할 수 있다.
현재 cmp 결과값이 0이 아니었기 때문에 JE문이 실행되지 않았는데,
cmp의 EIP값을 '점프 되었을 때의 주소'로 수정해 점프하도록 만들 수 있다.
점프되었을때의 주소를 복사해준다.(Ctrl+G)
cmp에서 마우스 우클릭 - [Change register at this location] 으로 들어가준다.
EIP에 복사한 주소를 붙여넣고 OK를 누른다.
다시 실행하면 위 사진과 같이 변조 성공한 모습을 볼 수 있다.
- x32dbg에서 변조하는 법
x32dbg에서 exe파일을 열은 뒤 EP로 들어가준다.
je부분에서 스페이스바를 눌러 je를 jmp(무조건 점프)로 수정해준다.
다시 실행시키면 다음과 같이 변조에 성공한 모습을 볼 수 있다.
je/jz Zero Flag = 1 일때 점프 jump equal : ZF가 1이면(cmp결과값=0) 점프 jump zero : ZF가 세팅되어 있으면 점프 즉, je = jz라고 볼 수 있다. jmp 무조건 점프 |
je/jz와 jmp의 차이점
'2. Reversing (리버싱)' 카테고리의 다른 글
[2024.04.06] 리버씽씽카 4주차 활동 (0) | 2024.05.04 |
---|---|
[2024.03.30] 리버씽씽카 3주차 활동 (0) | 2024.03.30 |
[2023.11.04] 리버싱 5주차 팀활동 (0) | 2023.11.10 |
[2023.10.07] 리버싱 3주차 팀활동 (0) | 2023.10.13 |
[2023.09.30] 리버싱 2주차 팀활동 (0) | 2023.10.06 |