Introduction

The given tasks gives us only one file:

  • Stretching.exe

Chall Description:

Warm your reverse skills we still have a long journy. Flag format : wwf{The_Right_val}

This is a rev challenge so the flag has to be found reverse engineering the program. As the program is not stripped its not difficult to understand which are the important functions.

Solution

I have extracted and refactored the important parts of the main to understand the how this challenge can be takled. Firstly i discovered three encrypted strings (in the code below flag_file_path_enc, ok_msg_enc and wrong_msg_enc).

undefined8 wmain(void) {
[...]
flag_file_path_enc = {
    -99, -0x69, -0x1e, -0x4d,
    -0x68, -0x7f, -0x41, -0x36,
    -0x70, -0x65,  -0x7a, -0x67, '\0'
};
ok_msg_enc = {
    -99, -0x3e, -0x34, -99,
    -0x65, -0x72, -0x56, -0x73,
    -0x28, -0x7d, -0x61, -0x76,
    -1, -0x59, '\0'
};
wrong_msg_enc = {
    -0x66, -0x28, -0x26, -0x76,
    -0x22, -0x67, -0x54, -0x2c,
    -0x62, -0x79, -0x61, -0x61,
    -0x46, -0x38, -0x34, -0x1b, '\0'
};

FUN_14000166d(flag_file_path_enc);
pcStack_28 = flag_file_path_enc;
pFStack_30 = fopen(pcStack_28,"r");
if (pFStack_30 == (FILE *)0x0) {
  puts("Error opening file! Error code: ");
  exit(1);
}

memset(flag,0,0x31);
fgets((char *)flag,0x31,pFStack_30);
pFVar6 = pFStack_30;
fclose(pFStack_30);

flag_enc = { 0xb33a2d07, 0x8565d2ad, 0x6233d52e, 0xd4a4ac94, 0x3b592793, 0x2412ad1c };
key = { 0xb2594e64, 0x36580af5, 0xb41d6e56, 0x9048ace6, 0xb979379e };

bVar1 = FUN_1400017f3();
if (bVar1 == 0) {
  for (i = 0; i < 4; i = i + 1) {
    FUN_1400016ed(key,(uint)i);
  }
  for (j = 0; j < 0x30; j = j + 8) {
    /* We need to reverse this function :) */
    enc(key,flag + (int)(uint)j);
  }
  uVar7 = 0x29;
  iVar3 = memcmp(flag,flag_enc,0x29);
  if (iVar3 == 0) {
    FUN_14000166d(ok_msg_enc);
    print(ok_msg_enc,&DAT_140005029,uVar7,in_R9);
  }
  else {
    FUN_14000166d(wrong_msg_enc);
    print(wrong_msg_enc,&DAT_140005029,uVar7,in_R9);
  }
  return 0;
}
[...]
}

After looking at the decryption function FUN_14000166d i reimplemented it in python to get the strings meaning:

void FUN_14000166d(char *enc_st) {
  byte key [7] = { 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 6};
  int local_c;

  for (local_c = 0; enc_st[local_c] != '\0'; local_c = local_c + 1) {
    enc_st[local_c] = enc_st[local_c] ^ key[local_c % 6];
  }
  return;
}

and got this messages:

[FLAG FILE PATH] C:\\flag.txt
[CORRECT FLAG MSG] Correct flag!
[INCORRECT FLAG MSG] Dude try harder

After decoding this messages it was pretty easy to understand how the program works. Firstly i understand what each function is doing and then i got to the reverse of the enc function:

NOTE:

Looking at this function we can see that ONLY key[4] is used, this imply that we could skip the reversing of FUN_1400016ed. Sadly i did it and it only decrypts the first 4 uint32_t of the key array that gives us this secret

[KEY STRING] Free_Palestine!!

NOTE:

The binary as it is gives problem to the decompilation, the instruction at the address 140001591 has to be nopped to get a good decompilation of the function out of Ghidra/IDA.

void enc(uint32_t *key,byte *buf) {
  right = (uint)buf[3] | (uint)*buf << 0x18 | (uint)buf[1] << 0x10 | (uint)buf[2] << 8;
  left = (uint)buf[7] | (uint)buf[4] << 0x18 | (uint)buf[5] << 0x10 | (uint)buf[6] << 8;
  uVar4 = key[4];

  bVar1 = *(byte *)((longlong)key + 0x11);
  bVar2 = *(byte *)((longlong)key + 0x12);
  bVar3 = *(byte *)((longlong)key + 0x13);

  j = 0;
  idx = 0;
  while (idx < 32) {
    right = right + (j + key[j & 3] ^ (left << 4 ^ left >> 5) + left);
    j = j + ((uint)bVar3 | (uint)(byte)uVar4 << 0x18 | (uint)bVar1 << 0x10 | (uint)bVar2 << 8);
    if ((j == 0) || (j != 0)) {
      uVar5 = right * 0x10;
    }
    else {
      uVar5 = func_0x000101fc5b2c();
    }
    left = left + (j + key[j >> 0xb & 3] ^ (uVar5 ^ right >> 5) + right);
    if ((left == 0) || (left != 0)) {
      idx = idx + 1;
    }
    else {
      func_0x000141f05b5d();
    }
  }
  *buf = (byte)(right >> 0x18);
  buf[1] = (byte)(right >> 0x10);
  buf[2] = (byte)(right >> 8);
  buf[3] = (byte)right;
  buf[4] = (byte)(left >> 0x18);
  buf[5] = (byte)(left >> 0x10);
  buf[6] = (byte)(left >> 8);
  buf[7] = (byte)left;
  return;
}

Then i proceded to reverse this function coming up with this code:

NOTE:

The first loop is from the main function, the inner loop is the one inside the enc function.

def dec_flag(key: list[int], flag_enc: list[int]) -> str:
    mask32 = 0xFFFFFFFF
    C = key[4] & mask32
    buff = flag_enc[:]
    for off in range(0, len(buff), 8):
        right = ( (buff[off+0] << 24) | (buff[off+1] << 16) | (buff[off+2] <<  8) |  buff[off+3] ) & mask32
        left = ( (buff[off+4] << 24)| (buff[off+5] << 16)| (buff[off+6] <<  8)|  buff[off+7] ) & mask32

        for i in range(31, -1, -1):
            j = ((i + 1) * C) & mask32

            k2 = key[(j >> 11) & 3]
            F2 = ((j + k2) ^ (((right << 4) & mask32) ^ (right >> 5)) + right) & mask32
            left = (left - F2) & mask32

            j0 = (i * C) & mask32

            k1 = key[j0 & 3]
            F1 = ((j0 + k1) ^ (((left << 4) & mask32) ^ (left >> 5)) + left) & mask32
            right = (right - F1) & mask32

        buff[off+0] = (right >> 24) & 0xFF
        buff[off+1] = (right >> 16) & 0xFF
        buff[off+2] = (right >>  8) & 0xFF
        buff[off+3] = (right      ) & 0xFF
        buff[off+4] = (left  >> 24) & 0xFF
        buff[off+5] = (left  >> 16) & 0xFF
        buff[off+6] = (left  >>  8) & 0xFF
        buff[off+7] = (left       ) & 0xFF
    return bytes(buff).decode('utf-8', errors='replace')