abex' crackme #1 write up

 

 

처음에 Immunity Debugger로 문제 파일을 연 후 F8키를 눌러보면서 한줄씩 실행시켜보았다.

 

 

 

위와 같은 어셈블리 코드와 메세지창을 볼 수 있었고 CD-ROM이 맞다는 메세지 창이 뜨도록 만드는 것이 이 문제의 목표였기 때문에 아래 그림의 코드 부분을 유심히 보았다.

 

 

일단 00401026 주소에 있는 JE 명령어는 어셈블리의 분기 명령어 중 하나로 Jump if equal 즉, CMP로 비교한 결과 값이 같다면 참이 되고, 이때 해당 주소로 점프하는 기능을 가진 명령어이다.

 

 

수정하기 전의 코드에서 CMP 명령어를 처리해줄때 EAX 레지스터에는 00000001 값이 들어있고 ESI에는 00401003 값이 들어있기 때문에 두 결과값은 같지 않으므로 0040103D라는 주소로 넘어가지 않고 그냥 그 다음주소(00401028)로 넘어간다.

 

 

위와 같이 옆에 주석 부분에서 볼 수 있듯이 Ok, I really think that your HD is a CD-ROM이라는 메세지가 있는 MessageBox가 실행되도록 하려면 CMP를 해준 값이 같도록 하여 JE를 만났을때 해당 주소(0040103D)로 넘어갈 수 있게 만들어주면 될 것이라고 생각했다.

 

 

그래서 위와 같이 MOV EAX, ESI를 해주어 두 값이 같도록 수정했더니 제대로 메세지 창이 뜨는 것을 확인할 수 있었다.

MOV 명령어는 operend1값에 operend2 값을 넣어준다는 의미이다.

 

또 다른 풀이법으로는 JE 명령어를 JMP 명령어로 바꿔주는 방식이 있다.

JE 명령어는 CMP해준 두 값이 같아야만 점프를 하는 반면 JMP 명령어는 무조건 해당 주소값으로 점프를 한다. 

 

 

그렇기 때문에 위와 같이 JE를 JMP로 수정해주면 해당 주소로 잘 넘어가고 원하는 메세지 창이 뜨게 할 수 있다.

 

이외에도 레지스터의 값을 증가시키거나 감소시키는 코드로 수정하여 EAX와 ESI의 값을 같게 만들어주는 방법도 있을 것이다.

'2021-2 STUDY > Reversing Study' 카테고리의 다른 글

Week02_Dreamhack rev-basic-2, rev-basic-3  (0) 2021.09.25
Week02_PE 파일 구조  (0) 2021.09.25
Week01_Dreamhack rev-basic-0, rev-basic-1  (0) 2021.09.11
Week01_32bit/64bit 호출 규약  (0) 2021.09.11
Week01_64bit 레지스터  (0) 2021.09.11

Dreamhack rev-basic-0

 

x64dbg를 이용하여 문제에서 주어진 파일을 실행시켰다.

 

 

먼저 메인 함수를 찾기 위해 F8키로 계속 확인해보다가 cmd 창에 "input: "이라는 문구가 뜨는 함수 호출 부분에 breakpoint를 걸어주었다.

 

 

아까 걸어주었던 breakpoint 부분에서 F7키를 눌러 함수 내부로 들어온 후 위와 같은 부분을 확인할 수 있었다.

 

여기에서 test eax, eax를 통해 eax가 0인지 아닌지 판단하는 부분을 찾아볼 수 있다.

이때 eax 값이 0이면 Wrong을 출력하고, 아니면 Correct를 출력한다는 것을 예상할 수 있다.

 

이때 좀 더 자세히 확인해 보기 위해 test 명령어 전에 호출하는 함수 내부를 들어가 보았다.

 

 

test 명령어 전에 호출되는 함수 내부를 확인해보니 eax가 0이 아니면 ss:[rsp+20] 주소 부분에 1이 담기고,

eax가 0이면 ss:[rsp+20] 주소 부분에 0이 담기고 함수를 빠져나가는 것을 확인할 수 있다. 

 

이때 "Correct"를 출력해주기 위해서는 eax가 결과적으로 0이 아니어야 하기 때문에 이 부분에서는 eax가 0이 되어야 한다.

 

여기서 call <JMP.&strcmp> 함수는 두 문자열을 비교하여 같으면 0, 다르면 1을 eax 레지스터에 저장하는 역할을 한다.

즉, eax가 0이 되도록 하기 위해서는 rcx와 rdx의 문자열이 서로 같으면 되기 때문에 compar3_the_string을 입력해주면 될 것이다.

 

 

위와 같이 Correct가 잘 출력되는 것을 확인할 수 있다.

 

 

Dreamhack rev-basic-1

 

x64dbg를 이용하여 문제에서 주어진 파일을 실행시켰다.

 

 

이 문제도 메인 함수를 찾기 위해 F8키로 계속 확인해보다가 cmd 창에 "input: "이라는 문구가 뜨는 함수 호출 부분에 breakpoint를 걸어주었다.

 

 

이 문제도 역시 Input값을 받아 test eax, eax를 해준 후  eax 값이 0이면 Wrong을 출력하고, 아니면 Correct를 출력한다는 것을 예상할 수 있다.

 

이 때 test 명령어 전 호출되는 함수에 breakpoint를 걸고 함수 내부로 들어가 보았다. 

 

 

함수 내부로 들어가 보면 위와 같이 cmp 명령어로 문자열을 하나씩 비교해주고 있는 것을 확인할 수 있다.

 

 

이때 하나씩 입력되는 문자열과 Input에 넣어주는 값이 같아야 하므로 Compar3_the_ch4ract3r를 입력해주면 된다.

 

 

위와 같이 Correct가 잘 출력되는 것을 확인할 수 있다.

'2021-2 STUDY > Reversing Study' 카테고리의 다른 글

Week02_Dreamhack rev-basic-2, rev-basic-3  (0) 2021.09.25
Week02_PE 파일 구조  (0) 2021.09.25
Week01_abex' crackme #1  (0) 2021.09.11
Week01_32bit/64bit 호출 규약  (0) 2021.09.11
Week01_64bit 레지스터  (0) 2021.09.11

▶ 함수 호출 규약 (Calling Convention)

 

→ 함수를 호출할 때 파라미터를 어떤 방식으로 전달할지 정해놓은 규약

 

함수 호출 시에는 유효하지 않은 파라미터를 삭제하는 과정이 필요하고, 유효하지 않은 파라미터를 가리키고 있는 ESP를 증가시켜 스택을 정리해주어야 한다. 이때 스택을 정리하는 방식에 대한 규약을 함수 호출 규약이라고 한다.

 

 

▶ 32bit 함수 호출 규약

 

▷ cdecl

 

- call(호출자)을 하는 쪽에서 스택을 정리하는 방식

- 인자를 오른쪽에서 왼쪽으로 넣음

- 가변인자 전달이 가능하다는 장점

- 함수 앞에 _를 추가하여 구분 가능

- ex) main( ) 함수에서 add( ) 함수를 호출하는 경우 add( ) 함수가 끝나고 main( ) 함수에서 스택에 저장되었던 파라미터를 정리하기 위해 esp 값을 증가시켜 스택 정리

 

▷ stdcall

 

- cdecl과 반대로 호출된 함수에서 스택을 정리하는 방식

- stdcall 형식으로 asm을 컴파일할 때 규약을 따름

- 호출된 함수의 마지막 부분에서 RETN 명령을 사용하여 함수 내에서 스택을 정리하고 함수를 빠져나옴

- 인자를 오른쪽에서 왼쪽으로 넣음

- main( ) 함수에 따로 스택을 정리하는 명령이 필요없기 때문에 코드 길이가 짧아진다는 장점

- 함수 앞에 _를 추가하고, 함수 이름 뒤에는 @를 추가

 

▷ fastcall

 

- stdcall 방식과 같은데, 함수에 전달하는 파라미터 일부(최대 2개)를 레지스터를 사용하여 전달

- 이용하는 레지스터는 ECX, EDX

- 레지스터를 이용하기 때문에 빠르게 함수를 호출할 수 있는 장점

- 스택 정리는 호출된 함수 내에서 함

- 함수 앞에 @를 추가하고, 함수 이름 뒤에는 @가 추가됨

- 스택 이용 바이트 수 표현

 

 

▶ 64bit 함수 호출 규약

 

- 32bit 함수 호출 규약과 다르게 fastcall 방식만 이용

- 파라미터 전달

 

  정수 실수
리눅스 EDI, ESI, EDX, E8, CX, R8, R9 XMM0~XMM7
윈도우 ECX,EDX,R8,R9 XMM0~XMM4

 

- ex) add(int a, int b)는 파라미터가 정수형이므로 EDI, ESI 레지스터에 들어가고, 오른쪽에서 왼쪽 방향으로 파라미터가 들어가기 때문에 int b는 EDI 레지스터, int a는 ESI 레지스터에 들어간다.

 

 

※ ROP할 때

 

32bit : 함수 호출 → pr → 인자

64bit: pr → 인자 → 함수 호출

'2021-2 STUDY > Reversing Study' 카테고리의 다른 글

Week02_Dreamhack rev-basic-2, rev-basic-3  (0) 2021.09.25
Week02_PE 파일 구조  (0) 2021.09.25
Week01_abex' crackme #1  (0) 2021.09.11
Week01_Dreamhack rev-basic-0, rev-basic-1  (0) 2021.09.11
Week01_64bit 레지스터  (0) 2021.09.11

▶ 64bit 운영체제

 

64bit 운영체제는 2^64만큼의 비트를 사용한다.

→ 메모리를 0부터 18,446,744,073,709,551,616까지 저장할 수 있다.

 

64bit 컴퓨터에서는 최대 1tb(2^10gb)만큼의 RAM이 들어간다.

 

 

▶ 64bit 레지스터

 

※ 레지스터란?

→ CPU가 요청을 처리하는 데 필요한 데이터를 일시적으로 젖아하는 기억장치

→ 레지스터의 용량이 클수록 메모리에서 더 많은 데이터를 가져와 저장할 수 있으므로 처리속도가 빨라진다.

 

 

▷ 범용 레지스터

 

RAX 산술/논리 연산 수행 후 함수의 return 값 저장
RBX 메모리 주소 저장
RCX 반복문에서 카운터로 사용되는 레지스터
RDX I/O 주소 지정 시 사용, 다른 레지스터를 서포트하는 보조 레지스터
R8~R15 64bit 프로세서에서 추가된 범용 레지스터, 다양한 용도로 사용

 

▷ 인덱스 레지스터

 

RSI 복사할 데이터의 주소 저장
RDI 복사된 데이터의 주소 저장

 

▷ 포인터 레지스터

 

RSP 스택의 끝 지점 주소 (현재 스택 주소) 저장
스택의 가장 높은 곳을 가리킴
push, pop 명령을 통해 RSP 값이 위아래로 8바이트씩 이동
RBP 함수 호출 시 형성되는 스택프레임의 시작 지점 주소 (스택 복귀 주소) 저장

 

▷ 플래그 레지스터

 

RFLAGS register 시스템 제어 용도, 비교/조건문 처리 용도
CF(Carry Flag) 부호 없는 수끼리 연산 결과에서 자리올림/자리내림이 발생할 때 1,
unsigned int 값을 벗어날 때 1
OF(Overflow Flag) 부호 있는 수끼리 연산 결과에서 용량을 초과했을 때 1
SF(Sign Flag) 연산 결과 최상위 비트가 1인 경우 1
ZF(Zero Flag) 연산 결과가 0이면 1
AF(Auximiliary-carry Flag) 16bit 연산 시 자리올림/자리내림이 발생할 때 1
PF(Parity Flag) 연산 결과가 짝수면 1, 홀수면 0
DF(Direction Flag) 방향 플래그
0으로 설정 시 해당되는 어셈블리 명령에 제공되는 주소 증가
IF(Interrupt Flag) 1은 인터럽트 활성화, 0은 인터럽트 비활성화
TF(Trap Flag) single step mode에서 프로세스의 동작 허용

 

 

※ 하나의 레지스터는 크기에 따라 적절히 쪼개 사용할 수 있다.

 

 

RAX(64 bits) - EAX(32 bits, Extended AX) - AX(16 bits) - AL(8 bits) - AH(8 bits)

 

'2021-2 STUDY > Reversing Study' 카테고리의 다른 글

Week02_Dreamhack rev-basic-2, rev-basic-3  (0) 2021.09.25
Week02_PE 파일 구조  (0) 2021.09.25
Week01_abex' crackme #1  (0) 2021.09.11
Week01_Dreamhack rev-basic-0, rev-basic-1  (0) 2021.09.11
Week01_32bit/64bit 호출 규약  (0) 2021.09.11

+ Recent posts