The flag is saved in the executable, and it's xored with the license. The program iterates for every character of the license and it executes different instructions, according to the character. Here is a map of the actions:
x:movthe first char fromLICENSEintor9y:movthe first char fromLICENSEintor10!:movthe first char fromLICENSEintor11a:movthe first char fromLICENSEintor121:movthe first char fromLICENSEintor13r:movplaygroundintor9O:movplaygroundintor10l:movplaygroundintor112:movplaygroundintor12W:movplaygroundintor13S: copy fromflagto*r9,r10bytesb: xor*r10with license,r11bytes?: callmalloc, withr9bytes. The allocated memory will be calledplaygroundj: callfreeaddressr11h: callprint_flagaddressr13
Some instructions can use the next character of the license as an argument. If the license is correct, then the binary will print the flag. The executable also checks that the inserted license is 15 characters long. The instructions that are called when checking the license are obfuscated. To execute an action the relevant code gets deobfucated, executed and then obfucated again.
The relevant instructions, along with the obfuscator, are placed in a separated memory area.
The code gets deobfuscated according to this formula:
clear_byte = obfuscated_byte ^ (0x13371337 + offset)
where offset is the position of the byte relative to the beginning of the memory area.
The deobfuscated assembly code looks like this:
L33T_CODE:
; code unpacker
; rsi contains license_ptr
; rdi contains lib_functions
; rdx contains "function" offset
; rcx contains "function" size
push rbp
mov rbp,rsp
push r8
push rdx
push rcx
push rsi
mov rsi, 0 ; flag, jump to code
.encoder:
mov rax, [rbp-16] ; init key
mov rcx, 3
mul rcx
add rax, 0x13371337
mov rcx, [rbp-8] ; move pointer to function
add rcx, [rbp-16]
mov rbx, [rbp-24]
add rbx, rcx ; last address
.loop:
xor [rcx], al ; decode / encode
inc rcx ; increment pointer
add rax, 3 ; update key
cmp rcx, rbx
jl L33T_CODE.loop
cmp rsi, 0
jne L33T_CODE.finish
pop rsi
mov rax, r8
add rax, [rbp-16]
jmp rax
; code repacker
.repacker:
push rax ; save chars to skip
mov rsi, 1 ; flag, jump to finish
jmp L33T_CODE.encoder
.finish:
pop rax
leave
ret
; from license to register
xor r9, r9
mov r9b, byte [rdi + 1]
mov rax, 2
jmp L33T_CODE.repacker
;
xor r10, r10
mov r10b, byte [rdi + 1]
mov rax, 2
jmp L33T_CODE.repacker
;
xor r11, r11
mov r11b, byte [rdi + 1]
mov rax, 2
jmp L33T_CODE.repacker
;
xor r12, r12
mov r12b, byte [rdi + 1]
mov rax, 2
jmp L33T_CODE.repacker
;
xor r13, r13
mov r13b, byte [rdi + 1]
mov rax, 2
jmp L33T_CODE.repacker
; copy address for allocated memory to register
mov r9, r15
mov rax, 1
jmp L33T_CODE.repacker
;
mov r10, r15
mov rax, 1
jmp L33T_CODE.repacker
;
mov r11, r15
mov rax, 1
jmp L33T_CODE.repacker
;
mov r12, r15
mov rax, 1
jmp L33T_CODE.repacker
;
mov r13, r15
mov rax, 1
jmp L33T_CODE.repacker
; copy flag from data to allocated memory
cld
mov rdi, r9
add rsi, 24
mov rsi, [rsi]
mov rcx, r10
rep movsb
mov rax, 1
jmp L33T_CODE.repacker
; xor chars in allocated memory with license
xor rax, rax
mov rcx, r10 ; move pointer to memory playground
mov rbx, rcx ; last address
add rbx, r11 ; set here flag length
add rsi, 32
mov rsi, [rsi]
.xor_loop:
lodsb
xor byte [rcx], al ; decode
inc rcx ; increment pointer
cmp rcx, rbx
jl L33T_CODE.xor_loop
mov rax, 1
jmp L33T_CODE.repacker
; call malloc
mov rdi, r9
call [rsi]
mov r15, rax
mov rax, 1
jmp L33T_CODE.repacker
; call free
mov rdi, r11
call [rsi+8]
mov rax, 1
jmp L33T_CODE.repacker
; call print_flag
mov rdi, r13
call [rsi+16]
mov rax, 1
jmp L33T_CODE.repacker
mov rax, 1 ; invalid instruction are treated as nop
jmp L33T_CODE.repackerThe license should be built this way:
x\x0f: Setr9with the flag length?: callmallocto allocate the memoryplaygroundr: setr9with the address ofplaygroundy\x0f: setr10with the flag lengthS: copy the flag to the memory pointed byplaygroundO: setr10with the address ofplayground!\x0f: setr11with the flag lengthb: xor the flag with the licenseW: setr13with the address ofplaygroundh: callprint_flag(that's basically aprintf)l: setr11with the address ofplaygroundj: callfree
The correct license is x\x0f?ry\x0fSO!\x0fbWhlj