feature: dev (shellcode projects) phase 1

This commit is contained in:
Dobin
2024-03-26 17:46:09 +00:00
parent aa194edef3
commit f08334dc1a
16 changed files with 285 additions and 55 deletions
+2 -1
View File
@@ -16,4 +16,5 @@ tools/
doc/
*.pickle
logs/
app/projects/*
app/projects/*
data/dev/*
+31
View File
@@ -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>
+23
View File
@@ -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>
-8
View File
@@ -10,14 +10,6 @@
<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>
</body>
</html>
+14 -1
View File
@@ -14,7 +14,20 @@
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<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>
</div>
</div>
+22
View File
@@ -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>
+84
View File
@@ -11,7 +11,10 @@ import difflib
from ansi2html import Ansi2HTMLConverter
import shutil
import subprocess
import time
from datetime import datetime
from observer import observer
from config import config
from model.settings import Settings
from model.defs import *
@@ -19,7 +22,10 @@ from supermega import start
from app.storage import storage, Project
from sender import scannerDetectsBytes
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 log import getlog
views = Blueprint('views', __name__)
@@ -37,6 +43,84 @@ def index():
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>")
def project(name):
project = storage.get_project(name)
+8 -39
View File
@@ -6,6 +6,7 @@ import logging
from config import config
from model.defs import *
from observer import observer
logger = logging.getLogger("Helper")
@@ -48,22 +49,28 @@ def run_process_checkret(args, check=True):
except Exception as e:
logger.warn(f"An error occurred: {e}")
# Handle other exceptions
with open(f"{logs_dir}/cmdoutput.log", "ab") as f:
cmd = "------------------------------------\n"
cmd += "--- " + " ".join(args) + "\n"
f.write(cmd.encode('utf-8'))
if ret.stdout != None:
observer.add_log(ret.stdout.decode('utf-8'))
f.write(ret.stdout)
if ret.stderr != None:
observer.add_log(ret.stderr.decode('utf-8'))
f.write(ret.stderr)
if ret.returncode != 0 and check:
logger.info("----! FAILED Command: {}".format(" ".join(args)))
if ret.stdout != None:
observer.add_log(ret.stdout.decode('utf-8'))
logger.info(ret.stdout.decode('utf-8'))
if ret.stderr != None:
observer.add_log(ret.stderr.decode('utf-8'))
logger.info(ret.stderr.decode('utf-8'))
raise Exception("Command failed: " + " ".join(args))
if config.ShowCommandOutput:
logger.info("> " + " ".join(args))
if ret.stdout != None:
@@ -92,16 +99,6 @@ def file_readall_binary(filepath) -> bytes:
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):
rbrunmode = str(rbrunmode)
if rbrunmode == "1":
@@ -112,34 +109,6 @@ def rbrunmode_str(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):
with open(filename, 'rb') as f:
+3
View File
@@ -52,6 +52,9 @@ def writelog():
for line in log_messages:
f.write(line + "\n")
def getlog():
return log_messages
def setup_logging(level = logging.INFO):
root_logger = logging.getLogger()
root_logger.setLevel(level)
+4 -2
View File
@@ -2,9 +2,8 @@ import json
import pprint
from capstone import Cs, CS_ARCH_X86, CS_MODE_64
from model import *
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 *
@@ -18,6 +17,9 @@ class Observer():
self.logs = []
self.idx = 0
def add_log(self, log):
self.logs.append(log)
def add_text(self, name, data):
self.write_to_file(name + ".txt", data)
self.idx += 1
+1 -1
View File
@@ -11,7 +11,7 @@ import keystone
from enum import IntEnum
import logging
from helper import hexdump
from utils import hexdump
from pe.superpe import SuperPe
from model.defs import *
+1 -1
View File
@@ -2,7 +2,7 @@ import r2pipe
import os
from model.defs import *
from helper import hexdump
from utils import hexdump
def r2_disas(data: bytes):
filename = "r2_data.bin"
+1 -1
View File
@@ -4,7 +4,7 @@ from enum import IntEnum
import logging
from typing import List
from helper import hexdump
from utils import hexdump
from model.defs import *
logger = logging.getLogger("superpe")
+41
View File
@@ -16,6 +16,47 @@ from model.exehost import ExeHost
logger = logging.getLogger("Compiler")
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(
c_in: FilePath,
+1 -1
View File
@@ -18,7 +18,7 @@ from model.project import Project
from model.settings import Settings
from model.defs import *
from log import setup_logging, writelog
from utils import delete_all_files_in_directory
def main():
"""Argument parsing for when called from command line"""
+49
View File
@@ -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)