kiddie
.:: @OREL ::.

Crackmes.one - Keygenme - by kawaii-flesh
[ 12/09/2019 ]
Original copy : [https]://crackmes.one/crackme/5d24585133c5d410dc4d0cbd --- [0 - Description [1 - High level analysis [1.1 - Symbols & strings [1.2 - Program behaviour [2 - In depth analysis [2.1 - Disassembly [2.2 - Reversing the key algorithm [3 - Final word ---
[0 - Description
Author Name Difficulty kawaii-flesh + keygenme + 2 - Easy | | +--------------------------------------------------------------+ | | Platform + Language + Upload Unix/linux etc. C/C++ 9:03 AM 07/09/2019 Goals: 1) Find key for your nickname 2) Write keygen Have fun!)
[1 - High level analysis
[1.1 - Symbols & strings
Let's start by extracting symbols and strings from our fresh binary :
[voidboy@voidsys keygenme]$ file keygenme keygenme: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=072e9dec01bb00- c59d209de44ddd2380daac95e8, for GNU/Linux 3.2.0, stripped [voidboy@voidsys keygenme]$ strings -n 7 keygenme [...] keygenme [name] [key] Good job! Wrong key! GCC: (GNU) 9.1.0 [...] [voidboy@voidsys keygenme]$ objdump -T keygenme keygenme: format de fichier elf64-x86-64 DYNAMIC SYMBOL TABLE: 0000000000000000 w D *UND* [..] _ITM_deregisterTMCloneTable 0000000000000000 DF *UND* [..] GLIBC_2.2.5 puts 0000000000000000 DF *UND* [..] GLIBC_2.2.5 strlen 0000000000000000 DF *UND* [..] GLIBC_2.2.5 __libc_start_main 0000000000000000 w D *UND* [..] __gmon_start__ 0000000000000000 DF *UND* [..] GLIBC_2.2.5 atoi 0000000000000000 w D *UND* [..] _ITM_registerTMCloneTable 0000000000000000 w DF *UND* [..] GLIBC_2.2.5 __cxa_finalize
Notice the atoi symbol, otherwise, there isn't any much to say.
[1.2 - Program behaviour
[voidboy@voidsys keygenme]$ ./keygenme keygenme [name] [key] [voidboy@voidsys keygenme]$ ./keygenme foo bar Wrong key!
The binary is looking for a name and his corresponding key. We can assume that the atoi symbol we saw earlier is used with the key and then, compared against a computed key created from the name.
[2 - In depth analysis
We did not retrieve any major information regarding key algorithm in our high level analysis, we are now going to disassemble the binary and identify how the key and name are handled.
[2.1 - Disassembly
Binary was stripped so we cannot access the main symbol, instead, we're going to break on __lib_start_main and analyse how our binary was mapped into memory. With that method, we can determine where the .text section is located :
[voidboy@voidsys keygenme]$ gdb -q keygenme Reading symbols from keygenme... (No debugging symbols found in keygenme) (gdb) r Starting program: /home/voidboy/crackmes.one/keygenme/keygenme keygenme [name] [key] [Inferior 1 (process 4916) exited normally] (gdb) b __libc_start_main Breakpoint 1 at 0x7ffff7e0cdf0 (gdb) r Starting program: /home/voidboy/crackmes.one/keygenme/keygenme Breakpoint 1, 0x00007ffff7e0cdf0 in __libc_start_main () from /usr/lib/libc.so.6 (gdb) maintenance info sections Exec file: [...] `/home/voidboy/crackmes.one/keygenme/keygenme', file type elf64-x86-64. [11] 0x00001020->0x00001060 at 0x00001020: .plt [...] [12] 0x00001060->0x000012d5 at 0x00001060: .text [...] [13] 0x000012d8->0x000012e5 at 0x000012d8: .fini [...] [...] (gdb) info proc mappings process 4920 Mapped address spaces: Start Addr End Addr Size Offset objfile 0x555555554000 0x555555555000 0x1000 0x0 [...]keygenme 0x555555555000 0x555555556000 0x1000 0x1000 [...]keygenme 0x555555556000 0x555555557000 0x1000 0x2000 [...]keygenme 0x555555557000 0x555555558000 0x1000 0x2000 [...]keygenme 0x555555558000 0x555555559000 0x1000 0x3000 [...]keygenme [...] (gdb) disas 0x555555555000,0x555555556000 Dump of assembler code from 0x555555555000 to 0x555555556000: [...] 0x0000555555555030 <puts@plt+0>: jmpq *0x2fe2(%rip) 0x0000555555555036 <puts@plt+6>: pushq $0x0 0x000055555555503b <puts@plt+11>: jmpq 0x555555555020 0x0000555555555040 <strlen@plt+0>: jmpq *0x2fda(%rip) 0x0000555555555046 <strlen@plt+6>: pushq $0x1 0x000055555555504b <strlen@plt+11>: jmpq 0x555555555020 0x0000555555555050 <atoi@plt+0>: jmpq *0x2fd2(%rip) 0x0000555555555056 <atoi@plt+6>: pushq $0x2 0x000055555555505b <atoi@plt+11>: jmpq 0x555555555020 [...] === keygeneration algorithm === 0x0000555555555159: push %rbp 0x000055555555515a: mov %rsp,%rbp 0x000055555555515d: push %rbx 0x000055555555515e: sub $0x28,%rsp 0x0000555555555162: mov %rdi,-0x28(%rbp) 0x0000555555555166: movl $0x0,-0x18(%rbp) 0x000055555555516d: movl $0x0,-0x14(%rbp) 0x0000555555555174: jmp 0x555555555190 0x0000555555555176: mov -0x14(%rbp),%eax 0x0000555555555179: movslq %eax,%rdx 0x000055555555517c: mov -0x28(%rbp),%rax 0x0000555555555180: add %rdx,%rax 0x0000555555555183: movzbl (%rax),%eax 0x0000555555555186: movsbl %al,%eax 0x0000555555555189: add %eax,-0x18(%rbp) 0x000055555555518c: addl $0x1,-0x14(%rbp) 0x0000555555555190: mov -0x14(%rbp),%eax 0x0000555555555193: movslq %eax,%rbx 0x0000555555555196: mov -0x28(%rbp),%rax 0x000055555555519a: mov %rax,%rdi 0x000055555555519d: callq 0x555555555040 0x00005555555551a2: cmp %rax,%rbx 0x00005555555551a5: jb 0x555555555176 0x00005555555551a7: mov -0x18(%rbp),%eax 0x00005555555551aa: add $0x28,%rsp 0x00005555555551ae: pop %rbx 0x00005555555551af: pop %rbp 0x00005555555551b0: retq === main === Check if there are 3 args 0x00005555555551b1: push %rbp 0x00005555555551b2: mov %rsp,%rbp 0x00005555555551b5: push %rbx 0x00005555555551b6: sub $0x28,%rsp 0x00005555555551ba: mov %edi,-0x24(%rbp) 0x00005555555551bd: mov %rsi,-0x30(%rbp) 0x00005555555551c1: cmpl $0x3,-0x24(%rbp) 0x00005555555551c5: je 0x5555555551da 0x00005555555551c7: lea 0xe36(%rip),%rdi # 0x555555556004 0x00005555555551ce: callq 0x555555555030 <puts@plt> 0x00005555555551d3: mov $0x0,%eax 0x00005555555551d8: jmp 0x555555555259 --- Arg[1] is sent to keygen fonction 0x00005555555551da: mov -0x30(%rbp),%rax 0x00005555555551de: add $0x8,%rax 0x00005555555551e2: mov (%rax),%rax 0x00005555555551e5: mov %rax,%rdi 0x00005555555551e8: callq 0x555555555159 --- ebx = keygen() ^ argv[1][0] * 2 0x00005555555551ed: mov %eax,%ecx 0x00005555555551ef: mov -0x30(%rbp),%rax 0x00005555555551f3: add $0x8,%rax 0x00005555555551f7: mov (%rax),%rax 0x00005555555551fa: movzbl (%rax),%eax 0x00005555555551fd: movsbl %al,%edx 0x0000555555555200: mov %edx,%eax 0x0000555555555202: add %eax,%eax 0x0000555555555204: add %edx,%eax 0x0000555555555206: mov %ecx,%ebx 0x0000555555555208: xor %eax,%ebx --- rbp-0x14 = ebx << strlen(argv[0]) 0x000055555555520a: mov -0x30(%rbp),%rax 0x000055555555520e: mov (%rax),%rax 0x0000555555555211: mov %rax,%rdi 0x0000555555555214: callq 0x555555555040 <strlen@plt> 0x0000555555555219: mov %eax,%ecx 0x000055555555521b: shl %cl,%ebx 0x000055555555521d: mov %ebx,%eax 0x000055555555521f: mov %eax,-0x14(%rbp) 0x0000555555555222: mov -0x30(%rbp),%rax --- if atoi(argv[2]) == rbp-0x14 -> Good boy 0x0000555555555226: add $0x10,%rax 0x000055555555522a: mov (%rax),%rax 0x000055555555522d: mov %rax,%rdi 0x0000555555555230: callq 0x555555555050 <atoi@plt> 0x0000555555555235: cmp %eax,-0x14(%rbp) 0x0000555555555238: jne 0x555555555248 0x000055555555523a: lea 0xdd9(%rip),%rdi # 0x55555555601a 0x0000555555555241: callq 0x555555555030 <puts@plt> 0x0000555555555246: jmp 0x555555555254 0x0000555555555248: lea 0xdd5(%rip),%rdi # 0x555555556024 0x000055555555524f: callq 0x555555555030 <puts@plt> 0x0000555555555254: mov $0x0,%eax 0x0000555555555259: add $0x28,%rsp 0x000055555555525d: pop %rbx 0x000055555555525e: pop %rbp 0x000055555555525f: retq
[2.2 - Reversing the key algorithm
Once we identify the main, we can extract the key generation algorithm which is pretty simple, here's the operations used :
for(i=0;i<strlen(argv[1);i++) a+=argv[i]; key = a ^ (strlen(argv[1][0] * 3)) << strlen(argv[0]);
I wrote the following keygen in C :
[voidboy@voidsys keygenme]$ cat solve.c #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { int i = 0; int s = 0; if(argc != 2) { printf("Usage : %s nickname", argv[0]); exit(0); } for(;i<strlen(argv[1]);i++) s+=argv[1][i]; s = (s ^ (argv[1][0] * 3)) << strlen(argv[0]); printf("key is : %d\n",s); return 0; } [voidboy@voidsys keygenme]$ gcc -o keygenhe solve.c [voidboy@voidsys keygenme]$ ./keygenhe kingTerry key is : 784384 [voidboy@voidsys keygenme]$ ./keygenme kingTerry 784384 Good job!
Since i'm learning assembly, I also wrote the keygen in asm :
[voidboy@voidsys keygenme]$ cat solve.asm section .data usage: db 'Usage ./solve [name]',0 newline: db 10 global _start section .text print_newline: mov rax, 1 mov rdx, 1 mov rdi, 1 mov rsi, newline syscall ret exit: mov rax, 60 syscall string_length: xor rax, rax .loop: cmp byte [rdi+rax], 0 jz .end inc rax jmp .loop .end: ret print_string: push rdi call string_length pop rsi mov rdx, rax mov rax, 1 mov rdi, 1 syscall ret print_uint: mov rax, rdi mov rdi, rsp push 0 sub rsp, 16 mov r8, 10 dec rdi .loop: xor rdx, rdx div r8 or rdx, 0x30 dec rdi mov [rdi], dl test rax, rax jnz .loop .end: call print_string add rsp, 24 ret _start: cmp byte [rsp], 0x2 jne .usage mov rsi, [rsp+0x10] xor rcx, rcx xor rax, rax .loop: mov dl, [rsi+rcx] add rax, rdx test rdx, rdx jz .next inc rcx jmp .loop .next: mov rcx, rax mov rsi, [rsp+0x10] mov byte al, [rsi] mov r8, 3 mul r8 xor rax, rcx mov rdi, [rsp+0x8] push rax call string_length pop rcx .again: shl rcx, 1 dec rax test rax, rax jnz .again mov rdi, rcx call print_uint call print_newline call exit .usage: mov rdi, usage call print_string call print_newline call exit
3] - Final word
My keygen written in asm does not work, lulz.

Tout est faux tout est conforme.