Browse Source

added block reordering

Marius Schwarz 4 years ago
parent
commit
7349611874
9 changed files with 436 additions and 43 deletions
  1. 2 0
      .gitignore
  2. 151 0
      Cargo.lock
  3. 4 2
      Cargo.toml
  4. 36 0
      README.md
  5. BIN
      img/block_reordering.png
  6. 1 1
      src/cpu_data/x64.rs
  7. 19 25
      src/encoder.rs
  8. 20 15
      src/main.rs
  9. 203 0
      src/reorder.rs

+ 2 - 0
.gitignore

@@ -1 +1,3 @@
 /target
+/test
+Makefile

+ 151 - 0
Cargo.lock

@@ -1,5 +1,156 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "capstone"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "capstone-sys 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.82 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "capstone-sys"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.82 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cmake"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.82 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasi 0.10.1+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "hex"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "keystone"
+version = "0.9.2"
+source = "git+https://github.com/keystone-engine/keystone#e1547852d9accb9460573eb156fc81645b8e1871"
+dependencies = [
+ "keystone-sys 0.9.2 (git+https://github.com/keystone-engine/keystone)",
+ "libc 0.2.82 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "keystone-sys"
+version = "0.9.2"
+source = "git+https://github.com/keystone-engine/keystone#e1547852d9accb9460573eb156fc81645b8e1871"
+dependencies = [
+ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.82 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rand"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.82 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_chacha 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_hc 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ppv-lite86 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "getrandom 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "shellc0der"
 version = "0.1.0"
+dependencies = [
+ "capstone 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "keystone 0.9.2 (git+https://github.com/keystone-engine/keystone)",
+ "rand 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "wasi"
+version = "0.10.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[metadata]
+"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+"checksum capstone 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f60e7f097987a09a9b678c6214b5a5eb326f9fc1e3eac88cce5d086c2b3b8dc9"
+"checksum capstone-sys 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aebe07897b48983847943662bfc3198aabfa51636c81313c1955d04d857ed739"
+"checksum cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
+"checksum cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+"checksum cmake 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)" = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855"
+"checksum getrandom 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4060f4657be78b8e766215b02b18a2e862d83745545de804638e2b545e81aee6"
+"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
+"checksum keystone 0.9.2 (git+https://github.com/keystone-engine/keystone)" = "<none>"
+"checksum keystone-sys 0.9.2 (git+https://github.com/keystone-engine/keystone)" = "<none>"
+"checksum libc 0.2.82 (registry+https://github.com/rust-lang/crates.io-index)" = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
+"checksum ppv-lite86 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+"checksum rand 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18519b42a40024d661e1714153e9ad0c3de27cd495760ceb09710920f1098b1e"
+"checksum rand_chacha 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
+"checksum rand_core 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5"
+"checksum rand_hc 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
+"checksum wasi 0.10.1+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9"

+ 4 - 2
Cargo.toml

@@ -1,5 +1,5 @@
 [package]
-name = "shellcodelab"
+name = "shellc0der"
 version = "0.1.0"
 authors = ["Marius Schwarz <marius.schwarz97@gmail.com>"]
 edition = "2018"
@@ -7,6 +7,8 @@ edition = "2018"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-keystone = { git = "https://github.com/tathanhdinh/keystone-rs" }
+keystone = { git = "https://github.com/keystone-engine/keystone"}
+capstone = "0.7.0"
 hex = "0.4.2"
 rand = "0.8.1"
+

+ 36 - 0
README.md

@@ -19,6 +19,39 @@ shellc0der -i <input.bin> -o <output.bin>
 
 ## Function
 
+This encoder supports several ways of changing the original shellcode:
+
+- Block Reordering
+- Payload Encoding
+- Instruction Substitution
+- Dead Code Insertion
+
+
+The _default_ functionality is the following:
+
+1) Divide the shellcode into blocks and reorder them
+2) Encode the full payload
+3) Generate unique decoder stub, insert dead code, switch instructions, ...
+4) Combine the stub and the encoded payload and write it to the output file
+
+
+## Block Reordering
+
+Block reordering works in the following way:
+
+1) Disassemble the payload (using capstone)
+2) Check for all JMP, Loop, JCC instructions and patch the destination by inserting newl generated labels
+3) Devide the instructions in blocks of X instructions each.
+4) The first and the last block stay the same
+5) The middle-blocks are randomly shuffled and glued together with `JMP` instructions
+
+It looks somewhat like that:
+
+![](img/block_reordering.png)
+
+
+## Payload Encoding
+
 The basic structure of the encoded shellcode looks like this:
 
 ![](img/structure.png)
@@ -31,8 +64,11 @@ The basic structure of the encoded shellcode looks like this:
 _Note:_ Every Block is a single byte
 
 2) A random decoder-stub is generated, that is setup in front of the encoded payload
+
 3) The registers used in the stub are randomly generated on each run
+
 4) Additionally, dead code snippets (random snippets & random # of snippets) are inserted into the stub
+
 5) Steps 1-4 can be repeated for arbitrary rounds, as seen below:
 
 ![](img/more_rounds.png)

BIN
img/block_reordering.png


+ 1 - 1
src/cpu_data/x64.rs

@@ -87,7 +87,7 @@ const DEAD_CODE_INSTRUCTIONS: [&str; 6] = [
 /// Generate an String of dead code
 pub fn generate_dead_code() -> String {
 
-    let mut blacklist = vec![Register::RSP, Register::RBP];
+    let blacklist = vec![Register::RSP, Register::RBP];
     // Output String
     let mut dead_code = String::new();
     let mut num_instructios = rand::random::<usize>() % 40;

+ 19 - 25
src/encoder.rs

@@ -6,7 +6,7 @@ use crate::cpu_data::x64;
 pub fn get_decoder_stub(seed: u8, payload_size: usize) -> Vec<u8> {
 
     // Maintain a blacklist for all the registers that are already used
-    let mut blacklist: Vec<x64::Register> = vec![x64::Register::RSP, x64::Register::RBP];
+    let mut blacklist: Vec<x64::Register> = vec![x64::Register::RSP, x64::Register::RBP, x64::Register::RDI];
 
     // generate a register for the COUNTER & add it to the blacklist
     let counter_register = x64::get_random_reg(&blacklist);
@@ -25,14 +25,13 @@ pub fn get_decoder_stub(seed: u8, payload_size: usize) -> Vec<u8> {
     let dc2 = x64::generate_dead_code();
 
     // Stub Prototype for x64
-    let stub = "{DEAD_CODE_1}\n\
+    let stub = "
     XOR {LENREG}, {LENREG}\n\
     XOR {KEYREG}, {KEYREG}\n\
     MOV {KEYREG},{K}\n\
     XOR {COUNTER}, {COUNTER}\n\
     MOV {LENREG},{S}\n\
     LEA RDI,[RIP+data]\n\
-    {DEAD_CODE_2}\n\
     decode:\n\
 	XOR BYTE [RDI+{COUNTER}*1],{KEYREG}\n\
         MOV {KEYREG}, [RDI+{COUNTER}*1]\n\
@@ -45,40 +44,35 @@ pub fn get_decoder_stub(seed: u8, payload_size: usize) -> Vec<u8> {
     let stub = stub.replace("{KEYREG}", &key_register.byte);
     let stub = stub.replace("{COUNTER}", &counter_register.full);
     let stub = stub.replace("{LENREG}", &length_register.full);
-    let stub = stub.replace("{K}", &seed.to_string());
-    let stub = stub.replace("{S}", &payload_size.to_string());
+    let stub = stub.replace("{K}", &format!("0x{:x}", seed));
+    let stub = stub.replace("{S}", &format!("0x{:x}", payload_size));
     let stub = stub.replace("{DEAD_CODE_1}", &dc1);
     let stub = stub.replace("{DEAD_CODE_2}", &dc2);
+
     // return the stub string
-    return assemble_asm(String::from(stub));
+    return assemble_asm(String::from(stub), OptionValue::SYNTAX_NASM).unwrap();
 }
 
 
 
-pub fn gen_dead_code() {
-
-    let dead_code = x64::generate_dead_code();
-    let assembled = assemble_asm(dead_code);
-
-    println!("{:?}", assembled);
-}
-
 /// The function uses capstone to assemble the stub and retrieve the raw bytes
-fn assemble_asm(stub: String) -> Vec<u8> {
+pub fn assemble_asm(stub: String, asm_syntax: OptionValue) -> Result<Vec<u8>, keystone::Error>  {
 
-    // Create the engine
-    let engine = Keystone::from(Arch::X86, Mode::Bit64)
-        .expect("Unable to initialize Keystone engine");
+    let engine = Keystone::new(Arch::X86, Mode::MODE_64)
+                .expect("Could not initialize Keystone engine");
 
-    // Set the Syntax to NASM (not Intel)
-    engine.option(OptionType::Syntax, OptionValue::SyntaxNasm)
-        .expect("Unable to set NASM syntax");
+    engine.option(OptionType::SYNTAX, asm_syntax)
+                .expect("Could not set option to nasm syntax");
 
     // Assemble the stub and return the bytes
-    let result = engine.asm(&stub, 0)
-        .expect("Unable to assemble");
-
-    result.encoding().to_vec()
+    let result = match engine.asm(stub, 0) {
+        Ok(v) => Ok(v.bytes),
+        Err(msg) => {
+            Err(msg)
+        }
+    };
+
+    return result;
 }
 
 /// This function does the plain shellcode encoding (XOR)

+ 20 - 15
src/main.rs

@@ -1,14 +1,12 @@
-//use std::io::{BufReader
 use hex;
 use rand;
-use std::fs::read_to_string;
 use std::fs::File;
 use std::io::{Write, Read};
 use std::io::{Seek, SeekFrom};
 use std::env;
 
-
 mod encoder;
+mod reorder;
 mod cpu_data;
 
 fn usage(args: &Vec<String>) {
@@ -18,12 +16,18 @@ fn usage(args: &Vec<String>) {
 
 fn main() {
 
-    let number_of_loops = 3;
+    let number_of_loops = 1;
 
     // Parsing the Arguments
     let args: Vec<String> = env::args().collect();
 
-    if args.len() != 5 {
+    // variable if code should be reordered
+    let mut reorder = false;
+    if args.contains(&"--reorder".to_string()) {
+        reorder = true;
+    }
+
+    if args.len() < 5 {
         usage(&args);
     }
 
@@ -36,7 +40,6 @@ fn main() {
     let output_file = &args[4];
 
 
-
     let mut shellcode = match File::open(input_file) {
         Ok(v) => v,
         Err(_) => {
@@ -53,11 +56,15 @@ fn main() {
 
     // Input Buffer for the shellcode
     let mut payload = vec![0; size as usize];
-    shellcode.read(&mut payload);
+    shellcode.read(&mut payload).unwrap();
 
-    // Output Buffer for the final Payload
-    let mut final_payload: Vec<u8> = Vec::new();
+    let prog = reorder::AsmProgram::new(&payload);
 
+    if reorder {
+         payload = prog.reorder();
+    }
+
+    // The Encoding Phase
     for i in 0..number_of_loops {
 
         println!("[*] Encoding Round {}", i);
@@ -75,21 +82,19 @@ fn main() {
         stub.append(&mut encoded_payload);
 
         // Set the [stub+payload] as the new raw payload
-        let payload = stub.clone();
+        payload = stub.clone();
     }
 
-
-    final_payload.append(&mut payload);
-
     //Write Payload to File:
     let mut file = match File::create(output_file) {
         Ok(v) => v,
         Err(_) => {
-            println!("[-] Cannot open Output File, exiting");
+            println!("[-] Cannot open Output File, outputting hex encoded payload:");
+            println!("{}", hex::encode(payload));
             std::process::exit(1);
         }
     };
-    file.write(&final_payload);
+    file.write(&payload).unwrap();
     println!("[+] Done, Generated encoded payload @ {}", output_file);
 
 }

+ 203 - 0
src/reorder.rs

@@ -0,0 +1,203 @@
+use rand::thread_rng;
+use rand::seq::IteratorRandom;
+use std::collections::HashMap;
+use crate::encoder;
+use capstone::prelude::*;
+use keystone::*;
+
+
+#[derive(Debug, Clone)]
+pub struct Instruction {
+    pub address: u64,
+    pub mnemonic: String,
+    pub operand: String
+}
+
+impl Instruction {
+
+    pub fn new(addr: u64, mnemonic: String, operand: String) -> Self {
+        Instruction {address: addr, mnemonic: mnemonic, operand: operand}
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct AsmProgram {
+    //pub instructions: HashMap<u64, Instruction>
+    pub instructions: Vec<Instruction>
+}
+
+impl AsmProgram {
+    pub fn new(bytecode: &Vec<u8>) -> Self {
+        let cs = Capstone::new()
+            .x86()
+            .mode(arch::x86::ArchMode::Mode64)
+            .syntax(arch::x86::ArchSyntax::Intel)
+            .detail(true)
+            .build()
+            .expect("Failed to create Capstone object");
+
+
+        let disas = cs.disasm_all(&bytecode, 0x0).unwrap();
+        let mut instructions: Vec<Instruction> = Vec::new();
+        for ins in disas.iter() {
+
+            let tmpins = Instruction::new(ins.address(),
+                                ins.mnemonic().unwrap().to_string(),
+                                ins.op_str().unwrap().to_string());
+            instructions.push(tmpins);
+        }
+
+        AsmProgram { instructions: instructions }
+    }
+
+    /// Output the ASM Instructions into a newline
+    /// separated string
+    pub fn to_string(&self) -> String {
+        // Map the instructions to a vector of strings
+        let s: Vec<String> = self.instructions.iter()
+            .map(|c| format!("{} {}", c.mnemonic, c.operand))
+            .collect();
+        // return the joined() version of the instructions
+        s.join("\n")
+    }
+
+    pub fn reorder(mut self) -> Vec<u8> {
+
+        println!("[+] Patching JMP/Loop/Call Instructions");
+        self.patch_jumps();
+        println!("[*] Reordering Blocks");
+        loop {
+            match self.reorder_blocks() {
+                Ok(v) => return v,
+                Err(v) => {
+                    match v.bits() {
+                        161 => {
+                            // KS_ERR_ASM_FIXUP_INVALID
+                            continue;
+                        }
+                        _ => {
+                            println!("[-] Failed to reorder blocks");
+                            std::process::exit(1);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    fn patch_jumps(&mut self) {
+
+        let mut label_ctr = 0;
+
+        // As we need to modify several items inside
+        let mut local_instructions = self.instructions.clone();
+        // to track the indizes into the local instructions
+
+        for instr in self.instructions.iter() {
+            // Check if the Instruction is a JMP instruction
+            if instr.mnemonic.chars().next().unwrap() == 'j'  || instr.mnemonic == "call" || instr.mnemonic == "loop" {
+
+                // If an JMP instruction is found,
+                // obtain the destination addrs and
+                // insert a label before the corresponding
+                // destination.
+
+                // First, check if the operand begins with `0x`, if not,
+                // the destination is a register
+                if !instr.operand.contains("0x") {
+                    // If the operand is a register, no action is needed as the value
+                    // should be set correctly anyway
+                    continue;
+                }
+                // else, the operand is parsed as u64
+                let wo_prefix = instr.operand.trim_start_matches("0x");
+                let jmp_destination = u64::from_str_radix(wo_prefix, 16).unwrap();
+
+                let new_label = format!("patched_jmp{}:", label_ctr);
+
+                // Get the position of the JMP destination in the instruction array
+                let local_jmp_pos = local_instructions.clone().iter().position(|c| c.address == jmp_destination).unwrap();
+
+                // Change the operand of the JMP instruction (JMP Label_{})
+                let pos_local = local_instructions.clone().iter().position(|c| c.address == instr.address).unwrap();
+                local_instructions[pos_local].operand = format!("patched_jmp{}", label_ctr);
+
+                // Create the patch
+                let new_instruction = Instruction::new(0, new_label, String::new());
+                local_instructions.insert(local_jmp_pos, new_instruction);
+
+                label_ctr += 1;
+            }
+        }
+
+        // replace the instance vector with the local vector
+        self.instructions = local_instructions;
+
+    }
+
+    /// Reorder the instructions
+    pub fn reorder_blocks(&self) -> Result<Vec<u8>, keystone::Error> {
+
+        let asm = self.to_string();
+
+        const INS_PER_BLOCK: usize = 6;
+
+
+        let instructions: Vec<String> = asm.split("\n").map(|c| c.to_string()).collect();
+
+
+        // Split in Chunks, (Vector of String Vectors)
+        let chunks: Vec<Vec<String>> = instructions.chunks(INS_PER_BLOCK).map(|c| c.to_vec()).collect();
+
+        let in_between_chunks = &chunks[1..chunks.len()-1];
+        let in_between_chunks = in_between_chunks.to_vec();
+
+
+        let mut hm: HashMap<String, Vec<String>> = HashMap::new();
+
+        let mut label_counter = 0;
+
+        for mut chunk in in_between_chunks {
+            chunk.insert(0, format!("label_{}:", label_counter));
+            chunk.push(format!("jmp label_{}", label_counter+1));
+            hm.insert(format!("label_{}", label_counter), chunk);
+            label_counter += 1;
+        }
+
+        let mut shuffled_payload: Vec<String> = Vec::new();
+        shuffled_payload.push(chunks[0].join("\n"));
+        shuffled_payload.push(format!("jmp label_0"));
+        //hm.shuffle(&mut thread_rng());
+
+
+        // Loop though the len of bloocks and choose a random block
+        for _ in 0..hm.len() {
+
+            // Get the labels of the blocks
+            let labels =  hm.keys().cloned();
+
+            // Choose a random label
+            let key = labels.choose(&mut thread_rng()).unwrap();
+
+            // Get the Instructions for that choosen label, generate string and
+            // Attach to the final, shuffled payload
+            let instructions = hm.get(&key).unwrap();
+            let instructions = instructions.join("\n");
+            shuffled_payload.push(instructions);
+
+            // Remove that key, as its already processe
+            hm.remove(&key);
+        }
+
+        let chunk_len = chunks.len();
+        shuffled_payload.push(format!("label_{}:", chunk_len-2));
+        shuffled_payload.push(chunks[chunk_len-1].join("\n"));
+
+        let asm_out = shuffled_payload.join("\n");
+
+        // return the assembled bytes
+        encoder::assemble_asm(asm_out, OptionValue::SYNTAX_INTEL)
+
+    }
+
+
+}