日立CTF Binary_絶対に通らないif文 Writeup Using Ghidra

Ghidraの勉強になると思って，日立CTFのBinary_絶対に通らないif文の静的解析にチャレンジした結果，うまくいったので共有する。

問題へのリンク

https://www.hitachi.co.jp/products/it/security/event/security_forum/index.html#p3

絶対に通らないif文

```c
int main(int argc, char **argv)
{
    if (1 == 2)
    {
        show_flag();
    }
    return 0;
}
```

逆アセンブル結果

```
0040B1C6: C7 45 FC 01 00 00 00  mov         dword ptr [ebp-4],1
0040B1CD: C7 45 F8 02 00 00 00  mov         dword ptr [ebp-8],2            
0040B1D4: 8B 45 FC              mov         eax,dword ptr [ebp-4]
0040B1D7: 3B 45 F8              cmp         eax,dword ptr [ebp-8]
0040B1DA: 75 05                 JNZ         LAB_0040B1E1
0040B1DC: e8 6f e3              CALL        FUN_00409550                                     
```
動的解析でフラグを得るならば，バイナリエディタで
C7 45 FC 01 00 00 00
を検索して
C7 45 FC 02 00 00 00
に変更すれば if (2 == 2) になってフラグが表示される。

--------------------------------------------
ここからがGhidraによる静的解析

FUN_00409550のデコンパイル結果

```c
void FUN_00409550(void)

{
  undefined4 extraout_EDX;
  int iVar1;
  int local_438;
  byte local_430 [4];
  undefined local_42c;
  undefined local_42b;
  undefined local_42a;
  undefined local_429;
  undefined local_428;
  undefined local_427;
  undefined local_426;
  undefined local_425;
  undefined local_424;
  undefined local_423;
  undefined local_422;
  undefined local_421;
  undefined local_420;
  undefined local_41f;
  undefined local_41e;
  undefined local_41d;
  undefined local_41c;
  undefined local_41b;
  undefined local_41a;
  undefined local_419;
  undefined local_418;
  undefined local_417;
  undefined local_416;
  undefined local_415;
  undefined local_414;
  undefined local_413;
  undefined local_412;
  undefined local_411;
  undefined4 local_410;
  byte local_40c [1024];
  uint local_c;
  int local_8;
  
  local_c = DAT_0040e004 ^ (uint)&stack0xfffffffc;
  local_40c[0] = 0x18;
  local_40c[1] = 0x13;
  local_40c[2] = 0x5e;
  local_40c[3] = 0x76;
  local_40c[4] = 0x34;
  （中略）
  local_40c[1019] = 0x35;
  local_40c[1020] = 0x7a;
  local_40c[1021] = 0x40;
  local_40c[1022] = 0x9b;
  local_40c[1023] = 0x36;
  local_430[0] = 0x53;
  local_430[1] = 0xb9;
  local_430[2] = 0xf;
  local_430[3] = 0xa4;
  local_42c = 0xb4;
  （中略）
  local_415 = 0x89;
  local_414 = 0x6a;
  local_413 = 0x47;
  local_412 = 0x8e;
  local_411 = 0x74;
  local_410 = 0x3ff;
  local_8 = 0;
  local_438 = 0x3ff;
  while (-1 < local_438) {
    local_8 = local_438 % 0x20;
    local_430[local_8] = local_430[local_8] ^ local_40c[local_438];
    local_438 = local_438 + -1;
  }
  iVar1 = 0;
  while (iVar1 < 0x20) {
    FID_conflict:_wprintf("%c",(uint)local_430[iVar1]);
    iVar1 = iVar1 + 1;
  }
  FID_conflict:_wprintf("\n");
  FUN_00401000(local_c ^ (uint)&stack0xfffffffc,extraout_EDX,(char)iVar1);
  return;
}
```

変数の型を修正して、デコンパイル誤りを補正する

byte local_430 [4];
↓
byte flag [32]; 

変数名を変更してわかりやすく

int local_438;　　→　　int i;
int local_8;　　　→　　int j;
byte local_40c [1024];　　→　　byte key [1024];


```c
void FUN_00409550(void)

{
  undefined4 extraout_EDX;
  int iVar1;
  int i;
  byte flag [32];
  byte key [1024];
  uint local_c;
  int j;
  
  local_c = DAT_0040e004 ^ (uint)&stack0xfffffffc;
  key[0] = 0x18;
  key[1] = 0x13;
  key[2] = 0x5e;
  key[3] = 0x76;
  key[4] = 0x34;
  （中略）
  key[1019] = 0x35;
  key[1020] = 0x7a;
  key[1021] = 0x40;
  key[1022] = 0x9b;
  key[1023] = 0x36;
  flag[0] = 0x53;
  flag[1] = 0xb9;
  flag[2] = 0xf;
  flag[3] = 0xa4;
  flag[4] = 0xb4;
  （中略）
  flag[27] = 0x89;
  flag[28] = 0x6a;
  flag[29] = 0x47;
  flag[30] = 0x8e;
  flag[31] = 0x74;
  j = 0;
  i = 0x3ff;
  while (-1 < i) {
    j = i % 0x20;
    flag[j] = flag[j] ^ key[i];
    i = i + -1;
  }
  iVar1 = 0;
  while (iVar1 < 0x20) {
    FID_conflict:_wprintf("%c",(uint)flag[iVar1]);
    iVar1 = iVar1 + 1;
  }
  FID_conflict:_wprintf("\n");
  FUN_00401000(local_c ^ (uint)&stack0xfffffffc,extraout_EDX,(char)iVar1);
  return;
}
```

keyが1024バイト
flagが32バイト
flag１バイトにつき32回xorする

ソルバー ( Ghidra Script )

```python
# step 1 extract key
key=[]
inst = getInstructionAt(toAddr(0x00409563))
i = 0
while i < 0x400:
    key.append(inst.getOpObjects(1)[0].getValue())
    inst = inst.getNext()
    i = i + 1    
#print(key)

# step 2 extract flag
flag=[]
inst = getInstructionAt(toAddr(0x0040affb))
i = 0
while i < 0x20:
    flag.append(inst.getOpObjects(1)[0].getValue())
    inst = inst.getNext()
    i = i + 1
#print(flag)

# step 3 xor
j = 0
i = 0x3ff
while -1 < i:
    j = i % 0x20
    flag[j] = flag[j] ^ key[i]
    i = i - 1

#print(flag)
print(''.join(map(chr,flag)))
```