예전에 rev-basic-2까지 풀었길래 이번 포스팅에서는 이어서 3을 풀어보려고 한다.
아무거나 입력해봤을 때, Wrong이라는 문구가 나오는 걸 확인할 수 있었다.
Search > For Strings에서 Wrong을 찾아갔다.
어셈블리와 디컴파일된 전체 코드를 확인할 수 있었다.
처음 열었을 때 나름 분석해서 주석으로 남겨보았지만 일단 어셈블리는 거의 이해할 수 없었다.
디컴파일된 전체 코드는 아래와 같다.
주석을 읽어보면 짐작한 내용이 엉망일 것 같은데🤣 일단 남겨본다..
void FUN_140001120(undefined8 param_1,undefined8 param_2,undefined8 param_3,undefined8 param_4)
{
undefined8 uVar1;
longlong lVar2;
undefined *puVar3;
undefined auStack312 [32];
undefined local_118 [256];
ulonglong local_18;
/* 무슨 뜻인지 모르겠음. 5바이트랑 256바이트랑 XOR연산을
한다? 왜인지 결과는 0일 것 같음 */
local_18 = DAT_140003028 ^ (ulonglong)auStack312;
/* 왜냐면 보통 변수를 0으로 초기화하는 것 같아서... */
puVar3 = local_118;
/* 256만큼 puVar3을 증가시키므로 puVar3는 256 아닐까? */
for (lVar2 = 256; lVar2 != 0; lVar2 = lVar2 + -1) {
*puVar3 = 0;
puVar3 = puVar3 + 1;
}
/* 아마 scanf 함수. 3개의 인자를 받는다. */
FUN_1400011b0("Input : ",param_2,param_3,param_4);
/* 분석 안해도 될 것 같음 */
FUN_140001210("%256s",local_118,param_3,param_4);
/* 분석해야 할 함수. 지역변수 local_118을 인자로 넣어서
결과가 0이 아닌 값이 리턴되어야 한다.
결국 local_118을 구해야 하는 것 같다. */
uVar1 = FUN_140001000((longlong)local_118);
if ((int)uVar1 == 0) {
puts("Wrong");
}
else {
puts("Correct");
}
FUN_140001300(local_18 ^ (ulonglong)auStack312);
return;
}
위의 전체 코드에서 아래의 부분을 발췌해서 보면 uVar1이라는 변수가 0이 아니어야 Correct를 출력하는 것을 알 수 있었다.
즉 local_118이라는 인자를 FUN_140001000 함수에 넣었을 때, 0이 아닌 값이 리턴되어야 한다. FUN_140001000에 들어가보았다.
uVar1 = FUN_140001000((longlong)local_118);
if ((int)uVar1 == 0) {
puts("Wrong");
}
else {
puts("Correct");
}
undefined8 FUN_140001000(longlong param_1_local_118)
{
uint local_18;
local_18 = 0;
while( true ) {
if (23 < local_18) {
return 1;
}
/* break되면 0이 리턴되므로 이 if문이 false가 되어야 함. -> 즉, 전향==후항. param_1을 param_1_local_118로 변수명 변경해주었다. */
if ((uint)(byte)(&DAT_140003000)[(int)local_18] !=
(*(byte *)(param_1_local_118 + (int)local_18) ^ local_18) + local_18 * 2) break;
local_18 = local_18 + 1;
}
return 0;
}
while문이 break되면 0이 반환되므로, 아래 식의 전항과 후항이 동일해야 한다(그래야 식이 false가 되어 break되지 않음)
((uint)(byte)(&DAT_140003000)[(int)local_18] !=
(*(byte *)(param_1_local_118 + (int)local_18) ^ local_18) + local_18 * 2
일단 local_18는 0부터 1식 증가하므로 인덱스를 의미하는 것 같다는 생각을 했다.
그러면 (&DAT_140003000)[(int)local_18]
는 문자열을 한글자씩 가져온다는 것 같다. DAT_140003000 부분을 더블클릭하여 들어가보았다.
16진수로 24개~의 글자가 있는 걸 확인했다. 아마 위의 식을 거치면 이 문자들이 변환되어 합쳐진 문자열이 답이 될 것이다.
a ^ b = c는 a ^ c = b와 같음
// 16진수이며, 어셈블리 코드에서 긁어왔다.
const array = [
'49',
'60',
'67',
'74',
'63',
'67',
'42',
'66',
'80',
'78',
'69',
'69',
'7B',
'99',
'6D',
'88',
'68',
'94',
'9F',
'8D',
'4D',
'A5',
'9D',
'45',
];
// 최종적으로 구할 문자열을 담을 result 배열.
// character라는 변수 선언
let result = [];
let character;
// 16진수를 10진수로 변환
for (let i = 0; i < array.length; i++) {
array_i = parseInt(array[i], 16);
// XOR의 특징을 이용한 역연산.
// 💥 왜 (array_i - i * 2) ^ i - i이 아닌지 모르겠다. 디컴파일된 코드를 보면 (byte *)(character + (int)local_18)이니까 local_18을 빼줘야 하는데.. character 인덴트를 말하는 것 같은데 왜인지 잘 모르겠다. 메모리와 포인터 개념을 공부해야 할 듯 싶다.
character = (array_i - i * 2) ^ i
result.push(String.fromCharCode(character));
}
// I_am_X0_xo_Xor_eXcit1ng
console.log(result.join(''));
I_am_X0_xo_Xor_eXcit1ng
를 입력하여 Correct를 출력하는 데 성공했다!