Skip to content

Instantly share code, notes, and snippets.

@Arno0x
Last active January 21, 2023 23:30
Show Gist options
  • Save Arno0x/1ec189d6bee3e92fdef1d72a72899b1d to your computer and use it in GitHub Desktop.
Save Arno0x/1ec189d6bee3e92fdef1d72a72899b1d to your computer and use it in GitHub Desktop.
Performs multiple useful transformation on files
#!/usr/bin/python
# -*- coding: utf8 -*-
#
# Author: Arno0x0x, Twitter: @Arno0x0x
#
import argparse
from Crypto.Cipher import AES
import pyscrypt
from base64 import b64encode
from os import urandom
from string import Template
import os
#=====================================================================================
# Crypto functions
#=====================================================================================
#------------------------------------------------------------------------
# XOR encryption
#------------------------------------------------------------------------
def xor(data, key):
""" data as a bytearray
key as a string
"""
l = len(key)
keyAsInt = map(ord, key)
return bytes(bytearray((
(data[i] ^ keyAsInt[i % l]) for i in range(0,len(data))
)))
#------------------------------------------------------------------------
# Class providing RC4 encryption functions
#------------------------------------------------------------------------
class RC4:
def __init__(self, key = None):
self.state = range(256) # initialisation de la table de permutation
self.x = self.y = 0 # les index x et y, au lieu de i et j
if key is not None:
self.key = key
self.init(key)
# Key schedule
def init(self, key):
for i in range(256):
self.x = (ord(key[i % len(key)]) + self.state[i] + self.x) & 0xFF
self.state[i], self.state[self.x] = self.state[self.x], self.state[i]
self.x = 0
# Encrypt binary input data
def binaryEncrypt(self, data):
output = [None]*len(data)
for i in xrange(len(data)):
self.x = (self.x + 1) & 0xFF
self.y = (self.state[self.x] + self.y) & 0xFF
self.state[self.x], self.state[self.y] = self.state[self.y], self.state[self.x]
output[i] = chr((data[i] ^ self.state[(self.state[self.x] + self.state[self.y]) & 0xFF]))
return ''.join(output)
#------------------------------------------------------------------------
# AES-CBC Encryption
#------------------------------------------------------------------------
def pad(s):
"""PKCS7 padding"""
return s + (AES.block_size - len(s) % AES.block_size) * chr(AES.block_size - len(s) % AES.block_size)
def aesEncrypt(data, key):
"""Encrypts data with the provided key.
Returns the 16 bytes IV used and the encrypted data
"""
# Generate a crypto secure random Initialization Vector
iv = urandom(AES.block_size)
# Perform PKCS7 padding so that data is a multiple of the block size
data = pad(data)
cipher = AES.new(key, AES.MODE_CBC, iv)
return iv,cipher.encrypt(bytes(data))
#=====================================================================================
# Output format functions
#=====================================================================================
def chunks(s, n):
"""
Author: HarmJ0y, borrowed from Empire
Generator to split a string s into chunks of size n.
"""
for i in xrange(0, len(s), n):
yield s[i:i+n]
def formatCPP(data):
"""data as a string representation"""
temp = "\\x"
temp += "\\x".join(format(ord(b),'02x') for b in data)
result = "unsigned char data[] = \"" + temp + "\";"
return result
def formatCSharp(data):
"""data as a string representation"""
temp = '0x'
temp += ',0x'.join(format(ord(b),'02x') for b in data)
result = "byte[] data = new byte[] { " + temp + " };"
return result
def formatPy(data):
"""data as a string representation"""
temp = '\\x'
temp += '\\x'.join(format(ord(b),'02x') for b in data)
result = "data = (\"" + temp + "\")"
return result
def formatVBA(data):
"""data as a string representation"""
temp = ''
for chunk in chunks(data, 80):
temp += ','.join(format(ord(b)) for b in chunk)
temp += ', _\n'
result = "Data = Array(" + temp[0:-4] + ")"
return result
def formatVBA2(data):
"""data as a string representation"""
temp = '&H'
temp += '&H'.join(format(ord(b),'02X') for b in data)
result = temp
return result
def formatXLM(data):
"""data as a string representation"""
temp = ''
for chunk in chunks(data, 255):
temp += '='
for b in chunk:
temp += 'CHAR({})&'.format(ord(b))
temp = temp[0:-1] + '\r\n'
return temp
#=====================================================================================
# Helper functions
#=====================================================================================
def color(string, color=None):
"""
Author: HarmJ0y, borrowed from Empire
Change text color for the Linux terminal.
"""
attr = []
if color:
if color.lower() == "red":
attr.append('31')
elif color.lower() == "green":
attr.append('32')
elif color.lower() == "blue":
attr.append('34')
return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)
else:
# bold
attr.append('1')
if string.strip().startswith("[!]"):
attr.append('31')
return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)
elif string.strip().startswith("[+]"):
attr.append('32')
return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)
elif string.strip().startswith("[?]"):
attr.append('33')
return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)
elif string.strip().startswith("[*]"):
attr.append('34')
return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)
else:
return string
#======================================================================================================
# MAIN FUNCTION
#======================================================================================================
if __name__ == '__main__':
#------------------------------------------------------------------------
# Parse arguments
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--input", help="File to transform", dest="inputFileName")
parser.add_argument("-e", "--encrypt", help="Optionnal type of encryption to algorithm to use", dest="cryptoAlgorithm", choices=['xor','aes', 'rc4'])
parser.add_argument("-k", "--key", help="Key used to encrypt the shellcode", dest="key")
parser.add_argument("-f", "--format", help="Output format (base64, C++, C#, Python, VBA, VB-Body, XLM)", dest="format", choices=['b64','cpp','cs','py','vba','vba2','xlm'])
parser.add_argument("-o", "--output", help="Output file", dest="outputFileName")
args = parser.parse_args()
if args.inputFileName:
#------------------------------------------------------------------------
# Open input file and read all bytes from it
try:
with open(args.inputFileName) as fileHandle:
fileBytes = bytearray(fileHandle.read())
fileHandle.close()
print color("[*] File [{}] successfully loaded !".format(args.inputFileName))
except IOError:
print color("[!] Could not open or read file [{}]".format(args.inputFileName))
quit()
print color("[*] Input length: [{}] bytes".format(len(fileBytes)))
#------------------------------------------------------------------------
# First transformation: should the input file be encrypted ?
if args.cryptoAlgorithm:
if not args.key:
print color("[!] Missing argument 'key' for the encryption algorithm")
quit()
if args.cryptoAlgorithm == 'xor':
print color("[*] Performing XOR encryption of the input file with key [{}]".format(args.key))
transformed1 = xor(fileBytes, args.key)
print color("[+] File XOR encrypted")
elif args.cryptoAlgorithm == 'aes':
# Derive a 16 bytes (128 bits) master key from the provided key
key = pyscrypt.hash(args.key, "saltmegood", 1024, 1, 1, 16)
print color("[*] Performing AES encryption of the input file")
iv, transformed1 = aesEncrypt(fileBytes, key)
print color("[+] File AES encrypted with IV [{}] and Key [{}]".format(b64encode(iv),b64encode(key)))
elif args.cryptoAlgorithm == 'rc4':
rc4Encryptor = RC4(args.key)
print color("[*] Performing RC4 encryption of the input file with key [{}]".format(args.key))
transformed1 = rc4Encryptor.binaryEncrypt(fileBytes)
print color("[+] File RC4 encrypted")
else:
print color("[*] Bypassing encryption")
transformed1 = str(fileBytes)
#------------------------------------------------------------------------
# Second transformation
if args.format:
if args.format == 'b64':
print color("[*] Formating output as base64 encoding")
transformed2 = b64encode(transformed1)
elif args.format == 'cpp':
print color("[*] Formating output as a C++ variable representation")
transformed2 = formatCPP(transformed1)
elif args.format == 'cs':
print color("[*] Formating output as a C# variable representation")
transformed2 = formatCSharp(transformed1)
elif args.format == 'py':
print color("[*] Formating output as a Python variable representation")
transformed2 = formatPy(transformed1)
elif args.format == 'vba':
print color("[*] Formating output as VBA variable representation")
transformed2 = formatVBA(transformed1)
elif args.format == 'vba2':
print color("[*] Formating output as VB body representation")
transformed2 = formatVBA2(transformed1)
elif args.format == 'xlm':
print color("[*] Formating output as XLM cells representation")
transformed2 = formatXLM(transformed1)
print color("[+] Output formating done")
else:
transformed2 = transformed1
#------------------------------------------------------------------------
# Finally, write output to stdout of to a file
if args.outputFileName:
try:
with open(args.outputFileName, 'w+') as fileHandle:
fileHandle.write(transformed2)
fileHandle.close()
print color("[+] Output file [{}] saved successfully".format(args.outputFileName))
except IOError:
print color("[!] Could not write file [{}]".format(args.outputFileName))
else:
print transformed2
print color("[*] Output length: [{}]".format(len(transformed2)))
else:
parser.print_help()
print color("\nExample: ./{} -i myFile -e xor -k myKey -cs -o outputFile\n".format(os.path.basename(__file__)),"green")
@shtry
Copy link

shtry commented Jan 17, 2021

Hello @Arno0x

I get an error.

python3 transformFile.py -i shellcode.bin -f xlm
  File "transformFile.py", line 166
    if string.strip().startswith("[!]"):
                                       ^
TabError: inconsistent use of tabs and spaces in indentation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment