Crack me #2 알고리즘 알아내기

- x32dbg로 abex' crack me 씨리얼 생성 알고리즘을 파악해보자.

 

먼저 abex' crack me #2를 디버거로 오픈한다.

 

저번장에서 우린이미 프로그램을 크랙했었다. 이제 시리얼 생성 알고리즘을 파악할 시간이다.

 

1. Serial 생성 알고리즘 찾기

프로그램의 check 버튼을 누르면 시리얼과 일치하는지를 검사하도록 되어있다.

전에 봤던 조건분기문은 분명히 [Check] 버튼의 이벤트로 발생하는 event handler? 일 것이다.

그렇다면 함수의 시작 부분부터 쭉~ 보다보면 다음과 같은 코드를 볼 수 있다.

 

* (ID는 ReverseCore로 입력했다)

호호

위의 push, mov는 전형적인 스택프레임을 구성할때 보이는 모습이고, 이부분이 함수의 시작임을 직관적으로(?) ㅇㅇ

따라서 이부분이 함수의 시작임을 알 수 있음.

그래서 여기에 캠프차리고 디버깅을 시작함.

[F8]막 눌러보면서 변화를 살펴보자!

 

몇번의 시행착오를 겪다보면 다음과 같은 코드를 만나게됨

AX값이 0이면 바로밑의 jmp문을 수행

에러문구를 보니 Name에 4글자가 안되면 AX가 0이 안되나보다! 아무튼 4글자 이상의 Name을 넣고 점프를 해보면!

다음과 같은 곳으로 뛰게된다.

짜잔!

mov, push는 스택프레임을 생성할 때 보이는 전형적인 패턴임을 알고간다.

루프문의 구조는 다음과 같다.

 

MOV EBX, 4								; 4개만 돌림
...
CALL DWORD PTR DS:[&~__vbaVarForInit]		
TEST EAX,EAX								; if(EAX==0) [loop start] 0되면 루프나감 ^^
JE abexcme2-.004032A5						
...
CALL dWORD PTR DS:[&~__vbaVarForNext]		
JMP abexcme2-00403197							; loop end
MOV EAX, DWORD PTR SS;[EBP+8]

여기가 원하는 알고리즘을 생성하는 부분이다.

그렇다면 이제 암호화 방법에 대해서 알아보자! 밑으로 내리다보면 다음의 부분이있다.

첫번째 PUSH(004031F6)에서 Name에서 가져온 유니코드값을 넣는다. ('R')

이후에 그 유니코드를 ASCII 변환을 한다 (004031F7)

 

0040323D까지 실행한후에 스택을 살펴보자.

ECX : 0018F3C4

EAX : 0018F384

EDX : 0018F40C

 

[CPU 범용 레지스터 까묵;;]

 

[보안] CPU 범용 레지스터

CPU 범용 레지스터 (EAX,EBX,ECX,EDX,EBP,ESI,EDI,ESP) - CPU 범용 레지스터란 범용적으로 사용되는(?) 레지스터 입니다. 모든 레지스터들은 각각 4byte(32bit)의 크기를 가진다고 하네요! 8개의 레지스터에서 상..

kyumoonhan.tistory.com

그럼 이제 각 메모리주소를 살펴본다.

ECX
EAX
EDX

다음을보면 ECX에서 18F3CC는 결과저장용 버퍼이다.

EAX의 18F38C에 암호화키 (64),

EDX에서 18F414는 Name에서 문자열의 첫 ASII키 값(내가입력한 'R' 52) 이다.

 

이 후에 밑의 함수를 실행시키면 ECX 레지스터가 가리키는 버퍼에 암호화된 값이 저장된다.

52 + 64 = B6 이겠죠?
ECX 결과값을 보니 정답!

계산결과 B6은 보다시피 원본값('R')에 64를 더해서 생성한 값임을 알 수 있었다!

이후에 아래의 부분을 이용해 'B6'값을 유니코드로 변경한다.

마지막 함수 호출시 변환

함수 호출직후 EAX가 가르키는 버퍼(0018F3C4)를 살펴보자

B6이 성공적으로 들어감!

이렇게 4번을 돌리겠죠? 끝으로 생성된 문자열을 붙여주는 코드가 뒤에 있다.

 

문자열 붙이기

- vbaVarCat() : 문자열 이어붙이기

함수 호출시 : old(ECX) + add(EDX) = NEW serial(EAX) ^오^

 

이런식으로 알고리즘이 짜여져있다.

그렇게 마지막 루프를 실행하게 되면

 

Serial = old("B6C9DA") + add("C9") = "B6C9DAC9"

이렇게 암호화 알고리즘을 풀었다.

(Reve의 아스키값에 64씩 더헀네)

 

정리

1. Name 문자열을 앞에서 한 문자씩 4회 읽는다.

2. Ascii로 변환한다.

3. 변환된거에 64를 더한다.

4. 다시 유니코드로 변환한다.

5. 변환된 문자를 연결시킨다.

 

 

 

 

 

'Reversing' 카테고리의 다른 글

PE File(2)  (0) 2019.04.03
PE File(1)  (0) 2019.04.02
리버싱 4  (0) 2019.03.29
리버싱 3 Stackframe  (0) 2019.03.28
리버싱 2  (0) 2019.03.27

+ Recent posts