주요점 Crash): data.txt가 없으면 fopen 결과를 체크하지 않고 fgets를 호출하여 즉시 Segmentation fault 발생

이후 아래와 같은 과정ㅇ르 거치면 해당 문제를 풀어낼 수 있다.

  1. ELF에서 시드 추출
  2. 해시 구현
  3. 프리이미지 브루트포스

Main

int main(int argc, char **argv, char **envp) {
  sub_19ED();                          // setvbuf(입출력 무버퍼)
  qword_4050 = sub_14B2(NULL);         // 루트 노드 생성 (자식=0, value=0)

  FILE *stream = fopen("./data.txt","r");
  sub_176A(stream);                    // <-- stream NULL 체크 없음 (crash 가능)
  fclose(stream);

  puts("[Custom Storage v0.1]");
  for (;;) {
    printf("> ");
    char s[256];
    scanf("%255s", s);
    if (!strcmp(s, "END")) break;

    const char *v = (const char *)sub_1612(s);   // 조회: 해시 경로 탐색
    if (v) printf("Found: %s\\n", v);
    else   puts("Not Found...");
    puts("Please wait...");
    sleep(3);
  }

  FILE *out = fopen("./dump.txt","w");
  sub_16B8(out, qword_4050, 0, 0);     // 트라이 전체 덤프
  fclose(out);
  return 0;
}

노드 생성부분 sub_14B2 함수

char *sub_14B2(const char *val) {
  char *node = (char *)malloc(0xC0);     // 192 bytes
  for (int i=0;i<16;i++) *(uint64_t*)&node[8*i] = 0;   // child[16]=NULL
  if (val) strncpy(node + 128, val, 0x3F);            // value[0..63]
  else     memset(node + 128, 0, 0x40);
  return node;
}

적재부분 sub_153D 함수 (키→해시→경로 생성)

uint64_t sub_153D(char *key, const char *val) {
  uint16_t seed = word_4010;
  size_t n = strlen(key);
  uint16_t h = sub_138A((int16_t*)key, n, seed);

  uint64_t cur = qword_4050;
  for (int i=0; i<=3; ++i) {
    int idx = h & 0xF;                       // LSB nibble
    if (!*(uint64_t*)(cur + 8*idx)) {        // 미존재시
      char *child = (i==3) ? sub_14B2(val)   // leaf: value 채움
                           : sub_14B2(NULL); // 중간: value 비움
      *(uint64_t*)(cur + 8*idx) = (uint64_t)child;
    }
    cur = *(uint64_t*)(cur + 8*idx);
    h >>= 4;
  }
  return cur; // leaf node
}