LoginSignup
2
2

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

Last updated at Posted at 2021-03-04

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

問題へのリンク

絶対に通らないif文

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のデコンパイル結果

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];

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バイト
flag1バイトにつき32回xorする

ソルバー ( Ghidra Script )

# 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)))
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2