For obvious reasons, the name of the software analysed in this article will be kept secret. "If you like it, buy it". I also contacted the editor of the software before publishing this blogpost.
As always with articles implying radare2, the goal is more to show what can be done with it rather than to focus on strict efficiency.
Yesterday, I was bored and stumbled upon a cracked version of [...],
and was curious about how well it was protected and hard to crack.
The pirated GNU/Linux x64 version is from a Turkish guy,
and has the sha1sum 49fca1f18a97[...]d04ff407b2f.
radiff2 legit_version cracked_version
0x000081e0 85c00f94c0 => 9090909090 0x000081e0
0x0007c805 85c0 => 9090 0x0007c805
0x0007c80a 84d2 => 9090 0x0007c80a
Only tree offsets, two nearly adjacent and with NOP. Smells like a quick'n'dirty crack.
[0x00406a70]> pd 3 @0x4081e0
0x004081e0 85c0 test eax, eax
0x004081e2 0f94c0 sete al
0x004081e5 84c0 test al, al
[0x00406a70]> pd 3 @0x47c805
0x0047c805 85c0 test eax, eax
0x0047c807 0f94c2 sete dl
0x0047c80a 84d2 test dl, dl
[0x00406a70]>
This looks like a test from the return value from a function.
[0x00406a70]> pd -2 @ 0x47c805
0x0047c7fe 8e00 mov es, [rax]
0x0047c800 e8eaf7ffff call fcn.0047bfef
[0x00406a70]> pd -2 @0x4081e0
0x004081d9 8e00 mov es, [rax]
0x004081db e80f3e0700 call fcn.0047bfef
[0x00406a70]>
This is likely this routine that checks the serial.
[0x00406a70]> afi 0x0047c805
[0x00406a70]>
It seems that r2 didn't detected the function. Since it's a x64 binary, parameters are passed by register.
[0x0047c805]> pd -32 @ 0x0047c805~push
0x0047c77e 4154 push r12
0x0047c780 55 push rbp
0x0047c781 53 push rbx
Three pushes in a row, likely the function prologue.
The af commands tells radare2 to analyse the function at
the given offset.
[0x0047c805]> af @ 0x0047c77e
[0x0047c805]>
For the second function, lets try something else.
Some compiler are padding function with nop; ret pairs.
[0x00406a70]> pd -30 @ 0x004081e0~ret
0x0040817a c3 ret
0x0040817c c3 ret
[0x00406a70]> pd -30 @ 0x004081e0~nop
0x0040817b 90 nop
0x0040817d 90 nop
[0x00406a70]> pd 4 @ 0x0040817a
0x0040817a c3 ret
0x0040817b 90 nop
0x0040817c c3 ret
0x0040817d 90 nop
[0x00406a70]> pd 10 @0x0040817d + 1
0x0040817e 4154 push r12
0x00408180 4989fc mov r12, rdi
0x00408183 55 push rbp
0x00408184 4c89c5 mov rbp, r8
0x00408187 53 push rbx
0x00408188 4889cb mov rbx, rcx
0x0040818b 4883ec70 sub rsp, 0x70
0x0040818f 488d7c2418 lea rdi, [rsp+0x18]
0x00408194 488d4c2428 lea rcx, [rsp+0x28]
0x00408199 48893424 mov [rsp], rsi
[0x00406a70]> af @0x0040817e
[0x00406a70]>
It seems that we're right! Now that we helped radare2 with analysis, it should display XREF correctly:
[0x00406a70]> pd 1 @ 0x0047bfef
; CALL XREF from 0x0047c800 (fcn.0047c77e)
; CALL XREF from 0x0040a199 (fcn.0040a0e5)
; CALL XREF from 0x004081db (fcn.0040817e)
; CALL XREF from 0x00408218 (fcn.004081e5)
0x0047bfef 4155 push r13
It seems that the crack author missed some checks, and they may be even more, but at least, this crack wasn't malicious.
Instead of patching some of the return value checks, the right way to do it would be to overwrite 0x0047bfef prologue with something like this:
xor eax, eax
inc eax
ret