mirror of
https://github.com/nixpal/shellsilo
synced 2026-06-06 16:24:28 +00:00
2687 lines
109 KiB
Python
2687 lines
109 KiB
Python
#!/usr/bin/python3
|
|
import re
|
|
import string
|
|
import random
|
|
import json
|
|
import sys
|
|
from constants import dataTypes, dataTypes_x86, specialVars, type_map
|
|
from keystone import *
|
|
import readline
|
|
import csv
|
|
import platform
|
|
from rich.console import Console
|
|
from rich.table import Table
|
|
from rich.panel import Panel
|
|
from rich import box
|
|
from rich.progress import Progress, BarColumn, TimeRemainingColumn
|
|
from rich.panel import Panel
|
|
import time
|
|
import threading
|
|
import subprocess
|
|
import os
|
|
|
|
console = Console()
|
|
|
|
rst="\033[0;0m"
|
|
red = "\033[38;5;9m"
|
|
by="\033[38;5;3m"
|
|
y = "\033[1;33m"
|
|
b="\033[38;5;27m"
|
|
p="\033[1;33;35m"
|
|
c="\033[38;5;6m"
|
|
w="\033[38;5;7m"
|
|
o="\033[38;5;202m"
|
|
lb="\033[38;5;117m"
|
|
g="\033[38;5;2m"
|
|
checkMark = u'\u2705'
|
|
crossMark = u'\u2715'
|
|
|
|
pure_red = "\033[0;31m"
|
|
dgr = "\033[0;32m"
|
|
orange = "\033[0;33m"
|
|
dark_blue = "\033[0;34m"
|
|
bright_purple = "\033[0;35m"
|
|
dark_cyan = "\033[0;36m"
|
|
dulw = "\033[0;37m"
|
|
publk = "\033[0;30m"
|
|
bright_red = "\033[0;91m"
|
|
light_green = "\033[0;92m"
|
|
yellow = "\033[0;93m"
|
|
yellow = "\033[1;33m"
|
|
bright_blue = "\033[0;94m"
|
|
magenta = "\033[0;95m"
|
|
light_cyan = "\033[0;96m"
|
|
brblk = "\033[0;90m"
|
|
bright_white = "\033[0;97m"
|
|
cyan_back = "\033[0;46m"
|
|
purple_back = "\033[0;45m"
|
|
white_back = "\033[0;47m"
|
|
blue_back = "\033[0;44m"
|
|
orange_back = "\033[0;43m"
|
|
green_back = "\033[0;42m"
|
|
pink_back = "\033[0;41m"
|
|
grey_back = "\033[0;40m"
|
|
grey = '\033[38;4;236m'
|
|
bold = "\033[1m"
|
|
underline = "\033[4m"
|
|
italic = "\033[3m"
|
|
darken = "\033[2m"
|
|
invisible = '\033[08m'
|
|
reverse_colour = '\033[07m'
|
|
grey = "\x1b[90m"
|
|
|
|
structs = []
|
|
hiddenstructs = []
|
|
mainVars = []
|
|
ebpVars = []
|
|
mainStructs = []
|
|
finalAssembly = []
|
|
allLoops = [None]
|
|
loopDetected = [False]
|
|
breakDetected = [False]
|
|
ifDetected = [False]
|
|
breakData = [None]
|
|
win10Checked = True
|
|
win11Checked = False
|
|
x64 = False
|
|
nasm = True
|
|
masm = False
|
|
dataSection = False
|
|
generateBinaryFile = False
|
|
funcCalls = {}
|
|
syscallsAndApiNum = {}
|
|
assemblyAndComments = []
|
|
|
|
def run_with_progress(operationType=None, taskArg=None):
|
|
result = []
|
|
exception = []
|
|
try:
|
|
with Progress(
|
|
"[progress.description]{task.description}",
|
|
BarColumn(),
|
|
"[progress.percentage]{task.percentage:>3.0f}%",
|
|
TimeRemainingColumn()
|
|
) as progress:
|
|
task = progress.add_task("Processing", total=100)
|
|
def readFileWithProgress():
|
|
try:
|
|
res = taskArg.readFile()
|
|
if res:
|
|
result.append("Operation successful")
|
|
else:
|
|
exception.append("Operation failed")
|
|
except Exception as e:
|
|
exception.append(e)
|
|
raise
|
|
def run_command(command):
|
|
try:
|
|
cmdResult = subprocess.run(
|
|
command,
|
|
check=True,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
text=True
|
|
)
|
|
result.append("Operation successful")
|
|
#if cmdResult.stdout:
|
|
#print("Output:", cmdResult.stdout)
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"failed!")
|
|
print("Error:", e.stderr)
|
|
exception.append("Operation failed")
|
|
raise
|
|
|
|
if operationType and operationType == "readfile":
|
|
thread = threading.Thread(target=readFileWithProgress)
|
|
thread.start()
|
|
elif operationType and operationType == "run":
|
|
thread = threading.Thread(target=run_command(taskArg))
|
|
thread.start()
|
|
|
|
while thread.is_alive():
|
|
progress.update(task, advance=1)
|
|
time.sleep(0.05)
|
|
|
|
if progress.tasks[0].percentage > 95:
|
|
progress.update(task, advance=0.1)
|
|
|
|
thread.join()
|
|
progress.update(task, completed=100) # Force 100% at end
|
|
|
|
# Result display
|
|
if exception:
|
|
console.print(f"[red]✗ Error: {exception[0]}[/red]")
|
|
return False
|
|
else:
|
|
console.print(f"[green]✓ {result[0]}[/green]")
|
|
return True
|
|
except Exception as e:
|
|
raise
|
|
|
|
class ContextCompleter:
|
|
def __init__(self):
|
|
self.commands = ['generate', 'load', 'help', 'exit', 'quit', 'set', 'enable']
|
|
self.command_args = {
|
|
'generate': ['assembly', 'shellcode', 'binary'],
|
|
'enable':['data'],
|
|
'set':['arch', 'assembler'],
|
|
'arch':['x64', 'x86'],
|
|
'assembler':['nasm', 'masm']
|
|
}
|
|
|
|
def complete(self, text, state):
|
|
line_org = readline.get_line_buffer()
|
|
tokens = re.split(r'(\s+)', line_org)
|
|
line = [token for token in tokens if token]
|
|
#line = readline.get_line_buffer().split()
|
|
#print("Length: ", len(line), line, "text: ", text)
|
|
if len(line) == 0:
|
|
possible_commands = [cmd for cmd in self.commands if cmd.startswith(text)]
|
|
if state < len(possible_commands):
|
|
return possible_commands[state]
|
|
|
|
if len(line) == 1:
|
|
options = [cmd for cmd in self.commands if cmd.startswith(text)]
|
|
if state < len(options):
|
|
return options[state]
|
|
|
|
if len(line) > 1:
|
|
if line[-1] == " ":
|
|
command = line[-2]
|
|
options = [arg for arg in self.command_args[command] if arg.startswith(text)]
|
|
if state < len(options):
|
|
return options[state]
|
|
else:
|
|
command = line[-1]
|
|
if command in self.command_args:
|
|
options = [arg for arg in self.command_args[command] if arg.startswith(text)]
|
|
if state < len(options):
|
|
return options[state]
|
|
else:
|
|
line = line[:-2]
|
|
command = line[-1]
|
|
options = [arg for arg in self.command_args[command] if arg.startswith(text)]
|
|
if state < len(options):
|
|
return options[state]
|
|
|
|
return None
|
|
|
|
class Structs:
|
|
def __init__(self):
|
|
self.Lines = []
|
|
self.Name = ''
|
|
self.Pointer = ''
|
|
|
|
self.totalSize = 0
|
|
self.Members = []
|
|
|
|
class Vars:
|
|
def __init__(self):
|
|
self.Name = ''
|
|
self.Type = ''
|
|
self.Value = ''
|
|
self.instance = ''
|
|
self.unicode = ''
|
|
self.assignedTo = ''
|
|
self.assigned = False
|
|
self.Size = 0
|
|
self.Length = 0
|
|
|
|
class Asm:
|
|
def __init__(self):
|
|
self.stackStart = 0x4
|
|
self.stackSize = 0x2000
|
|
self.assembly = ""
|
|
self.masm = ""
|
|
self.nasm = ""
|
|
self.dotData = ""
|
|
self.shellcode = ""
|
|
self.registers = {
|
|
"RAX":None,
|
|
"RBX":None,
|
|
"RCX":None,
|
|
"RDX":None,
|
|
"RSI":None,
|
|
"RDI":None,
|
|
"RBP":None,
|
|
"RSP":None,
|
|
"R8":None,
|
|
"R9":None,
|
|
"R10":None,
|
|
"R11":None,
|
|
"R12":None,
|
|
"R13":None,
|
|
"R14":None,
|
|
"R15":None
|
|
}
|
|
|
|
class whileLoop:
|
|
def __init__(self):
|
|
self.loopStart = None
|
|
self.loopEnd = None
|
|
|
|
|
|
class Reader:
|
|
def __init__(self, file):
|
|
self.file = file
|
|
asmObj = Asm()
|
|
|
|
def addUnicodeStr(self, ptrName, structName, structVal):
|
|
unicodeVal = structVal["u"]
|
|
return self.pushAscii(unicodeVal)
|
|
|
|
def assemblerDataSection(self):
|
|
asm = "global _start\n"
|
|
asm += "section .text\n"
|
|
asm += "_start:\n"
|
|
if nasm:
|
|
ds = "section .data\n"
|
|
elif masm:
|
|
ds = ".data\n"
|
|
ds += self.asmObj.dotData
|
|
ds += asm
|
|
return ds
|
|
|
|
def testShellcode(self, assembly):
|
|
assembly_lines = assembly.strip().split('\n')
|
|
for i, line in enumerate(assembly_lines):
|
|
try:
|
|
if x64:
|
|
ks = Ks(KS_ARCH_X86, KS_MODE_64)
|
|
else:
|
|
ks = Ks(KS_ARCH_X86, KS_MODE_32)
|
|
encoding, count = ks.asm(line)
|
|
if not encoding:
|
|
print(f"Didn't like this instruction: {y}{line}{rst}")
|
|
except Exception as e:
|
|
print(f"Error on line {i + 1}: {line}")
|
|
print(f"Error message: {e}")
|
|
|
|
|
|
def asm2Shellcode(self, assembly):
|
|
#self.testShellcode(assembly)
|
|
allText = ""
|
|
allText += f"\t\t {y}**********************\n"
|
|
allText += f"\t\t *****{o} Shellcode{y} ******\n"
|
|
allText += f"\t\t {y}**********************{rst}\n\n"
|
|
if x64:
|
|
ks = Ks(KS_ARCH_X86, KS_MODE_64)
|
|
else:
|
|
ks = Ks(KS_ARCH_X86, KS_MODE_32)
|
|
try:
|
|
if not dataSection:
|
|
encoding, _ = ks.asm(assembly)
|
|
opcode_hex = "".join(f"\\x{byte:02x}" for byte in encoding)
|
|
bytes_per_line = 16
|
|
allText += '\n'.join(opcode_hex[i:i + bytes_per_line * 4] for i in range(0, len(opcode_hex), bytes_per_line * 4))
|
|
allText += '\n'
|
|
except KsError as e:
|
|
print(f"[!] Shellcode generation failed")
|
|
except Exception as e:
|
|
print(f"[!] Shellcode generation failed")
|
|
|
|
return allText
|
|
|
|
def findEbpVar(self, value):
|
|
for ebp in ebpVars:
|
|
if value in ebp:
|
|
return ebp
|
|
return False
|
|
|
|
def sizeOf(self, data):
|
|
found = re.search(r'sizeof\(("?[^"]+"?)\)', data)
|
|
if found:
|
|
extracted = found.group(1)
|
|
foundVal = self.getValueType(extracted)
|
|
if foundVal == "int":
|
|
return hex(4)
|
|
elif foundVal == "string":
|
|
return hex(len(extracted.replace('"', '')))
|
|
elif foundVal == "variable" and extracted == "int":
|
|
return hex(4)
|
|
elif foundVal == "variable" and extracted == "char":
|
|
return hex(1)
|
|
elif foundVal == "variable" and (extracted != "int" or extracted != "char"):
|
|
varVal = self.getVarValue(extracted)
|
|
if varVal:
|
|
if "\\x" in varVal:
|
|
try:
|
|
varVal = varVal.replace("\\x", "").replace('"', '')
|
|
raw_bytes = bytes.fromhex(varVal)
|
|
return hex(len(raw_bytes))
|
|
except Exception as e:
|
|
print(e)
|
|
return hex(len(varVal.replace('"', '')))
|
|
else:
|
|
print(f"{red}Error: variable {extracted} doesn't exist.{rst}")
|
|
print(f"{w}Error on: {data}{rst}")
|
|
sys.exit()
|
|
else: return None
|
|
|
|
|
|
def rawBytesFormat(self, bytes_list, label=None, bytes_per_line=10):
|
|
try:
|
|
if not bytes_list:
|
|
return ""
|
|
hex_parts = []
|
|
for b in bytes_list:
|
|
hex_parts.append(f"0{b:02x}h") # MASM: 0AAh
|
|
|
|
chunks = [hex_parts[i:i+bytes_per_line]
|
|
for i in range(0, len(hex_parts), bytes_per_line)]
|
|
asm_lines = []
|
|
for i, chunk in enumerate(chunks):
|
|
if i == 0:
|
|
asm_lines.append(f"{label} db {', '.join(chunk)}")
|
|
else:
|
|
asm_lines.append(f" db {', '.join(chunk)}")
|
|
|
|
if len(bytes_list) > 20:
|
|
asm_lines.insert(0, f"; {len(bytes_list)} bytes")
|
|
asm = "\n".join(asm_lines)
|
|
return asm
|
|
except Exception as e:
|
|
raise
|
|
return None
|
|
|
|
def newVarAssm(self, Type, name, value, size):
|
|
varEbpDict = self.findEbpVar(name)
|
|
varEbpVal = None
|
|
assignedEbpVal = None
|
|
if varEbpDict:
|
|
varEbpVal = varEbpDict[name]
|
|
else:
|
|
if Type == "newVarAdd" or Type == "newVarSub":
|
|
print(f"{red}Error: could not find var {name}, did you forget to define it ?{rst}")
|
|
sys.exit()
|
|
|
|
currentStack = self.asmObj.stackStart
|
|
allTypes = dataTypes if x64 else dataTypes_x86
|
|
resVal = self.getValueType(value)
|
|
asm = ""
|
|
string = None
|
|
rawbytes = None
|
|
bytes_list = []
|
|
if resVal == "int":
|
|
value = hex(int(value))
|
|
elif resVal == "hex":
|
|
value = hex(int(value, 16))
|
|
elif resVal == "string":
|
|
pushedStr = self.pushString(value)
|
|
string = pushedStr
|
|
asm += pushedStr
|
|
elif resVal == "sizeof":
|
|
value = self.sizeOf(value)
|
|
elif resVal == "raw":
|
|
try:
|
|
rawbytes = True
|
|
hex_bytes = re.findall(r'\\x([0-9a-fA-F]{2})', value)
|
|
for seq in hex_bytes:
|
|
bytes_list.append(int(seq, 16))
|
|
dotDataBytes = self.rawBytesFormat(bytes_list, name, 10)
|
|
self.asmObj.dotData = f"{dotDataBytes}\n"
|
|
except Exception as e:
|
|
raise
|
|
|
|
else:
|
|
rtnDict = self.findEbpVar(value)
|
|
if rtnDict:
|
|
assignedEbpVal = rtnDict[value]
|
|
if value in specialVars:
|
|
value = specialVars[value]
|
|
for var in mainVars:
|
|
if name == var.Name:
|
|
size = var.Size
|
|
dType = type_map.get(hex(int(size)))
|
|
#if size == 4:
|
|
# dType = "dword"
|
|
#elif size == 2:
|
|
# dType = "word"
|
|
#elif size == 1:
|
|
# dType == "byte"
|
|
#else:
|
|
# print(f"Not found: {size}{var.Name}")
|
|
if x64:
|
|
size = 8
|
|
dType = "qword"
|
|
if string:
|
|
if x64:
|
|
dType = "qword"
|
|
assmLine = f" mov {y+dType+rst} ptr[rbp-{hex(currentStack)}], rbx"
|
|
else:
|
|
assmLine = f" mov {y+dType+rst} ptr[ebp-{hex(currentStack)}], ebx"
|
|
asm += "{:60s};{}={}".format(assmLine,lb+name,value+rst)
|
|
elif rawbytes:
|
|
if x64:
|
|
dType = "qword"
|
|
if masm:
|
|
if dataSection:
|
|
assmLine = f" lea rax, {name}\n"
|
|
assmLine += f" mov {y+dType+rst} ptr[rbp-{hex(currentStack)}], rax"
|
|
else:
|
|
assmLine = f";;; lea rax, {name}\n"
|
|
assmLine += f";;; mov {y+dType+rst} ptr[rbp-{hex(currentStack)}], rax"
|
|
elif nasm:
|
|
if dataSection:
|
|
assmLine = f" lea rax, [rel {name}]\n"
|
|
assmLine += f" mov {y+dType+rst} ptr[rbp-{hex(currentStack)}], rax"
|
|
else:
|
|
assmLine = f";;; lea rax, [rel {name}]\n"
|
|
assmLine += f";;; mov {y+dType+rst} ptr[rbp-{hex(currentStack)}], rax"
|
|
else:
|
|
print("[!] Error: Assembler not set")
|
|
sys.exit()
|
|
|
|
else:
|
|
if dataSection:
|
|
assmLine = f" lea eax, {name}\n"
|
|
assmLine += f" mov {y+dType+rst} ptr[ebp-{hex(currentStack)}], eax"
|
|
else:
|
|
assmLine = f";;; lea eax, {name}\n"
|
|
assmLine += f";;; mov {y+dType+rst} ptr[ebp-{hex(currentStack)}], eax"
|
|
|
|
|
|
asm += "{:87s};{}".format(assmLine,lb+name+rst)
|
|
else:
|
|
if Type == "newVarAdd" and varEbpVal:
|
|
if assignedEbpVal:
|
|
if x64:
|
|
dType = "qword"
|
|
assmLine = f" mov rbx, qword ptr[{assignedEbpVal}]"
|
|
asm += "{:47s};{}\n".format(assmLine,lb+name+rst)
|
|
assmLine = f" add {y+dType+rst} ptr[{varEbpVal}], rbx"
|
|
else:
|
|
assmLine = f" mov ebx, dword ptr[{assignedEbpVal}]"
|
|
asm += "{:47s};{}\n".format(assmLine,lb+name+rst)
|
|
assmLine = f" add {y+dType+rst} ptr[{varEbpVal}], ebx"
|
|
asm += "{:60s}".format(assmLine)
|
|
else:
|
|
assmLine = f" add {y+dType+rst} ptr[{varEbpVal}], {value}"
|
|
asm += "{:60s};{}".format(assmLine,lb+name+rst)
|
|
elif Type == "newVarSub" and varEbpVal:
|
|
if assignedEbpVal:
|
|
if x64:
|
|
dType = "qword"
|
|
assmLine = f" mov rbx, qword ptr[{assignedEbpVal}]"
|
|
asm += "{:47s};{}\n".format(assmLine, lb+name+rst)
|
|
assmLine = f" sub {y+dType+rst} ptr[{varEbpVal}], rbx"
|
|
else:
|
|
assmLine = f" mov ebx, dword ptr[{assignedEbpVal}]"
|
|
asm += "{:47s};{}\n".format(assmLine, lb+name+rst)
|
|
assmLine = f" sub {y+dType+rst} ptr[{varEbpVal}], ebx"
|
|
asm += "{:60s}".format(assmLine)
|
|
else:
|
|
assmLine = f" sub {y+dType+rst} ptr[{varEbpVal}], {value}"
|
|
asm += "{:60s};{}".format(assmLine,lb+name+rst)
|
|
else:
|
|
if varEbpVal: # if the assigned var (left side) exists already
|
|
if assignedEbpVal: # if the right side is a variable
|
|
if x64:
|
|
dType = "qword"
|
|
assmLine = f" mov rbx, qword ptr[{assignedEbpVal}]"
|
|
asm += "{:60s}\n".format(assmLine)
|
|
assmLine = f" mov {y+dType+rst} ptr[{varEbpVal}], rbx"
|
|
else:
|
|
assmLine = f" mov ebx, dword ptr[{assignedEbpVal}]"
|
|
asm += "{:60s}\n".format(assmLine)
|
|
assmLine = f" mov {y+dType+rst} ptr[{varEbpVal}], ebx"
|
|
asm += "{:60s};{}\n".format(assmLine,lb+name+rst)
|
|
else:
|
|
assmLine = f" mov {y+dType+rst} ptr[{varEbpVal}], {value}"
|
|
asm += "{:60s};{}".format(assmLine,lb+name+rst)
|
|
else:
|
|
if x64:
|
|
## assigning a value to a variable
|
|
assmLine = f" mov {y+dType+rst} ptr[rbp-{hex(currentStack)}], {value}"
|
|
else:
|
|
assmLine = f" mov {y+dType+rst} ptr[ebp-{hex(currentStack)}], {value}"
|
|
asm += "{:60s};{}".format(assmLine,lb+name+rst)
|
|
|
|
if varEbpVal:
|
|
assignedEbp = f"{varEbpVal}"
|
|
else:
|
|
if x64:
|
|
assignedEbp = f"rbp-{hex(currentStack)}"
|
|
else:
|
|
assignedEbp = f"ebp-{hex(currentStack)}"
|
|
self.asmObj.stackStart += size
|
|
ebpDict = {var.Name:assignedEbp,
|
|
"value":value,
|
|
"type":dType}
|
|
ebpVars.append(ebpDict)
|
|
return(asm)
|
|
|
|
def invokeSysCall(self):
|
|
asm = ""
|
|
if x64:
|
|
asm += f" mov r10, rcx\n"
|
|
asm += f" mov rax, rdi ; assume syscall number in rdi\n"
|
|
asm += f" call {lb}invokeSysCall{rst}\n"
|
|
else:
|
|
asm += f" mov eax, ecx ; assume syscall number in ecx\n"
|
|
asm += f" call {lb}invokeSysCall{rst}\n"
|
|
return asm
|
|
|
|
|
|
def getApiNumFromFile(self, funcName):
|
|
asm = ""
|
|
apiNumFromFile = readSysCalls(funcName, False, True)
|
|
if x64:
|
|
asm += f" mov rdi, {apiNumFromFile}\n"
|
|
else:
|
|
asm += f" mov edi, {apiNumFromFile}\n"
|
|
asm += f" call {lb}GetSysModelNumber{rst}\n"
|
|
return asm
|
|
|
|
def x64ParamAsm(self, idx, param):
|
|
asm = ""
|
|
## Assigning values to rcx, rdx, r8, r9
|
|
try:
|
|
param = str(param)
|
|
x64Mov = param.replace("dword", "qword")
|
|
if idx == 0:
|
|
asm += f" mov rcx, {x64Mov}"
|
|
elif idx == 1:
|
|
asm += f" mov rdx, {x64Mov}"
|
|
elif idx == 2:
|
|
asm += f" mov r8, {x64Mov}"
|
|
elif idx == 3:
|
|
asm += f" mov r9, {x64Mov}"
|
|
else:
|
|
asm += f" push {x64Mov}"
|
|
except Exception as e:
|
|
raise
|
|
return asm
|
|
|
|
|
|
def funcCallAssmHandler(self, stackAdjust, asm, funcName, assignedTo):
|
|
try:
|
|
apiNum = readSysCalls(funcName, False, True)
|
|
if apiNum:
|
|
syscallsAndApiNum.update({funcName:apiNum})
|
|
else:
|
|
print(f"Error: couldn't find api num from syscalls file")
|
|
asm += self.getApiNumFromFile(funcName)
|
|
asm += self.invokeSysCall()
|
|
if assignedTo:
|
|
for var in mainVars:
|
|
if var.Name == assignedTo:
|
|
if var.Value:
|
|
for ebp in ebpVars:
|
|
if var.Name in ebp:
|
|
ebpVal = ebp[var.Name]
|
|
if x64:
|
|
prepAsm = f" mov {lb}qword{rst} ptr[{ebpVal}], rax"
|
|
else:
|
|
prepAsm = f" mov {lb}dword{rst} ptr[{ebpVal}], eax"
|
|
asm += "{:64s};{} {}\n".format(prepAsm,lb+"save return value in",o+var.Name+rst)
|
|
else:
|
|
currentStack = self.asmObj.stackStart
|
|
if x64:
|
|
prepAsm = f" mov {y}qword{rst} ptr[rbp-{hex(currentStack)}], rax"
|
|
else:
|
|
prepAsm = f" mov {y}dword{rst} ptr[ebp-{hex(currentStack)}], eax"
|
|
asm += "{:64s};{} {}\n".format(prepAsm,lb+"save return value in",o+var.Name+rst)
|
|
if x64:
|
|
assignedEbp = f"rbp-{hex(currentStack)}"
|
|
var.Value = "RAX"
|
|
ebpDict = {var.Name:assignedEbp,
|
|
"value":"RAX",
|
|
"type":"dword"}
|
|
else:
|
|
assignedEbp = f"ebp-{hex(currentStack)}"
|
|
var.Value = "EAX"
|
|
ebpDict = {var.Name:assignedEbp,
|
|
"value":"EAX",
|
|
"type":"dword"}
|
|
if x64:
|
|
self.asmObj.stackStart += 0x8
|
|
else:
|
|
self.asmObj.stackStart += 0x4
|
|
if x64:
|
|
asm += f" add rsp, {hex(stackAdjust+32)}\n"
|
|
else:
|
|
asm += f" add esp, {hex(stackAdjust)}\n"
|
|
except Exception as e:
|
|
raise
|
|
return(asm)
|
|
|
|
def get_parameter_order(self, params):
|
|
if x64:
|
|
register_params = params[:4]
|
|
stack_params = params[4:][::-1] # Reverse only params 5+
|
|
return register_params + stack_params
|
|
else:
|
|
# x86 (32-bit): ALL params are pushed in reverse order
|
|
return params
|
|
|
|
def funcCallAssmX86(self, params, funcName, assignedTo):
|
|
params = self.get_parameter_order(params)
|
|
asm = ""
|
|
eaxAssm = ""
|
|
stackAdjust = 0
|
|
numberOfParams = len(params)
|
|
RCX = None
|
|
RDX = None
|
|
R8 = None
|
|
R9 = None
|
|
try:
|
|
for func in mainVars:
|
|
if func.Name == funcName:
|
|
for idx, param in enumerate(params if x64 else reversed(params)):
|
|
stackAdjust += 4
|
|
if param[0] != "&":
|
|
paramType = self.getValueType(param)
|
|
if paramType == "variable":
|
|
ebp = self.findEbpVar(param)
|
|
if ebp:
|
|
ebpOff = ebp[param]
|
|
ebpVal = ebp["value"]
|
|
if len(ebpVal) > 10 and "\\x" in ebpVal:
|
|
raw_bytes = ebpVal.encode('latin-1') if isinstance(ebpVal, str) else ebpVal
|
|
trim_bytes = raw_bytes[:10]
|
|
hex_str = ''.join([f'\\x{byte:02x}' for byte in trim_bytes])
|
|
hex_str += "# ...truncated"
|
|
ebpVal = hex_str
|
|
|
|
ebpType = ebp["type"]
|
|
reg = f"{y+ebpType+rst} ptr[{ebpOff}]"
|
|
if x64:
|
|
prepAsm = self.x64ParamAsm(idx, reg)
|
|
else:
|
|
prepAsm = f" push {y+ebpType+rst} ptr[{ebpOff}]"
|
|
#asm += "{:60s};{}:{}\n".format(prepAsm,lb+param,o+ebpVal+rst)
|
|
asm += "{:60s};{}:{}\n".format(prepAsm,lb+param,o+ebpVal+rst)
|
|
else:
|
|
if param in specialVars:
|
|
newParam = specialVars[param]
|
|
reg = f"{newParam}"
|
|
if x64:
|
|
prepAsm = self.x64ParamAsm(idx, newParam)
|
|
else:
|
|
prepAsm = f" push {newParam}"
|
|
asm += "{:47s};{}\n".format(prepAsm,lb+param+rst)
|
|
else:
|
|
newParam = self.reservedType(param)
|
|
if newParam != param:
|
|
newParam = hex(newParam)
|
|
if x64:
|
|
prepAsm = self.x64ParamAsm(idx,newParam)
|
|
else:
|
|
prepAsm = f" push {newParam}"
|
|
asm += "{:47s};{}\n".format(prepAsm,lb+param+rst)
|
|
else:
|
|
print(f"{red}Error: parameter {param} did not match any variable{rst}")
|
|
sys.exit()
|
|
|
|
elif paramType == "string":
|
|
isString = re.findall('"(.*)"', param)
|
|
if isString:
|
|
pushStr = isString[0]
|
|
strAsm = self.pushString(pushStr)
|
|
asm += strAsm
|
|
elif paramType == "int":
|
|
paramVal = hex(int(param))
|
|
if x64:
|
|
prepAsm = self.x64ParamAsm(idx, paramVal)
|
|
else:
|
|
prepAsm = f" push {paramVal}"
|
|
asm += "{:47s};{}\n".format(prepAsm,lb+param+rst)
|
|
elif paramType == "hex":
|
|
v = hex(int(param, 16))
|
|
if x64:
|
|
prepAsm = self.x64ParamAsm(idx, v)
|
|
else:
|
|
prepAsm = f" push {v}"
|
|
asm += "{:44s};{}\n".format(prepAsm,lb+param+rst)
|
|
elif paramType == "sizeof":
|
|
foundSizeOf, rtnVal = self.isSizeOf(param)
|
|
if foundSizeOf:
|
|
if self.isStruct(rtnVal):
|
|
paramVal = self.getStructSize(rtnVal)
|
|
if x64:
|
|
prepAsm = self.x64ParamAsm(idx, paramVal)
|
|
else:
|
|
prepAsm = f" push {paramVal}"
|
|
asm += "{:47s};{}\n".format(prepAsm,lb+param+rst)
|
|
else:
|
|
paramVal = self.sizeOf(param)
|
|
if x64:
|
|
prepAsm = self.x64ParamAsm(idx, paramVal)
|
|
else:
|
|
prepAsm = f" push {paramVal}"
|
|
asm += "{:47s};{}\n".format(prepAsm,lb+param+rst)
|
|
else:
|
|
if param in specialVars:
|
|
paramVal = specialVars[param]
|
|
if x64:
|
|
prepAsm = self.x64ParamAsm(idx, paramVal)
|
|
else:
|
|
prepAsm = f" push {paramVal}"
|
|
asm += "{:44s};{}\n".format(prepAsm,lb+param+rst)
|
|
|
|
else:
|
|
newParam = param.replace("&", "")
|
|
ebp = self.findEbpVar(newParam)
|
|
if ebp:
|
|
ebpOff = ebp[newParam]
|
|
ebpVal = ebp["value"]
|
|
ebpType = ebp["type"]
|
|
if x64:
|
|
prepAsm = f" lea rbx, {y+'qword'+rst} ptr[{ebpOff}]"
|
|
else:
|
|
prepAsm = f" lea ebx, {y+'dword'+rst} ptr[{ebpOff}]"
|
|
asm += "{:60s};{}:{}\n".format(prepAsm,lb+param,o+ebpVal+rst)
|
|
if x64:
|
|
prepAsm = self.x64ParamAsm(idx, "rbx")
|
|
asm += "{:60s}\n".format(prepAsm)
|
|
else:
|
|
asm += f" push ebx\n"
|
|
break
|
|
except Exception as e:
|
|
raise
|
|
if x64:
|
|
asm += " sub rsp, 0x20\n"
|
|
return self.funcCallAssmHandler(stackAdjust, asm, funcName, assignedTo)
|
|
|
|
|
|
|
|
def funcCallAssm(self, funcName, params, assignedTo):
|
|
asm = ""
|
|
try:
|
|
if funcName not in funcCalls:
|
|
asm += f"\n{lb+funcName+rst}:\n"
|
|
funcCalls.update({funcName:0})
|
|
else:
|
|
funcCallNum = funcCalls[funcName]
|
|
NewfuncName = f"{funcName}{funcCallNum+1}"
|
|
funcCalls.update({NewfuncName:funcCallNum+1})
|
|
asm += f"\n{lb+NewfuncName+rst}:\n"
|
|
result = self.funcCallAssmX86(params, funcName, assignedTo)
|
|
asm += result
|
|
except Exception as e:
|
|
raise
|
|
return asm
|
|
|
|
|
|
def structPtrAsm(self,ptr):
|
|
currentStack = self.asmObj.stackStart
|
|
asm = ""
|
|
ptrOffset = 0
|
|
pointerName = ""
|
|
for s in structs:
|
|
if s.Pointer == ptr:
|
|
pointerName = s.Name
|
|
if x64:
|
|
ptrOffset = f"rbp-{hex(currentStack)}"
|
|
else:
|
|
ptrOffset = f"ebp-{hex(currentStack)}"
|
|
ebpDict = {s.Pointer:ptrOffset,
|
|
"value":"0x0",
|
|
"type":"struct",
|
|
"members":[]}
|
|
members = s.Members
|
|
|
|
for mem in members:
|
|
for key, value in mem.items():
|
|
dType = type_map.get(hex(int(key)) if "0x" not in key else key)
|
|
#if key == "0x4":
|
|
# dType = "dword"
|
|
#elif key == "0x2":
|
|
# dType = "word"
|
|
#elif key == "0x1":
|
|
# dType = "byte"
|
|
#elif key == "0x8":
|
|
# dType = "qword"
|
|
ebpDict["members"].append({value:hex(currentStack)})
|
|
if x64:
|
|
prepAsm = f" mov {y+dType+rst} ptr[rbp-{hex(currentStack)}], 0x0"
|
|
else:
|
|
prepAsm = f" mov {y+dType+rst} ptr[ebp-{hex(currentStack)}], 0x0"
|
|
asm += "{:60s};{}\n".format(prepAsm, lb+value+rst)
|
|
if x64:
|
|
ptrOffset = f"rbp-{hex(currentStack)}"
|
|
else:
|
|
ptrOffset = f"ebp-{hex(currentStack)}"
|
|
currentStack += int(key, 16)
|
|
ebpVars.append(ebpDict)
|
|
self.asmObj.stackStart = currentStack
|
|
return asm,ptrOffset,pointerName
|
|
|
|
|
|
def checkStructPtr(self, st):
|
|
members = st.Members
|
|
for mem in members:
|
|
for key, value in mem.items():
|
|
if "->" in value:
|
|
structPtr = value.split("->")[1]
|
|
return True,structPtr
|
|
return False,None
|
|
|
|
def genStructAssembly(self, members, var, offset=None, ptrName=None):
|
|
v = var
|
|
asm = ""
|
|
finalAsm = ""
|
|
if v.instance != "":
|
|
v.Name = v.instance
|
|
if x64:
|
|
currStackPtr = f"rbp-{hex(self.asmObj.stackStart)}"
|
|
else:
|
|
currStackPtr = f"ebp-{hex(self.asmObj.stackStart)}"
|
|
ebpDict = {v.Name:currStackPtr,
|
|
"value":"0x0",
|
|
"type":"struct",
|
|
"members":[]}
|
|
tmpStackPtr = 0
|
|
try:
|
|
for mem in members:
|
|
for key, value in mem.items():
|
|
possibleArr = re.search(r'\[(\d+)\]', value)
|
|
if possibleArr:
|
|
ArrSize = possibleArr.group(1)
|
|
key = hex(int(key, 16) * int(ArrSize))
|
|
currentStack = self.asmObj.stackStart
|
|
if key == "0x4":
|
|
dType = "dword"
|
|
elif key == "0x2":
|
|
dType = "word"
|
|
elif key == "0x1":
|
|
dType = "byte"
|
|
elif key == "0x8":
|
|
dType = "qword"
|
|
else:
|
|
print(f"[!] Unknwon type")
|
|
ebpDict["members"].append({value:hex(currentStack)})
|
|
if x64:
|
|
tmpStackPtr = f"rbp-{hex(currentStack)}"
|
|
else:
|
|
tmpStackPtr = f"ebp-{hex(currentStack)}"
|
|
if "->" in value:
|
|
isInitialized = v.Value.replace(" ", "")
|
|
if "0" in isInitialized or "{0}" in isInitialized:
|
|
if x64:
|
|
prepAsm = f" mov {y}dword{rst} ptr[rbp-{hex(self.asmObj.stackStart)}], 0x0"
|
|
else:
|
|
prepAsm = f" mov {y}dword{rst} ptr[ebp-{hex(self.asmObj.stackStart)}], 0x0"
|
|
asm += "{:60s};{}\n".format(prepAsm, lb+"ptr:"+ptrName+rst)
|
|
else:
|
|
if x64:
|
|
prepAsm = f" lea rbx, {y}qword{rst} ptr[{offset}]"
|
|
asm += "{:60s};{}\n".format(prepAsm, lb+"ptr:"+ptrName+rst)
|
|
prepAsm = f" mov {y}qword{rst} ptr[rbp-{hex(self.asmObj.stackStart)}], rbx"
|
|
else:
|
|
prepAsm = f" lea ebx, {y}dword{rst} ptr[{offset}]"
|
|
asm += "{:60s};{}\n".format(prepAsm, lb+"ptr:"+ptrName+rst)
|
|
prepAsm = f" mov {y}dword{rst} ptr[ebp-{hex(self.asmObj.stackStart)}], ebx"
|
|
#asm += "{:60s};{}\n".format(prepAsm, lb+"ptr:"+ptrName+rst)
|
|
asm += "{:60s}\n".format(prepAsm)
|
|
self.asmObj.stackStart += int(key, 16)
|
|
else:
|
|
if "0" in v.Value or "null" in v.Value.lower():
|
|
if x64:
|
|
prepAsm = f" mov {y+dType+rst} ptr[rbp-{hex(self.asmObj.stackStart)}], 0x0"
|
|
else:
|
|
prepAsm = f" mov {y+dType+rst} ptr[ebp-{hex(self.asmObj.stackStart)}], 0x0"
|
|
asm += "{:60s};{}\n".format(prepAsm, lb+value+rst)
|
|
self.asmObj.stackStart += int(key, 16)
|
|
elif v.Value == "":
|
|
if x64:
|
|
prepAsm = f" mov {y+dType+rst} ptr[rbp-{hex(self.asmObj.stackStart)}], 0x0"
|
|
else:
|
|
prepAsm = f" mov {y+dType+rst} ptr[ebp-{hex(self.asmObj.stackStart)}], 0x0"
|
|
asm += "{:60s};{}\n".format(prepAsm, lb+value+rst)
|
|
self.asmObj.stackStart += int(key, 16)
|
|
except Exception as e:
|
|
raise
|
|
ebpDict[v.Name] = tmpStackPtr
|
|
ebpVars.append(ebpDict)
|
|
finalAsm += asm
|
|
return finalAsm
|
|
|
|
def structAssm(self, name, value):
|
|
asm = ""
|
|
finalAsm = ""
|
|
structOffset = None
|
|
for var in mainVars:
|
|
if var.Name == name:
|
|
for m in structs:
|
|
if m.Name == name:
|
|
isPtrExist,ptrName = self.checkStructPtr(m)
|
|
if isPtrExist:
|
|
rtnAsm,structOffset,ptrName = self.structPtrAsm(ptrName)
|
|
finalAsm += rtnAsm
|
|
if structOffset:
|
|
tmpAsm = self.genStructAssembly(m.Members, var,structOffset,ptrName)
|
|
finalAsm += tmpAsm
|
|
|
|
else:
|
|
tmpAsm = self.genStructAssembly(m.Members, var)
|
|
finalAsm += tmpAsm
|
|
return finalAsm
|
|
|
|
|
|
|
|
def findStructMember(self, structInstance, structMember):
|
|
for m in ebpVars:
|
|
sName = list(m.keys())[0]
|
|
if m["type"] == "struct" and sName == structInstance:
|
|
allMembers = m["members"]
|
|
for mem in allMembers:
|
|
for key, value in mem.items():
|
|
if key == structMember:
|
|
offset = value
|
|
return offset
|
|
|
|
|
|
def findStructMemType(self, stMember):
|
|
for st in structs:
|
|
for m in st.Members:
|
|
for key, value in m.items():
|
|
if value == stMember:
|
|
return key
|
|
def isUnicode(self, varName):
|
|
for v in mainVars:
|
|
if v.Name == varName and v.Type == "unicode":
|
|
return True
|
|
|
|
def getVarValue(self, varName):
|
|
for v in mainVars:
|
|
if (v.Name == varName) and v.Type != "structInstance":
|
|
return v.Value
|
|
elif (v.Name == varName) and v.Type == "structInstance":
|
|
if self.isUnicode(varName):
|
|
offset = self.findStructMember(varName, "Buffer")
|
|
if x64:
|
|
result = f"rbp-{offset}"
|
|
else:
|
|
result = f"ebp-{offset}"
|
|
return result
|
|
return self.getEbpValue(varName)
|
|
|
|
def getEbpValue(self, varName):
|
|
for v in ebpVars:
|
|
vName, ebpValue = next(iter(v.items()))
|
|
vValue = v["value"]
|
|
if varName == vName:
|
|
return ebpValue
|
|
|
|
def getValueType(self, value):
|
|
try:
|
|
int(value)
|
|
return "int"
|
|
except Exception as e:
|
|
try:
|
|
int(value, 16)
|
|
return "hex"
|
|
except:
|
|
if "sizeof" in value:
|
|
foundSizeOf = re.search(r'sizeof\(("?[^"]+"?)\)', value)
|
|
if foundSizeOf:
|
|
return "sizeof"
|
|
if '"' in value:
|
|
try:
|
|
hex_bytes = re.findall(r'\\x([0-9a-fA-F]{2})', value)
|
|
if hex_bytes:
|
|
return "raw"
|
|
return "string"
|
|
except Exception as c:
|
|
raise
|
|
elif "u:" in value:
|
|
return "unicode"
|
|
else:
|
|
return "variable"
|
|
|
|
def getStructSize(self, structName):
|
|
size = 0
|
|
for st in structs:
|
|
if st.Name == structName:
|
|
for i in st.Members:
|
|
for k in i:
|
|
size += int(k, 16)
|
|
return(hex(size))
|
|
|
|
def isStruct(self, value):
|
|
for st in structs:
|
|
if st.Name == value:
|
|
return True
|
|
|
|
|
|
def isSizeOf(self, value):
|
|
foundSizeOf = re.search(r'sizeof\(("?[^"]+"?)\)',value)
|
|
if foundSizeOf:
|
|
return True,foundSizeOf.group(1)
|
|
return False, False
|
|
|
|
def structMember(self, name, value):
|
|
stName = name.split(".")[0]
|
|
stMember = name.split(".")[1]
|
|
asm = ""
|
|
memberOffset = self.findStructMember(stName, stMember)
|
|
memberSize = self.findStructMemType(stMember)
|
|
foundSizeOf, rtnVal = self.isSizeOf(value)
|
|
if foundSizeOf:
|
|
if self.isStruct(rtnVal):
|
|
value = self.getStructSize(rtnVal)
|
|
else:
|
|
value = self.sizeOf(value)
|
|
|
|
if not memberSize:
|
|
return
|
|
|
|
dType = type_map.get(hex(int(memberSize)) if "0x" not in memberSize else memberSize)
|
|
#if memberSize == "0x4":
|
|
# dType = "dword"
|
|
#elif memberSize == "0x2":
|
|
# dType = "word"
|
|
#elif memberSize == "0x1":
|
|
# dType = "byte"
|
|
|
|
if value == "NULL":
|
|
value = 0
|
|
vType = self.getValueType(value)
|
|
|
|
if vType == "int":
|
|
varValue = int(value)
|
|
if x64:
|
|
prepAsm = f" mov {y+dType+rst} ptr[rbp-{memberOffset}], {hex(int(varValue))}"
|
|
else:
|
|
prepAsm = f" mov {y+dType+rst} ptr[ebp-{memberOffset}], {hex(int(varValue))}"
|
|
asm += "{:60s};{}={}\n".format(prepAsm, lb+stMember+rst, lb+str(varValue)+rst)
|
|
elif vType == "hex":
|
|
if x64:
|
|
prepAsm = f" mov {y+dType+rst} ptr[rbp-{memberOffset}], {value}"
|
|
else:
|
|
prepAsm = f" mov {y+dType+rst} ptr[ebp-{memberOffset}], {value}"
|
|
asm += "{:60s};{}={}\n".format(prepAsm, lb+stMember+rst, lb+str(value)+rst)
|
|
elif vType == "string":
|
|
pushedStr = self.pushString(value)
|
|
if x64:
|
|
dType = "qword"
|
|
prepAsm = f" mov {y+dType+rst} ptr[rbp-{memberOffset}], rbx"
|
|
else:
|
|
prepAsm = f" mov {y+dType+rst} ptr[ebp-{memberOffset}], ebx"
|
|
asm += pushedStr
|
|
asm += "{:60s};{}={}\n".format(prepAsm, lb+stMember+rst, lb+str(value)+rst)
|
|
elif vType == "variable":
|
|
isVariable = value
|
|
varValue = self.getVarValue(isVariable)
|
|
varType = self.getValueType(varValue)
|
|
varEbpVal = self.getEbpValue(isVariable)
|
|
if x64:
|
|
prepAsm = f" mov rbx, qword ptr[{varEbpVal}]"
|
|
asm += "{:47s};{}\n".format(prepAsm, lb+isVariable+rst)
|
|
prepAsm = f" mov qword ptr[rbp-{memberOffset}], rbx"
|
|
else:
|
|
prepAsm = f" mov ebx, dword ptr[{varEbpVal}]"
|
|
asm += "{:47s};{}\n".format(prepAsm, lb+isVariable+rst)
|
|
prepAsm = f" mov dword ptr[ebp-{memberOffset}], ebx"
|
|
asm += "{:47s};{}<=>{}\n".format(prepAsm, lb+stMember+rst, lb+isVariable+rst)
|
|
elif vType == "unicode":
|
|
extractVal = value.split("u:")[1]
|
|
hexVal = self.toHex(extractVal)
|
|
uniVal = self.toUnicode(hexVal)
|
|
pushedStr = self.pushAscii(uniVal)
|
|
if x64:
|
|
dType = "qword"
|
|
prepAsm = f" mov {y+dType+rst} ptr[rbp-{memberOffset}], rbx"
|
|
else:
|
|
prepAsm = f" mov {y+dType+rst} ptr[ebp-{memberOffset}], ebx"
|
|
asm += pushedStr
|
|
asm += "{:60s};{}={}\n".format(prepAsm, lb+stMember+rst, lb+str(value)+rst)
|
|
|
|
return asm
|
|
|
|
def toAssembly(self, Type, name, value, size=None, assignedTo=None):
|
|
if Type == "newVar" or Type == "newVarAdd" or Type == "newVarSub":
|
|
return self.newVarAssm(Type,name,value,size)
|
|
elif Type == "funcCall":
|
|
return self.funcCallAssm(name, value,assignedTo)
|
|
elif Type == "newstruct":
|
|
return self.structAssm(name, value)
|
|
elif Type == "structMember":
|
|
return self.structMember(name,value)
|
|
|
|
def getFunctionParams(self, line, lines):
|
|
funcName = re.findall('([a-zA-Z0-9]*)\(', line)
|
|
currentPos = lines.index(line)
|
|
params = []
|
|
for newline in lines[currentPos:]:
|
|
firstParam = re.findall('\(([a-zA-Z0-9&_|]+),', newline)
|
|
lastParam = re.findall('([a-zA-Z0-9&_|]+)\)', newline)
|
|
if firstParam:
|
|
parsed = firstParam[0]
|
|
params.append(parsed)
|
|
elif lastParam:
|
|
parsed = lastParam[0]
|
|
params.append(parsed)
|
|
break
|
|
else:
|
|
if newline.strip() == ");":
|
|
break
|
|
parsed = newline.replace(",", "").strip()
|
|
params.append(parsed)
|
|
|
|
if funcName and params:
|
|
return funcName, params
|
|
else:
|
|
return None,None
|
|
|
|
def isExist(self, varName):
|
|
for var in mainVars:
|
|
if varName == var.Name and not var.assigned:
|
|
return True,False
|
|
elif varName == var.Name and var.assigned:
|
|
return True,True
|
|
return False,False
|
|
|
|
def reservedType(self, varVal):
|
|
res = 0
|
|
if "MEM_COMMIT" in varVal or "MEM_RESERVE" in varVal:
|
|
varVal = varVal.replace("MEM_COMMIT", str(specialVars["MEM_COMMIT"]))
|
|
varVal = varVal.replace("MEM_RESERVE", str(specialVars["MEM_RESERVE"]))
|
|
if "|" in varVal:
|
|
varVal = varVal.replace("|", "+")
|
|
operands = varVal.split("+")
|
|
for op in operands:
|
|
res += int(op, 16)
|
|
else:
|
|
res += int(varVal, 16)
|
|
varVal = res
|
|
|
|
elif "PAGE_READWRITE" in varVal or "PAGE_EXECUTE_READWRITE" in varVal or "PAGE_READONLY" in varVal:
|
|
varVal = varVal.replace("PAGE_EXECUTE_READWRITE", str(specialVars["PAGE_EXECUTE_READWRITE"]))
|
|
varVal = varVal.replace("PAGE_READONLY", str(specialVars["PAGE_READONLY"]))
|
|
varVal = varVal.replace("PAGE_READWRITE", str(specialVars["PAGE_READWRITE"]))
|
|
res += int(varVal, 16)
|
|
varVal = res
|
|
elif "MEM_RELEASE" in varVal:
|
|
varVal = varVal.replace("MEM_RELEASE", str(specialVars["MEM_RELEASE"]))
|
|
res += int(varVal, 16)
|
|
varVal = res
|
|
|
|
return varVal
|
|
|
|
def getStartofLoop(self, line, lines, index):
|
|
for i in range(index, -1, -1):
|
|
if "while(" in lines[i]:
|
|
return i
|
|
|
|
def checkType(self, lineNum, lines, line, varObj):
|
|
line = line.replace(";", "")
|
|
sName = line.split(" ")[0]
|
|
if re.search("while\(.*\)", line):
|
|
if not loopDetected[0]:
|
|
return True,None,"start","while",None,None
|
|
|
|
if "}" in line and not ifDetected[0]:
|
|
if loopDetected[0] and not breakDetected[0]:
|
|
start_index = lineNum
|
|
end_index = self.getStartofLoop(line, lines, lineNum)
|
|
loopData = lines[end_index:start_index+1]
|
|
loopDataStr = '\n'.join(i for i in loopData)
|
|
print(f"{w}Warning, no break detected\n{rst}{red}{loopDataStr}{rst}")
|
|
return True,None,"end","while",None,None
|
|
elif loopDetected[0] and breakDetected[0]:
|
|
return True,None,"end","while",None,None
|
|
if "break" in line:
|
|
return True,None,None,"break",None,None
|
|
|
|
if re.search("if\s+\(.*\).*", line):
|
|
ifData = re.search("if\s+\((.*)\).*", line)
|
|
return True,None,ifData.group(1),"if", None,None
|
|
|
|
if "}" in line and ifDetected[0]:
|
|
return True,None,"end","if",None,None
|
|
for s in structs:
|
|
if sName == s.Name:
|
|
sValue = line.split(" ")[1]
|
|
if "=" in line:
|
|
assigned = re.findall('.*=(.*)', line)
|
|
if assigned:
|
|
assignedVal = assigned[0].strip().replace(";", "")
|
|
varObj.Name = sName
|
|
varObj.Value = assignedVal
|
|
varObj.Type = "structInstance"
|
|
varObj.unicode = sName
|
|
varObj.assigned = True
|
|
varObj.instance = sValue
|
|
#mainVars.append(varObj)
|
|
else:
|
|
print(f"[!] Syntax Error on {line}")
|
|
else:
|
|
varObj.Name = sName
|
|
varObj.Type = "structInstance"
|
|
varObj.assigned = False
|
|
varObj.Value = ""
|
|
varObj.unicode = sName
|
|
varObj.instance = sValue
|
|
return True,sName,sValue,"struct",None,True
|
|
|
|
elif sName == s.Pointer:
|
|
sValue = line.split(" ")[1]
|
|
return True,sName,sValue,"structPtr",None,False
|
|
|
|
if "InitUnicodeStr" in line:
|
|
return True,'',line,"unicode",None,False
|
|
|
|
allData = dataTypes if x64 else dataTypes_x86
|
|
if sName in allData: #check if handle, pvoid, ulong..etc
|
|
size = allData[sName]
|
|
if "=" in line and "+=" not in line:
|
|
lineData = ''.join(line.split(" ")[1:])
|
|
varName = lineData.split("=")[0]
|
|
varVal = lineData.split("=")[1]
|
|
varVal = self.reservedType(varVal)
|
|
return True,varName,varVal,"variable",size,True
|
|
elif "+=" in line:
|
|
lineData = ''.join(line.split(" ")[1:])
|
|
varName = lineData.split("+=")[0]
|
|
varVal = lineData.split("+=")[1]
|
|
varVal = self.reservedType(varVal)
|
|
return True,varName,varVal,"varAdd",size,True
|
|
elif "-=" in line:
|
|
lineData = ''.join(line.split(" ")[1:])
|
|
varName = lineData.split("-=")[0]
|
|
varVal = lineData.split("-=")[1]
|
|
varVal = self.reservedType(varVal)
|
|
return True,varName,varVal,"varSub",size,True
|
|
|
|
else:
|
|
varName = line.split(" ")[1]
|
|
return True,varName,None,"variable",size,False
|
|
else:
|
|
params = None
|
|
isFunction = re.findall('[a-zA-Z0-9]*\((.*)\)', line)
|
|
if isFunction and "=" not in line: # Check if the line is a function E.g func(param1, param2)
|
|
params = isFunction[0].replace(" ", "").split(",")
|
|
funcName = re.findall('([a-zA-Z0-9]*)\(', line)
|
|
if funcName:
|
|
funcName = funcName[0]
|
|
if "=" not in line:
|
|
varObj.assignedTo = False
|
|
return True,funcName,params,"functionCall",None,None
|
|
elif "=" in line:
|
|
assignedVar = line.replace(" ", "").split("=")[0]
|
|
varObj.assignedTo = assignedVar
|
|
return True,funcName,params,"functionCall",None,None
|
|
else:
|
|
if "(" in line and ")" not in line: # check if multiline function call
|
|
if re.findall('[a-zA-Z0-9]*\(',line):
|
|
funcName, params = self.getFunctionParams(line, lines)
|
|
if funcName and params:
|
|
funcName = funcName[0]
|
|
if "=" in line:
|
|
assignedVar = line.replace(" ", "").split("=")[0]
|
|
varObj.assignedTo = assignedVar
|
|
return True,funcName,params,"functionCall",None,None
|
|
elif re.findall('[a-zA-Z0-9]+\((.*)\)', line) and "sizeof" not in line:
|
|
funcName = re.findall('([a-zA-Z0-9]+)\(', line)
|
|
params = isFunction[0].replace(" ", "").split(",")
|
|
if funcName:
|
|
funcName = funcName[0]
|
|
if "=" in line and "sizeof" not in funcName:
|
|
assignedVar = line.replace(" ", "").split("=")[0]
|
|
varObj.assignedTo = assignedVar
|
|
return True,funcName,params,"functionCall",None,None
|
|
|
|
else:
|
|
if "=" in line and "+=" not in line and "-=" not in line:
|
|
lineData = ''.join(line.split(" ")).replace(";", "")
|
|
varName = lineData.split("=")[0]
|
|
varVal = lineData.split("=")[1]
|
|
varVal = self.reservedType(varVal)
|
|
if "." in varName:
|
|
return True,varName,varVal,"structMember",None,True
|
|
elif "->" in varVal:
|
|
hiddenStruct = re.match('(\w+)\s*=\s*\((\w+)\)(\w+)->(\w+)$', line)
|
|
hiddenStructNested = re.match('(\w+)\s*=\s*\((\w+)\)(\w+)->(\w+)->(\w+)', line)
|
|
if hiddenStruct:
|
|
assignedVar = hiddenStruct.group(1)
|
|
hiddenStructName = hiddenStruct.group(2)
|
|
hiddenVarName = hiddenStruct.group(3)
|
|
hiddenStructMember = hiddenStruct.group(4)
|
|
hiddenStructData = {"type":"regular",
|
|
"assignedVar":assignedVar,
|
|
"structName":hiddenStructName,
|
|
"structMemberName":hiddenStructMember,
|
|
"hiddenVarName":hiddenVarName}
|
|
|
|
return True,assignedVar,hiddenStructData,"hiddenStruct",None,True
|
|
elif hiddenStructNested:
|
|
assignedVar = hiddenStructNested.group(1)
|
|
hiddenStructName = hiddenStructNested.group(2)
|
|
hiddenVarName = hiddenStructNested.group(3)
|
|
hiddenStructMember = hiddenStructNested.group(4)
|
|
hiddenStructNestedMember = hiddenStructNested.group(5)
|
|
hiddenStructData = {"type":"nested",
|
|
"assignedVar":assignedVar,
|
|
"structName":hiddenStructName,
|
|
"structMemberName":hiddenStructMember,
|
|
"hiddenVarName":hiddenVarName,
|
|
"hiddenNestedMember":hiddenStructNestedMember}
|
|
return True,assignedVar,hiddenStructData,"hiddenStruct",None,True
|
|
|
|
|
|
return True,varName,varVal,"variable",None,True
|
|
elif "+=" in line:
|
|
lineData = ''.join(line.split(" ")).replace(";", "")
|
|
varName = lineData.split("+=")[0]
|
|
varVal = lineData.split("+=")[1]
|
|
varVal = self.reservedType(varVal)
|
|
return True,varName,varVal,"varAdd",None,True
|
|
elif "-=" in line:
|
|
lineData = ''.join(line.split(" ")).replace(";", "")
|
|
varName = lineData.split("-=")[0]
|
|
varVal = lineData.split("-=")[1]
|
|
varVal = self.reservedType(varVal)
|
|
return True,varName,varVal,"varSub",None,True
|
|
|
|
return False,None,None,None,None,None
|
|
|
|
def pushNull(self):
|
|
if x64:
|
|
tmp = "\n xor rbx, rbx\n"
|
|
tmp += " push rbx\n"
|
|
else:
|
|
tmp = "\n xor ebx, ebx\n"
|
|
tmp += " push ebx\n"
|
|
return tmp
|
|
|
|
def pushString(self, str2push):
|
|
varStr = str2push.replace('"', '')
|
|
i = len(varStr)
|
|
|
|
pushList = []
|
|
while (i >= 0):
|
|
if (i - 4 < 0):
|
|
tmp = varStr[:i]
|
|
pushList.append(tmp)
|
|
else:
|
|
|
|
tmp = varStr[i-4:i]
|
|
pushList.append(tmp)
|
|
i -= 4
|
|
|
|
asmCode2 = self.pushNull()
|
|
|
|
Flag = True
|
|
for word in pushList:
|
|
data = word[::-1]
|
|
wordLen = len(data)
|
|
if wordLen == 4:
|
|
wordHex = "".join("{:02x}".format(ord(c)) for c in data)
|
|
prepAsm = f" push 0x{wordHex}"
|
|
asmLine = {"instr":prepAsm, "comment":data}
|
|
asmCode2 += "{:47s};{}\n".format(prepAsm,lb+data+rst)
|
|
|
|
elif wordLen == 2:
|
|
wordHex = "".join("{:02x}".format(ord(c)) for c in data)
|
|
prepAsm = f" mov bx, 0x{wordHex}\n"
|
|
prepAsm += " push bx"
|
|
asmLine = {"instr":prepAsm, "comment":data}
|
|
asmCode2 += "{:64s};{}\n".format(prepAsm,lb+data+rst)
|
|
|
|
elif wordLen == 1 or wordLen == 3:
|
|
Flag = False
|
|
wordHex = "".join("{:02x}".format(ord(c)) for c in data)
|
|
tmp = wordHex + "00"
|
|
|
|
letters = string.ascii_lowercase
|
|
randStr = (''.join(random.choice(letters) for i in range(4)))
|
|
randStr = "".join("{:02x}".format(ord(c)) for c in randStr)
|
|
|
|
randStr2Int = int(randStr, 16)
|
|
wordHex2Int = int(tmp, 16)
|
|
Xored = randStr2Int ^ wordHex2Int
|
|
Xored = hex(Xored).replace("0x", "")
|
|
|
|
tmpAsm = ' mov ebx, 0x{}'.format(Xored)
|
|
tmpAsm = "{:47s};{}\n".format(tmpAsm, lb+data+rst)
|
|
tmpAsm += ' xor ebx, 0x{}\n'.format(randStr)
|
|
if(wordLen == 1):
|
|
tmpAsm += ' push bx\n'
|
|
else:
|
|
if x64:
|
|
tmpAsm += ' push rbx\n'
|
|
else:
|
|
tmpAsm += ' push ebx\n'
|
|
if x64:
|
|
tmpAsm += " mov rbx, rsp\n"
|
|
tmpAsm += ' inc rbx\n'
|
|
else:
|
|
tmpAsm += " mov ebx, esp\n"
|
|
tmpAsm += ' inc ebx\n'
|
|
|
|
asmCode2 += tmpAsm
|
|
if Flag:
|
|
if x64:
|
|
prepAsm = " push rsp"
|
|
asmCode2 += "{:47s};{}\n".format(prepAsm,lb + str2push+rst)
|
|
prepAsm = " pop rbx\n"
|
|
asmCode2 += " pop rbx\n"
|
|
else:
|
|
prepAsm = " push esp"
|
|
asmCode2 += "{:47s};{}\n".format(prepAsm,lb + str2push+rst)
|
|
prepAsm = " pop ebx\n"
|
|
asmCode2 += " pop ebx\n"
|
|
return asmCode2
|
|
|
|
def pushAsciiX64(self, asciiArr):
|
|
bytes_per_chunk = 8 # 4 UTF-16 chars = 8 bytes
|
|
total_len = len(asciiArr)
|
|
chunks = []
|
|
i = 0
|
|
while i < total_len:
|
|
end = min(i + bytes_per_chunk, total_len)
|
|
chunk = asciiArr[i:end]
|
|
while len(chunk) < bytes_per_chunk:
|
|
chunk.append('00')
|
|
chunks.append(chunk)
|
|
i += bytes_per_chunk
|
|
|
|
asm = ""
|
|
total_size = len(chunks) * bytes_per_chunk
|
|
asm += f" sub rsp, 0x{total_size:02x}\n"
|
|
|
|
for idx, chunk in enumerate(chunks):
|
|
hex_str = ''.join(chunk)
|
|
bytes_le = bytes.fromhex(hex_str)
|
|
little_endian = ''.join(f"{b:02x}" for b in reversed(bytes_le))
|
|
offset = f"+{idx * bytes_per_chunk}" if idx != 0 else ""
|
|
asm += f" mov rax, 0x{little_endian}\n"
|
|
asm += f" mov qword ptr[rsp{offset}], rax\n"
|
|
|
|
asm += " mov rbx, rsp\n"
|
|
return asm
|
|
|
|
|
|
def pushAscii(self, asciiArr):
|
|
if x64:
|
|
return self.pushAsciiX64(asciiArr)
|
|
length = len(asciiArr)
|
|
i = 0
|
|
newData = []
|
|
asm = ""
|
|
while(i < length):
|
|
if(i+4) > length:
|
|
tmp = ''.join(asciiArr[i:])
|
|
newData.append(f"{tmp}")
|
|
else:
|
|
tmp = ''.join(asciiArr[i:i+4])
|
|
newData.append(f"{tmp}")
|
|
i+=4
|
|
newData.reverse()
|
|
numberOfPushes = 0
|
|
for group in newData:
|
|
numberOfPushes += 1
|
|
newHex = ""
|
|
for byte in reversed(bytes.fromhex(group)):
|
|
b = format(byte, '02x')
|
|
newHex += b
|
|
asm += f" push 0x{newHex}\n"
|
|
if x64:
|
|
asm += " mov rbx, rsp\n"
|
|
asm += f" add rsp, {hex(numberOfPushes*4)}\n"
|
|
else:
|
|
asm += " mov ebx, esp\n"
|
|
asm += f" add esp, {hex(numberOfPushes*4)}\n"
|
|
return asm
|
|
|
|
def initUnicode(self, ptrName, unicode, length, line):
|
|
asm = ""
|
|
data = {
|
|
"u":unicode,
|
|
"len":length
|
|
}
|
|
found = False
|
|
for vr in mainVars:
|
|
if vr.Type == "structInstance":
|
|
#for st in structs:
|
|
if ptrName == vr.Name:
|
|
asm += self.structMember(f"{vr.Name}.Buffer", f"u:{unicode}")
|
|
asm += self.structMember(f"{vr.Name}.Length", f"{length}")
|
|
found = True
|
|
break
|
|
if found:
|
|
return asm
|
|
else:
|
|
print(f"{red}Error: could not match structure name{rst}")
|
|
print(f"{w}Error line: {line}{rst}")
|
|
sys.exit()
|
|
|
|
def reAssign(self, rName, rValue):
|
|
for var in mainVars:
|
|
if var.Name == rName:
|
|
var.Value = rValue
|
|
|
|
def removeAsmComments(self, asm):
|
|
#ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
|
|
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
|
|
cleaned_lines = []
|
|
for line in asm.split('\n'):
|
|
line = ansi_escape.sub('', line)
|
|
line = re.sub(r';.*$', '', line).strip()
|
|
if line: # Keep non-empty lines
|
|
cleaned_lines.append(line)
|
|
#line = re.sub(r';.*$', '', line).strip()
|
|
return '\n'.join(cleaned_lines)
|
|
#return ansi_escape.sub('', asm)
|
|
|
|
def genRandStr(self, length):
|
|
letters = string.ascii_letters
|
|
return ''.join(random.choice(letters) for _ in range(length))
|
|
|
|
def parseWhileLoop(self, loopType,line, lines):
|
|
loopObj = whileLoop()
|
|
LoopStartAt = lines.index(line)
|
|
asm = ""
|
|
if loopType == "start":
|
|
loopStr = self.genRandStr(3)
|
|
loopStart = f"loopStart_{loopStr}"
|
|
loopObj.loopStart = f"loopStart_{loopStr}"
|
|
loopStr = self.genRandStr(3)
|
|
loopObj.loopEnd = f"loopEnd_{loopStr}"
|
|
allLoops[0] = loopObj
|
|
asm += f"{lb}{loopStart}:{rst}\n"
|
|
elif loopType == "end":
|
|
loopData = allLoops[0]
|
|
loopStart = loopData.loopStart
|
|
loopEnd = loopData.loopEnd
|
|
asm += f" jmp {lb}{loopStart}{rst}\n"
|
|
asm += f"{lb}{loopEnd}{rst}:\n"
|
|
else:
|
|
print(f"{red}Error: could not parse while loop{rst}")
|
|
print(f"{w}Error line: {line}{rst}")
|
|
sys.exit()
|
|
return asm
|
|
|
|
def recvBreak(self, op, jmpTo):
|
|
asm = ""
|
|
asm += f" {op} {lb}{jmpTo}{rst}\n"
|
|
return asm
|
|
|
|
def hiddenStructAsm(self, varName, offset, hiddenVarName, size):
|
|
asm = ""
|
|
srcVarEbp = None
|
|
destVarEbp = None
|
|
data_types = {"0x8":"qword","0x4":"dword", "0x2":"word", "0x2":"byte"}
|
|
register_type = {"0x4":"ebx", "0x8":"rbx"}
|
|
for ebp in ebpVars:
|
|
vName, ebpVal = next(iter(ebp.items()))
|
|
if vName == hiddenVarName:
|
|
srcVarEbp = ebpVal
|
|
elif vName == varName:
|
|
destVarEbp = ebpVal
|
|
if srcVarEbp and destVarEbp:
|
|
if x64:
|
|
prepAsm = f" mov rbx, qword ptr[{srcVarEbp}]"
|
|
else:
|
|
prepAsm = f" mov ebx, dword ptr[{srcVarEbp}]"
|
|
asm += "{:47s};{}\n".format(prepAsm, lb+"Get address of "+hiddenVarName+rst)
|
|
|
|
dType = data_types.get(size)
|
|
if not dType:
|
|
print("couldn't find for ", size, hiddenVarName, varName, offset)
|
|
|
|
register = register_type.get(size)
|
|
if offset == 0:
|
|
if x64:
|
|
prepAsm = f" mov {register}, {dType} ptr[rbx]"
|
|
else:
|
|
prepAsm = f" mov ebx, dword ptr[ebx]"
|
|
else:
|
|
if x64:
|
|
prepAsm = f" mov {register}, {dType} ptr[rbx+{hex(offset)}]"
|
|
else:
|
|
prepAsm = f" mov ebx, dword ptr[ebx+{hex(offset)}]"
|
|
asm += "{:47s};{}\n".format(prepAsm, lb+"Access offset " + str(hex(offset)) + " in " +hiddenVarName+rst)
|
|
if x64:
|
|
prepAsm = f" mov qword ptr[{destVarEbp}], rbx"
|
|
else:
|
|
prepAsm = f" mov dword ptr[{destVarEbp}], ebx"
|
|
asm += "{:47s};{}\n".format(prepAsm, lb+"Copy value to " +varName+rst)
|
|
return asm
|
|
|
|
def findHiddenStruct(self, structName):
|
|
for hs in hiddenstructs:
|
|
if hs.Name == structName:
|
|
return hs.Members
|
|
return False
|
|
|
|
def findSizeByDataType(self):
|
|
pass
|
|
def findNestedMemberSize(self, data, nestedMember):
|
|
totalSize = 0
|
|
found = False
|
|
offset = 0
|
|
size = 0
|
|
iteration = 0
|
|
for count,field in enumerate(data):
|
|
for size_str, name in field.items():
|
|
size = int(size_str, 16)
|
|
if x64:
|
|
#alignment = min(size, 8) if size <= 8 else 8
|
|
pad = (size - (offset % size)) % size
|
|
offset += pad
|
|
#if offset % alignment != 0:
|
|
# print(f"[*] Offset {offset} not aligned, alignment {alignment}")
|
|
# pad = alignment - (offset % alignment)
|
|
# print(f"Aligning offset {offset} , padding {pad}")
|
|
# offset += pad
|
|
if name == nestedMember:
|
|
if count == 0:
|
|
offset = 0
|
|
return True, offset, size
|
|
offset += size
|
|
return False, offset, size
|
|
|
|
def hiddenStruct(self, varName, structData):
|
|
hiddenType = structData["type"]
|
|
structName = structData["structName"]
|
|
structMember = structData["structMemberName"]
|
|
hiddenVarName = structData["hiddenVarName"]
|
|
offset = 0
|
|
found = False
|
|
foundSize = 0
|
|
members = self.findHiddenStruct(structName)
|
|
if not members:
|
|
print(f"{red}Error: could not find struct name structName {rst}")
|
|
sys.exit()
|
|
sizeAndName = [(key, value) for memberDict in members for key, value in memberDict.items()]
|
|
sizeAndNameDict = [{key :value} for memberDict in members for key, value in memberDict.items()]
|
|
if hiddenType == "regular":
|
|
found, recvSize, memberSize = self.findNestedMemberSize(sizeAndNameDict, structMember)
|
|
if found:
|
|
if memberSize < 1:
|
|
print(f"[!] Error: invalid member size")
|
|
sys.exit()
|
|
#foundSize = f"{hex(recvSize)}"
|
|
offset += recvSize
|
|
memberSize = f"0x{memberSize}"
|
|
else:
|
|
print(f"[!] Error: couldn't find member size")
|
|
sys.exit()
|
|
#offset1 = 0
|
|
#for size1, name1 in sizeAndName:
|
|
# if structMember == name1:
|
|
# found1 = True
|
|
# foundSize1 = size1
|
|
# offset1 += int(size1, 16)
|
|
# break
|
|
# offset1 += int(size1, 16)
|
|
#print(offset1, foundSize1 , offset, foundSize)
|
|
#input("Result------------")
|
|
|
|
|
|
elif hiddenType == "nested":
|
|
nestedMember = structData["hiddenNestedMember"]
|
|
for size, name in sizeAndName:
|
|
if type(name) == dict:
|
|
memberNameAndPtr = [i for i in name][0]
|
|
memberName = memberNameAndPtr.split("->")[0]
|
|
if memberName == structMember:
|
|
found, recvSize, memberSize = self.findNestedMemberSize(name[memberNameAndPtr], nestedMember)
|
|
offset += recvSize
|
|
memberSize = f"{hex(memberSize)}"
|
|
if found:
|
|
break
|
|
else:
|
|
offset += int(size, 16)
|
|
|
|
if not found:
|
|
print(f"{red}Error: could not find member {structMember}, are you sure it's not nested member ? {rst}")
|
|
sys.exit()
|
|
asm = self.hiddenStructAsm(varName, offset, hiddenVarName, memberSize)
|
|
return asm
|
|
|
|
|
|
def ifStatement(self, data, line):
|
|
operator = re.search("(==)|(!=)|(>=)|(<=)|(>)|(<)", data)
|
|
data = data.replace(" ", "")
|
|
ifDetected[0] = True
|
|
if operator:
|
|
op = operator.group()
|
|
if op == "==":
|
|
asmOp = "je"
|
|
elif op == "!=":
|
|
asmOp = "jne"
|
|
elif op == ">=":
|
|
asmOp = "jge"
|
|
elif op == "<=":
|
|
asmOp = "jle"
|
|
elif op == ">":
|
|
asmOp = "jg"
|
|
elif op == "<":
|
|
asmOp = "jl"
|
|
left = data.split(op)[0]
|
|
right = data.split(op)[1]
|
|
return asmOp,left,right
|
|
else:
|
|
print(f"{red}Error: could not read if statement operator{rst}")
|
|
print(f"{w}Error line: {line}{rst}")
|
|
sys.exit()
|
|
|
|
def ifStatementAsm(self, op, left, right, lType, rType, line, name):
|
|
asm = ""
|
|
leftEbp = self.findEbpVar(left)
|
|
leftEbpValue = leftEbp[left]
|
|
loopData = allLoops[0]
|
|
loopEnd = loopData.loopEnd
|
|
if loopDetected[0]:
|
|
if rType != "string":
|
|
breakData[0] = {op:loopEnd}
|
|
elif rType == "string":
|
|
breakData[0] = {"jecxz":loopEnd}
|
|
if rType == "int":
|
|
if x64:
|
|
asm += f" mov rax, qword ptr[{leftEbpValue}]\n"
|
|
asm += f" cmp rax, {hex(int(right))}\n"
|
|
else:
|
|
asm += f" mov eax, dword ptr[{leftEbpValue}]\n"
|
|
asm += f" cmp eax, {hex(int(right))}\n"
|
|
elif rType == "hex":
|
|
if x64:
|
|
asm += f" mov rax, qword ptr[{leftEbpValue}]\n"
|
|
asm += f" cmp rax, {right}"
|
|
else:
|
|
asm += f" mov eax, dword ptr[{leftEbpValue}]\n"
|
|
asm += f" cmp eax, {right}"
|
|
elif rType == "string":
|
|
if x64:
|
|
asm += f" mov rdi, dword ptr[{leftEbpValue}]\n"
|
|
else:
|
|
asm += f" mov edi, dword ptr[{leftEbpValue}]\n"
|
|
rtnStringVal = self.pushString(right)
|
|
asm += rtnStringVal
|
|
strLen = self.sizeOf(f"sizeof({right})")
|
|
if x64:
|
|
asm += f" mov rsi, rbx\n"
|
|
asm += f" mov rcx, {strLen}\n"
|
|
else:
|
|
asm += f" mov esi, ebx\n"
|
|
asm += f" mov ecx, {strLen}\n"
|
|
asm += " cld\n"
|
|
asm += " repe cmpsb\n"
|
|
elif rType == "variable":
|
|
for v in mainVars:
|
|
if v.Name == name:
|
|
if any(reg in right for reg in ("ebp", "rbp")) and v.Type == "unicode":
|
|
if x64:
|
|
asm += f" mov rdi, qword ptr[{leftEbpValue}]\n"
|
|
asm += f" mov rsi, qword ptr[{right}]\n"
|
|
asm += f" mov rcx, {hex(v.Length)}\n"
|
|
else:
|
|
asm += f" mov edi, dword ptr[{leftEbpValue}]\n"
|
|
asm += f" mov esi, dword ptr[{right}]\n"
|
|
asm += f" mov ecx, {hex(v.Length)}\n"
|
|
asm += " cld\n"
|
|
asm += " repe cmpsb\n"
|
|
else:
|
|
print(f"{red}Error: could not evaluate right side of if statement{rst}")
|
|
print(f"{w}Error line: {line}{rst}")
|
|
sys.exit()
|
|
return asm
|
|
|
|
def sysCallAsm(self):
|
|
asm = ""
|
|
asm += f"{lb}invokeSysCall{rst}:\n"
|
|
if x64:
|
|
asm += f" syscall\n"
|
|
else:
|
|
asm += f" call {y}dword{rst} ptr fs:[0xc0]\n"
|
|
asm += f" ret\n"
|
|
asm += f"{lb}Begin{rst}:\n"
|
|
return asm
|
|
|
|
def checkSyscallNumAsm(self, modelNum):
|
|
asm = ""
|
|
for api, val in syscallsAndApiNum.items():
|
|
if x64:
|
|
asm += f" cmp rdi, {val}\n"
|
|
else:
|
|
asm += f" cmp edi, {val}\n"
|
|
syscallNum = readSysCalls(api, modelNum, False)
|
|
if x64:
|
|
asm += f" mov rbx, {syscallNum}\n"
|
|
asm += f" cmovz rdi, rbx\n"
|
|
else:
|
|
asm += f" mov ebx, {syscallNum}\n"
|
|
asm += f" cmovz ecx, ebx\n"
|
|
asm += " ret\n"
|
|
return asm
|
|
|
|
def GetSyscallNumber(self):
|
|
asm = ""
|
|
asm += f"jmp {lb}Begin{rst}\n"
|
|
asm += f"{lb}m_10240:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("10240")
|
|
asm += f"{lb}m_10586:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("10586")
|
|
asm += f"{lb}m_14393:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("14393")
|
|
asm += f"{lb}m_15063:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("15063")
|
|
asm += f"{lb}m_16299:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("16299")
|
|
asm += f"{lb}m_17134:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("17134")
|
|
asm += f"{lb}m_17763:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("17763")
|
|
asm += f"{lb}m_18362:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("18362")
|
|
asm += f"{lb}m_18363:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("18363")
|
|
asm += f"{lb}m_19041:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("19041")
|
|
asm += f"{lb}m_19042:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("19042")
|
|
asm += f"{lb}m_19043:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("19043")
|
|
asm += f"{lb}m_19044:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("19044")
|
|
asm += f"{lb}m_19045:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("19045")
|
|
asm += f"{lb}m_22000:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("22000")
|
|
asm += f"{lb}m_20348:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("20348")
|
|
asm += f"{lb}m_22621:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("22621")
|
|
asm += f"{lb}m_22631:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("22631")
|
|
asm += f"{lb}m_25398:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("25398")
|
|
asm += f"{lb}m_26100:{rst}\n"
|
|
asm += self.checkSyscallNumAsm("26100")
|
|
|
|
return asm
|
|
|
|
def GetModelNumber(self):
|
|
asm = ""
|
|
asm += f"""{lb}GetSysModelNumber{rst}:
|
|
"""
|
|
if x64:
|
|
asm += """ mov rax, gs:[0x60]
|
|
mov rax, [rax+0x120]
|
|
and rax, 0xffff
|
|
"""
|
|
else:
|
|
asm += f""" mov edx, fs:[0x30]
|
|
mov eax, [edx+0xAC]
|
|
and eax, 0xFFFF
|
|
"""
|
|
asm += """ cmp eax, 10240
|
|
je m_10240
|
|
cmp eax, 10586
|
|
je m_10586
|
|
cmp eax, 14393
|
|
je m_14393
|
|
cmp eax, 15063
|
|
je m_15063
|
|
cmp eax, 16299
|
|
je m_16299
|
|
cmp eax, 17134
|
|
je m_17134
|
|
cmp eax, 17763
|
|
je m_17763
|
|
cmp eax, 18362
|
|
je m_18362
|
|
cmp eax, 18363
|
|
je m_18363
|
|
cmp eax, 19041
|
|
je m_19041
|
|
cmp eax, 19042
|
|
je m_19042
|
|
cmp eax, 19043
|
|
je m_19043
|
|
cmp eax, 19044
|
|
je m_19044
|
|
cmp eax, 19045
|
|
je m_19045
|
|
cmp eax, 22000
|
|
je m_22000
|
|
cmp eax, 20348
|
|
je m_20348
|
|
cmp eax, 22621
|
|
je m_22621
|
|
cmp eax, 22631
|
|
je m_22631
|
|
cmp eax, 25398
|
|
je m_25398
|
|
cmp eax, 26100
|
|
je m_26100
|
|
ret
|
|
"""
|
|
return asm
|
|
|
|
def stackSpace(self):
|
|
if x64:
|
|
asm = "push rbp\n"
|
|
asm += "mov rbp, rsp\n"
|
|
asm += "sub rsp, 0x500\n"
|
|
else:
|
|
asm = "push ebp\n"
|
|
asm += "mov ebp, esp\n"
|
|
asm += "sub esp, 0x500\n"
|
|
return asm
|
|
|
|
def stackEnd(self):
|
|
if x64:
|
|
asm = "leave\n"
|
|
asm += "ret\n"
|
|
else:
|
|
asm = "leave\n"
|
|
asm += "ret\n"
|
|
return asm
|
|
|
|
def ignoreRawBytes(self, asm):
|
|
assemblyOnly = '\n'.join(
|
|
line for line in asm.split('\n') if not line.strip().startswith(';;;'))
|
|
return assemblyOnly
|
|
def convertToMasmHex(self, assembly):
|
|
lines = assembly.split('\n')
|
|
converted_lines = []
|
|
for line in lines:
|
|
converted_line = re.sub(
|
|
r'0x([0-9a-fA-F]+)',
|
|
lambda m: f"0{m.group(1)}h" if m.group(1)[0].upper() in 'ABCDEF' else f"{m.group(1)}h",
|
|
line
|
|
)
|
|
#converted_line = re.sub(r'0x([0-9a-fA-F]+)', lambda m: f"{m.group(1)}h", line)
|
|
converted_lines.append(converted_line)
|
|
return '\n'.join(converted_lines)
|
|
|
|
def formatAssemblyAndComments(self, code):
|
|
asm = ""
|
|
instrAndComments = []
|
|
for line in code.split("\n"):
|
|
line = line.replace(lb, "").replace(y, "").replace(o, "").replace(rst, "")
|
|
try:
|
|
instr, comment = [part for part in (line.split(";", 1) + [""])[:2]]
|
|
instrAndComments.append({"instruction":instr, "comment":comment})
|
|
except Exception as e:
|
|
raise
|
|
longest_instruction_len = max(len(line["instruction"]) for line in instrAndComments) + len(o) + len(rst)
|
|
for line in instrAndComments:
|
|
try:
|
|
instruction = line["instruction"]
|
|
comment = line["comment"]
|
|
is_label = re.search(r".*:$", instruction)
|
|
padded_line = instruction.ljust(longest_instruction_len)
|
|
colored_instr = (f"{lb}{instruction}{rst}" if is_label
|
|
else f"{w}{instruction}{rst}")
|
|
colored_instr = colored_instr.ljust(longest_instruction_len)
|
|
if comment:
|
|
comment = re.sub(
|
|
r'(:\s*)(.*)', # Capture group 1: colon + spaces, group 2: everything after
|
|
lambda m: f"{m.group(1)}{g}{m.group(2)}{rst}",
|
|
comment,
|
|
count=1 # Only replace first occurrence
|
|
)
|
|
colored_instr += f" ; {o}{comment}{rst}"
|
|
asm += f"{colored_instr}\n"
|
|
except Exception as e:
|
|
raise
|
|
return asm
|
|
|
|
def parseMain(self, lines):
|
|
finalAssm = ""
|
|
self.asmObj.assembly = ""
|
|
try:
|
|
for index, line in enumerate(lines):
|
|
varObj = Vars()
|
|
isValid,rName,rValue,rType,rSize,isAssigned = self.checkType(index, lines, line, varObj)
|
|
if isValid:
|
|
if rType == "struct" or rType == "structPtr":
|
|
mainVars.append(varObj)
|
|
asm = self.toAssembly("newstruct",rName, rValue, rSize)
|
|
finalAssm += f"{asm}"
|
|
elif rType == "while" and rValue == "start":
|
|
asm = self.parseWhileLoop("start", line, lines)
|
|
finalAssm += asm
|
|
loopDetected[0] = True
|
|
elif rType == "while" and rValue == "end":
|
|
asm = self.parseWhileLoop("end", line, lines)
|
|
finalAssm += asm
|
|
loopDetected[0] = False
|
|
elif rType == "hiddenStruct":
|
|
asm = self.hiddenStruct(rName, rValue)
|
|
finalAssm += asm
|
|
elif rType == "if" and rValue != "end":
|
|
op,left,right = self.ifStatement(rValue, line)
|
|
leftType = self.getValueType(left)
|
|
if leftType == "variable":
|
|
leftValue = self.getVarValue(left)
|
|
elif leftType == "int" or leftType == "string":
|
|
print(f"Error: {line}\nLeft side cannot be a string or integer")
|
|
sys.exit()
|
|
rightType = self.getValueType(right)
|
|
if rightType == "variable":
|
|
rightValue = self.getVarValue(right)
|
|
rightType = self.getValueType(rightValue)
|
|
else:
|
|
rightValue = right
|
|
finalAssm += self.ifStatementAsm(op, left, rightValue, leftType, rightType, line, right)
|
|
elif rType == "if" and rValue == "end":
|
|
ifDetected[0] = False
|
|
elif rType == "break":
|
|
if loopDetected[0]:
|
|
#loopDetected[0] = False
|
|
if breakData[0] is not None:
|
|
for op, jmpTo in breakData[0].items():
|
|
finalAssm += self.recvBreak(op, jmpTo)
|
|
else:
|
|
print(f"{red}Error: loop and break detected, but break data not found")
|
|
print(f"{w}Error line: {line}{rst}")
|
|
sys.exit()
|
|
breakDetected[0] = True
|
|
elif rType == "unicode":
|
|
ptr, inStr = self.extractString(rValue)
|
|
|
|
if ptr and inStr:
|
|
hexStr = self.toHex(inStr)
|
|
unicodeStr = self.toUnicode(hexStr)
|
|
varObj.Name = ptr
|
|
varObj.Type = rType
|
|
varObj.Value = inStr
|
|
ucodeLen = len(unicodeStr)
|
|
varObj.Length = ucodeLen
|
|
mainVars.append(varObj)
|
|
finalAssm += self.initUnicode(ptr, inStr, ucodeLen, line)
|
|
elif rType == "variable" or rType == "varAdd" or rType == "varSub":
|
|
varObj.Name = rName
|
|
varObj.Type = rType
|
|
varObj.Value = rValue
|
|
varObj.assigned = isAssigned
|
|
varObj.Size = rSize
|
|
exist, assigned = self.isExist(rName)
|
|
if not exist and isAssigned and rSize:
|
|
mainVars.append(varObj)
|
|
if not exist and not isAssigned:
|
|
mainVars.append(varObj)
|
|
if exist and not isAssigned and not rValue:
|
|
print(f"[!] {red}Error{rst} Line: {lb+line+rst}")
|
|
print(f"[!] {red}Error:{rst} cannot redefine variable {lb+rName+rst}")
|
|
return
|
|
if not exist and isAssigned and not rSize:
|
|
print(f"[!] {red}Error{rst} Line: {lb+line+rst}")
|
|
print(f"[!] {red}Error:{rst} Variable {lb+rName+rst} is not defined")
|
|
return
|
|
if exist and isAssigned and rValue:
|
|
self.reAssign(rName, rValue)
|
|
if rValue:
|
|
if rType == "varAdd":
|
|
assm = self.toAssembly("newVarAdd", rName,rValue,rSize)
|
|
elif rType == "varSub":
|
|
assm = self.toAssembly("newVarSub", rName,rValue,rSize)
|
|
else:
|
|
assm = self.toAssembly("newVar", rName,rValue,rSize)
|
|
finalAssm += f"{assm}\n"
|
|
currentStack = self.asmObj.stackStart
|
|
|
|
elif rType == "functionCall":
|
|
varObj.Name = rName
|
|
varObj.Type = rType
|
|
varObj.Value = rValue
|
|
mainVars.append(varObj)
|
|
assm = self.toAssembly("funcCall", rName,rValue,"None",varObj.assignedTo)
|
|
finalAssm += f"{assm}\n"
|
|
elif rType == "structMember":
|
|
varObj.Name = rName
|
|
varObj.Type = rType
|
|
varObj.Value = rValue
|
|
mainVars.append(varObj)
|
|
assm = self.toAssembly("structMember",rName,rValue,"None",varObj.assignedTo)
|
|
finalAssm += assm
|
|
#print(f"{self.asmObj.dotData}")
|
|
except Exception as e:
|
|
raise
|
|
self.asmObj.assembly += self.stackSpace()
|
|
self.asmObj.assembly += self.GetSyscallNumber()
|
|
self.asmObj.assembly += self.GetModelNumber()
|
|
self.asmObj.assembly += self.sysCallAsm()
|
|
self.asmObj.assembly += finalAssm
|
|
self.asmObj.assembly += self.stackEnd()
|
|
if nasm:
|
|
if dataSection:
|
|
self.asmObj.nasm += self.assemblerDataSection()
|
|
self.asmObj.nasm += self.asmObj.assembly
|
|
nasmAsmTemp = self.asmObj.nasm
|
|
nasmAsmTemp = self.ignoreRawBytes(nasmAsmTemp)
|
|
self.asmObj.nasm = nasmAsmTemp.replace("ptr", "")
|
|
self.asmObj.nasm = self.formatAssemblyAndComments(self.asmObj.nasm)
|
|
noCommentAsm = self.removeAsmComments(self.asmObj.nasm)
|
|
shellcode = self.asm2Shellcode(noCommentAsm)
|
|
self.asmObj.shellcode = shellcode
|
|
|
|
elif masm:
|
|
if dataSection:
|
|
self.asmObj.nasm += self.assemblerDataSection()
|
|
self.asmObj.masm += self.ignoreRawBytes(self.asmObj.assembly)
|
|
self.asmObj.masm = self.formatAssemblyAndComments(self.asmObj.masm)
|
|
noCommentAsm = self.removeAsmComments(self.asmObj.masm)
|
|
shellcode = self.asm2Shellcode(noCommentAsm)
|
|
self.asmObj.shellcode = shellcode
|
|
finalAssembly.append(self.asmObj)
|
|
noCommentAsm = self.removeAsmComments(self.asmObj.assembly)
|
|
#shellcode = self.asm2Shellcode(noCommentAsm)
|
|
#self.asmObj.shellcode = shellcode
|
|
|
|
def readMain(self,lines):
|
|
code = None
|
|
try:
|
|
mainLines = [k.replace("\n", "").strip() for k in lines]
|
|
mainLines = list(filter(None, mainLines))
|
|
if mainLines[1] == "{" and mainLines[-1] == "}":
|
|
code = mainLines[2:-1]
|
|
else:
|
|
for num, line in reversed(list(enumerate(mainLines))):
|
|
if line == "}":
|
|
code = mainLines[2:num]
|
|
break
|
|
except Exception as e:
|
|
raise
|
|
if code:
|
|
self.parseMain(code)
|
|
|
|
def hiddenStructFound(self, struct, structObj, structName, structPtr):
|
|
constTypes = {
|
|
"PWSTR":0x4,
|
|
"PVOID":0x4,
|
|
"PWCHAR":0x4,
|
|
"PSIZE_T":0x4,
|
|
"HANDLE":0x4,
|
|
"SIZE_T":0x4,
|
|
"UCHAR":0x1,
|
|
"USHORT":0x2,
|
|
"BYTE":0x1,
|
|
"ULONG":0x4,
|
|
"ULONG_PTR":0x4,
|
|
"SIZE_T":0x4,
|
|
"NTSTATUS":0x4,
|
|
"DWORD":0x4,
|
|
"KPRIORITY":0x4,
|
|
"ACCESS_MASK":0x4,
|
|
"LARGE_INTEGER":0x8}
|
|
|
|
struct = struct[1:-1]
|
|
types = dataTypes if x64 else dataTypes_x86
|
|
try:
|
|
for stLine in struct:
|
|
memSize = 0
|
|
stLine = stLine.lstrip()
|
|
dType = stLine.strip().split(" ")[0]
|
|
if dType in types:
|
|
memberName = stLine.strip().split(" ")[-1]
|
|
memberName = memberName.replace(";", "")
|
|
possibleArr = re.search(r'\[(\d+)\]', memberName)
|
|
if possibleArr:
|
|
arrSize = possibleArr.group(1)
|
|
memSize += (types[dType] * int(arrSize))
|
|
else:
|
|
memSize += types[dType]
|
|
memDict = {hex(memSize):memberName}
|
|
structObj.Members.append(memDict)
|
|
else:
|
|
for st in structs:
|
|
if st.Name in dType:
|
|
totalStructSize = 0
|
|
hexSizes = [list(item.keys())[0] for item in st.Members]
|
|
decimalSizes = [int(size, 16) for size in hexSizes]
|
|
totalStructSize += sum(decimalSizes)
|
|
dName = stLine.split(" ")[1]
|
|
dName = dName.strip().replace("\n", "").replace(";","")
|
|
memDict = {hex(totalStructSize):{dName+"->"+st.Name:st.Members[::-1]}}
|
|
structObj.Members.append(memDict)
|
|
except Exception as e:
|
|
raise
|
|
|
|
def structFound(self,struct, structObj, structName, structPtr):
|
|
struct = struct[1:-1]
|
|
types = dataTypes if x64 else dataTypes_x86
|
|
size = 0
|
|
structRev = struct[::-1]
|
|
try:
|
|
for stLine in structRev:
|
|
currentStackPtr = self.asmObj.stackStart
|
|
stLine = stLine.lstrip()
|
|
dType = stLine.split(" ")[0]
|
|
if dType in types:
|
|
memberName = stLine.split(" ")[-1].strip()
|
|
memberName = memberName.replace(";", "")
|
|
possibleArr = re.search(r'\[(\d+)\]', memberName)
|
|
if possibleArr:
|
|
arrSize = possibleArr.group(1)
|
|
size += (types[dType] * int(arrSize))
|
|
else:
|
|
size += types[dType]
|
|
memDict = {hex(types[dType]):memberName}
|
|
structObj.Members.append(memDict)
|
|
else:
|
|
for st in structs:
|
|
if st.Name in dType:
|
|
dName = stLine.split(" ")[1]
|
|
dName = dName.strip().replace("\n", "").replace(";","")
|
|
ptrLoc = st.Members[0]
|
|
ptrHex = [x for x in ptrLoc][0]
|
|
memDict = {hex(4):dName+"->"+dType}
|
|
structObj.Members.append(memDict)
|
|
except Exception as e:
|
|
raise
|
|
structObj.totalSize = size
|
|
|
|
|
|
def toUnicode(self, Arr):
|
|
newArr = []
|
|
for i in Arr:
|
|
newArr.append(i)
|
|
newArr.append('00')
|
|
return newArr
|
|
|
|
def getStructData(self, chunk):
|
|
for count, value in enumerate(chunk):
|
|
if "," in value and "*" in value:
|
|
return(chunk[:count+1])
|
|
elif "}" in value and ";" in value:
|
|
return (chunk[:count+1])
|
|
|
|
def getStructNameAndPointer(self, chunk):
|
|
line = chunk[-1]
|
|
name = re.findall('[a-zA-Z0-9_]+,', line)
|
|
ptr = re.findall('[a-zA-Z0-9_]+;', line)
|
|
if ptr and not name:
|
|
return(ptr[0][:-1], "")
|
|
|
|
elif name and ptr:
|
|
return(name[0][:-1], ptr[0][:-1])
|
|
|
|
def toHex(self, Arr):
|
|
converted = []
|
|
try:
|
|
for char in Arr:
|
|
ordDec = ord(str(char))
|
|
Hex = f'{ordDec:x}'
|
|
converted.append(Hex)
|
|
return converted
|
|
except Exception as e:
|
|
raise
|
|
|
|
def extractString(self, line):
|
|
getString = re.search('InitUnicodeStr\((.*),\s*(.*)\)', line)
|
|
if getString:
|
|
inStr = getString.group(2).replace('"',"")
|
|
structPtr = getString.group(1)
|
|
return structPtr,inStr
|
|
else:
|
|
print(f"{red}Error: cannot extract unicode string{rst}")
|
|
print(f"Error line: {line}")
|
|
sys.exit()
|
|
|
|
def debug(self, text, Type):
|
|
dbg = "[{}] {}".format(o + "*" + rst, g + "DEBUG" + rst)
|
|
print("{} {} {}".format(dbg, c + text+ rst, red + Type + rst))
|
|
|
|
def parser(self, lines):
|
|
try:
|
|
for count, line in enumerate(lines):
|
|
if "typedef" in line and "struct" in line:
|
|
self.structObj = Structs()
|
|
structData = self.getStructData(lines[count:])
|
|
structName, structPtr = self.getStructNameAndPointer(structData)
|
|
self.structObj.Name = structName
|
|
self.structObj.Pointer = structPtr
|
|
self.structObj.Lines = structData
|
|
structs.append(self.structObj)
|
|
self.structFound(self.structObj.Lines, self.structObj, structName, structPtr)
|
|
continue
|
|
elif "hidden" in line and "struct" in line:
|
|
self.structObj = Structs()
|
|
structData = self.getStructData(lines[count:])
|
|
structName, structPtr = self.getStructNameAndPointer(structData)
|
|
self.structObj.Name = structName
|
|
self.structObj.Pointer = structPtr
|
|
self.structObj.Lines = structData
|
|
hiddenstructs.append(self.structObj)
|
|
self.hiddenStructFound(self.structObj.Lines, self.structObj, structName, structPtr)
|
|
elif "<MAIN>" in line:
|
|
self.readMain(lines[count:])
|
|
return True
|
|
except Exception as e:
|
|
raise
|
|
return False
|
|
|
|
def readFile(self):
|
|
allLines = []
|
|
with open(self.file, "r") as content:
|
|
for line in content:
|
|
allLines.append(line)
|
|
|
|
return self.parser(allLines)
|
|
|
|
|
|
def show_help():
|
|
table = Table(title="\nAvailable Commands",
|
|
show_header=True,
|
|
header_style="bold magenta",
|
|
box=box.ROUNDED,
|
|
border_style="dim blue")
|
|
|
|
table.add_column("Command", style="cyan", width=30)
|
|
table.add_column("Description", style="green")
|
|
|
|
# Configuration Group
|
|
table.add_row(" set arch <x64|x86>", "Switch between 32/64-bit modes")
|
|
table.add_row(" set assembler <masm|nasm>", "Select assembler syntax")
|
|
table.add_row(" generate shellcode", "Output raw bytes")
|
|
table.add_row(" generate assembly", "Output assembly instructions")
|
|
table.add_row(" generate binary", "Output nasm generated binary")
|
|
table.add_row(" enable data", "Enable .data section. Important if using third party shellcode")
|
|
table.add_row(" load <filename>", "Load custom C file")
|
|
table.add_row(" help", "Print this help menu")
|
|
console.print(table)
|
|
|
|
|
|
def help():
|
|
allText = ""
|
|
allText += "\n"
|
|
allText += f"\t {y}******************\n"
|
|
allText += f"\t ******{o} Help{y} ******\n"
|
|
allText += f"\t {y}******************{rst}"
|
|
|
|
T = f"""
|
|
{w}
|
|
load [filepath] Load and read c file from given path
|
|
print assembly Translate c code to assembly
|
|
print shellcode Convert assembly to shellcode
|
|
exit Exit the program
|
|
{rst}
|
|
|
|
"""
|
|
print(allText)
|
|
print(T)
|
|
|
|
|
|
def readSysCalls(syscall_name, model_number=None, find_api_num=None):
|
|
csv_file = "syscallslist.csv"
|
|
with open(csv_file, 'r') as file:
|
|
reader = csv.reader(file)
|
|
headers = next(reader)
|
|
try:
|
|
for row in reader:
|
|
api_num = row[0]
|
|
ntApiName = row[1]
|
|
if ntApiName == syscall_name: # Check System call column
|
|
if find_api_num:
|
|
return hex(int(api_num)) # Return the line number
|
|
else:
|
|
col_index = headers.index(model_number)
|
|
return row[col_index] # Return the syscall number in hex
|
|
except Exception as e:
|
|
raise
|
|
return None # Model number not found
|
|
|
|
return None # Syscall not found
|
|
|
|
|
|
def readSysCalls2(syscall_name, model_number=None, find_api_num=None):
|
|
try:
|
|
file_path = "syscallslist.txt"
|
|
data_dict = {}
|
|
apis_and_nums = {}
|
|
with open(file_path, newline='') as csvfile:
|
|
reader = csv.reader(csvfile, delimiter='\t')
|
|
header = next(reader)
|
|
for row in reader:
|
|
service_name = row[1]
|
|
service_id = row[0]
|
|
api_num_dict = {service_name:service_id}
|
|
apis_and_nums.update(api_num_dict)
|
|
values = row[2:] # Values start from index 2 onward
|
|
data_dict[service_name] = {}
|
|
for i, value in enumerate(values):
|
|
column_number = header[i+2] # +2 to skip # and ServiceName columns
|
|
if value.strip():
|
|
data_dict[service_name][column_number] = value
|
|
else:
|
|
data_dict[service_name][column_number] = None
|
|
if not find_api_num:
|
|
if syscall_name in data_dict and model_number in data_dict[syscall_name]:
|
|
value = data_dict[syscall_name][model_number]
|
|
return hex(int(value, 16))
|
|
else:
|
|
return None
|
|
else:
|
|
api_num = apis_and_nums[syscall_name]
|
|
return hex(int(api_num))
|
|
except Exception as e:
|
|
raise
|
|
|
|
|
|
def getAssemblerCmd():
|
|
nasm_command = [
|
|
"nasm",
|
|
"-f", "win64",
|
|
"-o", "main.obj",
|
|
"main.asm"
|
|
]
|
|
return nasm_command
|
|
|
|
def generateBinary(rawAssembly):
|
|
writeAsmToFile(rawAssembly)
|
|
assemblyCmd = getAssemblerCmd()
|
|
binFileName = input(f"{c}[*]{rst} Enter file name: ")
|
|
if not binFileName.lower().endswith(".exe"):
|
|
binFileName += ".exe"
|
|
compileCmd = getCompilerCmd(binFileName)
|
|
console.print("[bold cyan]Assembling...[/bold cyan]")
|
|
run_with_progress("run", assemblyCmd)
|
|
console.print("[bold cyan]Compiling...[/bold cyan]")
|
|
if run_with_progress("run", compileCmd):
|
|
output_path = os.path.join("bin", binFileName)
|
|
print(f"File saved to {g}{output_path}{rst}")
|
|
|
|
def getCompilerCmd(outputFileName):
|
|
os.makedirs("bin", exist_ok=True)
|
|
full_output_path = os.path.join("bin", outputFileName)
|
|
mingw_command = [
|
|
"x86_64-w64-mingw32-gcc",
|
|
"-o", full_output_path,
|
|
"main.obj",
|
|
"-lkernel32",
|
|
"-mconsole",
|
|
"-nostartfiles"
|
|
]
|
|
return mingw_command
|
|
|
|
def writeAsmToFile(asmCode):
|
|
nasm_syntax = """
|
|
global _start
|
|
section .text
|
|
_start:
|
|
"""
|
|
try:
|
|
with open("main.asm", "w") as f:
|
|
#f.write(nasm_syntax)
|
|
f.write(asmCode)
|
|
return True
|
|
except:
|
|
return False
|
|
|
|
def cli():
|
|
completer = ContextCompleter()
|
|
readline.set_completer(completer.complete)
|
|
system_name = platform.system()
|
|
global x64
|
|
global masm
|
|
global nasm
|
|
global dataSection
|
|
if system_name == "Darwin":
|
|
readline.parse_and_bind('bind ^I rl_complete')
|
|
elif system_name == "Linux":
|
|
readline.parse_and_bind('tab: complete')
|
|
readerObject = None
|
|
while True:
|
|
try:
|
|
fullCmd = input(f"{brblk}S{o}I{y}L{o}O{brblk}>{rst} ")
|
|
if not fullCmd.strip():
|
|
continue
|
|
else:
|
|
cmdLine = fullCmd.split(" ")
|
|
numArgs = len(cmdLine)
|
|
if numArgs == 2:
|
|
cmd = cmdLine[0]
|
|
if cmd.lower() == "load":
|
|
filePath = cmdLine[1]
|
|
try:
|
|
console.print("[bold cyan]Loading file...[/bold cyan]")
|
|
r = Reader(filePath)
|
|
readerObject = r
|
|
run_with_progress("readfile", r)
|
|
except Exception as e:
|
|
print(f"{w}{e}{rst}")
|
|
elif cmd.lower() == "generate":
|
|
cType = cmdLine[1]
|
|
if cType == "assembly":
|
|
if masm:
|
|
if len(Reader.asmObj.masm) < 1:
|
|
print(f"{y}[!]{rst} {c}Please load a file first")
|
|
else:
|
|
print("\n")
|
|
print(Reader.asmObj.masm)
|
|
elif nasm:
|
|
if len(Reader.asmObj.nasm) < 1:
|
|
print(f"{y}[!]{rst} {c}Please load a file first")
|
|
else:
|
|
print("\n")
|
|
print(Reader.asmObj.nasm)
|
|
else:
|
|
print("\n")
|
|
print(Reader.asmObj.assembly)
|
|
|
|
elif cType == "shellcode":
|
|
print("\n")
|
|
print(Reader.asmObj.shellcode)
|
|
elif cType == "binary":
|
|
if len(Reader.asmObj.nasm) < 1:
|
|
print(f"{y}[!]{rst} {c}Please load a file first")
|
|
else:
|
|
if nasm:
|
|
rawAssembly = readerObject.removeAsmComments(Reader.asmObj.nasm)
|
|
generateBinary(rawAssembly)
|
|
else:
|
|
print(f"{y}[!]{rst} {c}Sorry, only NASM works for binary generation.")
|
|
|
|
else:
|
|
print(f"{red}[!]{rst} Invalid command")
|
|
elif cmd.lower() == "enable" and cmdLine[1] == "data":
|
|
if dataSection:
|
|
print(f"{c}[*]{rst} Data section already enabled")
|
|
else:
|
|
dataSection = True
|
|
print(f"{c}[*]{rst} Data section enabled")
|
|
|
|
else:
|
|
print(f"{red}[!]{rst} Invalid command")
|
|
continue
|
|
elif numArgs == 3:
|
|
cmd = cmdLine[0]
|
|
if cmd.lower() in "set":
|
|
cType = cmdLine[1]
|
|
if cType in "arch":
|
|
arch = cmdLine[2]
|
|
if arch == "x64":
|
|
x64 = True
|
|
print(f"{c}[*]{rst} Arch set to {g}x64{rst}")
|
|
elif arch == "x86":
|
|
print(f"{c}[*]{rst} Arch set to {g}x86{rst}")
|
|
else:
|
|
print(f"{red}[!]{rst} Invalid arch, defaulting to {g}x86{rst}")
|
|
elif cType in "assembler":
|
|
flavor = cmdLine[2]
|
|
if flavor == "masm":
|
|
if masm:
|
|
nasm = False
|
|
print(f"{c}[*]{rst} Assembler already set to {g}MASM{rst}")
|
|
else:
|
|
masm = True
|
|
nasm = False
|
|
print(f"{c}[*]{rst} Assembler set to {g}MASM{rst}")
|
|
elif flavor == "nasm":
|
|
if nasm:
|
|
masm = False
|
|
print(f"{c}[*]{rst} Assembler already set to {g}NASM{rst}")
|
|
else:
|
|
nasm = True
|
|
masm = False
|
|
print(f"{c}[*]{rst} Assembler set to {g}NASM{rst}")
|
|
else:
|
|
print(f"{red}[!]{rst} Invalid Assembler, type help for more options")
|
|
|
|
elif numArgs == 1:
|
|
if fullCmd in ["exit", "quit"]:
|
|
print(f"{w}Exiting..{rst}")
|
|
break
|
|
elif fullCmd == "help":
|
|
show_help()
|
|
else:
|
|
print(f"{red}[!]{rst} Invalid command")
|
|
else:
|
|
print(f"{red}[!]{rst} Invalid command")
|
|
|
|
except KeyboardInterrupt:
|
|
print(f"\n[!] Closing..")
|
|
break
|
|
except Exception as e:
|
|
raise
|
|
|
|
|
|
def banner2():
|
|
|
|
T = """
|
|
[bold cyan] ███████╗██╗ ██╗███████╗██╗ ██╗ ███████╗██╗██╗ ██████╗
|
|
██╔════╝██║ ██║██╔════╝██║ ██║ ██╔════╝██║██║ ██╔═══██╗
|
|
███████╗███████║█████╗ ██║ ██║ ███████╗██║██║ ██║ ██║
|
|
╚════██║██╔══██║██╔══╝ ██║ ██║ ╚════██║██║██║ ██║ ██║
|
|
███████║██║ ██║███████╗███████╗███████╗███████║██║███████╗╚██████╔╝
|
|
╚══════╝╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝╚══════╝╚═╝╚══════╝ ╚═════╝ [/bold cyan][bold yellow]
|
|
╔══════════════════════[white] SHELLSILO [/]══════════════════════╗
|
|
║ [bold cyan]0x48 0x89 0xFE[/bold cyan] [bold red]0x0F 0x05[/bold red] │ [dim]v1.0[/dim] │ [white]Tarek Ahmed ☢️[/] ║
|
|
╚═══════════════════════════════════════════════════════╝[/bold yellow]"""
|
|
console.print(T, end="")
|
|
def banner():
|
|
|
|
T = f"""
|
|
{y}@@@@@@@@@
|
|
@@@@@@@@@@@@@@@@@
|
|
@@@@@@@@@@@@@@@@@@@@@@@
|
|
@@@{brblk}:::{y}@@@@@@@@@@@@@{brblk}:::{y}@@@
|
|
@@@@{brblk}:::::{y}@@@@@@@@@@@{brblk}:::::{y}@@@@
|
|
@@@{brblk}::::::::{y}@@@@@@@@@{brblk}::::::::{y}@@@
|
|
@@@{brblk}::::::::::{y}@@@@@@@{brblk}::::::::::{y}@@@
|
|
@@@{brblk}:{o}PUSH RAX{brblk}::{y}@@@@@{brblk}::{o}PUSH RBX{brblk}:{y}@@@
|
|
@@{brblk}:::::::::::{y}@{brblk}:::::{y}@{brblk}:::::::::::{y}@@
|
|
@@@{brblk}::::::::::{y}@@{brblk}:::::{y}@@{brblk}::::::::::{y}@@@
|
|
@@@@@@@@@@@@@@{brblk}:::::{y}@@@@@@@@@@@@@@
|
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
@@@@@@@@@@@@@{brblk}:::::::{y}@@@@@@@@@@@@@
|
|
@@@@@@@@@@@{brblk}:::::::::{y}@@@@@@@@@@@
|
|
@@@@@@@@@{brblk}:::::::::::{y}@@@@@@@@@
|
|
@@@@@@{brblk}:::{o}SYSCALL{brblk}:::{y}@@@@@@
|
|
@@@@@{brblk}:::::::::::::{y}@@@@@
|
|
@@@@@@@@@@@@@@@@@
|
|
@@@@@@@@@
|
|
"""
|
|
print(T)
|
|
|
|
def main():
|
|
banner2()
|
|
banner()
|
|
cli()
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
main()
|
|
except Exception:
|
|
import traceback
|
|
traceback.print_exc()
|