[드림핵] rev-basic-8 풀이

비얌·2025년 2월 27일
0

리버싱

목록 보기
25/25

개요

저번 rev-basic-6 문제에 이어서 rev-basic-8 문제를 풀어보기로 했다.

파일 실행해보기

PE파일 포맷이어서 윈도우에서 실행해보았더니, Input을 입력하라고 뜨고 아무거나 입력하면 Wrong이라는 출력이 나온다.

정적 분석하기 - FUN_140001000

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 함수 분석하기

처음에 FUN_140001000 함수에 들어가면, 아래와 같은 내용이 보인다.

  • param_1이 input이므로 longlong param_1을 char *param으로 바꿔줬다.
  • local_18을 i로 바꿔줬다.
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;
}

코드

JS 코드

처음에 작성한 JS 코드

처음에는 아래와 같이 작성했었다. 그런데 결과가 나오지 않았고, 그건 당연했다. 왜냐하면 양수 * 음수 === 양수가 될 수는 없기 때문이다.

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월 이내로 공부해서 내용 수정 예정

수정 JS 코드

주의 : 연산자 우선순위때문에 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언어 코드

C언어 코드는 익숙하지 않아서 혼자 다시 한번 작성해봤다.

  • 💥(char) 타입캐스팅이 필요한 이유 : 안하면 좌항은 int형이되고 우항은 char임. 그래서 문제가 발생할 수 있음
#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를 비교하는 건지 이부분을 찾아봐야 할 것 같다!

profile
🐹강화하고 싶은 기억을 기록하고 공유하자🐹

0개의 댓글

관련 채용 정보