안녕하세요. 해킹하는 개발자가 되고 싶은 컴공 대학생입니다.
정보 보안 분야에 관심이 많아 드림핵으로 리버스 엔지니어링 학습 중입니다.
드림핵 사이트의 워게임 rev-basic-4 문제 풀이 진행하겠습니다.
https://dreamhack.io/wargame/challenges/18/
문제 유형을 파악하기 위해 Windows의 PowerShell을 이용하여 프로그램을 실행시켜줍니다. 아래와 같이 임의의 문자열을 입력하면 'Wrong'이 출력됩니다.
이를 통해 오답 시 'Wrong', 정답 시 'Correct'가 출력됨을 예측할 수 있습니다.
main 함수를 디컴파일합니다. (단축키 F5)
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[256]; // [rsp+20h] [rbp-118h] BYREF
memset(v4, 0, sizeof(v4));
sub_1400011C0("Input : ", argv, envp);
sub_140001220("%256s", v4);
if ( (unsigned int)sub_140001000((__int64)v4) )
puts("Correct");
else
puts("Wrong");
return 0;
}
sub_140001000 함수를 더블클릭하여 함수의 내용을 확인합니다.
__int64 __fastcall sub_140001000(__int64 a1)
{
int i; // [rsp+0h] [rbp-18h]
for ( i = 0; (unsigned __int64)i < 0x1C; ++i )
{
if ( ((unsigned __int8)(16 * *(_BYTE *)(a1 + i)) | ((int)*(unsigned __int8 *)(a1 + i) >> 4)) != byte_140003000[i] )
return 0i64;
}
return 1i64;
}
(16 * a1[i]) | (a1[i] >> 4) == byte_140003000[i]
를 만족하는 a1을 찾아야 합니다.
(a1[i] << 4) | (a1[i] >> 4) == byte_140003000[i]
16을 곱하는 것은 4비트 왼쪽 시프트하는 것과 같으므로 위와 같이 변경합니다.
a1[0]을 예시로 위 연산을 진행해보겠습니다.
a1[0] = 0010 0100 (0x24)
a1[0] << 4 = 0100 0000 (0x4)
a1[0] >> 4 = 0000 0010 (0x2)
(a1[i] << 4) | (a1[i] >> 4) → 0100 0010 (0x42)
즉, a1[0]의 앞뒤 위치가 바뀝니다.
그렇다면 byte_140003000[i]의 앞뒤 위치를 바꾼 수가 a1[i]가 됩니다.
byte_140003000는 IDA에서 더블클릭하여 정보를 확인할 수 있습니다.
이를 바탕으로 코드를 작성합니다.
tmp = [0x24, 0x27, 0x13, 0xC6, 0xC6, 0x13, 0x16, 0xE6, 0x47, 0xF5, 0x26, 0x96, 0x47, 0xF5, 0x46, 0x27, 0x13, 0x26, 0x26, 0xC6, 0x56, 0xF5, 0xC3, 0xC3, 0xF5, 0xE3, 0xE3]
for i in range(len(tmp)) :
print(chr((tmp[i]<<4 | tmp[i]>>4) % (16 * 16)), end='')
%(16 * 16)으로 함수 sub_140001000의 (_BYTE *)를 적용했습니다.
이는 16진수의 바이트만 사용하는 것으로 & 0xFF를 적용해주어도 무관합니다.
이 코드로 출력되는 문자열이 정답이 됩니다.
Br1ll1antbit_dr1bble<<_>>