Skip to content

Instantly share code, notes, and snippets.

@commiebstrd
Last active March 23, 2022 21:03
Show Gist options
  • Save commiebstrd/5da4b4fb61418f924dabe8b0d40494e7 to your computer and use it in GitHub Desktop.
Save commiebstrd/5da4b4fb61418f924dabe8b0d40494e7 to your computer and use it in GitHub Desktop.
encode shellcode from a sentence or byte array
#!env python3
# -*- coding: utf-8 -*-
import sys
import string
import logging
from random import randint
from pprint import pprint
def get_random(val, max):
if val == None:
return randint(0, max)
tmp = randint(0, max)
# shouldnt happen often
while tmp == val: # keep looping until we get a different index
tmp = randint(0, max)
return tmp
def encode_byte_additive(sentence, sc_byte, previous=0, random=True):
logging.debug(f" finding for byte: {sc_byte}")
idx = get_random(0, len(sentence)-1) if random else previous
byte_offsets = [] # single list of offsets to sentence
offset_total = 0 # allow this to grow as needed
# check first byte of offset instead of whole, allow for multiple overflows
while (off_byte := offset_total.to_bytes(4, 'little')[0]) != sc_byte:
dbg_str = ""
if idx >= len(sentence):
idx = 0
if isinstance(sentence[idx], str):
char_val = ord(sentence[idx])
else:
char_val = sentence[idx] # expect bytes/int
tmp_val = off_byte + char_val # should NEVER be over 2 bytes
if tmp_val == sc_byte:
dbg_str += f" found final idx at {idx}"
# handle overflows, should be under total desired
elif tmp_val > 0xff and tmp_val-0xff < sc_byte:
dbg_str += f" adding idx with overflow at {idx}"
# now what should be most cases, additions being lower than total
elif tmp_val < 0xff and sc_byte <= 0x41 and sc_byte < tmp_val:
dbg_str += f" adding larger but not overflowing at {idx}"
elif tmp_val < sc_byte:
dbg_str += f" adding idx at {idx}"
else:
# nothing good matched, new index and continue, skip storage
#idx = get_random(idx, len(sentence))
idx += 1
continue
# store and prep for next loop when found
byte_offsets.append(idx)
offset_total += char_val
idx = get_random(0, len(sentence)-1) if random else idx + 1
logging.debug(f"{dbg_str}, with total={offset_total:X}")
return byte_offsets
def encode_byte_absolute(sentence, sc_byte, previous=0, random=True):
logging.debug(f" finding for byte: {sc_byte}")
byte_offsets = [] # single list of offsets to sentence
offset_total = 0 # allow this to grow as needed
while (off_byte := offset_total.to_bytes(4, 'little')[0]) != sc_byte:
idx = get_random(0, len(sentence)-1) if random else previous
dbg_str = f" Using idx:{idx} "
try:
if isinstance(sentence[idx], str):
char_val = ord(sentence[idx])
else:
char_val = sentence[idx] # expect bytes/int
except:
print(idx)
sys.exit(1)
pos = (offset_total + char_val).to_bytes(4, 'little')[0]
neg = abs(offset_total - char_val).to_bytes(4, 'little')[0]
dbg_str += f"val:{char_val} = {pos}(pos), {neg}(neg)"
# find actual match
if pos == sc_byte:
byte_offsets.append(idx)
break
elif neg == sc_byte:
byte_offsets.append(-idx) # use negative indexes to show sub
break
# determine best fit
if pos < sc_byte:
if neg < sc_byte: # both over desired
if pos < neg: # closest is smaller value
byte_offsets.append(-idx) # negative is closer
offset_total = neg
dbg_str += " - using neg"
else: # pos >= neg
byte_offsets.append(idx)
offset_total = pos
dbg_str += " - using pos"
else: # neg > sc_bytes
pos_abs = sc_byte - pos
neg_abs = neg - sc_byte
if pos_abs <= neg_abs:
byte_offsets.append(idx) # positive is better fit
offset_total = pos
dbg_str += " - using pos"
else: # pos_abs > neg_abs
byte_offsets.append(-idx)
offset_total = neg
dbg_str += " - using neg"
else: # sc_byte < pos
if sc_byte < neg:
if neg < pos:
byte_offsets.append(-idx) # negative is closer
offset_total = neg
dbg_str += " - using neg"
else:
byte_offsets.append(idx)
offset_total = pos
dbg_str += " - using pos"
else: # neg < sc_byte
pos_abs = pos - sc_byte
neg_abs = sc_byte - neg
if pos_abs <= neg_abs:
byte_offsets.append(idx) # positive is better fit
offset_total = pos
dbg_str += " - using pos"
else: # pos_abs > neg_abs
byte_offsets.append(-idx)
offset_total = neg
dbg_str += " - using neg"
logging.debug(dbg_str)
previous = idx + 1 if previous < len(sentence)-1 else 0
return byte_offsets
def encode(sentence, shellcode, fn, attempts=5, random=True):
'''
args:
sentence - str or byte array of values to look through
shellcode - byte array of shellcode to transcribe
fn - function doing search method through sentence variable
attempts - if random, how many times to try fn and find shortest
- if not random, length to iterate through sentence
random - if true, uses random locations in sentence each call of fn
- if false, starts at 0
returns:
list of lists, index of outer list is for each shellcode byte, inner is result of encoder
'''
logging.info(f"Encoding shellcode[{len(shellcode)}] with sentence[{len(sentence)}] using {fn.__name__}")
offsets = [] # really a list of lists
for sc_byte in shellcode:
shortest = []
for _ in range(0, attempts):
byte_offsets = fn(sentence, sc_byte, random=random)
# end of while, append found offsets
if len(byte_offsets) < len(shortest):
shortest = byte_offsets
elif not shortest:
shortest = byte_offsets
logging.info(f" byte({sc_byte}) translated to len({len(shortest)})")
offsets.append(shortest)
return offsets
if __name__ == '__main__':
logging.basicConfig(format='%(message)s', encoding='utf-8', level=logging.INFO)
sentence = string.printable.encode('utf-8')
shellcode = [0xf9, 0x41, 0x1, 0x5, 0x15]
encoded = encode(sentence, shellcode, encode_byte_absolute, 1000)
print(f"shellcode[{len(shellcode)}][] = {{")
for idx,array in enumerate(encoded):
s = str(array)[1:-1]
print(f" {{ {str(array)[1:-1]} }}, // {shellcode[idx]}")
print("}")
#include<stdio.h>
#include<stdlib.h>
char sentence[] = "As he crossed toward the pharmacy at the corner he involuntarily turned his head because of a burst of light that had ricocheted from his temple, and saw, with that quick smile with which we greet a rainbow or a rose, a blindingly white parallelogram of sky being unloaded from the van—a dresser with mirrors across which, as across a cinema screen, passed a flawlessly clear reflection of boughs sliding and swaying not arboreally, but with a human vacillation, produced by the nature of those who were carrying this sky, these boughs, this gliding façade.";
int offsets[][] = {
{1,56,30},
{60,20,100}
};
int main(int argc, char** argv) {
uint8_t shellcode[] = (uint8_t *) malloc(2*sizeof(uint8_t)); // length offsets * 1
if shellcode <= 0x00 { // zero and neg are errors or undef
printf("Failed shellcode malloc!\n");
exit(1);
}
for (int off_idx=0; off_idx<2; off_idx+=1) { // length offsets
int byte_offsets[] = offsets[off_idx]; // temp reference
int total = 0;
// length of inner offset array for this byte translation
for (int off_inner=0, off_inner<sizeof(byte_offsets)/sizeof(int); off_inner+=1) {
total += (int) byte_offsets[off_inner]; // offsets[off_idx][off_inner]
}
// offset index and shellcode index are the same
shellcode[off_idx] = (uint8_t) (total & 0xff);
}
(void *) shellcode ();
}
@commiebstrd
Copy link
Author

encode() definitely needs some work on choosing best bytes, maybe looping through and storing closest match for a set period of randomly chosen words. still has issues with smaller byte values but a better sentence or multibyte unicode chars that allowed for single digits without non-printable ascii would probably be ideal

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