The flag provided in argv[1] is transformed by several xor functions into 3 malloced buffers and the final buffer's bytes are compared to some arbitrary value. Each xor function involves the global variable xor_var located at 0x804a194 and initialized to 10, whose value seems to be changed only twice.

So this is a simple anti debug function, whose main purpose is to check that the environment variable LD_PRELOAD isn't set, and that the process can be ptraced. It silently alters xor_var if one of these conditions is not true. To bypass these checks, one can simply run the executable LD_PRELOADing a library that modifies getenv() and ptrace() return values. I actually just patched the PLT entries of getenv(), ptrace() and sleep(), as sleeps get pretty annoying during debug:

Those modifications just bypass the GOT calls, and ensure that ptrace() always returns 0 and getenv() always returns NULL. From there on it should just be a matter of inversing the xor functions: xor_var should be 0xa in the first loop, 0xb in the second, and 0xe in the third and fourth loops. Doing so gives the flag "DbC~ai\x19{=Di^~>ny" that still gets a "Wrong flag" output. Checking the xor_var value at the end of main():

So xor_var finishes at 0x24, pretty far away from the expected 0xe. There must be some hidden code executed, but no constructors are set, xor_var is indeed 0xa at the beginning of main() and there isn't any additional code to be found within .text. Debugging step by step shows surprising xor_var incrementations after some libc function calls. The only code that should be involved between main() and libc functions is dynamic relocation, so we check PLT and GOT entries:

PLT first instructions call the functions pointed to by their respective GOT entries. Before any call is made, those entries should point back to PLT addresses (ranging from 0x08048450 to 08048430) for dynamic relocation. After symbol resolution, the relevant GOT entry is replaced by the function's actual address.
We can see here that printf, malloc, puts and strlen GOT entries do not point back to PLT, but to 0x08049XXX addresses. This segment does not appear in objdump -h and seems to lie in between eh_frame and init_array_start. It doesn't matter anyway as the kernel copies whole ELFs in memory during execve syscalls, so these addresses remain valid and reachable. To study them, one may for instance load the ELF as a binary in IDA with the proper loading offset (0x08048000). There is probably a prettier workaround with segments definition though.

Two of those hidden functions (puts and strlen) look like main()'s anti-debugging prologue: getenv/ptrace and some xor_var incrementations. The other two increment xor_var by as many 0xcc as they find in puts and strlen wrappers code. Those four functions start with a call to 0x804940b that copies the addresses of those wrappers in their GOT entries again. They end with a relocation call, that will eventually overwrite GOT entries with actual libc values. This means that two consecutive PLT calls to one of those functions trigger the wrapper only *once*. The wrapper can be called again after one of the remaining three wrapped functions is executed, overwriting the GOT entries once again.

The last thing to do is to set up breakpoints before and after each one of those functions in our patched executable to see how they affect xor_var:

So each one basically does xor_var++, and printf should do the same thing than malloc. We can deduce xor_var values for each xor loop: for the first loop it's 0xe, second 0x14, third 0x1b, and the three executions of the fourth get respectively 0x1d, 0x20 and 0x23. After the final puts("done\n"), xor_var is indeed 0x24 as seen earlier. Calculating the inverse of the xor functions is now pretty straightforward: