picoCTF Investigative Reversing 1 Writeup Using Ghidra

Ghidraのデコンパイル誤りを訂正する訓練になるので記録に残しておく。

問題の入手先

https://picoctf.org/

問題としては，ELFバイナリ「mystery」と PNG画像「mystery.png」「mystery2.png」「mystery3.png」が渡される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/a65bc411-d365-8094-d40a-de3708bab68f.png)
PNGを確認すると，フッターの後にフラグらしきものが見える。

Ghidraでデコンパイルしてみる

```c:mystery
void main(void)
{
  FILE *__stream;
  FILE *__stream_00;
  FILE *__stream_01;
  FILE *__stream_02;
  long in_FS_OFFSET;
  char local_6b;
  int local_68;
  int local_64;
  int local_60;
  char local_38 [4];
  char local_34;
  char local_33;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  __stream = fopen("flag.txt","r");
  __stream_00 = fopen("mystery.png","a");
  __stream_01 = fopen("mystery2.png","a");
  __stream_02 = fopen("mystery3.png","a");
  if (__stream == (FILE *)0x0) {
    puts("No flag found, please make sure this is run on the server");
  }
  if (__stream_00 == (FILE *)0x0) {
    puts("mystery.png is missing, please run this on the server");
  }
  fread(local_38,0x1a,1,__stream);
  fputc((int)local_38[1],__stream_02);
  fputc((int)(char)(local_38[0] + '\x15'),__stream_01);
  fputc((int)local_38[2],__stream_02);
  local_6b = local_38[3];
  fputc((int)local_33,__stream_02);
  fputc((int)local_34,__stream_00);
  local_68 = 6;
  while (local_68 < 10) {
    local_6b = local_6b + '\x01';
    fputc((int)local_38[local_68],__stream_00);
    local_68 = local_68 + 1;
  }
  fputc((int)local_6b,__stream_01);
  local_64 = 10;
  while (local_64 < 0xf) {
    fputc((int)local_38[local_64],__stream_02);
    local_64 = local_64 + 1;
  }
  local_60 = 0xf;
  while (local_60 < 0x1a) {
    fputc((int)local_38[local_60],__stream_00);
    local_60 = local_60 + 1;
  }
  fclose(__stream_00);
  fclose(__stream);
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}
```
真っ先に気になる点

```c
  char local_38 [4];
  fread(local_38,0x1a,1,__stream);
```
0x1a を読み込むのに char[4]はないよね

local_38 の型を char[26] に

変数名については
local_38　を　flag　に
\_\_stream_00　を　\_\_stream_p1　に
\_\_stream_01　を　\_\_stream_p2　に
\_\_stream_02　を　\_\_stream_p3　に
local_68　を　i　に
local_64　を　j　に
local_60　を　k　に
local_6b　を　temp　に

```c:mystery
void main(void)
{
  long lVar1;
  FILE *__stream;
  FILE *__stream_p1;
  FILE *__stream_p2;
  FILE *__stream_p3;
  long in_FS_OFFSET;
  char temp;
  int i;
  int j;
  int k;
  char flag [26];
  
  lVar1 = *(long *)(in_FS_OFFSET + 0x28);
  __stream = fopen("flag.txt","r");
  __stream_p1 = fopen("mystery.png","a");
  __stream_p2 = fopen("mystery2.png","a");
  __stream_p3 = fopen("mystery3.png","a");
  if (__stream == (FILE *)0x0) {
    puts("No flag found, please make sure this is run on the server");
  }
  if (__stream_p1 == (FILE *)0x0) {
    puts("mystery.png is missing, please run this on the server");
  }
  fread(flag,0x1a,1,__stream);
  fputc((int)flag[1],__stream_p3);
  fputc((int)(char)(flag[0] + '\x15'),__stream_p2);
  fputc((int)flag[2],__stream_p3);
  temp = flag[3];
  fputc((int)flag[5],__stream_p3);
  fputc((int)flag[4],__stream_p1);
  i = 6;
  while (i < 10) {
    temp = temp + '\x01';
    fputc((int)flag[i],__stream_p1);
    i = i + 1;
  }
  fputc((int)temp,__stream_p2);
  j = 10;
  while (j < 0xf) {
    fputc((int)flag[j],__stream_p3);
    j = j + 1;
  }
  k = 0xf;
  while (k < 0x1a) {
    fputc((int)flag[k],__stream_p1);
    k = k + 1;
  }
  fclose(__stream_p1);
  fclose(__stream);
  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}
```

デコンパイル結果がソースコードに近くなったところでソルバー作成

```python
png1 = list("CF{An1_e2630725}")
png2 = list("\x85s")
png3 = list("icT0tha_")
    
ans = [0] * 0x1a

# png3
ans[1] = png3[0]
ans[2] = png3[1]
ans[5] = png3[2]
j = 10
while j < 0xf:
    ans[j] = png3[j-7]
    j = j + 1

# png2
ans[0] = chr(ord(png2[0]) - 0x15)
temp = png2[1]

# png1
ans[4] = png1[0]
i = 6
while i < 10:
    temp = chr(ord(temp) - 0x1)
    ans[i] = png1[i-5]
    i = i + 1

k = 0xf
while k < 0x1a:
    ans[k] = png1[k-10]
    k = k + 1

ans[3] = temp

#print(ans)
print(''.join(ans))
```

※ソルバーに全角文字が混じっていました。（2021/4/20訂正）