What do we want to do today? We want to learn how to crack a (very easy) program with Assembler. What we will use for this:

  • C programming language for our program
  • gcc for compiling the program
  • objdump for disassembling
  • a hexeditor for editing the binary file

The C program

What we will program is essentially a program that asks for a password and then displays either a secret information or denies access. Actually it sucks a bit, because you could just read out our secret string from the compiled binary, but imagine the program does a rights check and will do complex multiplications (you cannot do without having rights and without this program).

So this is our C code:

#include <stdio.h>

int main() {
        int code;
        scanf("%d", &code;);

        if (code == 5) {
                printf("Very secret information\n");
        } else {
                printf("You have no access\n");
        }
        return 0;
}

Compile it with C and test it:

You will get something similar to these two test runs:

brati ~ $ ./a.out 
6
You have no access
brati ~ $ ./a.out 
5
Very secret information

But what if we had not seen before that the password is 5?

Disassemble with objdump

This is where objdump kicks in. This is a program that can dump the assembler instructions for you. Usually it’s used for debugging and you can only disassemble small stuff with it, but it’s enough for our purpose here.

With the option -d you can tell objdump to disassemble the code for you. So let’s do this and drop it to a file:

objdump -d a.out > access_disass

It will give you different sections containing source code (or expected to contain source code). Among them should be the .text segment. With -j .text you could have assigned objdump to only export the .text section, but it doesn’t really matter in this case. Somewhere in the disassembly should be the main label which denotes the main function of our program.

You should now study the assembler code on the right clearly to search for a place where there could a password check. Have you found it? If not, it should be the following commands in order:

  • cmp (compare)
  • jne (jump not equal)

These compare our input to the correct password (which you could read from here, but that would be boring) and if it is not right, jumps to the code to display the error message. If it is right though, it will go on with the secret part.

We want to turn the program to accept a wrong password now. For this, we will just replace the jne command with a je (jump equal) command which jumps to the error section if the password is right (meaning we will get to the restricted section if the password is wrong). We could also replace it with jmp (unconditioned jump), but then we would have to adjust the jump-length, too. Otherwise the program would jump to the error message even if the password was right ;) So jne is equal effective, but less editing. Even though you can also try out jmp later for training.

From the left hand side you can get the opcode belonging to the command. In my case it’s 75 for jne and 74 for je (both taking a hex code for the number of lines to jump as argument).

Replacing the opcodes in the binary file

If we replace jne with je, the program will jump to the secret area, if the password is wrong. For this you can open the binary file (a.out as gcc default) with a hexeditor (e.g. hexedit on Linux). Then search for the desired line, in my case “75 0e”.

Replace the 75 (jne) with 74 (je). Of course if your architecture has other opcodes, you have to adjust them. After having saved the file, you can just rerun it. Isn’t it a strange feeling to run a binary file, you have just editted with your bare hands? :)

Now you should get an output similar to this, which shows we can get the secret information with wrong passwords. Only the right password will not be accepted anymore.

brati ~ $ ./a.out 
3
Very secret information
brati ~ $ ./a.out 
5
You have no access

Training with jmp

Now try editing the binary file so that it always accepts the input, no matter if it’s correct or wrong. Don’t forget you have to adjust the jump length.

The test run should then look like this:

brati ~ $ ./a.out 
4
Very secret information
brati ~ $ ./a.out 
5
Very secret information