[CrackMe] Remove Me

Suh doods, got another challenge which will probably be my last one for a while due to my lack of knowledge of the Linux system. I may make some Windows challenges if anyone wishes.

If anyone would like the source code to this, please tell me!


Difficulty

Depends on your current knowledge. Personally, I’d say it is somewhere between easy and intermediate.

  • Covfefe
  • Easy
  • Between easy and intermediate
  • Intermediate
  • Hard
  • Ultra Hard
  • Impossible
  • What is Reverse Engineering?

0 voters


Goal

The aim of this challenge is to modify the binary such that you remove the Remove me! message from displaying. Any method is acceptable however, the real goal is to apply the simplest (most elegant) and fewest patches as possible (in terms of bytes). Please comment your method and the number of modified bytes.

Correct Output

$ ./crackme
Hello!
$ _

Rules of Engagement

None.


Hints

Hint #1: Don’t make any assumptions about the code.
Hint #2: Understand all the phases of the deobfuscation.
Hint #3: Perhaps there’s a way to apply a patch which persists through all the of deobfuscation?


Binary

Use the following command to recover the binary:

cat crackme | base64 -d | gunzip > a.out && chmod +x a.out

Normal mode (Not Stripped)

H4sICOZgNlkAA2tyYWNrbWUAjZM9bNNAFMefU7eEwgBMSCwpEoIp4qNDhyIi4VQMWcqAYAo2vtiO
HTvx2TmQkEiaLohWSjtF0J0FBBJCShMJBlJ1QiyMZe9aqYiBhvAujss16sBJ93/v9/z8fHd+9yyb
W5AkCeKRgAngNF2Xk7NoexNRfBZSGL8CU6PnD/msyUk+5zHA5wmMnYGj409qK5PrVTentj710Lv2
/vtk2A1X5SXlQG4oGUVRtpczS8oAIRtDH4G/hnCxoXxb3F5eaCizh4HnPQyg3c+gjbKvjmfPHc1u
KIO4uILpB9lDGGa8PdftdtsV3MruTVzz7v3BYNBZwRPYrKF0+X7bMsrXWqfFo82xaJfvtC1FPj+R
2g3ldv03P8Nw/wu8azXXX7R+NFs7v/p7/X7/Y2ttbR39n+jfJSWvSlIlMjMNp7HAHeI4HvpJOH7w
6txGfwFAr8ecAEnIk2FvcEp4zv/sedSywJdQA4Gvoz4V+BZqTeAc6orAD1CbAhdQWwJTYb2Aq6uh
VgReRV2s/+OXqPcEfgNRH8KwryR4jXbjkBPwYYw7Ywy2rz6ySyRNgfhWaDJiakyjUPEsUnKpQ0LL
A/SZ5RZtSmwfyh4zCrph6qbmACkzYlkWMYnpArMtZjmuWnBMA9NsnZleyPwgAGaFWrVKdScomxBa
vuow1zewEBA7YKzsWUXmGuAwnxiOXaKqVgC/7NGirVG1ahDI5zVK8zRQ/QDyRFcDFY2rA6Tpk1Kg
amgDP7Jm7AXkcQDpYe7/jwvDU43u6fDu8r4Rmia+uzOjPH71ef/oCHNCHXlkz45y4vEK4bLAkmAT
QnwDAxmck6NvyiN7cqzeDr70+Zh6fwHton6mtAQAAA==

Good luck!

12 Likes

This challenge is great mate! I’ll love to see the code
Congrats

I believe this is not what you were looking for, but according to rules, should be fine as It removes the message.

[spoiler]I just modified 1 byte… the size of the string to be removed. Setting it to 0 the write system call will just do nothing…

echo -ne "\xfd" | dd of=a.out bs=1 seek=368 count=1 conv=notrunc

[/spoiler]

9 Likes

Wow, great job, very elegant! :ok_hand: Bonus points to you for a single byte patch! :+1:

2 Likes

@0x00pf totally nailed this but here’s a blow-by-blow account of my analysis along with an alternative (less elegant) solution.

Running ./a.out prints:

Remove me!
Hello!

and then exits.

Running objdump -d -Mintel a.out shows that the ‘_start’ function:

  1. Sets the EAX register to 0x8048071 (the address of the ‘ektwwpoijwng’ function)
  2. Calls the ‘lwreglkmsabf’ function
  3. Calls the ‘ektwwpoijwng’ function
  4. Makes a 32-bit ‘write’ system call (‘int 0x80’ with ‘eax’ set to 4), writing the string at 0x8048180 but writing 0x804818c bytes… hmmm…
  5. Makes a second ‘write’ system call, this time writing the string at 0x8048190. 0x8048198 bytes of it… double hmmm…
  6. Makes an ‘exit(0)’ system call (‘int 0x80’ with ‘eax’ set to 1 and ‘ebx’ set to 0)

Let’s look at the strings that are being written:

Running gdb -q a.out then x/s 0x8048180 displays the string:

"Remove me!\n"

And similarly x/s 0x8048190 displays the string:

"Hello!\n"

So, on the face of it ‘_start’ seems to contain the code we’re interested in. However, the length of the strings being written seem wrong.

We can test this pretty easily by moving the entry point of the application. Running readelf -h a.out shows that the entry point address is 0x804810a (the address of the ‘_start’ function). Given little endianness this address is stored in the executable as ‘0A 81 04 08’.

The second call to ‘write’ starts at 0x804812f so we can jump straight to it by modifying a single byte of the entry point like so:

echo -ne "\x2f" | dd of=a.out bs=1 seek=24 count=1 conv=notrunc

And running ./a.out now displays:

Hello!

…followed by a whole load of garbage, thanks to the crazy number of bytes requested to be written… :expressionless:

OK. Well let’s patch the byte count too:

echo -ne "\x07\x00\x00\x00" | dd of=a.out obs=1 seek=304 count=1 conv=notrunc

Rerunning ‘./a.out’ now simply prints ‘Hello!’ as required.

However, this seems pretty inelegant. @dtm mentions obfuscation in his hints and we’ve not encountered any of that yet. Furthermore, @0x00pf solved this with a single byte patch and we’d hate to be outdone! :smiley:

Alright then, let’s dig into those two functions that ‘_start’ calls.

The first function call is to ‘lwreglkmsabf’ which looks like this (output from ‘objdump -d -Mintel a.out’):

08048151 <lwreglkmsabf>:
mov ebx,0x8048060
08048156 <rposjkbsavge>:
xor BYTE PTR [ebx],0x44
inc ebx
cmp ebx,0x804810a
jne 8048156 <rposjkbsavge>
ret

This simply initializes ebx to the address of the first byte of code in the .text section and then loops over each byte, xoring it with ‘0x44’. When the loop reaches the beginning of the _start function, it terminates and returns.

In a conventionally compiled program, self-modifying code like this wouldn’t be possible, but running ‘readelf -SW a.out’ shows that the .text section is not only readable and executable (as expected) but also writable.

_start then calls ektwwpoijwng which was modified by the previous xoring. Using gdb and stepping over the deobfuscation shows that it now contains the following instructions:

nop
inc ecx
xor edi,edi
xor ecx,ecx
inc eax
mov BYTE PTR [eax],0xb8
inc eax
mov DWORD PTR [eax],0x4
add eax,0x4
mov BYTE PTR [eax],0xbb
inc eax
mov DWORD PTR [eax],0x1
add eax,0x4
mov BYTE PTR [eax],0xb9
inc eax
mov DWORD PTR [eax],0x8048164
add eax,0x4
mov WORD PTR [eax],0x158b
add eax,0x2
mov DWORD PTR [eax],0x8048170
add eax,0x4
mov WORD PTR [eax],0x80cd
add eax,0x2
mov WORD PTR [eax],0x4b0
add eax,0x2
mov BYTE PTR [eax],0xb9
inc eax
mov DWORD PTR [eax],0x8048174
add eax,0x4
mov WORD PTR [eax],0x158b
add eax,0x2
mov DWORD PTR [eax],0x804817c
add eax,0x4
move WORD PTR [eax],0x80cd
add eax,0x2
mov DWORD PTR [eax],0xbb
add eax,0x4
mov BYTE PTR [eax],0x0
inc eax
mov DWORD PTR [eax],0x1b8
add eax,0x4
mov BYTE PTR [eax],0x0
inc eax
mov WORD PTR [eax],0x80cd
jmp 0x8048060 <uiralwnrgowg>

These instructions modify themselves to three system calls: two 'write’s and an ‘exit’. Note, for example the three mov WORD PTR [eax],0x80cd instructions which write the bytes ‘CD 80’ which is ‘int 80’, a system call. The final instruction then jumps to function ‘uiralwnrgowg’ that xor’s the memory between 0x8048164 and 0x8048180 with 0xfd. Once deobfuscated, this memory holds the strings and byte counts referenced by the ‘write’ calls.

The altered instructions are then executed. They print “Remove Me!\n” then “Hello!\n” before exiting. This is the code, then, that really performs the program logic. The instructions in ‘_start’ are merely a red herring.

All the deobfuscation and self-modifying has to execute for the program to function correctly. And once that has occurred there aren’t any handy jump instructions which can be modified to prevent “Remove me” from being printed. Instead we can, as @0x00pf did, turn the first ‘write’ essentially into a no-op by changing the length of the string to be written to zero.

This length is held at address 0x8048170 (byte at offset 0x170, 368 in decimal) but is xor’ed with 0xfd before being used. Therefore, since we want this value to be zero we need to change the byte to 0xfd (as 0x00 xor 0xfd == 0xfd):

echo -ne "\xfd" | dd of=a.out obs=1 seek=368 count=1 conv=notrunc

And running ‘./a.out’ one last time shows that we’ve done it! :slight_smile:

4 Likes

Well done, excellent analysis! I hope this challenge has taught you some things. :stuck_out_tongue:

2 Likes

@dtm it certainly did! Thanks for creating this - I’d love to see the source if you’re willing to share?

Another solution

[spoiler]Setting the length of a write to 0 works in this case, but let’s extrapolate this challenge to a real world case. Imagine that instead of printing a message in the console, the program is actually invoking some protection code that prevents us to reverse the program. In that case, what we really want to do is to skip the execution of that function, or deactivate the protection. As our “function” is just a write to stdout, let’s solve the challenge skipping the code instead.

This solution is a lot longer but it is way more interesting.

First thing I have to say is that this challenge is very cool. It first deobfuscate the real code that is XOR encoded at the beginning of the .text segment. Then it runs that code that, instead of showing the messages in the console, “writes” new code to write the messages in the console. After that, it deobfuscate the data segment (actually the equivalent to .rodata) with a different key and finally, it runs the generated code, the one printing the message we have to remove. As I said this is really cool stuff. Kudos to @dtm!

So, let’s get started.

Using gdb and setting a couple of break points (I will not give you all the details so you can still have some fun :slight_smile: you can easily deobfuscate the original code and then run it to get the final code (sure, a little bit of dynamic analysis will not hurt). The original deobfuscated code looks like this:

Dump of assembler code for function ektwwpoijwng:
   0x08048071 <+0>:	90			nop
   0x08048072 <+1>:	41			inc    %ecx
   0x08048073 <+2>:	31 ff			xor    %edi,%edi
   0x08048075 <+4>:	31 c9			xor    %ecx,%ecx
   0x08048077 <+6>:	40			inc    %eax
   0x08048078 <+7>:	c6 00 b8		movb   $0xb8,(%eax)
   0x0804807b <+10>:	40			inc    %eax
   0x0804807c <+11>:	c7 00 04 00 00 00	movl   $0x4,(%eax)
   0x08048082 <+17>:	83 c0 04		add    $0x4,%eax
   0x08048085 <+20>:	c6 00 bb		movb   $0xbb,(%eax)
   0x08048088 <+23>:	40		        inc    %eax
   0x08048089 <+24>:	c7 00 01 00 00 00	movl   $0x1,(%eax)
   0x0804808f <+30>:	83 c0 04		add    $0x4,%eax
   0x08048092 <+33>:	c6 00 b9	        movb   $0xb9,(%eax)
   0x08048095 <+36>:	40		        inc    %eax
   0x08048096 <+37>:	c7 00 64 81 04 08	movl   $0x8048164,(%eax)
   0x0804809c <+43>:	83 c0 04		add    $0x4,%eax
   0x0804809f <+46>:	66 c7 00 8b 15	        movw   $0x158b,(%eax)
   0x080480a4 <+51>:	83 c0 02	        add    $0x2,%eax
   0x080480a7 <+54>:	c7 00 70 81 04 08	movl   $0x8048170,(%eax)
   (...)

And, once it is executed, the final code is unveiled:

Dump of assembler code for function ektwwpoijwng:
   0x08048071 <+0>:	90			nop
   0x08048072 <+1>:	b8 04 00 00 00		mov    $0x4,%eax
   0x08048077 <+6>:	bb 01 00 00 00		mov    $0x1,%ebx
   0x0804807c <+11>:	b9 64 81 04 08		mov    $0x8048164,%ecx
   0x08048081 <+16>:	8b 15 70 81 04 08	mov    0x8048170,%edx
   0x08048087 <+22>:	cd 80	       		int    $0x80
   0x08048089 <+24>:	b0 04			mov    $0x4,%al
   0x0804808b <+26>:	b9 74 81 04 08		mov    $0x8048174,%ecx
   0x08048090 <+31>:	8b 15 7c 81 04 08	mov    0x804817c,%edx
   0x08048096 <+37>:	cd 80	       		int    $0x80
   0x08048098 <+39>:	bb 00 00 00 00		mov    $0x0,%ebx
   0x0804809d <+44>:	b8 01 00 00 00		mov    $0x1,%eax
   0x080480a2 <+49>:	cd 80	    		int    $0x80

Now we have to work backwards. First decide what to patch in the final code, then patch the generator code to produce what we want, and finally obfuscate our patch to be able to apply it to the original file.

We have many options for the first step. I’m not sure whether the one I have chose is the best but it just works. You guys can try to beat this :slight_smile:

If we look at the code we can see that we need EBX set to 1 also for the second write call (the second int $0x80), I decide to hook into the mov $0x8048164,%ecx so I let the original code to set EBX for me. If we change this instruction (the mov into ecx) into a jmp to 0x08048089 then we are done. So we will have to inject a relative jump (2 bytes) at address 0x0804807c to skip the first write and continue with the second, located at 0x08048089. This leads us to the following offset for our relative jump: 0x08048089 - (0x0804807c + 2) -1 = 0x0a

So, we want jmp +0x0a at 0x0804807… that translates to opcodes eb 0a.

Fine. Now it’s time to look into the generator function. The commands that generates the instruction we want to patch are these:

   0x08048092 <+33>:	c6 00 b9	        movb   $0xb9,(%eax)
   0x08048095 <+36>:	40		        inc    %eax
   0x08048096 <+37>:	c7 00 64 81 04 08	movl   $0x8048164,(%eax)

You can see how the program first pokes B9 and then, after increasing the write pointer, the address to load on ECX. These three instructions effectively produce:

  0x0804807c <+11>:	b9 64 81 04 08		mov    $0x8048164,%ecx

So, what we are going to do is to remove the inc and use the immediate addressing parameter to store our jump instruction. I want to have just one patch command because I prefer to have sequential bytes to patch even if I have to write some byte that is already there.

So, my patching sequence for the generator function will be:

90 c7 00 eb 0a

(remember the 90 NOP removes the INC so we start writing at the beginning of the generated instruction).

You see that I’m writing again C7 and 00. This 2 values are already there and we do not need to write them again but, as I said, this way I can just run 1 patch command. (Note that it is pretty easy to patch this with two non-consecutive writes just 2 bytes… it may even be a 1byte patch solution IDK :slight_smile:

Now, the last part is to obfuscate those bytes so we can patch the original file and then, when the de-obfuscate code is executed it will put our bytes in the right place in the generator function who will produce the code we wanted.

We already know that the key for the deobfuscator is 0x44 (I haven’t said this before, but I’m pretty sure you can figure this out yourself), so xoring our patch with the key (0x44) we get the final patch:

44 44 44 44 44
XOR
90 c7 00 eb 0a
--------------
d4 83 44 af 4e

The last piece of information we need is the offset in the file to write our patch. I’m pretty sure that, if you are reading this you already know how to calculate this… but, just in case.

First, let’s get the information for our .text section from the binary

$  readelf -S removeme.orig  | grep ".text"
  [ 1] .text             PROGBITS        08048060 000060 000103 00 WAX  0   0 16

So, the .text segment is located at offset 60 in the file and it is mapped at 0x08048060 in memory. So, the file offset we are interest on is:

0x0804807c - 0x08048060 + 60 = 7c = 149

If you do not recall where does 0x0804807c comes from, just scroll up a bit and read again. As you can see, the offset in the file is 60 and the section address is 0x08048060, then we can just use the lower part of the address to know the file offset for any address. This is usually the case :slight_smile:

Now we can just patch the file with this data!

$ echo -ne "\xd4\x83\x44\xaf\x4e" | dd of=removeme.patch2 bs=1 seek=149 count=5 conv=notrunc

… and we are done.[/spoiler]

6 Likes

Hello,
thanks @dtm for this crackme, it was nice relax during Sunday afternoon for me.
My original solution was the same as @0x00pf presented in first post, so I try find another single-byte patch.

Instead of patching only the length of printed string, I try to change the “malicious” piece of code. The int 0x80 (syscall) instruction. Idea is similar than in the latest post from @0x00pf : avoid the malicious code to run, or modify it to do something innocent.

Syscall instruction consists of two bytes “0xcd 0x80”, I want to patch only one of them. Because the byte “0xcd” is opcode of software interrupt, I want to patch this one byte and change the instruction “int 0x80” to something else. Good candidates are arithmetic operations. My choose is the instruction “add al, 0x80” with code “0x04 0x80”. Notice that this instruction is irrelevant because before next syscall (for printing “Hello” message) is register eax reinitialized togerhet with registers ebx, ecxm edx.

Crete a patch: locate the first instruction “mov word [eax], 0x80cd” in deobfuscated code, change it to “mov word [eax], 0x8004” and obfuscate back. In the obfuscated file (xored with “0x44”), we need to patch bytes “0x89 0xc4” to “0x40 0xc4”. So this is it (“0x40 == @”):

echo -ne "@" | dd of=a.out bs=1 seek=179 count=1 conv=notrunc

Edited: it seems that preformatted inline text doesn’t work inside of spoiler. I am sorry, this is my first post.

5 Likes

Hi @dtm, I am really curious to see the source code if possible :slight_smile:
I am new here and start reading all RE stuff and this one is really interesting for me to do !
Thanks

It seems your profile is hidden, please PM me so I can send you the source.

Bigger challenge, crack iPiSoft’s mocap software