mirror of
https://github.com/dobin/SuperMega
synced 2026-06-03 01:27:11 +00:00
feature: dev (shellcode projects) phase 1
This commit is contained in:
+2
-1
@@ -16,4 +16,5 @@ tools/
|
|||||||
doc/
|
doc/
|
||||||
*.pickle
|
*.pickle
|
||||||
logs/
|
logs/
|
||||||
app/projects/*
|
app/projects/*
|
||||||
|
data/dev/*
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
{% include 'header.html' %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% include 'navigation.html' %}
|
||||||
|
|
||||||
|
<div class="indent">
|
||||||
|
|
||||||
|
<h1> ShcDev: {{name}}</h1>
|
||||||
|
|
||||||
|
<table class="table">
|
||||||
|
{% for file in files %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="/dev/{{name}}/file/{file['name']}">{{ file['name']}}</a></td>
|
||||||
|
<td>{{file["date"]}}</td>
|
||||||
|
<td>{{file["info"]}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<a href="/dev/{{name}}/build">Build</a>
|
||||||
|
|
||||||
|
<br><hr>
|
||||||
|
|
||||||
|
<pre>{{log}}</pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
{% include 'header.html' %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% include 'navigation.html' %}
|
||||||
|
|
||||||
|
<div class="indent">
|
||||||
|
|
||||||
|
<h1> ShcDevs: </h1>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for item in data %}
|
||||||
|
<li><a href="/dev/{{item['name']}}">{{ item['name'] }}</a>
|
||||||
|
({{item["date"]}})
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -10,14 +10,6 @@
|
|||||||
|
|
||||||
<h1> SuperMega </h1>
|
<h1> SuperMega </h1>
|
||||||
|
|
||||||
<!-- iterate through data and print as ul -->
|
|
||||||
<ul>
|
|
||||||
{% for item in data %}
|
|
||||||
<li><a href="/project/{{item.name}}">{{ item.name }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<a href="/add_project">Add Project</a>
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -14,7 +14,20 @@
|
|||||||
|
|
||||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
<ul class="navbar-nav mr-auto">
|
<ul class="navbar-nav mr-auto">
|
||||||
<li class="nav-item"><a class="nav-link {{ 'active' if request.path == '/' else '' }}" href="/">Home</a></li>
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {{ 'active' if request.path == '/' else '' }}"
|
||||||
|
href="/">Home</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {{ 'active' if request.path == '/projects' else '' }}"
|
||||||
|
href="/projects">Projects</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {{ 'active' if request.path == '/dev' else '' }}"
|
||||||
|
href="/dev">ShcDev</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
{% include 'header.html' %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% include 'navigation.html' %}
|
||||||
|
|
||||||
|
<div class="indent">
|
||||||
|
|
||||||
|
<h1> Projects </h1>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for item in data %}
|
||||||
|
<li><a href="/project/{{item.name}}">{{ item.name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<a href="/add_project">Add Project</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -11,7 +11,10 @@ import difflib
|
|||||||
from ansi2html import Ansi2HTMLConverter
|
from ansi2html import Ansi2HTMLConverter
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import time
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from observer import observer
|
||||||
from config import config
|
from config import config
|
||||||
from model.settings import Settings
|
from model.settings import Settings
|
||||||
from model.defs import *
|
from model.defs import *
|
||||||
@@ -19,7 +22,10 @@ from supermega import start
|
|||||||
from app.storage import storage, Project
|
from app.storage import storage, Project
|
||||||
from sender import scannerDetectsBytes
|
from sender import scannerDetectsBytes
|
||||||
from phases.injector import verify_injected_exe
|
from phases.injector import verify_injected_exe
|
||||||
|
from phases.compiler import compile_dev
|
||||||
|
from phases.assembler import asm_to_shellcode
|
||||||
from helper import run_process_checkret
|
from helper import run_process_checkret
|
||||||
|
from log import getlog
|
||||||
|
|
||||||
views = Blueprint('views', __name__)
|
views = Blueprint('views', __name__)
|
||||||
|
|
||||||
@@ -37,6 +43,84 @@ def index():
|
|||||||
return render_template('index.html', data=storage.data)
|
return render_template('index.html', data=storage.data)
|
||||||
|
|
||||||
|
|
||||||
|
@views.route("/projects")
|
||||||
|
def projects_route():
|
||||||
|
return render_template('projects.html', data=storage.data)
|
||||||
|
|
||||||
|
|
||||||
|
@views.route("/dev")
|
||||||
|
def devs_route():
|
||||||
|
data = []
|
||||||
|
path = "data/dev"
|
||||||
|
for file_path in os.listdir(path):
|
||||||
|
creation_time = os.path.getctime("data/dev" + "/" + file_path)
|
||||||
|
readable_time = datetime.fromtimestamp(creation_time).strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
data.append({
|
||||||
|
"name": file_path,
|
||||||
|
"date": readable_time,
|
||||||
|
})
|
||||||
|
return render_template('devs.html', data=data)
|
||||||
|
|
||||||
|
|
||||||
|
@views.route("/dev/<name>")
|
||||||
|
def dev_route(name):
|
||||||
|
data = []
|
||||||
|
log = ""
|
||||||
|
path = "data/dev/{}".format(name)
|
||||||
|
for file_path in os.listdir(path):
|
||||||
|
creation_time = os.path.getctime(path + "/" + file_path)
|
||||||
|
readable_time = datetime.fromtimestamp(creation_time).strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
info = ""
|
||||||
|
if file_path.endswith(".asm"):
|
||||||
|
info = "text assembly (cleaned, from compiled .c)"
|
||||||
|
elif file_path.endswith(".bin"):
|
||||||
|
info = "generated shellcode (from .exe)"
|
||||||
|
elif file_path.endswith(".c"):
|
||||||
|
info = "input C code"
|
||||||
|
elif file_path.endswith(".exe"):
|
||||||
|
info = "temporary shellcode holder (from .c)"
|
||||||
|
elif file_path.endswith(".log"):
|
||||||
|
info = "log file"
|
||||||
|
with open(path + "/" + file_path, "r") as f:
|
||||||
|
log = f.read()
|
||||||
|
|
||||||
|
print(log)
|
||||||
|
|
||||||
|
data.append({
|
||||||
|
"name": file_path,
|
||||||
|
"date": readable_time,
|
||||||
|
"info": info,
|
||||||
|
})
|
||||||
|
|
||||||
|
return render_template('dev.html',
|
||||||
|
name=name, files=data, log=log)
|
||||||
|
|
||||||
|
|
||||||
|
@views.route("/dev/<name>/build")
|
||||||
|
def dev_build_route(name):
|
||||||
|
|
||||||
|
c_in = "data/dev/{}/main.c".format(name)
|
||||||
|
asm_out = "data/dev/{}/main.asm".format(name)
|
||||||
|
build_exe = "data/dev/{}/main.exe".format(name)
|
||||||
|
shellcode_out = "data/dev/{}/main.bin".format(name)
|
||||||
|
log = "data/dev/{}/main.log".format(name)
|
||||||
|
|
||||||
|
compile_dev(c_in, asm_out)
|
||||||
|
asm_to_shellcode(asm_out, build_exe, shellcode_out)
|
||||||
|
|
||||||
|
with open(log, "w") as f:
|
||||||
|
for log_line in getlog():
|
||||||
|
f.write("{}\n".format(log_line))
|
||||||
|
|
||||||
|
f.write("\n\n")
|
||||||
|
|
||||||
|
for log in observer.logs:
|
||||||
|
f.write("{}".format(log))
|
||||||
|
|
||||||
|
return redirect("/dev/{}".format(name), code=302)
|
||||||
|
|
||||||
|
|
||||||
@views.route("/project/<name>")
|
@views.route("/project/<name>")
|
||||||
def project(name):
|
def project(name):
|
||||||
project = storage.get_project(name)
|
project = storage.get_project(name)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import logging
|
|||||||
|
|
||||||
from config import config
|
from config import config
|
||||||
from model.defs import *
|
from model.defs import *
|
||||||
|
from observer import observer
|
||||||
|
|
||||||
logger = logging.getLogger("Helper")
|
logger = logging.getLogger("Helper")
|
||||||
|
|
||||||
@@ -48,22 +49,28 @@ def run_process_checkret(args, check=True):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(f"An error occurred: {e}")
|
logger.warn(f"An error occurred: {e}")
|
||||||
# Handle other exceptions
|
# Handle other exceptions
|
||||||
|
|
||||||
with open(f"{logs_dir}/cmdoutput.log", "ab") as f:
|
with open(f"{logs_dir}/cmdoutput.log", "ab") as f:
|
||||||
cmd = "------------------------------------\n"
|
cmd = "------------------------------------\n"
|
||||||
cmd += "--- " + " ".join(args) + "\n"
|
cmd += "--- " + " ".join(args) + "\n"
|
||||||
f.write(cmd.encode('utf-8'))
|
f.write(cmd.encode('utf-8'))
|
||||||
if ret.stdout != None:
|
if ret.stdout != None:
|
||||||
|
observer.add_log(ret.stdout.decode('utf-8'))
|
||||||
f.write(ret.stdout)
|
f.write(ret.stdout)
|
||||||
if ret.stderr != None:
|
if ret.stderr != None:
|
||||||
|
observer.add_log(ret.stderr.decode('utf-8'))
|
||||||
f.write(ret.stderr)
|
f.write(ret.stderr)
|
||||||
|
|
||||||
if ret.returncode != 0 and check:
|
if ret.returncode != 0 and check:
|
||||||
logger.info("----! FAILED Command: {}".format(" ".join(args)))
|
logger.info("----! FAILED Command: {}".format(" ".join(args)))
|
||||||
if ret.stdout != None:
|
if ret.stdout != None:
|
||||||
|
observer.add_log(ret.stdout.decode('utf-8'))
|
||||||
logger.info(ret.stdout.decode('utf-8'))
|
logger.info(ret.stdout.decode('utf-8'))
|
||||||
if ret.stderr != None:
|
if ret.stderr != None:
|
||||||
|
observer.add_log(ret.stderr.decode('utf-8'))
|
||||||
logger.info(ret.stderr.decode('utf-8'))
|
logger.info(ret.stderr.decode('utf-8'))
|
||||||
raise Exception("Command failed: " + " ".join(args))
|
raise Exception("Command failed: " + " ".join(args))
|
||||||
|
|
||||||
if config.ShowCommandOutput:
|
if config.ShowCommandOutput:
|
||||||
logger.info("> " + " ".join(args))
|
logger.info("> " + " ".join(args))
|
||||||
if ret.stdout != None:
|
if ret.stdout != None:
|
||||||
@@ -92,16 +99,6 @@ def file_readall_binary(filepath) -> bytes:
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def delete_all_files_in_directory(directory_path):
|
|
||||||
files = glob.glob(os.path.join(directory_path, '*'))
|
|
||||||
for file_path in files:
|
|
||||||
try:
|
|
||||||
os.remove(file_path)
|
|
||||||
#logger.info(f"Deleted {file_path}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.info(f"Error deleting {file_path}: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
def rbrunmode_str(rbrunmode):
|
def rbrunmode_str(rbrunmode):
|
||||||
rbrunmode = str(rbrunmode)
|
rbrunmode = str(rbrunmode)
|
||||||
if rbrunmode == "1":
|
if rbrunmode == "1":
|
||||||
@@ -112,34 +109,6 @@ def rbrunmode_str(rbrunmode):
|
|||||||
return "Invalid: {}".format(rbrunmode)
|
return "Invalid: {}".format(rbrunmode)
|
||||||
|
|
||||||
|
|
||||||
def hexdump(data, addr = 0, num = 0):
|
|
||||||
s = ''
|
|
||||||
n = 0
|
|
||||||
lines = []
|
|
||||||
if num == 0: num = len(data)
|
|
||||||
|
|
||||||
if len(data) == 0:
|
|
||||||
return '<empty>'
|
|
||||||
|
|
||||||
for i in range(0, num, 16):
|
|
||||||
line = ''
|
|
||||||
line += '%04x | ' % (addr + i)
|
|
||||||
n += 16
|
|
||||||
|
|
||||||
for j in range(n-16, n):
|
|
||||||
if j >= len(data): break
|
|
||||||
line += '%02x ' % (data[j] & 0xff)
|
|
||||||
|
|
||||||
line += ' ' * (3 * 16 + 7 - len(line)) + ' | '
|
|
||||||
|
|
||||||
for j in range(n-16, n):
|
|
||||||
if j >= len(data): break
|
|
||||||
c = data[j] if not (data[j] < 0x20 or data[j] > 0x7e) else '.'
|
|
||||||
line += '%c' % c
|
|
||||||
|
|
||||||
lines.append(line)
|
|
||||||
return '\n'.join(lines)
|
|
||||||
|
|
||||||
|
|
||||||
def file_to_lf(filename):
|
def file_to_lf(filename):
|
||||||
with open(filename, 'rb') as f:
|
with open(filename, 'rb') as f:
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ def writelog():
|
|||||||
for line in log_messages:
|
for line in log_messages:
|
||||||
f.write(line + "\n")
|
f.write(line + "\n")
|
||||||
|
|
||||||
|
def getlog():
|
||||||
|
return log_messages
|
||||||
|
|
||||||
def setup_logging(level = logging.INFO):
|
def setup_logging(level = logging.INFO):
|
||||||
root_logger = logging.getLogger()
|
root_logger = logging.getLogger()
|
||||||
root_logger.setLevel(level)
|
root_logger.setLevel(level)
|
||||||
|
|||||||
+4
-2
@@ -2,9 +2,8 @@ import json
|
|||||||
import pprint
|
import pprint
|
||||||
from capstone import Cs, CS_ARCH_X86, CS_MODE_64
|
from capstone import Cs, CS_ARCH_X86, CS_MODE_64
|
||||||
|
|
||||||
from model import *
|
|
||||||
from pe.r2helper import r2_disas
|
from pe.r2helper import r2_disas
|
||||||
from helper import delete_all_files_in_directory
|
from utils import delete_all_files_in_directory
|
||||||
from model.defs import *
|
from model.defs import *
|
||||||
|
|
||||||
|
|
||||||
@@ -18,6 +17,9 @@ class Observer():
|
|||||||
self.logs = []
|
self.logs = []
|
||||||
self.idx = 0
|
self.idx = 0
|
||||||
|
|
||||||
|
def add_log(self, log):
|
||||||
|
self.logs.append(log)
|
||||||
|
|
||||||
def add_text(self, name, data):
|
def add_text(self, name, data):
|
||||||
self.write_to_file(name + ".txt", data)
|
self.write_to_file(name + ".txt", data)
|
||||||
self.idx += 1
|
self.idx += 1
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ import keystone
|
|||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from helper import hexdump
|
from utils import hexdump
|
||||||
from pe.superpe import SuperPe
|
from pe.superpe import SuperPe
|
||||||
from model.defs import *
|
from model.defs import *
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ import r2pipe
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from model.defs import *
|
from model.defs import *
|
||||||
from helper import hexdump
|
from utils import hexdump
|
||||||
|
|
||||||
def r2_disas(data: bytes):
|
def r2_disas(data: bytes):
|
||||||
filename = "r2_data.bin"
|
filename = "r2_data.bin"
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ from enum import IntEnum
|
|||||||
import logging
|
import logging
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from helper import hexdump
|
from utils import hexdump
|
||||||
from model.defs import *
|
from model.defs import *
|
||||||
|
|
||||||
logger = logging.getLogger("superpe")
|
logger = logging.getLogger("superpe")
|
||||||
|
|||||||
@@ -16,6 +16,47 @@ from model.exehost import ExeHost
|
|||||||
logger = logging.getLogger("Compiler")
|
logger = logging.getLogger("Compiler")
|
||||||
use_templates = True
|
use_templates = True
|
||||||
|
|
||||||
|
# NOTE: Mostly copy-pasted from compiler.py::compile()
|
||||||
|
def compile_dev(
|
||||||
|
c_in: FilePath,
|
||||||
|
asm_out: FilePath,
|
||||||
|
short_call_patching: bool = False,
|
||||||
|
):
|
||||||
|
logger.info("--[ Compile C to ASM: {} -> {} ".format(c_in, asm_out))
|
||||||
|
|
||||||
|
# Compile C To Assembly (text)
|
||||||
|
run_process_checkret([
|
||||||
|
config.get("path_cl"),
|
||||||
|
"/c",
|
||||||
|
"/FA",
|
||||||
|
"/GS-",
|
||||||
|
"/Fa{}/".format(os.path.dirname(c_in)),
|
||||||
|
c_in,
|
||||||
|
])
|
||||||
|
if not os.path.isfile(asm_out):
|
||||||
|
raise Exception("Error: Compiling failed")
|
||||||
|
file_to_lf(asm_out)
|
||||||
|
observer.add_text("carrier_asm_orig", file_readall_text(asm_out))
|
||||||
|
|
||||||
|
# Assembly cleanup (masm_shc)
|
||||||
|
asm_clean_file = asm_out + ".clean"
|
||||||
|
logger.info("---[ ASM masm_shc: {} ".format(asm_out))
|
||||||
|
params = Params(asm_out, asm_clean_file,
|
||||||
|
inline_strings=False, # not for DATA_REUSE
|
||||||
|
remove_crt=True,
|
||||||
|
append_rsp_stub=True) # required atm
|
||||||
|
process_file(params)
|
||||||
|
|
||||||
|
if not os.path.isfile(asm_clean_file):
|
||||||
|
raise Exception("Error: Cleaned up ASM file {} was not created".format(
|
||||||
|
asm_clean_file
|
||||||
|
))
|
||||||
|
|
||||||
|
# Move to destination we expect
|
||||||
|
shutil.move(asm_clean_file, asm_out)
|
||||||
|
if config.debug:
|
||||||
|
observer.add_text("carrier_asm_cleanup", file_readall_text(asm_out))
|
||||||
|
|
||||||
|
|
||||||
def compile(
|
def compile(
|
||||||
c_in: FilePath,
|
c_in: FilePath,
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ from model.project import Project
|
|||||||
from model.settings import Settings
|
from model.settings import Settings
|
||||||
from model.defs import *
|
from model.defs import *
|
||||||
from log import setup_logging, writelog
|
from log import setup_logging, writelog
|
||||||
|
from utils import delete_all_files_in_directory
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Argument parsing for when called from command line"""
|
"""Argument parsing for when called from command line"""
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import glob
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from config import config
|
||||||
|
from model.defs import *
|
||||||
|
|
||||||
|
logger = logging.getLogger("Utils")
|
||||||
|
|
||||||
|
|
||||||
|
def delete_all_files_in_directory(directory_path):
|
||||||
|
files = glob.glob(os.path.join(directory_path, '*'))
|
||||||
|
for file_path in files:
|
||||||
|
try:
|
||||||
|
os.remove(file_path)
|
||||||
|
#logger.info(f"Deleted {file_path}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.info(f"Error deleting {file_path}: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def hexdump(data, addr = 0, num = 0):
|
||||||
|
s = ''
|
||||||
|
n = 0
|
||||||
|
lines = []
|
||||||
|
if num == 0: num = len(data)
|
||||||
|
|
||||||
|
if len(data) == 0:
|
||||||
|
return '<empty>'
|
||||||
|
|
||||||
|
for i in range(0, num, 16):
|
||||||
|
line = ''
|
||||||
|
line += '%04x | ' % (addr + i)
|
||||||
|
n += 16
|
||||||
|
|
||||||
|
for j in range(n-16, n):
|
||||||
|
if j >= len(data): break
|
||||||
|
line += '%02x ' % (data[j] & 0xff)
|
||||||
|
|
||||||
|
line += ' ' * (3 * 16 + 7 - len(line)) + ' | '
|
||||||
|
|
||||||
|
for j in range(n-16, n):
|
||||||
|
if j >= len(data): break
|
||||||
|
c = data[j] if not (data[j] < 0x20 or data[j] > 0x7e) else '.'
|
||||||
|
line += '%c' % c
|
||||||
|
|
||||||
|
lines.append(line)
|
||||||
|
return '\n'.join(lines)
|
||||||
Reference in New Issue
Block a user