Solve Crackmes Without Knowledge of Assembly

Hello, dear reader. This is my first post on this blog and I wanted to use it to explain something that bugged me for a while. At ALX-Holberton, we had some optional tasks which involved cracking the passwords to compiled programs.

We were told we could use GDB, objdump, ltrace and other helpful tools. I tried doing this and found it daunting due to the sometimes necessary knowledge of assembly and the uphill tasks required in learning these tools.

I however found a relatively simple solution. Anybody can easily solve the crackme tasks and it doesn't have to be a headache. All you need is a working knowledge of C and a free cross platform reverse engineering software which I'll introduce now.

Hello Cutter :) Hello Cutter

We will be going through how I did Crackme1.

prerequisites

  • Fair knowledge of C programming
  • Vim text editor
  • gcc compiler
  • Cutter software. download here Cutter

First of all we run chmod 755 101-crackme to make the file executable.

Next up is to try running the program to figure out how it works and what is actually expected of us

Let's see how the program works Let's see how the program works

Ok, from the above.. we have a little understanding of what is required of us.

Let's jump into the fun part... :)

Fire up Cutter and select the program we want to crack

when you just open cutter when you just open cutter

First click on select. Browse through your directories and select the program you want to crack. Then click open at the bottom right corner. And this should bring you here >>>

Default settings are ok Default settings are ok

Leave the default setting the way it is and press Ok.

Don't let this scare you, we don't need most of it Don't let this scare you, we don't need most of it

Double click on main. One of the listed functions on the top left. Highlighted in green on the picture above

This takes you to the assembly view of the code. WE DON'T NEED THIS. Click on the decompiler tab at the bottom right of the screen. If you can't see, go to the top of the screen, click on windows and then click on decompiler. It should appear now.

Disassembly View Disassembly View

Decompiled to C -  What we've been waiting for Decompiled to C - What we've been waiting for

from the beautiful C code above we see that if the number of command line arguments passed to the program is more than 2. It returns an error.

 if (argc == 2) {
        iVar2 = checksum((char **)argv[1]);
        if (iVar2 == 0xad4) {
            puts("\a\a\aTada! Congrats");
            uVar1 = 0;
        } else {
            puts("Wrong password");
            uVar1 = 1;
        }
    } else {
        printf("Usage: %s password\n", *argv);
        uVar1 = 1;
    }

from the above code, if we convert 0xad4 to decimal from hex, it gives us 2772. Ok interesting.

We see another interesting function called checksum that surely holds the secret to what we are looking for. Lets unravel it! Double click on checksum

int64_t checksum(char **arg1)
{
    char **var_18h;
    int64_t var_8h;

    var_8h = 0;
    for (var_18h = arg1; *(char *)var_18h != '\0'; var_18h = (char **)((int64_t)var_18h + 1)) {
        var_8h = var_8h + *(char *)var_18h;
    }
    return var_8h;
}

This is what we see when we double click on checksum. if you don't see this... on the bottom right corner. change your decompiler from jsdec to ghidra.

The code looks a bit incomprehensible but guess what? It's valid C code. So lets use some print statements to know whats actually happening. create a new program and call it test.c, copy the above code and paste, then add some print statements. The above code can be rewritten like this

#include <stdio.h>
#include <stdint.h>

int64_t checksum(char *arg1);

int main(void)
{
        char *arg1 = "AAA";
        int a = checksum(arg1);
        printf("sum %d\n", a);
        return (0);
}

int64_t checksum(char *arg1)
{
    char var_18h;
    int64_t var_8h;

    var_8h = 0;
    for (var_18h = *arg1; *arg1 != '\0'; arg1++) {

        /*adding a printf statement to know what is getting added to var_8h*/
        printf("%c\n", var_18h);
        var_8h = var_8h + var_18h;
        var_18h = *arg1;

    }
    return var_8h;
}

now type gcc test.c -o main

run the code and we see

wisdom@ubuntu:~/Documents/Vs_Code/ALX/crackmes/test$ ./main 
A
A
A
sum 195

A in ASCII decimal is 65, and 65 * 3 is 195. Interesting!!

from this our conclusion is that checksum checks the sum of the individual characters in the string we supplied as password and if the sum is 2772, it passes it as correct.

Lets confirm this, shall we? The ASCII code in decimal for ~ is 126. 126 in 22 places is 2772. Time for the moment of truth. Count carefully....

Counting Exercise Counting Exercise

The next part is to write a solution that generates random ascii codes that add up to 2772. I leave that to you.

Have fun. There is lots more you can do it with cutter and you can find easier ways to use it. Feel free to ask your questions.

Till next time. Bye.