저번 rev-basic-6 문제에 이어서 rev-basic-8 문제를 풀어보기로 했다.
PE파일 포맷이어서 윈도우에서 실행해보았더니, Input을 입력하라고 뜨고 아무거나 입력하면 Wrong이라는 출력이 나온다.
Ghidra에 올려보았을 때, 아래의 Wrong이나 Correct 문자열이 있는 부분을 호출하는 부분을 찾아갔고 FUN_140001120라는 함수를 볼 수 있었다.
아래 코드에서 중요한 부분은 FUN_140001000 함수라고 생각했다. 일단 FUN_140001210("%256s",local_118
에서 local_118이 input이라는 예상을 했고, 그리고 FUN_140001000의 리턴값(uVar1)에 따라 Wrong 혹은 Correct가 출력되니 FUN_140001000 함수를 일단 보기로 했다.
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;
local_18 = DAT_140003028 ^ (ulonglong)auStack312;
puVar3 = local_118;
for (lVar2 = 0x100; lVar2 != 0; lVar2 = lVar2 + -1) {
*puVar3 = 0;
puVar3 = puVar3 + 1;
}
FUN_1400011b0("Input : ",param_2,param_3,param_4);
FUN_140001210("%256s",local_118,param_3,param_4);
uVar1 = FUN_140001000((longlong)local_118);
if ((int)uVar1 == 0) {
puts("Wrong");
}
else {
puts("Correct");
}
FUN_140001300(local_18 ^ (ulonglong)auStack312);
return;
}
처음에 FUN_140001000 함수에 들어가면, 아래와 같은 내용이 보인다.
char *param
으로 바꿔줬다.undefined8 FUN_140001000(longlong param_1)
{
uint local_18;
local_18 = 0;
while( true ) {
if (0x14 < local_18) {
return 1;
}
if ((char)(*(char *)(param_1 + (int)local_18) * -5) != (&DAT_140003000)[(int)local_18]) break;
local_18 = local_18 + 1;
}
return 0;
}
그랬더니 아래와 같이 코드가 조금 더 간결해졌다.
undefined8 FUN_140001000(char *input)
{
uint i;
i = 0;
while( true ) {
if (20 < i) {
return 1;
}
if ((char)(input[(int)i] * -5) != (&DAT_140003000)[(int)i]) break;
i = i + 1;
}
return 0;
}
처음에는 아래와 같이 작성했었다. 그런데 결과가 나오지 않았고, 그건 당연했다. 왜냐하면 양수 * 음수 === 양수가 될 수는 없기 때문이다.
const DAT_140003000 = [0xac, 0xf3, 0x0c, 0x25, 0xa3, 0x10, 0xb7, 0x25, 0x16, 0xc6, 0xb7, 0xbc, 0x07, 0x25, 0x02, 0xd5, 0xc6, 0x11, 0x07, 0xc5];
const result = [];
for (let i = 0; i < 20; i++) {
for (let j = 0; j < 127; j++) {
if (j * -5 == DAT_140003000[i]) {
result[i] = j;
break;
}
}
}
console.log(result.map((value) => String.fromCharCode(value)).join(''));
그래서 놓치고 있는 개념이 있을 것이라고 생각해서 질문하게 되었고 알게 된 개념은 아래와 같다.
C : char는 8비트
JavaScript : number 64비트
그래서 8비트가 넘어가면 잘리기 때문에 자바스크립트에서는 &0xff를 사용해서 잘라줘야 하는 것이었다.(💥 그런데 왜 C의 char과 JS의 Number를 비교하는 걸까? 이부분은 잘 모르겠다.)
--------> 이부분 뭔가 잘못 알고 있는 것 같다. 25년 4월 이내로 공부해서 내용 수정 예정
주의 : 연산자 우선순위때문에 if (((c * -5) & 0xff)
를 if ((c * -5 & 0xff)
라고 하면 답이 안나온다.
const DAT_140003000 = [0xac, 0xf3, 0x0c, 0x25, 0xa3, 0x10, 0xb7, 0x25, 0x16, 0xc6, 0xb7, 0xbc, 0x07, 0x25, 0x02, 0xd5, 0xc6, 0x11, 0x07, 0xc5, 0x00];
let result = '';
for (let idx = 0; idx < 21; ++idx) {
for (let c = 0; c < 127; ++c) {
if (((c * -5) & 0xff) === DAT_140003000[idx]) {
result += String.fromCharCode(c);
console.log(result);
break;
}
}
}
C언어 코드는 익숙하지 않아서 혼자 다시 한번 작성해봤다.
#include <stdbool.h>
#include <stdio.h>
char DAT_140003000[] = {
0xac, 0xf3, 0x0c, 0x25, 0xa3, 0x10, 0xb7, 0x25,
0x16, 0xc6, 0xb7, 0xbc, 0x07, 0x25, 0x02, 0xd5,
0xc6, 0x11, 0x07, 0xc5, 0x00,
};
int main() {
char input[21] = {};
for (int idx = 0; idx < 21; ++idx) {
for (int c = 0; c < 127; ++c) {
if ((char)(c * -5) == DAT_140003000[idx]) {
input[idx] = c;
printf("%s\n", input);
break;
}
}
}
}
왜 C의 char과 JS의 Number를 비교하는 건지 이부분을 찾아봐야 할 것 같다!