리버싱 3차시

이동규·2026년 6월 8일

Layer7과제

목록 보기
9/22

드림핵 문제풀이 정리

recover

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  char ptr; // [rsp+Bh] [rbp-25h] BYREF
  int v5; // [rsp+Ch] [rbp-24h]
  _BYTE *v6; // [rsp+10h] [rbp-20h]
  FILE *stream; // [rsp+18h] [rbp-18h]
  FILE *s; // [rsp+20h] [rbp-10h]
  unsigned __int64 v9; // [rsp+28h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  v6 = &unk_2004;
  stream = fopen("flag.png", "rb");
  if ( !stream )
  {
    puts("fopen() error");
    exit(1);
  }
  s = fopen("encrypted", "wb");
  if ( !s )
  {
    puts("fopen() error");
    fclose(stream);
    exit(1);
  }
  v5 = 0;
  while ( fread(&ptr, 1u, 1u, stream) == 1 )
  {
    ptr ^= v6[v5 % 4];
    ptr += 19;
    fwrite(&ptr, 1u, 1u, s);
    ++v5;
  }
  fclose(stream);
  fclose(s);
  return 0;
}

분석

stream과 s가 비어있는지 확인한다
enc에서 1바이트씩 읽어서 ptr에 저장후 읽을게 있으면 계속 반복
ptr을 xor v6에 0,1,2,3번째 있는 값들로 돌림xor을 해주고 19를 더한다

int main() {
  unsigned char table[4] = {0xDE, 0xAD, 0xBE, 0xEF};
  unsigned char ptr;

  FILE *enc = fopen("encrypted", "rb");
  FILE *flag = fopen("flag.png", "wb");
  if(!enc || !flag) return 1;
  int v5 = 0;
  while ( fread(&ptr, 1u, 1u, enc) == 1 )
  {
    ptr -= 19;
    ptr ^= table[v5 % 4];
    fwrite(&ptr, 1u, 1u, flag);
    ++v5;
  }
  fclose(flag);
  fclose(enc);
  return 0;
}

풀이

역으로 해서 파일들이 있는 디렉토리에서 컴파일 해준다

후후후 flag.png를 explorer.exe로 열어서 확인한다면?

Happy New Year!

int __fastcall main(int argc, const char **argv, const char **envp)
{
  int i; // [rsp+4h] [rbp-12Ch]
  _QWORD v5[5]; // [rsp+10h] [rbp-120h]
  _BYTE v6[11]; // [rsp+38h] [rbp-F8h]
  __int64 v7; // [rsp+43h] [rbp-EDh]
  char s[8]; // [rsp+50h] [rbp-E0h] BYREF
  __int64 v9; // [rsp+58h] [rbp-D8h]
  __int64 v10; // [rsp+60h] [rbp-D0h]
  __int64 v11; // [rsp+68h] [rbp-C8h]
  __int64 v12; // [rsp+70h] [rbp-C0h]
  __int64 v13; // [rsp+78h] [rbp-B8h]
  __int64 v14; // [rsp+80h] [rbp-B0h]
  __int64 v15; // [rsp+88h] [rbp-A8h]
  __int64 v16; // [rsp+90h] [rbp-A0h]
  __int64 v17; // [rsp+98h] [rbp-98h]
  __int64 v18; // [rsp+A0h] [rbp-90h]
  __int64 v19; // [rsp+A8h] [rbp-88h]
  int v20; // [rsp+B0h] [rbp-80h]
  char dest[8]; // [rsp+C0h] [rbp-70h] BYREF
  __int64 v22; // [rsp+C8h] [rbp-68h]
  __int64 v23; // [rsp+D0h] [rbp-60h]
  __int64 v24; // [rsp+D8h] [rbp-58h]
  __int64 v25; // [rsp+E0h] [rbp-50h]
  __int64 v26; // [rsp+E8h] [rbp-48h]
  __int64 v27; // [rsp+F0h] [rbp-40h]
  __int64 v28; // [rsp+F8h] [rbp-38h]
  __int64 v29; // [rsp+100h] [rbp-30h]
  __int64 v30; // [rsp+108h] [rbp-28h]
  __int64 v31; // [rsp+110h] [rbp-20h]
  __int64 v32; // [rsp+118h] [rbp-18h]
  int v33; // [rsp+120h] [rbp-10h]
  unsigned __int64 v34; // [rsp+128h] [rbp-8h]

  v34 = __readfsqword(0x28u);
  v5[0] = 0xC313A0A11150D18LL;
  v5[1] = 0x2C37426D44472F19LL;
  v5[2] = 0x1B1A3A1704000F00LL;
  v5[3] = 0x1301263B1904312ALL;
  v5[4] = 0x361F06041A0A3E17LL;
  *(_DWORD *)v6 = 738656770;
  *(_QWORD *)&v6[3] = 0x2C1018043E1C3E2CLL;
  v7 = 0x1F0004160A151F2BLL;
  *(_QWORD *)s = 0;
  v9 = 0;
  v10 = 0;
  v11 = 0;
  v12 = 0;
  v13 = 0;
  v14 = 0;
  v15 = 0;
  v16 = 0;
  v17 = 0;
  v18 = 0;
  v19 = 0;
  v20 = 0;
  *(_QWORD *)dest = 0;
  v22 = 0;
  v23 = 0;
  v24 = 0;
  v25 = 0;
  v26 = 0;
  v27 = 0;
  v28 = 0;
  v29 = 0;
  v30 = 0;
  v31 = 0;
  v32 = 0;
  v33 = 0;
  printf("Input : ");
  __isoc99_scanf("%59s", s);
  if ( strlen(s) == 59 )
  {
    strcpy(dest, s);
    for ( i = 0; i <= 58; ++i )
      dest[i] ^= *((_BYTE *)v5 + i);
    if ( !strcmp(dest, "Please_input_the_correct_new_year_greetings_at_this_problem") )
      printf("Correct! Flag is DH{%s}\n", s);
    else
      puts("Wrong!");
  }
  else
  {
    puts("Wrong!");
  }
  return 0;
}

분석

59글자 플래그를 입력받으면 Correct와 플래그출력

 v5[0] = 0xC313A0A11150D18LL;
  v5[1] = 0x2C37426D44472F19LL;
  v5[2] = 0x1B1A3A1704000F00LL;
  v5[3] = 0x1301263B1904312ALL;
  v5[4] = 0x361F06041A0A3E17LL;
  *(_DWORD *)v6 = 738656770;
  *(_QWORD *)&v6[3] = 0x2C1018043E1C3E2CLL;
  v7 = 0x1F0004160A151F2BLL;
  *(_QWORD *)s = 0;
  v9 = 0;
  v10 = 0;
  v11 = 0;
  v12 = 0;
  v13 = 0;
  v14 = 0;
  v15 = 0;
  v16 = 0;
  v17 = 0;
  v18 = 0;
  v19 = 0;
  v20 = 0;
  *(_QWORD *)dest = 0;

v5주소부터 리틀엔디안으로 저장된 값들과 xor을 해서 나오는 값을 저 길다란 문자열과 한글자씩 비교한다

풀이

import struct
>>> key = b""
>>> key += struct.pack('<Q', 0xC313A0A11150D18)
>>> key += struct.pack('<Q', 0x2C37426D44472F19)
>>> key += struct.pack('<Q', 0x1B1A3A1704000F00)
>>> key += struct.pack('<Q', 0x1301263B1904312A)
>>> key += struct.pack('<Q', 0x361F06041A0A3E17)
>>> key += b"\x02\x02\x07" 
>>> key += struct.pack('<Q', 0x2C1018043E1C3E2C)
>>> key += struct.pack('<Q', 0x1F0004160A151F2B)
>>> target="Please_input_the_correct_new_year_greetings_at_this_problem"
>>> flag =""
>>> for i in range(59):
...     flag+=chr((ord(target[i]) ^ key[i]) & 0xFF)
...
>>> print(flag)

python에 있는 모듈로 리틀엔디안 저장 방식을 배열로 만든뒤 하나하나 나와있는 문자열과 xor을 해주면 flag가 나온다

simple-opertion

  v7 = 0;
  v6 = 0;
  v11 = 0;
  initialize();
  buf = malloc(69u);
  fd = open("./flag", 0);
  read(fd, buf, 0x45u);
  close(fd);
  /// buf에 플래그
  get_rand_num(&v6);
  printf("Random number: %#x\n", v6);
  printf("Input? ");
  __isoc99_scanf("%d", &v7);
  /// v7 d입력받기
  v11 = v6 ^ v7;
  snprintf(s, 9u, "%08x", v6 ^ v7);
  for ( i = 0; i <= 7; ++i )
    s1[i] = s[7 - i];
  printf("Result: %s\n", s1);
  s2 = "a0b4c1d7";
  if ( !strcmp(s1, "a0b4c1d7") )
  {
    puts("Congrats!");
    puts((const char *)buf);
  }
  else
  {
    puts("Try again");
  }
  return 0;
}
	

분석

입력 ^ rand => 거꾸로 = a0b4c1d7

풀이

거꾸로하고 xor해준값을 입력한다

my favorite fruit

분석

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int v4; // [rsp+8h] [rbp-18h]
  char s1[8]; // [rsp+Fh] [rbp-11h] BYREF
  char v6; // [rsp+17h] [rbp-9h]
  unsigned __int64 v7; // [rsp+18h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  *(_QWORD *)s1 = 0;
  v6 = 0;
  v4 = 0;
  do
  {
    printf("What is your favorite fruit?\n> ");
    __isoc99_scanf("%10sbanana", s1);
    if ( !strcmp(s1, "banana") )
    {
      puts("I also like banana.");
      if ( (v4 & 1) == 0 )
      {
        v4 |= 1u;
        sub_11E9("banana");
      }
    }
    else if ( !strcmp(s1, "strawberry") )
    {
      puts("Strawberries! Great choice.");
      if ( (v4 & 2) == 0 )
      {
        v4 |= 2u;
        sub_11E9("strawberry");
      }
    }
    else if ( !strcmp(s1, "erwin") )
    {
      puts("I never heard of it, but it looks delicious.");
      if ( (v4 & 4) == 0 )
      {
        v4 |= 4u;
        sub_11E9("erwin");
      }
    }
    else if ( !strcmp(s1, "mandarin") )
    {
      puts("It's so sour...");
      if ( (v4 & 8) == 0 )
      {
        v4 |= 8u;
        sub_11E9("mandarin");
      }
    }
    else if ( !strcmp(s1, "melon") )
    {
      puts("I wanna eat it with jamon.");
      if ( (v4 & 0x10) == 0 )
      {
        v4 |= 0x10u;
        sub_11E9("melon");
      }
    }
    else
    {
      puts("Ew, I don't like it.");
    }
  }
  while ( v4 != 31 );
  printf("Here is the flag: %s\n", a0);
  return 0;
}

입력을 받고 과일에 따라 다른 대답을 해주나 보다
하지만 딸기는 길이가 10이라 입력이 9까지밖에 안되서 못 읽는다

풀이


패치를 10까지 받을 수 있도록 online binary hex 에디터를 이용해 맛있게 해준다

뭔가 마음에 들지 않지만 작동만 잘 해준다면야

야호

patch

풀이

실행해보자

오이런

저걸 띄우는 것들인 것 같다
sub_1400032F0을 보자

중간에 있는 sub_140002C40이 무언가 수상하다

오옹

jackpot
함수의 return을 0으로 해서 함수의 팔다리를 절단해보자

hex에서 본 첫번째 위치이다
xor eax,eax로 eax를 0으로 만들고
ret를 하는 것은 31 C0 C3 90 90 (90은 nop : no operation 계산안해서 밀리거나 그런거 없게 해준다)
으로 패치해준다음 실행한다면

(가리긴 했는데 안그려져서 플래그가 나온다)


0개의 댓글