@리버싱
- 역공학 분석 : 실행 파일을 역으로 분석하는 행위
- 정상적인 리버싱 : 프로그램 분석 , 업데이트 , 패치 , 악성 코드 분석
- 악의적인 리버싱 : 프로그램 크랙 , 무단 사용 , 시리얼 키 우회 , 악성 코드 제작/유포
- 실행 파일 (Excutable File)
- 명령어에 의해서 특정 작업을 수행할 수 있도록 생성된 파일 ( Code , Data 포함되어 있음 )
- 각각의 운영체제마다 실행 파일 형식은 다음과 같다.
- Windows - PE ( Portable Exectable)
- Linux - ELF ( Excutable & Linkable Format)
- MAC - Mach-O ( Mach Object File Format)
@프로그램 & 프로세스 & 프로세스 & 쓰레드
- 프로그램 : 작업을 수행하기 위해서 명령어들이 포함되어 있는 실행 파일
- 프로세스 : 작업을 수행하기 위해서 메모리에 올라간 프로그램 단위
- 프로세서 : 메모리에 올라간 프로세스를 처리하는 CPU
- 쓰레드 : 생성된 프로세스에서 처리 및 흐름 과정을 담당하는 프로세스 안에 또 다른 프로세스
OllyDbg (프로그램)
- 프로그램을 분석할 때 사용하는 디버거
- 선수 지식: 어셈블리어, PE 파일 구조, DLL 기본 개념, 메모리 주소 관련
레지스터: CPU가 사용하려고 가지고 있는 데이터
EAX: 계산에 대한 저장을 하는 데이터 -> 32bit
ax -> 16bit
ah/al -> 8bit
EBX: 베이스 레지스터
ECX: 카운터 레지스터 (for 문)
EDX: 데이터 레지스터
ESI: 소스 인덱스 (출발지)
EDI: 데스티네이션 인덱스 (목적지)
EBP: 스택의 아랫부분 (베이스) 포인터
ESP: 스택의 윗부분 (탑) 포인터
EIP: CPU가 다음에 실행할 명령어 주소
<올리디 버거에서 자주 쓰이는 단축키>
- F2 : Break Point 설정 / 해제
- F7 : Step Into(한 줄씩 실행하며, 함수 안으로 들어감)
- F8 : Setup Over(한 줄씩 실행하며, 함수 안으로 들어가지 않음)
- F9 : 실행 및 Break Point 설정된 곳으로 이동
- Ctrl + F2 : 재시작
- Ctrl + F9 : 함수 코드 내에서 RETN 명령어까지 실행(함수 빠져 나옴)
- Ctrl + E : 해당 영역의 데이터 수정
- Ctrl + G : 원하는 창 선택 후 해당 명령어 입력하면 원하는 주소 값을 찾음
- Ctrl + B : hex dump 창에서 일치하는 곳을 찾음
- 수정한 부분 저장하기
1. 수정한 부분 > 우 클릭 > copy to executable > All modifications > copy all
2. 변경된 내용의 어셈블리어 창이 뜨면 우 클릭 > save file
어셈블리어 명령어
JL (jump if less) : 왼쪽 값이 작으면 점프 아니면 진행 (A<B)
JG (jump if greater) : 왼쪽 값이 크면 점프 (A>B)
JA (jump if above) : 왼쪽 값이 크면 점프 (A>B)
JB (jump if below) : 왼쪽 값이 작으면 점프 (A>B) == JC (jump if carry flag1): CF가 1일 때 점프
JAE (jump if above or equal) : 왼쪽 값이 크거나 같으면 점프 (A>=B) == JNC (jump if carry flag 0):CF가 0일 때 점프
JBE (jump if below or equal) : 왼쪽 값이 작거[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[B)
JNE (jump if not equal) : 두 값이 다르면 점프 (A! B)
JNZ (Jump if not zero) : zero flag가 0이 아니면 점프
JZ (jump if zero) : zero flag 가 0일 때 점프
CMP : 비교 연산자
JMP (jump) : 목적지 주소로 이동
LEA (Load Effective Address) : 주소를 가져오는 명령어 전역변수의 주소도 가져올 수 있다
TEST (Logical Compare) 논리 비교 : bit-wise logical 'AND' 연산과 동일(operand 값이 변경되지 않고 EFLAGS 레지스터만 변경됨)도 operand 중에 하나가 0이면 AND 연산 결과는 0 → ZF=1로 세팅됨. 즉, TEST의 AND 연산 결과값이 0이면 ZF가 1로 세트, 0이 아니면 ZF가 0으로 세트 된다.
레지스터 플래그
CF(Carry Flag)
부호 없는 수(unsigned integer)의 오버플로가 발생했을 때 1로 세팅된다. 예를 들어 1바이트의 값
1111 1111에 1을 더하면 1 0000 0000이 되어 마지막 1이 1바이트를 넘어서는 오버플로가 발생하여
CF는 1로 세팅된다. 그런데 더하기 뿐만 아니라 뺄셈에서도 오버플로가 발생하는데, 예를 들어 1바이트
값 0000 0001에 10을 빼면, .... 1111 1111 1111이 되어 1바이트를 넘어서는 오버플로가 발생하게
되어 CF는 1로 세팅된다. 이러한 성질 때문에 조건 점프 명령어 JA, JB에 이용된다.
PF(Parity Flag)
연산 결과, 하위 8비트에 '1'이 짝수 개 있으면 1로 세팅되고 그 외에는 0으로 세팅된다.
AF(Auxiliary carry Flag)
연산 결과 하위 니블(4bits)에서 비트 범위를 넘어섰을 때 참이 된다. 이진화 십진법(BCD) 연산에 사용된다.
ZF(Zero Flag)
연산 명령 후에 결과 값이 0이 되면 ZF가 1(True)로 세팅된다. CMP 명령어도 내부적으로 피연산자끼리 빼는 역할을 하기 때문에, 두 피연산자가 같으면 ZF가 1이 된다. 단, MOV 명령어로 0을 만들어줄 경우는 제외. 주로 조건 점프 명령어 JE, JNE에 이용된다.
SG(Sign Flag)
연산 명령 후 최상위 비트(부호 비트)가 1이라면 SG=1이 되고, 최상위 비트가 0이라면 SG=0이 된다.
TF(Trap Flag)
TF 값을 1로 세팅하면, CPU는 Single Step 모드로 변경된다. CPU는 Single Step 모드에서 하나의 명령어를 실행시킨 후, EXCEPTION_SINGLE_STEP 예외를 발생시킨다. 이후 Trap Flag는 자동으로 초기화(0) 된다.
OF(Overflow Flag)
연산 명령후 부호 있는 수(signd integer)의 최상위 비트에 오버플로가 발생했을 때 1로 세팅된다. 예를 들어 1바이트 값 0111 1111에 1을 더하게 되면, 최상위 비트가 1로 되기 때문에 OF=1이 된다. 그러나 오버플로가 발생했더라도, 최상위 비트가 0이라면 OF=0이 되는데, 예를 들어, 1바이트 값 0111 0000에 1100 0000을 더하게 되면, 1 0011 000이 되어 오버플로가 발생하긴 했지만, 최상위 비트가 0이기 때문에 OF=0이 된다. SG와 별반 차이 없어 보이지만, SG는 연산 결과 단순히 최상위 비트가 1이면 SG=1이지만, OF는 "오버플로" and "최상위 비트 1"이라는 조건이 충족되어야 OF=1이 된다.
올리디버거 프로그램을 이용하여 레나 level1 리버싱 시작

올리디버거를 이용하요 레나 level1을 분석

프로그램을 실행시키면 이런 식으로 이 프로그램을 더 사용하려면 라이선스 키가 있어야지 실행시킬 수 있다는 문구가 뜬다 아 reverserMe.exe라는 프로그램을 올리디버거로 분석해본다

올리디버거를 이용해 reverserMe.exe 실행 하게되면
이런 식으로 창이 뜨게 된다.

1. 프로그램 실행되어 프로세스가 될 때 가상 메모리 주소
2.cpu가 읽어들이는 기계어 3번이랑 mapping
3.2번을 사람이 읽을 수 있게 만든 어셈블리어 2번이랑 mapping
4. 어셈블리어의 주석 comment
5. 레지스터
6. 데이터 세그먼트 (메모리 덤프)
7. 스택
F8을 눌러 쭉 실행 시키다보면


이 부분에 걸려서 더 이상 진행되지 않고 아까 프로그램을 그냥 실행시켰을 때 떴던 문구가 뜨면서 자동으로 프로그램이 종료된다 이 문구를 띄우지 않고 프로그램을 실행시키는 방법은 크게 두 가지로 나뉜다 코드 한 줄 한 줄 어셈블리어 명령어를 바꿔주어 실행시키거나 주석에 써져있는 key 파일을 만들거나 둘 중에 하나를 골라서 해야 한다 우선 어셈블리어를 수정하여 프로그램을 실행시켜보겠다.

쭉 실행시키다 보면 오른쪽 주석에 써져있는 것 처럼 keyfile.dat라는 파일이 없으면 밑에 JNZ라는 구문 jump if not zero 즉 (ZF) zero flag의 결과값이 0이 아니라면 점프시키는 구문을 넘기지 못 하고 바로 밑에 오른쪽 주석에 써져있는 것처럼 CreateFile을 지나고 JNZ 분기문이 나온다.
JNZ은 0이 아닐 때 점프하는 명령어로 ZF가 0일 때 점프한다.
ZF(Zero Flag)는 결과값이 0일 때 1(set), 0이 아닐 때 0(unset)이다
JNZ으로 점프하지 않으면 바로 메시지가 뜨고 프로세스가 종료함을 알 수 있다.

이런 문구를 MessageBoxA 함수를 이용해 ExitProcess 프로그램을 종료한다고 써져있다 우리는 이 구문을 점프하기 위해 JNZ의 ZF(zero flag) 를 변경해줘야 한다

이 부분을 잘 보면 JNZ 구문이 나오고 ZF 가 0이 아니면 오른쪽에 써져있는 SHORT reverseM. 0040109A라는 정상적인 구문으로 점프하지 않고 위에 처럼 메시지 박스를 띄우며 프로그램이 종료되는 구문으로 넘어가게 된다 이 구문의 ZF 를 0으로 바꿔서 점프를 해서 정상적인 구문으로 가게 해보자

오른쪽의 Zeri flag를 1에서 0으로 바꿔주었다 이제 다시 F8로 실행시켜보면

왼쪽의 빨간색으로 선이 그어져있는 만큼 JNZ 구문에 0040109A라고 써져있는 곳으로 점프하게 된다

또 쭉쭉 실행하다 보면 JNZ 구문이 하나 더 나오게 된다 오른쪽 주석에 ReadFile이라고 적혀있는 걸 보니 위쪽에 써져있던 keyfile.dat 파일의 암호를 읽어온다고 추측할 수 있다. 우리는 keyfile.dat이라는 것을 만들지 않고 플레그를 수정하여 이 프로그램을 실행시킬 것 이라서 이번에도 JNZ 구문에 있는 플레그를 1에서 0으로 수정하여 바로 밑에 있는 JMP 점프 구문을 패스해보자

패스를 하면 004010B4 라고 써져있는 곳으로 이동하게 된다

만약 플레그를 수정하지 않는다면 keyfile.dat라는 암호 키에 암호가 맞지 않다며 또 다른 메시지 박스를 띄우며 프로그램을 종료하게 되지만 우리는 플레그를 건드려 이 곳으로 오지 않고 넘어갈 수 있는 것이다.

다시 F8을 눌러 쭉쭉 실행하다 보면 JL 구문과 JE, JNZ, 구문을 마주치게 된다. 이 JL 구문을 넘기지 못하면
004010F7로 가지 않고 빨간색 선으로 그어져있는 곳 까지 가게 되어

또다시 이 오류 문구를 마주하게 된다.
이 오류 문구를 넘기려면

JL 구문에 SF 를 1에서 0으로 바꾸어 넘어갈 수도 있지만 space bar로 명령어를 수정해서 넘어가 보자

JL 구문을 nop으로 바꾸어 모든 조건문을 건너뛰고

you really did it congratz!!! 성공적이게 프로그램을 종료 하였다.
지금 이 방법은 두 가지 방법을 사용한 것이다
첫 번째는 직접적으로 레지스터를 건드려서 프로그램이 정답을 맞췄다고 착각하게 만들어 점프를 하게 만든 것이고
두 번째는 직접적으로 어셈블리어를 NOP이라고 수정하여 프로그램 자체를 건드린 것이다 이런 경우에 저 프로그램은 크랙 파일이 되는 것이다
또는 keyfile.dat라는 keyfile을 만들어 주어 프로그램에 직접적으로 아무것도 건드리지 않고 풀 수도 있다.
사실 이런 류의 프로그램은 처음 JNG 구문에서 바로 JMP 명령어로 바꾸어 마지막 부분으로 넘어갈 수 있다. (레나에서 만든 연습용 프로그램이라서 가능)

All referenced text strings를 누르면

이런 식으로 이 프로그램에 작성해놓은 모든 텍스트가 나오게 되는데 저기 밑에 성공 문구를 누르면 그 부분으로 이동을 하게 된다

이렇게 나오게 되는데 여기서 처음 JNG 구문을 JMP 401205로 수정하게 되면


바로 이 부분으로 넘어오게 하는 것이 가능하다.. 이렇게 레나 level1 끝
'Reversing' 카테고리의 다른 글
리버싱 (Reverse engineering) (1) | 2023.11.03 |
---|