GoCrackMe1

TENNNNNN-HUT!

Welcome to the Go Dojo, gophers in training!

Go malware is on the rise. So we need you to sharpen up those Go reverse engineering skills. We’ve written three simple CrackMe programs in Go to turn you into Go-binary reverse engineering ninjas!

First up is the easiest of the three. Go get em!

Solution:

1. Use IDA to decompile the binary

gocrackme1_1

2. Analyze main function

Since this is a Go binary, we need to note that main function is part of the Go’s runtime setup and main_main is the entry point of the actual code within the main package.

Here is the decompiled C code in main_main:

// main.main
// local variable allocation has failed, the output may be wrong!
void __fastcall main_main()
{
  __int128 v0; // xmm15
  uint8 *v1; // rax
  __int64 i; // rcx
  int len; // rbx OVERLAPPED
  string v4; // kr00_16
  uint8 *str; // rax
  void *v6; // rax
  os_File *v7; // rbx
  const runtime_itab *v8; // rax OVERLAPPED
  void *p_a; // rcx OVERLAPPED
  __int64 v10; // rdi
  __int64 v11; // rsi
  _BYTE v12[38]; // [rsp+Ah] [rbp-56h] BYREF
  string v13; // [rsp+30h] [rbp-30h] BYREF
  void **v14; // [rsp+40h] [rbp-20h]
  _slice_interface_ a; // [rsp+48h] [rbp-18h] BYREF

  qmemcpy(v12, "0:71-44coc``3dg0cc3c`nf2cno0e24435f0n+", sizeof(v12));
  v1 = (uint8 *)runtime_makeslice((runtime__type *)&RTYPE_uint8_0, 38LL, 38LL);
  for ( i = 0LL; i < 38; ++i )
    v1[i] = v12[i] ^ 0x56;
  v4 = runtime_slicebytetostring(0LL, v1, 38LL);
  len = v4.len;
  v13.str = v4.str;
  if ( main_checkCondition() )
  {
    *(_OWORD *)&a.array = v0;
    str = v13.str;
    v6 = runtime_convTstring(*(string *)(&len - 1));
    a.array = (interface_ *)&RTYPE_string_0;
    a.len = (int)v6;
    v7 = os_Stdout;
    v8 = &go_itab__ptr_os_File_comma_io_Writer;
    p_a = &a;
  }
  else
  {
    v13.len = (int)&RTYPE_string_0;
    v14 = &off_4BADB8;
    v7 = os_Stdout;
    v8 = &go_itab__ptr_os_File_comma_io_Writer;
    p_a = &v13.len;
  }
  v10 = 1LL;
  v11 = 1LL;
  fmt_Fprintln(*(io_Writer *)&v8, *(_slice_interface_ *)&p_a);
}
3. Analyze the operations and functions of decompiled code

From the decompiled code, it call main_checkCondition() and based on the condition, it will print out the decoded string if the condition is true.

At this part of the code:

qmemcpy(v12, "0:71-44coc``3dg0cc3c`nf2cno0e24435f0n+", sizeof(v12));
v1 = (uint8 *)runtime_makeslice((runtime__type *)&RTYPE_uint8_0, 38LL, 38LL);
for ( i = 0LL; i < 38; ++i )
    v1[i] = v12[i] ^ 0x56;

It uses XOR encryption operation on the string 0:71-44coc3dg0cc3cnf2cno0e24435f0n+ with the hex key of 0x56`

4. Decode the XOR operation

Here it the decode script in Python:

def decode_string(encoded_str, key):
    # Convert string to bytes
    encoded_bytes = encoded_str.encode('ascii')
    # XOR each byte with the key
    decoded_bytes = bytes([b ^ key for b in encoded_bytes])
    # Try to decode as ASCII, fallback to hex representation
    try:
        return decoded_bytes.decode('ascii')
    except UnicodeDecodeError:
        return decoded_bytes.hex()

# The encoded string from the binary
encoded = "0:71-44coc``3dg0cc3c`nf2cno0e24435f0n+"
key = 0x56

decoded = decode_string(encoded, key)
print(f"Decoded string: {decoded}")

Output:

Decoded string: flag{bb59566e21f55e5680d589f3dbbec0f8}

Flag: flag{bb59566e21f55e5680d589f3dbbec0f8}