파악
ReversingKr KeygenMe
Find the Name when the Serial is 5B134977135E7D13
문제 파일과 같이 들어있는 ReadMe 파일을 열면 위와 같이 시리얼 번호가 "5B134977135E7D13"일 때 Name의 값을 찾으라고 한다.
CMD에서 Keygen 파일을 실행한 후 Name과 Serial에 임의의 값을 입력하면 위와 같이 "Wrong"가 뜬다.
분석
위는 EP 부분이다.
x32dbg의 문자열 검색 기능을 이용하면 위와 같이 문자열들이 나온다.
그 중 "Input Name: " 부분을 더블 클릭해서 이동한다.
그러면 위의 부분이 나온다.
401000 주소에 F2로 BP를 설정하고, F9를 눌러 실행한다.
40101E 주소의 rep stosd 명령을 실행하기 직전까지 F8로 실행한다.
rep stos 명령은 https://sean.tistory.com/413에서 설명했듯이 ecx 레지스터에 담긴 값만큼 반복하여 eax에 담긴 값을 edi에 담긴 값에 해당하는 주소에 복사한다는 명령이다.
위의 40101E 주소의 명령은 rep stosd 이므로 ecx에 담긴 값 18h * 4 = 60h이고, 이 값은 10진수로 96이다.
40101E 주소의 rep stosd 명령을 실행하기 전의 esp+11(19FE09) 주소를 보면 위와 같이 되어 있는데
40101E 주소의 rep stosd 명령을 실행한 후에는 위와 같이 19FE09 주소부터 19FE68 주소까지 0으로 채워졌다.
이어서 401033 주소에서 두 번째 rep stosd 명령 부분이 나온다.
위는 401033 주소의 rep stosd 명령을 수행하기 전 esp+75(19FE6D) 주소 영역이다.
401033 주소의 rep stosd 명령이 수행되면, ecx에 담긴 값 31h * 4 = C4h이고, 이는 10진수로 196이므로 196byte가 0으로 채워졌다.
F8 키로 401059 주소의 함수 호출 명령까지 실행한다.
esp+10, esp+11, esp+12 주소에 각각 10, 20, 30을 넣고, 4011B9 주소의 함수를 호출한 다음 esp+10 주소에 있는 값을 스택에 넣고 40805C 주소에 있는 "%s"를 스택에 넣고 4011A2 주소의 함수를 호출한다.
40805C 주소에 있는 문자열 "%s"을 스택에 넣는 것으로 보아 4011A2 주소에 있는 함수는 사용자에게 입력을 받는 함수 인 것 같다.
401059 주소의 4011A2 주소의 함수 호출하는 명령까지 실행하면 위와 같이 Name을 입력하라고 뜬다.
임의로 Name값을 입력한다.
40106E 주소에 repne scasb 명령이 보인다.
이전의 rep stosb 명령과 비슷한 것 같지만 다른 명령이다.
전체적인 동작은 비슷한데, ecx에 담긴 값이 0보다 클 동안 AL 레지스터의 값과 EDI 레지스터의 값을 비교하여 일치하면 ZF 플래그를 1로 세팅한다.
repne(rep not equal)
- ecx에 담긴 값이 0보다 클 동안 반복한다.
scas(scan string) : al, ax, eax의 값을 edi에 담긴 값에 해당하는 주소에 있는 데이터와 비교하여 같으면 ZF 플래그를 1로 세팅한다.
scasb : AL(bytes)
scasw : AX(words)
scasd : EAX (double words)
이후 ecx에 있는 값을 not 연산한 값에 1을 감소한 다음 AND 연산하여 0이면, 40106 주소로 점프하고 AND 연산 값이 1이면 esi와 3을 비교한 후 3보다 작으면 40107E로 점프하고 3보다 작지 않으면 esi의 값을 0으로 만든다.
현재는 3보다 작기 때문에 40107E 주소로 점프한다.
40107E 주소에서 esp+esi+c 주소에 있는 값 10을 ecx 담고, 401083 주소에서 esp+ebp+10 주소에 있는 값 's'를 edx에 담는다.
10과 73을 xor 연산하면 63이라는 결과가 나오는데, 스택에 ecx의 값 10, esp+74 주소, 408054 주소의 "%s%02x" 문자열, esp+7C 주소를 차례대로 넣고, 401150 주소의 함수를 호출한다.
(40108A 주소와 401090 주소에서의 esp+74, esp+7C는 같은 주소를 가리킨다.)
4010AD 주소에서 repne scasb 명령을 수행하여 al의 값과 esp+10(19FE0D) 주소의 값을 FFFFFFFF번 반복하여 비교한다.
4010AD 주소의 repne scasb 명령을 수행하기 전에 4010A2 주소에서 ebp의 값을 1 증가시키는데, 이는 repne scasb 명령을 수행한 후 ecx와 비교하여 ecx의 값보다 ebp의 값이 작으면 401077 주소로 점프해 반복하라는 것이다.
ecx의 값은 not 연산 후 5로 바뀌며, dec 명령으로 4가 된다.
(ecx의 값이 사용자가 입력한 Name의 문자 개수이다.)
esi의 값은 repne scasb 명령을 수행하기 바로 직전에 1씩 증가된다.
이렇게 위의 401077 주소부터 4010B4 주소까지가 사용자가 입력한 Name 값을 가지고 암호화 하는 부분이고, ebp의 값이 ecx보다 작을 때까지 총 3번 반복을 도는데, 40107E 주소에서 esp+esi+C의 값은 1번 째 루프에서는 10, 2번 째 루프에서는 20, 3번째 루프에서는 30이 되며, 401083 주소에서 esp+ebp+10의 값은 사용자가 입력한 값이다.
즉, 10과 사용자가 입력한 문자열의 첫 번째 문자, 20과 사용자가 입력한 문자열의 두 번째 문자, 30과 사용자가 입력한 문자열의 세 번째 문자를 xor 연산을 해 특정 메모리 주소에 이어붙여 넣는 것이다.
3번의 반복이 끝나고 esi와 3을 비교하는데 3번 루프를 돌면서 esi의 값이 3으로 증가되었으므로 40107E 주소로 점프하지 않고 esi 레지스터의 값을 0으로 만든 다음
다시 10부터 하여 사용자가 입력한 문자열에서 3글자씩 끊어와 xor 연산하는 것이다.
이렇게 사용자가 입력한 문자열에서 3글자 씩 가져와 10, 20, 30과 xor 연산을 한 결과는 위와 같다.
결과
#include <stdio.h>
int main(void)
{
int arr[] = {0x5B, 0x13, 0x49, 0x77, 0x13, 0x5E, 0x7D, 0x13};
int key[] = {0x10, 0x20, 0x30};
for(int i = 0, j=0; i < (sizeof(arr) / sizeof(arr[0])); i++, j++)
{
if(j == 3) j = 0;
printf("%c", arr[i] ^ key[j]);
}
return 0;
}
K3yg3nm3
xor은 A xor B = C이고, B xor C = A, C xor A = B가 나오는 성질이 있기 때문에
위의 코드를 실행하면 "K3yg3nm3" 이라는 답이 나온다.
인증
'전쟁 > reversing.kr' 카테고리의 다른 글
[reversing.kr] Replace (0) | 2023.12.17 |
---|---|
[reversing.kr] Music Player (0) | 2023.06.23 |
[reversing.kr] Easy_UnpackMe (0) | 2023.06.22 |
[reversing.kr] Easy Crack (0) | 2023.06.21 |