pico_CTF reverse_cipher Writeup Using Ghidra

pico_CTF reverse_cipher を Ghidra を使って静的解析した。
Ghidraのデコンパイル誤りを正す訓練になる。

問題であるが，ELF と rev_thisというファイルが渡される。

rev_thisの内容は，0x16文字のテキストデータ

```
picoCTF{w1{1wq8/7376j.:}
```

flagを一部暗号化したような感じ

ELFを表層解析すると flag.txt の文字が見つかる。
xrefを確認すると普通にmain関数から見ればokとわかる。

Import直後のmain関数

```c
void main(void)

{
  size_t sVar1;
  char local_58 [23];
  char local_41;
  int local_2c;
  FILE *local_28;
  FILE *local_20;
  uint local_14;
  int local_10;
  char local_9;
  
  local_20 = fopen("flag.txt","r");
  local_28 = fopen("rev_this","a");
  if (local_20 == (FILE *)0x0) {
    puts("No flag found, please make sure this is run on the server");
  }
  if (local_28 == (FILE *)0x0) {
    puts("please run this on the server");
  }
  sVar1 = fread(local_58,0x18,1,local_20);
  local_2c = (int)sVar1;
  if ((int)sVar1 < 1) {
                    /* WARNING: Subroutine does not return */
    exit(0);
  }
  local_10 = 0;
  while (local_10 < 8) {
    local_9 = local_58[local_10];
    fputc((int)local_9,local_28);
    local_10 = local_10 + 1;
  }
  local_14 = 8;
  while ((int)local_14 < 0x17) {
    if ((local_14 & 1) == 0) {
      local_9 = local_58[(int)local_14] + '\x05';
    }
    else {
      local_9 = local_58[(int)local_14] + -2;
    }
    fputc((int)local_9,local_28);
    local_14 = local_14 + 1;
  }
  local_9 = local_41;
  fputc((int)local_41,local_28);
  fclose(local_28);
  fclose(local_20);
  return;
}
```
flag.txt を一部暗号化してrev_thisに書き出すプログラムのようだ。

最後の方のfputcとかデコンパイル誤りの匂いがプンプンする。

```c
  char local_58 [23];
  char local_41;

（中略）

    local_14 = local_14 + 1;
  }
  local_9 = local_41;
  fputc((int)local_41,local_28);
```

といってもこの程度のデコンパイル誤りはGhidraでは普通のことなので気にしてはいけない。
main関数内のC言語関数をネットで調べて適切な変数名に変えていく。
また，変数の型を変更することで致命的なデコンパイル誤りを訂正できる。

今回の例では，local_58の型をchar[23]からchar[24]に変更することが最も重要で，かつ，これを真っ先に行う必要がある。
もし，変数名の変更を一通り行った後で，この型変更を行うと，変更した変数名が勝手に変わってしまい，変数名を変更しようとしてもすでに使っていますとエラーになるはずだ。

変数の型，変数名を適切に変更してデコンパイル誤りを正したmain関数

```c
void main(void)

{
  FILE *fp_flag;
  FILE *fp_this;
  size_t ret;
  char flag [24];
  uint j;
  int i;
  char temp;
  
  fp_flag = fopen("flag.txt","r");
  fp_this = fopen("rev_this","a");
  if (fp_flag == (FILE *)0x0) {
    puts("No flag found, please make sure this is run on the server");
  }
  if (fp_this == (FILE *)0x0) {
    puts("please run this on the server");
  }
  ret = fread(flag,0x18,1,fp_flag);
  if ((int)ret < 1) {
                    /* WARNING: Subroutine does not return */
    exit(0);
  }
  i = 0;
  while (i < 8) {
    fputc((int)flag[i],fp_this);
    i = i + 1;
  }
  j = 8;
  while ((int)j < 0x17) {
    if ((j & 1) == 0) {
      temp = flag[(int)j] + '\x05';
    }
    else {
      temp = flag[(int)j] + -2;
    }
    fputc((int)temp,fp_this);
    j = j + 1;
  }
  fputc((int)flag[23],fp_this);
  fclose(fp_this);
  fclose(fp_flag);
  return;
}
```

ソルバー

```python
enc_string = "picoCTF{w1{1wq8/7376j.:}"

enc = list(enc_string)
    
ans = []
    
i = 0
while i < 0x8:
    ans.append(ord(enc[i]))
    i = i + 1
    
while i < 0x17:
    if (i & 1) == 0:
        ans.append(ord(enc[i]) - 0x5)
    else:
        ans.append(ord(enc[i]) + 0x2)
    i = i + 1
    
ans.append(ord(enc[23]))

print(''.join(map(chr,ans)))

```