I want to crack a simple C program password file by changing the assembly code with objdump .
I want to crack this C program by changing "jne" operation to "NOP" in objdump:
int is_valid(const char* password)
{
if (strcmp(password, "") == 0) {
return 1;
} else {
return 0;
}
}
int main()
{
char* input = malloc(256);
printf("What is the password? " );
scanf("%s" , input);
if (is_valid(input)){
printf("Correct! Go inside\n");
} else {
printf("Wrong.. you shall not enter!\n");
}
free(input);
return 0;
}
when i compile it with gcc and i try to change the "jne" to "nop" it works fine and when i type random characters as password it says:"Correct! Go inside" but when i compile it with clang and then i change the "jne" to "nop" , and when i run it and when i type some words as password it gives "zsh: segmentation fault" error.
I modify the file when i compiled it with gcc with
"printf "\x90\x90" | dd of=pass bs=1 seek=4525 count=2 conv=notrunc"
and when i compiled it with clang i modify it with
"printf "\x90\x90" | dd of=pass bs=1 seek=4511 count=2 conv=notrunc"
i compile it with this command in my terminal
clang Pass.c -o pass
and jne is available in both gcc and clang compiled file in "is_valid" function.
this is is the assembly code that i get on clang compiled file:
0000000000001180 <is_valid>:
is_valid():
1180: 55 push %rbp
1181: 48 89 e5 mov %rsp,%rbp
1184: 48 83 ec 10 sub $0x10,%rsp
1188: 48 89 7d f0 mov %rdi,-0x10(%rbp)
118c: 48 8b 7d f0 mov -0x10(%rbp),%rdi
1190: 48 8d 35 6d 0e 00 00 lea 0xe6d(%rip),%rsi # 2004 <_IO_stdin_used+0x4>
1197: e8 b4 fe ff ff call 1050 <strcmp@plt>
119c: 83 f8 00 cmp $0x0,%eax
119f: 0f 85 0c 00 00 00 jne 11b1 <is_valid+0x31>
11a5: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
11ac: e9 07 00 00 00 jmp 11b8 <is_valid+0x38>
11b1: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
11b8: 8b 45 fc mov -0x4(%rbp),%eax
11bb: 48 83 c4 10 add $0x10,%rsp
11bf: 5d pop %rbp
11c0: c3 ret
11c1: 66 2e 0f 1f 84 00 00 00 00 00 cs nopw 0x0(%rax,%rax,1)
11cb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
and this is the assembly code from gcc complier:
0000000000001189 <is_valid>:
is_valid():
1189: 55 push %rbp
118a: 48 89 e5 mov %rsp,%rbp
118d: 48 83 ec 10 sub $0x10,%rsp
1191: 48 89 7d f8 mov %rdi,-0x8(%rbp)
1195: 48 8b 45 f8 mov -0x8(%rbp),%rax
1199: 48 8d 15 64 0e 00 00 lea 0xe64(%rip),%rdx # 2004 <_IO_stdin_used+0x4>
11a0: 48 89 d6 mov %rdx,%rsi
11a3: 48 89 c7 mov %rax,%rdi
11a6: e8 b5 fe ff ff call 1060 <strcmp@plt>
11ab: 85 c0 test %eax,%eax
11ad: 75 07 jne 11b6 <is_valid+0x2d>
11af: b8 01 00 00 00 mov $0x1,%eax
11b4: eb 05 jmp 11bb <is_valid+0x32>
11b6: b8 00 00 00 00 mov $0x0,%eax
11bb: c9 leave
11bc: c3 ret
There are two different encodings of jne
. See https://www.felixcloutier.com/x86/jcc. gcc is using the "short" jump JNE rel8, opcode 0x75 plus a one-byte displacement. clang is using the "near" encoding, opcode 0x0f 0x85 plus a four-byte displacement. So for the clang version, you need to overwrite 6 bytes with 0x90, instead of just 2. You can see this directly by counting the number of bytes appearing in the second field of the objdump
output for the instruction.
Since the displacement is less than 128 bytes, clang could also be using the short encoding, which would be more efficient in terms of code size. It looks like this code was compiled without optimizations; if it were compiled with optimizations, the short encoding would probably be used instead.