Skip to main content

#LabyREnth CTF - Windows track no. 1 - AntiD.exe

In this task we have to reverse file called 'AntiD.exe'. After first examination of this, it looks to be simple PE32 executable, packed with UPX. Unfortunately we can't decompress it using UPX tool, so I started to unpack it manually. First thing to notice is that in PE Optional Header - DllCharasteristics is set to 8140, which means that DLLs in this executable can move around a bit (I'm usually using programs like 'CFF Explorer' or something similar to check this things out). I've changed this header to 8100, what actually terminated this behaviour ;)



To decompress this .exe I personally used x64dbg and Scylla, but the tool doesn't matter at all - it could be any runtime debugger and ImpRec I suppose. What we need to do is stop program execution at Entry Point of AntiD.exe, and run exactly one instruction : pushal - in my case, as you can see on image below (but You can also see this as PUSHAD in OllyDbg, or any other debugger).




After executing PUSHAD, You'll notice that value of ESP register had changed. We have to right click on this value, and click Follow in Dump. Then in the Dump Window of our debugger we need to check first 4 bytes and right-click again to set a Hardware Breakpoint on access. Then we simply run our program and wait for break to occur. We should land exactly in this place:



If we pass through jmp antid.71647 instruction, our executable will be already unpacked in process memory. What we must do now, is to dump this process from memory to another .exe and correct IAT (Import Address Table). Both this things can be easily done by 'Scylla', which is integrated in x64dbg, but You can use OllyDump, then ImpRec as well.
The last thing to change is OEP in the header of our new file. After quick examination in IDA I decided to redirect our new entry to address:  0x1380.


Main function looks exactly like on the image above and its quite easy to reverse. First puts "Figure the key out: " on the console output, then gets input from user and pass that to function which I called 'Check_Key' in IDA. If that fuction will return 1, the string: "Well done! A+! You get a gold star!\n" will be printed to us, else we'll see: "You wrong, why you so wrong at this?\n". But we still don't have a flag. We have to dig deeper - next step is to examine function "Check Key". Here's my version of it's disassembly:
char __cdecl Check_Key(char *Str)
{
  char result; // al@5
  char v2; // [sp+0h] [bp-38h]@2
  signed int i; // [sp+4h] [bp-34h]@2
  char v4; // [sp+8h] [bp-30h]@4
  char v5; // [sp+8h] [bp-30h]@6
  char v6; // [sp+8h] [bp-30h]@8
  char v7; // [sp+8h] [bp-30h]@10
  int v8; // [sp+8h] [bp-30h]@12
  unsigned __int8 hash_tab[40]; // [sp+Ch] [bp-2Ch]@1

  hash_tab[0] = 0x8Cu;
  hash_tab[1] = 0xF1u;
  hash_tab[2] = 0x53;
  hash_tab[3] = 0xA3u;
  hash_tab[4] = 8;
  hash_tab[5] = 0xD7u;
  hash_tab[6] = 0xDCu;
  hash_tab[7] = 0x48;
  hash_tab[8] = 0xDBu;
  hash_tab[9] = 0xC;
  hash_tab[10] = 0x3A;
  hash_tab[11] = 0xEEu;
  hash_tab[12] = 0x15;
  hash_tab[13] = 0x22;
  hash_tab[14] = 0xC4u;
  hash_tab[15] = 0xE5u;
  hash_tab[16] = 0xC9u;
  hash_tab[17] = 0xA0u;
  hash_tab[18] = 0xA5u;
  hash_tab[19] = 0xC;
  hash_tab[20] = 0xD3u;
  hash_tab[21] = 0xDCu;
  hash_tab[22] = 0x51;
  hash_tab[23] = 0xC7u;
  hash_tab[24] = 0x39;
  hash_tab[25] = 0xFDu;
  hash_tab[26] = 0xD0u;
  hash_tab[27] = 0xF8u;
  hash_tab[28] = 0x3B;
  hash_tab[29] = 0xE8u;
  hash_tab[30] = 0xCCu;
  hash_tab[31] = 3;
  hash_tab[32] = 6;
  hash_tab[33] = 67;
  hash_tab[34] = 0xF7u;
  hash_tab[35] = 0xDAu;
  hash_tab[36] = 0x7E;
  hash_tab[37] = 0x65;
  hash_tab[38] = 0xAEu;
  hash_tab[39] = 0x80u;
  if ( strlen(Str) == 16 )
  {
    v2 = 0;
    for ( i = 0; i < 40; ++i )
    {
      v4 = Str[i] ^ 0x33;
      if ( check_1() )
        return 0;
      v5 = v4 + 0x44;
      if ( check_2() )
        return 0;
      v6 = v5 ^ 0x55;
      if ( check_3() )
        return 0;
      v7 = v6 - 0x66;
      if ( check_4() )
        return 0;
      v8 = (unsigned __int8)(v7 ^ v2);
      if ( v8 != hash_tab[i] )
        return 0;
      v2 += v8;
    }
    result = 1;
  }
  else
  {
    result = 0;
  }
  return result;
}
From now we can see exactly what is going on here. Our input has to have 16 characters to move on. If it is indeed, then our flag should be produced in a loop. I didn't care about all that checking functions, beacuse I decided to write my own decoder than debugging the flag on runtime. Here's the code to do the job:
 
#include 
#include 

using namespace std;

int main(void)
{
 unsigned char v2 = 0;
 unsigned char tab[] = 
     { 0x8C,0xF1,0x53,0xA3,0x08,0xd7,0xDC,0x48,0xDB,0x0C,
       0x3A,0xEE,0x15,0x22,0xC4,0xE5,0xC9,0xA0,0xA5,0x0C,
       0xD3,0xDC,0x51,0xC7,0x39,0xFD,0xD0,0xF8,0x3B,0xE8,
       0xCC,0x03,0x06,0x43,0xF7,0xDA,0x7E,0x65,0xAE,0x80 };
 
 for (char j = 0; j < 40; j++)
 {
  x = 0;
  for (char i = 0; i < 0xff; i++)
  {
   x = i ^ 0x33;
   x = x + 0x44;
   x = x ^ 0x55;
   x = x - 0x66;
   x = x ^ v2;
   if (x == tab[j]) 
   {
    printf("%c", i);
    break;
   }
  }
  v2 = x + v2;
 }
 cout << endl;
 return 0;
}
And that's all - it will print our flag! 
Link to the file: AntiD.exe

Comments

Popular posts from this blog

#IceCTF - Thor's a hacker now

I've spend over half an hour on solving this task, beside of that wasn't a hard one. But thanks to this exercise I had to learn using regular expressions in my text editor :) Text file connected to this task looked exactly like that (but was much larger): 00000000: 4c5a 4950 01b3 007f b61b edf0 8440 58e3 LZIP.........@X. 00000010: 91de 1027 5861 8a67 4282 46a4 92f9 4cad ...'Xa.gB.F...L. 00000020: 2d5d 14eb 3099 2c31 01c2 d13a 74d2 c620 -]..0.,1...:t.. 00000030: de27 3a8f fa92 0644 5468 2d02 01fa 24bb .':....DTh-...$. 00000040: 719f a0fd a191 1678 8bff a2c4 2627 9871 q......x....&'.q 00000050: 83bf cff2 f8af 99fa c465 2b7c 6bdf ee3c .........e+|k..< 00000060: b71b f61b 0b5e 0ce7 d14f f6a8 0466 6470 .....^...O...fdp 00000070: de67 02da 7be1 1abd e9f0 ac87 131a bcc0 .g..{........... 00000080: 0b0b 9f31 9400 48e3 616a 8f3f 4804 79ad ...1..H.aj.?H.y. 00000090: a6bb 863a f641 01da b1ee c4fe b338 9289 ...:.A.......8.. 000000a0: 2a90 8302 4170 773c 88d3

#IceCTF - Substituted

It's one of very easy cryptographic tasks. We have to decrypt message: Lw! Gyzvecy ke WvyVKT! W'zz by reso dsbdkwksky tzjq teo kly ujr. Teo keujr, gy joy dksurwmq bjdwv vorakeqojalr jmu wkd jaazwvjkwemd. Vorakeqojalr ljd j zemq lwdkeor, jzklesql gwkl kly juxymk et vecaskyod wk ljd qekkym oyjzzr vecazwvjkyu. Decy dwcazy ezu vwalyod joy kly Vjydjo vwalyo, kly Xwqymyoy vwalyo, kly dsbdkwkskwem vwalyo, glwvl wd klwd emy, jmu de em. Jzcedk jzz et klydy vwalyod joy yjdwzr boeiym keujr gwkl kly lyza et vecaskyod. Decy myg ymvorakwem cykleud joy JYD, kly vsooymk dkjmujou teo ymvorakwem, jzemq gwkl ODJ. Vorakeqojalr wd j xjdk twyzu jmu wd xyor wmkyoydkwmq klesql. De iwvi bjvi, oyju sa em decy veez vwalyod jmu ljxy tsm! El jmu teo reso oyveoud cr mjcy wd WvyVKT{jzgjrd_zwdkym_ke_reso_dsbdkwksky_tzjqd}. We already know that every flag in this CTF, starts witch "IceCTF{" phrase, so there's no problem with first six substitutions. Then it's even easier. Here&#