일단 문제를 보면 Key값이 주어졌고 이를 이용하여 Name을 찾는 문제였다.

 

이번 문제는 너무 어려워서 다른 라이트업을 참고했지만 그것도 완벽히 이해하지는 못했다...

 

 

먼저 주어진 Key 입력하고 Name 아무거나 입력해보았다. Check it을 눌러보았더니

 

 

위와 같이 Key값을 더 입력하라는 메세지가 떴다..

처음에는 Name이 한자리라고 했으니까 다 입력해볼까 생각도 했지만 일단 먼저 디버거로 열어봤다.

 

 

코드를 진행하다가 위와 같은 부분을 발견할 수 있었다.

 

 

 

0045BB12~18 부분을 통해 내가 입력한 문자열을 불러올 것을 예측할 수 있었다.

이때 0045BB24 부분을 보면 CMP EAX,3으로 되어 있는데 문제에서 Name값이 한자리라고 했으므로 CMP EAX,1로 패치를 해주어야 한다.

또한, 아까 봤던 Please Enter More Chars가 있는 것을 확인할 수 있고

밑의 주석 부분은 30글자가 넘으면 나오는 메세지임을 예측할 수 있다.

 

 

또한 좀 더 코드를 살펴보면 위와 같이 성공 메세지 창이 뜨는 부분을 확인할 수 있다.

 

 

일단 위와 같이 CMP EAX, 1로 패치해준 후 코드를 한줄씩 실행했다.

 

 

위와 같이 첫번째 루틴이 나오고 이러한 연산이 몇 번 반복된다.

 

 

그렇게 계속 진행시키다보면 0045BBA9에서 내가 입력한 값이 위와 같이 저장된 것을 확인할 수 있다.

이때 첫번째 루틴이 끝나고 EDX 레지스터에 저장된 값을 확인해보면 어떻게 연산을 해도 항상 4자리가 같다는 것을 확인할 수 있다.

 

이렇게 연산을 다시 진행하여 BEDA-2F56-BC4F4368-8A71-870B이 나오도록 구해주면 된다.

 

이때 코드를 직접 짜서 확인해주는 작업이 필요한데 이 부분은 완벽히 이해하지 못해서 라이트업을 참고했다.

 

 

위와 같이 코드를 짜준 후에 실행 결과를 확인해보면

 

 

위와 같이 F를 연산했을 때 beda가 나오는 것을 확인할 수 있다.

 

 

따라서 재시작 후 Name에 F를 입력해주면 위와 같이 아까 주석으로 본 성공메세지창이 잘 나타나는 것을 확인할 수 있다.

 

또한, 사이트에서는 F의 MD5 해쉬값으로 인증을 해주면 된다.

1. 레지스터란?

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

- 메모리로 연산의 결과를 보내고 영구적으로 저장할 데이터를 하드디스크에 저장하는 등의 명령 처리

- 연산 속도가 메모리보다 훨씬 빠르며 특정 주소를 가리키거나 값을 읽어올 수 있음

- 컴퓨터의 bit가 클수록 처리속도가 빠름

- 어셈블리에서 레지스터란 CPU가 사용하는 변수를 의미

 

 

2. 레지스터의 종류

1) 범용 레지스터 (General Purpose Register)

 

- 작은 데이터의 임시 저장 공간

- 연산 처리 및 번지 지정을 도와주며 컴퓨터의 장치를 제어함

 

종류 특징
EAX
(Accumulator)
  - 누산기 레지스터로 입출력, 산술연산, 논리연산을 수행
  - 함수의 리턴 값 저장
  - AX는 EAX의 오른쪽 16비트 부분
  - AH는 AX의 왼쪽 8비트 상위부분, AL은 AX의 오른쪽 8비트 하위부분
EBX
(Base address)
  - 주소 지정을 확장하기 위해 인덱스로서 사용하는 레지스터
  - BX는 EBX의 오른쪽 16비트 부분
  - BH는 BX의 왼쪽 8비트 상위부분, BL은 BX의 오른쪽 8비트 하위부분
ECX
(Counter)
  - 반복문을 수행할 때 반복 횟수를 지정하는데 사용
  - CX는 ECX의 오른쪽 16비트 부분
  - CH는 CX의 왼쪽 8비트 상위부분, CL은 CX의 오른쪽 8비트 하위부분
EDX
(Data)
  - 큰 수의 산술연산, 논리연산을 할 때 EAX의 보조적 역할로 사용
  - EAX 레지스터와 같이 쓰임
  - 부호 확장 명령 등에 사용
  - DX는 EDX의 오른쪽 16비트 부분
  - DH는 DX의 왼쪽 8비트 상위부분, DL은 DX의 오른쪽 8비트 하위부분

 

2) 포인터 레지스터 (Pointer Register)

 

- 메모리 스택 영역과 관련된 주소 값을 나타냄

 

종류 특징
ESP (Extended Stack Pointer)   - 스택 영역의 최상단을 가리킴
EBP (Extended Base Pointer)   - 스택 영역의 기준이 되는 주소를 가리킴
EIP (Extended Instruction Pointer)   - 다음 실행할 명령이 들어 있는 메모리의 주소를 가리킴

 

3) 인덱스 레지스터 (Index Register)

 

- 문자열을 복사/비교

- 인덱스 주소지정과 덧셈, 뺄셈에서 사용 가능

 

종류 특징
ESI (Extended Source Index)   - 복사/비교의 대상의 주소를 가리킴
EDI (Extended Destination Index)   - 복사/비교를 할 곳의 주소를 가리킴

 

4) 세그먼트 레지스터 (Segment Register)

 

- 다양한 크기로 구분을 하는 목적으로 사용

- 16비트로 구성

 

종류 특징
CS (Code Segment)   - 함수와 제어문 같은 명령어들이 저장되는 코드 세그먼트
DS (Data Segment)   - 전역, 정적 변수 데이터가 들어있는 데이터 세그먼트
SS (Stack Segment)   - 주소와 데이터를 일시적으로 저장할 목적으로 쓰이는 세그먼트
  - 스택의 주소를 지정하는데 사용
ES (Extra Segment)   - 추가 레지스터로 문자 데이터의 주소를 지정하는데 사용

 

5) 플래그 레지스터 (Extended Flags Register)

 

- 실행 순서를 제어하기 위한 목적으로 사용

- 플래그를 1로 설정하는 것을 SET, 0으로 설정하는 것을 CLEAR 또는 RESET이라고 함

 

종류 특징
상태플래그 CF (Carry Flag)   - 산술 연산 후 상위 비트의 캐리를 포함
  - 자리이동 또는 회전연산 후 마지막의 비트내용을 포함
PF (Parity Flag)   - 연산 결과 1비트들의 개수에 따라 짝수 패리티와 홀수 패리티로 나타냄
OF (Overflow Flag)   - 산술 연산 후 상위비트의 오버플로우를 나타냄
AF (Auxiliary Flag)   - 특수화된 산술에서 사용
  - 비트 3에서 비트 4로의 캐리를 포함
ZF (Zero Flag)   - 산술이나 비교 연산의 결과를 나타냄
SF (Sign Flag)   - 산술 연산의 결과값에 대한 부호를 포함
제어플래그 DF (Direction Flag)   - 스트링 데이터를 이동시키거나 비교할 때 방향 결정
시스템플래그 TF (Trap Flag)   - 단일 단계 모드의 프로세서 연산 허용
IF (Interrupt Flag)   - 키보드 입력과 같은 외부 인터럽트의 처리 여부를 나타냄

 

먼저 문제를 확인해보면 C드라이브의 이름이 CodeEngn일 때 생성되는 시리얼 값이 어떤 것으로 변경되는지 알아보는 것이다.

 

 

먼저 실행을 한 후 아무거나 입력해보면 위와 같은 메세지창이 뜨는 것을 확인할 수 있다.

 

 

먼저 C드라이브 이름이 CodeEngn이라고 했으므로 내컴퓨터 C드라이브 이름을 바꾸어준 후에

Immunity Debugger로 실행 파일을 열어 보았다.

어떻게 시작해야할지 몰라 코드를 확인해보다가 위와 같은 부분을 발견할 수 있었다.

004010FC 부분에서 EAX레지스터의 값과 0을 비교하여 시리얼값 정답 여부를 판별해주는 분기문을 볼 수 있었다.

 

 

코드를 실행하다보면 위와 같이 GetVolumeInformationA라는 함수를 발견할 수 있는데 이는 하드디스크의 볼륨값을 불러오는 함수로 이 함수를 통해 내 컴퓨터의 C드라이브 값을 불러온다는 것을 예측할 수 있다.

 

 

위와 같이 004010AD 부분으로 이동한 후 코드를 확인해봤더니 스택의 값을 1씩 더해주는 것을 두 번 반복하는 코드를 확인할 수 있다.

 

 

위에서 봤던 코드를 한줄씩 실행시켰더니 아까와는 다르게 Code 부분이 Eqfg로 바뀐 것을 확인할 수 있다.

 

 

또한 StringToAdd를 실행시켜주면 해당된 문자열을 연결해준 것이 Serial이라는 것을 예측할 수 있다.

004010ED를 보면 알 수 있듯이 내가 입력한 Serial값인 1234와 문자열을 연결한 Serial 값을 비교할 것이다.

 

 

위 부분까지 실행한 후 레지스터 창을 확인해보면 EAX레지스터에 위와 같은 값이 들어가 있는 것을 확인할 수 있고 이 값을 CMP로 비교하여 아까 봤던 분기문을 판단해주는 것이다.

 

 

따라서 다시 실행한 후 위처럼 Serial 값을 입력해주었더니 성공 메세지창이 뜨는 것을 확인할 수 있었다.

 

또한, 문제에서 인증키는 CodeEngn이 변경된 값이었기 때문에 답은 EqfgEngn이 된다.

 

 

먼저 문제를 보면 Serial 값을 찾는 문제이다.

 

 

 

주어진 파일을 실행시켜보면 위와 같은 창이 뜨는 것을 확인할 수 있다.

 

 

Name이 CodeEngn이라고 했으니 그렇게 입력해주고 Serial 값은 아무거나 입력했더니 위와 같이 Try Again!이라는 메세지창이 뜨는 것을 확인할 수 있었다.

 

 

Immunity Debugger로 파일을 열어준 후 코드를 실행시킨 후 아까 위에서 실행했던 것처럼 Name에는 CodeEngn, Serial에는 1234를 입력한 상태이다.

위의 코드를 보면 00458831 부분에 EAX레지스터의 값과 스택에서 45B844 부분에 저장된 값을 비교하여 정답 여부를 확인해 주는 코드를 볼 수 있다.

여기서 두 값이 같다면 You cracked the ~~ 부분으로 넘어갈 것이고 다르다면 Try Again 부분으로 넘어갈 것이다.

 

 

먼저 EAX 레지스터를 확인해보면 위와 같이 1234라고 입력한 값이 저장된 것을 확인할 수 있다.

 

 

입력한 1234를 16진수로 변환한 수는 4D2이기 때문에 위와 같이 EAX레지스터에 4D2가 저장된 것을 확인할 수 있다.

 

 

또한 아까 EAX 레지스터와 비교하는 주소의 값을 확인하기 위해 Hex Dump 창에서 해당 주소(0045B844)로 이동해봤고 위와 같은 값을 확인할 수 있었다.

이때 덤프주소 값은 little endian 방식으로 읽어주어야 하고 이 방식은 낮은 주소에 데이터의 낮은 바이트부터 저장하는 방식을 의미한다. 이는 평소 숫자를 사용하는 선형 방식과는 반대로 거꾸로 값을 읽어주어야 한다.

또한, 아까 자료형이 DWORD였고 이는 4byte를 의미하므로 위의 값을 읽어보면 00 00 61 60이 된다.

 

 

즉, 위에서 본 값을 10진수로 바꿔준 값을 Serial에 입력하면 EAX레지스터에는 그 값이 16진수로 바뀌어 저장될 것이므로 CMP를 해주었을때 점프하지 않고 바로 다음 코드를 실행시킬 것이다.

위와 같이 계산기로 6160을 10진수로 바꿔주면 24928이라는 것을 확인할 수 있다.

 

 

프로그램을 다시 실행한 후 위와 같이 Serial 값을 입력해주었더니 성공창이 뜨는 것을 확인할 수 있다.

 

+ Recent posts