mirror of
https://github.com/bitdefender/bddisasm.git
synced 2024-11-25 17:08:35 +00:00
Add support for shemu in disasmtool_lix (thanks to Bogdan Bosinta - @bbosinta).
This commit is contained in:
parent
1aa0e0d71b
commit
5aa353867c
@ -30,6 +30,9 @@ set(disasmtool_src_files
|
||||
find_library(DISASM_LIB bddisasm PATHS "${DISASM_DIRECTORY}/${DISASM_BUILD_PREFIX}/${CMAKE_BUILD_TYPE}" NO_DEFAULT_PATH)
|
||||
message(STATUS "Disasm lib used: ${DISASM_LIB}")
|
||||
|
||||
find_library(SHEMU_LIB bdshemu PATHS "${DISASM_DIRECTORY}/${DISASM_BUILD_PREFIX}/${CMAKE_BUILD_TYPE}" NO_DEFAULT_PATH)
|
||||
message(STATUS "Shemu lib used: ${SHEMU_LIB}")
|
||||
|
||||
find_package(RapidJSON)
|
||||
|
||||
if (RapidJSON_FOUND)
|
||||
@ -253,6 +256,7 @@ endif()
|
||||
|
||||
include_directories(
|
||||
${DISASM_DIRECTORY}/inc
|
||||
${DISASM_DIRECTORY}/inc/bdshemu
|
||||
${DISASM_DIRECTORY}/bddisasm/include
|
||||
)
|
||||
|
||||
@ -272,6 +276,7 @@ set_target_properties(${CMAKE_PROJECT_NAME}
|
||||
CXX_EXTENSIONS ON
|
||||
)
|
||||
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} ${DISASM_LIB})
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} ${SHEMU_LIB} ${DISASM_LIB})
|
||||
|
||||
unset(DISASM_LIB CACHE)
|
||||
unset(SHEMU_LIB CACHE)
|
||||
|
@ -44,7 +44,7 @@ typedef size_t SIZE_T;
|
||||
#endif
|
||||
|
||||
// Main disasm header file.
|
||||
// #include "bdshemu.h"
|
||||
#include "bdshemu.h"
|
||||
#include "bddisasm.h"
|
||||
|
||||
#include <unistd.h>
|
||||
@ -68,3 +68,4 @@ StringBuffer instrux_to_json(INSTRUX *instrux, size_t rip, bool text_only = fals
|
||||
StringBuffer byte_to_json(uint8_t byte, size_t rip);
|
||||
StringBuffer disassemble_one(uint8_t *bytes, size_t size, size_t rip, uint8_t bits, uint8_t vendor = ND_VEND_INTEL);
|
||||
|
||||
bool regs_from_json(const std::string &str, SHEMU_GPR_REGS ®s, bool &update_rsp);
|
||||
|
@ -12,6 +12,9 @@
|
||||
|
||||
#include "disasm.hpp"
|
||||
|
||||
#define STACK_SIZE 0x2000
|
||||
#define PAGE_MASK 0xFFFFFFFFFFFFF000
|
||||
|
||||
static const long NSEC_PER_SEC = (1000ULL * 1000ULL * 1000ULL);
|
||||
|
||||
static const char *gSpaces[16] =
|
||||
@ -52,9 +55,15 @@ struct options {
|
||||
bool json_output;
|
||||
bool extended;
|
||||
|
||||
bool shemu;
|
||||
std::string shctx;
|
||||
bool kernel;
|
||||
|
||||
std::string in_file;
|
||||
std::string hex_string;
|
||||
std::string hex_file;
|
||||
std::string shctx_file;
|
||||
std::string shdec_file;
|
||||
|
||||
// From here on, these are set internally
|
||||
std::unique_ptr<uint8_t[]> bytes;
|
||||
@ -104,7 +113,7 @@ static bool _hexstring_to_bytes(options &opts)
|
||||
opts.hex_string.erase(std::remove_if(opts.hex_string.begin(), opts.hex_string.end(), isspace), opts.hex_string.end());
|
||||
|
||||
// This is the maximum size, not the actual size
|
||||
auto initial_size = opts.hex_string.length() / 2;
|
||||
auto initial_size = opts.hex_string.length() / 2 + 1;
|
||||
|
||||
opts.bytes = std::make_unique<uint8_t[]>(initial_size);
|
||||
auto bytes = opts.bytes.get();
|
||||
@ -131,6 +140,26 @@ static bool _hexstring_to_bytes(options &opts)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _load_shctx(options &opts)
|
||||
{
|
||||
if (opts.shctx_file.empty())
|
||||
return false;
|
||||
|
||||
auto f = std::ifstream(opts.shctx_file, std::ios::in);
|
||||
if (!f.is_open()) {
|
||||
std::cout << "Failed to open file " << opts.shctx_file << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
f.seekg(0, std::ios::end);
|
||||
opts.shctx.reserve(f.tellg());
|
||||
f.seekg(0, std::ios::beg);
|
||||
|
||||
opts.shctx.assign((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _file_to_bytes(options &opts)
|
||||
{
|
||||
auto f = std::ifstream(opts.in_file, std::ios::in | std::ios::binary);
|
||||
@ -458,6 +487,138 @@ StringBuffer disassemble_one(uint8_t *bytes, size_t size, size_t rip, uint8_t bi
|
||||
return instrux_to_json(&instrux, rip);
|
||||
}
|
||||
|
||||
void shemu_log(PCHAR msg)
|
||||
{
|
||||
printf("%s", msg);
|
||||
}
|
||||
|
||||
bool shemu_access_mem(void * /* Ctx */, uint64_t /* Gla */, size_t Size, uint8_t *Buffer, bool Store)
|
||||
{
|
||||
if (!Store)
|
||||
{
|
||||
memset(Buffer, 0, Size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void shemu(options &opts)
|
||||
{
|
||||
SHEMU_CONTEXT ctx = { };
|
||||
SHEMU_STATUS shstatus;
|
||||
|
||||
auto stack = std::make_unique<uint8_t[]>(STACK_SIZE);
|
||||
auto intbuf = std::make_unique<uint8_t[]>(opts.actual_size + STACK_SIZE);
|
||||
auto shellcode = std::make_unique<uint8_t[]>(opts.actual_size);
|
||||
|
||||
ctx.Stack = stack.get();
|
||||
memset(ctx.Stack, 0, STACK_SIZE);
|
||||
|
||||
ctx.Intbuf = intbuf.get();
|
||||
memset(ctx.Intbuf, 0, opts.actual_size + STACK_SIZE);
|
||||
|
||||
ctx.Shellcode = shellcode.get();
|
||||
memcpy(ctx.Shellcode, opts.bytes.get(), opts.actual_size);
|
||||
|
||||
ctx.ShellcodeSize = opts.actual_size;
|
||||
ctx.StackSize = STACK_SIZE;
|
||||
ctx.Registers.RegRsp = 0x101000;
|
||||
ctx.IntbufSize = opts.actual_size + STACK_SIZE;
|
||||
|
||||
ctx.Registers.RegFlags = NDR_RFLAG_IF | 2;
|
||||
ctx.Registers.RegRip = opts.rip;
|
||||
ctx.Segments.Cs.Selector = 0x10;
|
||||
ctx.Segments.Ds.Selector = 0x28;
|
||||
ctx.Segments.Es.Selector = 0x28;
|
||||
ctx.Segments.Ss.Selector = 0x28;
|
||||
ctx.Segments.Fs.Selector = 0x30;
|
||||
ctx.Segments.Fs.Base = 0x7FFF0000;
|
||||
ctx.Segments.Gs.Selector = 0x30;
|
||||
ctx.Segments.Gs.Base = 0x7FFF0000;
|
||||
|
||||
// Dummy values, to resemble regular CR0/CR4 values.
|
||||
ctx.Registers.RegCr0 = 0x0000000080050031;
|
||||
ctx.Registers.RegCr4 = 0x0000000000170678;
|
||||
|
||||
ctx.Mode = opts.bits;
|
||||
ctx.Ring = opts.kernel ? 0 : 3;
|
||||
ctx.TibBase = (opts.bits == ND_DATA_32 ? ctx.Segments.Fs.Base : ctx.Segments.Gs.Base);
|
||||
ctx.MaxInstructionsCount = 4096;
|
||||
ctx.Options = SHEMU_OPT_TRACE_EMULATION;
|
||||
ctx.Log = shemu_log;
|
||||
ctx.AccessMemory = shemu_access_mem;
|
||||
|
||||
// Configurable thresholds.
|
||||
ctx.NopThreshold = SHEMU_DEFAULT_NOP_THRESHOLD;
|
||||
ctx.StrThreshold = SHEMU_DEFAULT_STR_THRESHOLD;
|
||||
ctx.MemThreshold = SHEMU_DEFAULT_MEM_THRESHOLD;
|
||||
|
||||
bool update_rsp = false;
|
||||
|
||||
if (!opts.shctx.empty() && !regs_from_json(opts.shctx, ctx.Registers, update_rsp)) {
|
||||
std::cerr << "Failed to parse context file." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Consider the stack base at least with a page before the current RSP. In case of pushes or operations
|
||||
// which decrease the RSP, we will always give SHEMU_ABORT_BRANCH_OUTSIDE otherwise.
|
||||
ctx.StackBase = ctx.Registers.RegRsp - 0x1000;
|
||||
ctx.ShellcodeBase = (ctx.Registers.RegRip ? ctx.Registers.RegRip & PAGE_MASK : 0x200000);
|
||||
|
||||
shstatus = ShemuEmulate(&ctx);
|
||||
|
||||
printf("Emulation terminated with status 0x%08x, flags: 0x%llx, %u NOPs\n",
|
||||
shstatus, (unsigned long long)ctx.Flags, ctx.NopCount);
|
||||
if (ctx.Flags & SHEMU_FLAG_NOP_SLED)
|
||||
{
|
||||
printf(" SHEMU_FLAG_NOP_SLED\n");
|
||||
}
|
||||
if (ctx.Flags & SHEMU_FLAG_LOAD_RIP)
|
||||
{
|
||||
printf(" SHEMU_FLAG_LOAD_RIP\n");
|
||||
}
|
||||
if (ctx.Flags & SHEMU_FLAG_WRITE_SELF)
|
||||
{
|
||||
printf(" SHEMU_FLAG_WRITE_SELF\n");
|
||||
}
|
||||
if (ctx.Flags & SHEMU_FLAG_TIB_ACCESS)
|
||||
{
|
||||
printf(" SHEMU_FLAG_TIB_ACCESS\n");
|
||||
}
|
||||
if (ctx.Flags & SHEMU_FLAG_SYSCALL)
|
||||
{
|
||||
printf(" SHEMU_FLAG_SYSCALL\n");
|
||||
}
|
||||
if (ctx.Flags & SHEMU_FLAG_STACK_STR)
|
||||
{
|
||||
printf(" SHEMU_FLAG_STACK_STR\n");
|
||||
}
|
||||
if (ctx.Flags & SHEMU_FLAG_KPCR_ACCESS)
|
||||
{
|
||||
printf(" SHEMU_FLAG_KPCR_ACCESS\n");
|
||||
}
|
||||
if (ctx.Flags & SHEMU_FLAG_SWAPGS)
|
||||
{
|
||||
printf(" SHEMU_FLAG_SWAPGS\n");
|
||||
}
|
||||
if (ctx.Flags & SHEMU_FLAG_SYSCALL_MSR_READ)
|
||||
{
|
||||
printf(" SHEMU_FLAG_SYSCALL_MSR_READ\n");
|
||||
}
|
||||
if (ctx.Flags & SHEMU_FLAG_SYSCALL_MSR_WRITE)
|
||||
{
|
||||
printf(" SHEMU_FLAG_SYSCALL_MSR_WRITE\n");
|
||||
}
|
||||
|
||||
if (!opts.shdec_file.empty()) {
|
||||
auto f = std::ofstream(opts.shdec_file, std::ios::out | std::ios::binary);
|
||||
|
||||
if (!f.is_open())
|
||||
std::cerr << "Failed to open file " << opts.shdec_file<< std::endl;
|
||||
else
|
||||
f.write(reinterpret_cast<char*>(ctx.Shellcode), ctx.ShellcodeSize);
|
||||
}
|
||||
}
|
||||
|
||||
size_t disassemble(options &opts)
|
||||
{
|
||||
@ -602,6 +763,13 @@ static bool _validate_and_fix_args(options& opts)
|
||||
if (!isatty(fileno(stdout)))
|
||||
opts.output_redirected = true;
|
||||
|
||||
if (!opts.hex_file.empty())
|
||||
opts.shdec_file = opts.hex_file + "_decoded.bin";
|
||||
else if (!opts.in_file.empty())
|
||||
opts.shdec_file = opts.in_file + "_decoded.bin";
|
||||
else
|
||||
opts.shdec_file = "hex_string_decoded.bin";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -633,6 +801,9 @@ int main(int argc, const char **argv)
|
||||
parser.add_argument("--verbose", "Verbose mode", false);
|
||||
parser.add_argument("--json", "Output to json", false);
|
||||
parser.add_argument("--extended", "Extended instruction info", false);
|
||||
parser.add_argument("--shemu", "Emulate the input hexfile", false);
|
||||
parser.add_argument("--kernel", "Kernel mode for shemu context", false);
|
||||
parser.add_argument("--shctx", "Shemu context file. Must be a JSON file.", false);
|
||||
|
||||
parser.enable_help();
|
||||
|
||||
@ -662,6 +833,9 @@ int main(int argc, const char **argv)
|
||||
opts.verbose = parser.exists("verbose");
|
||||
opts.json_output = parser.exists("json");
|
||||
opts.extended = parser.exists("extended");
|
||||
opts.shemu = parser.exists("shemu");
|
||||
opts.kernel = parser.exists("kernel");
|
||||
opts.shctx_file = parser.get<std::string>("shctx");
|
||||
|
||||
if (opts.verbose) {
|
||||
std::cout << "interactive: " << opts.interactive << std::endl;
|
||||
@ -677,6 +851,9 @@ int main(int argc, const char **argv)
|
||||
std::cout << "hex: " << opts.hex_string << std::endl;
|
||||
std::cout << "json: " << opts.json_output << std::endl;
|
||||
std::cout << "extended: " << opts.extended << std::endl;
|
||||
std::cout << "shemu:" << opts.shemu << std::endl;
|
||||
std::cout << "kernel:" << opts.kernel << std::endl;
|
||||
std::cout << "shctx:" << opts.shctx_file << std::endl;
|
||||
}
|
||||
|
||||
if (!_validate_and_fix_args(opts)) {
|
||||
@ -695,7 +872,14 @@ int main(int argc, const char **argv)
|
||||
if (opts.offset >= opts.actual_size)
|
||||
return 1;
|
||||
|
||||
disassemble(opts);
|
||||
if (!opts.shemu) {
|
||||
disassemble(opts);
|
||||
}
|
||||
else {
|
||||
_load_shctx(opts);
|
||||
shemu(opts);
|
||||
}
|
||||
|
||||
} else {
|
||||
while (true) {
|
||||
opts.hex_string.clear();
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/writer.h>
|
||||
#include <rapidjson/reader.h>
|
||||
|
||||
|
||||
using namespace rapidjson;
|
||||
@ -1172,3 +1173,37 @@ const char *json_to_string(StringBuffer &j)
|
||||
{
|
||||
return j.GetString();
|
||||
}
|
||||
|
||||
bool regs_from_json(const std::string &str, SHEMU_GPR_REGS ®s, bool &update_rsp)
|
||||
{
|
||||
Document d;
|
||||
if (d.Parse(str.c_str()).IsNull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
regs.RegRax = d["rax"].GetUint64();
|
||||
regs.RegRcx = d["rcx"].GetUint64();
|
||||
regs.RegRdx = d["rdx"].GetUint64();
|
||||
regs.RegRbx = d["rbx"].GetUint64();
|
||||
regs.RegRsp = d["rsp"].GetUint64();
|
||||
regs.RegRbp = d["rbp"].GetUint64();
|
||||
regs.RegRsi = d["rsi"].GetUint64();
|
||||
regs.RegRdi = d["rdi"].GetUint64();
|
||||
regs.RegR8 = d["r8"].GetUint64();
|
||||
regs.RegR9 = d["r9"].GetUint64();
|
||||
regs.RegR10 = d["r10"].GetUint64();
|
||||
regs.RegR11 = d["r11"].GetUint64();
|
||||
regs.RegR12 = d["r12"].GetUint64();
|
||||
regs.RegR13 = d["r13"].GetUint64();
|
||||
regs.RegR14 = d["r14"].GetUint64();
|
||||
regs.RegR15 = d["r15"].GetUint64();
|
||||
|
||||
if ((update_rsp = !d["rsp"].IsNull())) {
|
||||
regs.RegRsp = d["rsp"].GetUint64();
|
||||
}
|
||||
|
||||
if (!d["rip"].IsNull())
|
||||
regs.RegRip = d["rip"].GetUint64();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user