Description

    드림이는 비밀스런 이미지 파일을 자신이 공부한 알고리즘을 통해 인코딩 하였어요.
    인코딩 프로그램을 분석하여 원본 이미지를 알아내주세요.
    원본 파일을 구한 경우 imageviewer.py를 통해 이미지를 볼 수 있습니다.

    Files

    secret_message
    ├── imageviewer.py (이미지 뷰어)
    ├── prob (이미지 암호화 프로그램)
    └── secretMessage.enc (암호화된 FLAG 이미지 파일)

    prob: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=afc20364a7c42c723bd1715bf513330d7ad5db86, stripped

    Decompiled Code

    __int64 __fastcall main(int a1, char **a2, char **a3)
    {
      FILE *secretMessage_raw_stream; // [rsp+0h] [rbp-10h]
      FILE *secretMessage_enc_stream; // [rsp+8h] [rbp-8h]
    
      secretMessage_raw_stream = fopen("secretMessage.raw", "rb");
      secretMessage_enc_stream = fopen("secretMessage.enc", "wb");
      sub_5578276007FA(secretMessage_raw_stream, secretMessage_enc_stream);
      remove("secretMessage.raw");
      puts("done!");
      fclose(secretMessage_enc_stream);
      fclose(secretMessage_raw_stream);
      return 0LL;
    }
    __int64 __fastcall sub_5578276007FA(FILE *secretMessage_raw_stream, FILE *secretMessage_enc_stream)
    {
      unsigned __int8 v3; // [rsp+17h] [rbp-9h]
      int c; // [rsp+18h] [rbp-8h]
      int v5; // [rsp+1Ch] [rbp-4h]
    
      if ( secretMessage_raw_stream && secretMessage_enc_stream )
      {
        v5 = -1;
        v3 = 0;
        while ( 1 )
        {
          c = fgetc(secretMessage_raw_stream);
          if ( c == -1 )
            return 0LL;
          fputc(c, secretMessage_enc_stream);
          if ( c == v5 )
          {
            v3 = 0;
            while ( 1 )
            {
              c = fgetc(secretMessage_raw_stream);
              if ( c == -1 )
                break;
              if ( c != v5 )
              {
                fputc(v3, secretMessage_enc_stream);
                fputc(c, secretMessage_enc_stream);
                v5 = c;
                break;
              }
              if ( ++v3 == 255 )
              {
                fputc(255, secretMessage_enc_stream);
                v5 = -1;
                break;
              }
            }
          }
          else
          {
            v5 = c;
          }
          if ( c == -1 )
          {
            fputc(v3, secretMessage_enc_stream);
            return 0LL;
          }
        }
      }
      else
      {
        *__errno_location() = 2;
        return 0xFFFFFFFFLL;
      }
    }

    바이트를 하나씩 읽어서 복붙하는데,
    이전에 읽었던 하나의 바이트와 서로 같을 경우에, 중복되는 바이트를 지우고, 중복되는 카운트 수를 fputc로 넣는다.

    왼쪽에 원본 파일, 오른쪽에 암호화된 파일을 예로 보여드리면,

    앞바이트와 뒷바이트가 서로 00 00으로 같지만,
    뒤에 더이상 중복되는 바이트가 없으므로 00 바이트를 새로 넣는다.

    앞바이트와 뒷바이트가 서로 20 20으로 같지만,
    뒤에 4번이나 더 중복되는 바이트가 있으므로, 중복되는 20 20 20 20 바이트를 지우고 04 바이트를 새로 넣는다.

    마찬가지로 서로 20 20으로 같지만,
    뒤에 1번 더 중복되는 바이트가 있으므로, 중복되는 20 바이트를 지우고 01 바이트를 새로 넣는다.


    #include <stdio.h>
    
    int decrypt(FILE *enc, FILE *dec) {
        int ch = 0, prev = -1;
        while(1)
        {
            if((ch = fgetc(enc)) == EOF)
            {
                break;
            }
    
            if(prev == ch) {
                int cnt = fgetc(enc);
                if(cnt > 0) {
                    for (int i = 0; i < cnt; i++) {
                        fputc(ch, dec);
                    }
                }
            }
    
            prev = ch;
            fputc(ch, dec);
        }
    
        return 0;
    }
    
    int main(void) {
    
        FILE *secretMessage_enc_stream = fopen("secretMessage.enc", "rb");
        FILE *secretMessage_dec_stream = fopen("secretMessage.raw", "wb");
    
        decrypt(secretMessage_enc_stream, secretMessage_dec_stream);
    
        fclose(secretMessage_enc_stream);
        fclose(secretMessage_dec_stream);
    
        return 0;
    }

    서로 다른 Hex를 비교하는데 WinMerge라는 쓸만한 프로그램을 발견할 수 있어서 좋았다.

    답글 남기기

    이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다