Hello software developers :)
I've decided to try and "crack" a (very simple) program I've written myself, just for the sake of it.
Here's the code:

#include <stdio.h>

const int serialCode = 255;
int guess;

int main() {
    printf("Please enter your serial code: ");
    scanf("%d", &guess);

    if(guess == serialCode) {
        printf("Thank you for CRACKING this software!\n");
        return 0;
    }

    printf("YOU FAILED!\n");
    return 0;
}

I would like it to be so that once you've submitted your guess, it'll skip the validation and just tell you that you've got it right, right away.
This is the disassembly generated by GDB:

Dump of assembler code for function main:
0x0000000100000e30 <main+0>:	push   %rbp
0x0000000100000e31 <main+1>:	mov    %rsp,%rbp
0x0000000100000e34 <main+4>:	sub    $0x10,%rsp
0x0000000100000e38 <main+8>:	xor    %al,%al
0x0000000100000e3a <main+10>:	lea    0xc7(%rip),%rcx        # 0x100000f08
0x0000000100000e41 <main+17>:	mov    %rcx,%rdi
0x0000000100000e44 <main+20>:	callq  0x100000eba <dyld_stub_printf>
0x0000000100000e49 <main+25>:	xor    %cl,%cl
0x0000000100000e4b <main+27>:	lea    0xd6(%rip),%rdx        # 0x100000f28
0x0000000100000e52 <main+34>:	lea    0x21f(%rip),%rsi        # 0x100001078 <guess>
0x0000000100000e59 <main+41>:	mov    %rdx,%rdi
0x0000000100000e5c <main+44>:	mov    %cl,%al
0x0000000100000e5e <main+46>:	callq  0x100000ec6 <dyld_stub_scanf>
0x0000000100000e63 <main+51>:	lea    0x20e(%rip),%rax        # 0x100001078 <guess>
0x0000000100000e6a <main+58>:	mov    (%rax),%eax
0x0000000100000e6c <main+60>:	mov    0x92(%rip),%ecx        # 0x100000f04 <serialCode>
0x0000000100000e72 <main+66>:	cmp    %ecx,%eax
0x0000000100000e74 <main+68>:	jne    0x100000e8e <main+94>
0x0000000100000e76 <main+70>:	lea    0xb3(%rip),%rax        # 0x100000f30
0x0000000100000e7d <main+77>:	mov    %rax,%rdi
0x0000000100000e80 <main+80>:	callq  0x100000ec0 <dyld_stub_puts>
0x0000000100000e85 <main+85>:	movl   $0x0,-0x8(%rbp)
0x0000000100000e8c <main+92>:	jmp    0x100000ea4 <main+116>
0x0000000100000e8e <main+94>:	lea    0xc1(%rip),%rax        # 0x100000f56
0x0000000100000e95 <main+101>:	mov    %rax,%rdi
0x0000000100000e98 <main+104>:	callq  0x100000ec0 <dyld_stub_puts>
0x0000000100000e9d <main+109>:	movl   $0x0,-0x8(%rbp)
0x0000000100000ea4 <main+116>:	mov    -0x8(%rbp),%eax
0x0000000100000ea7 <main+119>:	mov    %eax,-0x4(%rbp)
0x0000000100000eaa <main+122>:	mov    -0x4(%rbp),%eax
0x0000000100000ead <main+125>:	add    $0x10,%rsp
0x0000000100000eb1 <main+129>:	pop    %rbp
0x0000000100000eb2 <main+130>:	retq   
End of assembler dump.

It's however this snippet that has caught my interest:

0x0000000100000e72 <main+66>:	cmp    %ecx,%eax
0x0000000100000e74 <main+68>:	jne    0x100000e8e <main+94>
0x0000000100000e76 <main+70>:	lea    0xb3(%rip),%rax        # 0x100000f30

Right after it compared your guess to the actual serial code, it'll jump to <main+94> if you guessed wrong, tell you then exit. I want to change the destination of that conditional jump so that it will go to <main+70> and, regardless of the results, tell me that I was correct, and then exit the program.
The issue is that once I jump to 0x0000000100000e74 in HexEdit these are the hex codes I will see:

00 00 39 C8 75 18 48 8D 05 B3 00 00 00 48 89 C7
And it will place the cursor right after C8. I'm totally new at cracking and this is my first time doing something other than just manipulating data values. I was just thinking that the destination of the jump would be "hidden" somewhere in that line but I don't know where. Could you please help me?

Dani AI

Generated

The moderator closed this thread because the topic — changing a program’s control flow to bypass its checks — can easily be abused. That concern is legitimate. For readers who arrived here to learn low‑level internals rather than to perform unauthorized modifications, the following is a safe, conceptual clarification and some legal, practical next steps.

On x86/x86_64 the disassembler shows resolved absolute addresses for readability, but the CPU executes encoded opcodes and a small immediate displacement. Conditional jumps normally encode their destination as a signed offset relative to the instruction that follows the jump. There are compact encodings (small signed byte) and longer encodings (larger signed displacement). Because the jump’s operand size is fixed by its encoding, a naive byte-for-byte edit in a hex editor can corrupt the bytes that follow the instruction — in other words it’s not always possible to change the target by overwriting a few bytes without re-encoding or rearranging surrounding code.

If the goal is learning, do it safely and legally: write tiny programs you own (C or assembly), build them for your current OS/architecture, then inspect them with a disassembler and debugger. Modern toolchains and protections (ASLR, code signing and SIP on recent macOS releases) change how on-disk patching behaves, so experimentation in a disposable VM or container is recommended. Use purpose-built learning resources (open-source examples, deliberately educational reverse‑engineering challenges) and tooling such as objdump/otool, lldb/gdb, radare2 or Ghidra to study encodings and runtime state.

I echo the precautionary tone from and : don’t apply what you learn to modify software you don’t own. ’s suggestion to practice with small assembly programs is sensible — update that approach to target your current OS/ABI and keep experiments isolated and lawful.

Recommended Answers

All 5 Replies

I sure as hell won't help you "learn" how to do it, and I am sure there are many here that won't either. Please keep this crap out of DaniWeb

I agree with GunnerInc.
With that said, you should write both ends in assembly, first.
Start with a .com file so you can practice small jumps.
Once you get that trick down, try it with a exe file.

Keep in mind, these same tricks are used to create and attach viruses and things like this are suspicious.

I'm not trying to write a computer virus, or trying to learn how to crack software illegally! I'm just curious about the way computer programs work internally. That being said, you're suggesting I should write this in Assembly and assemble it into a pure binary (.com) for basic practice at "binary manipulation"?

It won't be binary manipulation.
It will truly be encapsulating the original program inside of another program (the crack)
So:
orig command 1
orig command 2
orig command 3
quit

becomes

new command 1 jump to new command 2 (takes place of orig 1)
orig command 2
orig command 3
quit
new command 2 do some stuff
orig command 1
new command 3 jump to orig command 2

You can do this manually or you can write a program that moves the bytes around.

I'm not trying to write a computer virus, or trying to learn how to crack software illegally!

That may not be your intention, but this is a public forum. How can you guarantee that what you learn in this thread can't be taken by others and used for malicious purposes?

Since the direct application of your exercise is for hacking, I'm closing this thread. We don't allow discussion of hacking, benign or not.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.