summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Brentjes <d.brentjes@gmail.com>2021-01-25 23:23:42 +0100
committerDennis Brentjes <d.brentjes@gmail.com>2021-01-25 23:23:42 +0100
commit67bfeba1035dedf98d67cb00ea89e550de673aa4 (patch)
tree547928f5efd4098f73f045e914dc7c38ca10e330
parent3cb35ec664734cfe04bf788b3a9c11402fd0f878 (diff)
downloadopenwar-67bfeba1035dedf98d67cb00ea89e550de673aa4.tar.gz
openwar-67bfeba1035dedf98d67cb00ea89e550de673aa4.tar.bz2
openwar-67bfeba1035dedf98d67cb00ea89e550de673aa4.zip
Adds runner and 32-bit-runner to start implementing software interrupts.
-rw-r--r--run/CMakeLists.txt41
-rw-r--r--run/common.hpp11
-rw-r--r--run/dos_emu.cpp49
-rw-r--r--run/dos_emu.hpp5
-rw-r--r--run/run.cpp111
-rw-r--r--run/runner.cpp94
6 files changed, 311 insertions, 0 deletions
diff --git a/run/CMakeLists.txt b/run/CMakeLists.txt
new file mode 100644
index 0000000..ef723e3
--- /dev/null
+++ b/run/CMakeLists.txt
@@ -0,0 +1,41 @@
+
+add_library(runner-common STATIC
+ common.hpp
+)
+
+target_include_directories(runner-common
+ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+set_target_properties(runner-common PROPERTIES LINKER_LANGUAGE CXX)
+
+add_executable(run
+ run.cpp
+)
+
+set(THREADS_PREFER_PTHREAD_FLAG ON)
+find_package(Threads REQUIRED)
+
+find_package(Boost COMPONENTS program_options filesystem REQUIRED)
+
+find_package(distorm3 REQUIRED CONFIG)
+
+target_link_libraries(run
+ PRIVATE Threads::Threads
+ PRIVATE Boost::program_options
+ PRIVATE Boost::filesystem
+ PRIVATE distorm3
+ PRIVATE le
+ PRIVATE runner-common
+)
+
+add_executable(32-bit-runner
+ runner.cpp
+ dos_emu.hpp dos_emu.cpp
+)
+
+set_target_properties(32-bit-runner PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
+
+target_link_libraries(32-bit-runner
+ PRIVATE runner-common
+)
diff --git a/run/common.hpp b/run/common.hpp
new file mode 100644
index 0000000..becd0c9
--- /dev/null
+++ b/run/common.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <string>
+
+const std::string socket_name = "/tmp/openle.socket";
+
+struct __attribute__((packed, aligned(4))) BinaryLoadMessage {
+ uint32_t binary_size;
+ uint32_t base_address;
+ uint32_t eip;
+};
diff --git a/run/dos_emu.cpp b/run/dos_emu.cpp
new file mode 100644
index 0000000..f8e294d
--- /dev/null
+++ b/run/dos_emu.cpp
@@ -0,0 +1,49 @@
+#include "dos_emu.hpp"
+
+#include <cstdint>
+#include <cstdlib>
+#include <cstdio>
+
+#include <atomic>
+
+#include <ucontext.h>
+
+static void dos_functions(mcontext_t& mcontext);
+static void dpmi_functions(mcontext_t& mcontext);
+
+void dos_emu_handler(int, siginfo_t*, void* c) {
+ ucontext_t* context = (ucontext_t*) c;
+
+ uint8_t* instruction = (uint8_t*) context->uc_mcontext.gregs[REG_EIP];
+ fprintf(stderr, "eip: 0x%lx\n", instruction);
+ if (instruction[0] == 0xFB) //mnemonic STI
+ {
+ //we cant do this in user space so ignore for now.
+ context->uc_mcontext.gregs[REG_EIP] += 1;
+ }
+ else if (instruction[0] == 0xCD) //mnemonic INT
+ {
+ if(instruction[1] == 0x21) {
+ dos_functions(context->uc_mcontext);
+ }
+ if(instruction[1] == 0x31) {
+ dpmi_functions(context->uc_mcontext);
+ }
+
+ //skip the interrupt and hopefully we handled it owk.
+ context->uc_mcontext.gregs[REG_EIP] += 2;
+ } else {
+ //whoops we fucked up something fierce.
+ abort();
+ }
+
+ return;
+}
+
+static void dos_functions(mcontext_t&) {
+
+}
+
+static void dpmi_functions(mcontext_t&) {
+
+}
diff --git a/run/dos_emu.hpp b/run/dos_emu.hpp
new file mode 100644
index 0000000..ab285d7
--- /dev/null
+++ b/run/dos_emu.hpp
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <csignal>
+
+void dos_emu_handler(int sig, siginfo_t* info, void* c);
diff --git a/run/run.cpp b/run/run.cpp
new file mode 100644
index 0000000..2f02a7b
--- /dev/null
+++ b/run/run.cpp
@@ -0,0 +1,111 @@
+#include <distorm.h>
+
+#include <boost/program_options.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/asio.hpp>
+
+#include <iostream>
+#include <fstream>
+
+#include "le_file.hpp"
+#include "le_parse_util.hpp"
+
+#include "common.hpp"
+
+static boost::asio::io_context io_context;
+static le::File file;
+static boost::asio::local::stream_protocol::socket connection_socket(io_context);
+
+static uint32_t message_size;
+
+void action_handler(boost::system::error_code const& error, size_t)
+{
+ if(!error)
+ {
+ }
+
+ io_context.post([](){
+ connection_socket.async_receive(boost::asio::buffer(&message_size, sizeof message_size), 0, action_handler);
+ });
+}
+
+void accept_handler(boost::system::error_code const& error)
+{
+ if(!error)
+ {
+ std::vector<uint8_t> binary = load_binary(file);
+ uint32_t base_address = file.object_table.entries.at(file.le_header.EIP_object).reloc_base_address;
+ uint32_t binary_size = binary.size();
+ BinaryLoadMessage message {
+ .binary_size = binary_size,
+ .base_address = base_address,
+ .eip = file.le_header.EIP + base_address
+ };
+
+ connection_socket.send(boost::asio::buffer(&message, sizeof message));
+ connection_socket.send(boost::asio::buffer(binary, binary.size()));
+
+ io_context.post([](){
+ connection_socket.async_receive(boost::asio::buffer(&message_size, sizeof message_size), 0, action_handler);
+ });
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ boost::program_options::options_description description;
+ description.add_options()
+ ("help,h", "produces this help message")
+ ("exe,e", boost::program_options::value<std::string>(), "The LE executable to parse the header for.")
+ ;
+
+ boost::program_options::variables_map vm;
+ boost::program_options::store(boost::program_options::parse_command_line(argc, argv, description), vm);
+ boost::program_options::notify(vm);
+
+ if(vm.count("help")) {
+ std::cout << description << std::endl;
+ return 0;
+ }
+
+ boost::filesystem::path file_path;
+ if(vm.count("exe")) {
+ std::string exe_file = vm["exe"].as<std::string>();
+
+ if(boost::filesystem::exists(exe_file)) {
+ if(!boost::filesystem::is_directory(exe_file)) {
+ file_path = exe_file;
+ } else {
+ std::cerr << exe_file << " is a folder" << std::endl;
+ std::cerr << std::endl;
+ std::cerr << description << std::endl;
+ return -1;
+ }
+ } else {
+ std::cerr << "file: " << exe_file << " does not exist" << std::endl;
+ std::cerr << std::endl;
+ std::cerr << description << std::endl;
+ return -1;
+ }
+ } else {
+ std::cerr << "Option \"exe_file\" is required";
+ std::cerr << std::endl;
+ std::cerr << description << std::endl;
+ return -1;
+ }
+
+ std::ifstream file_stream(file_path, std::ios::binary);
+ file_stream.unsetf(std::ios::skipws);
+ file = le::parse_file(file_stream);
+
+ boost::filesystem::remove(socket_name);
+
+ boost::asio::local::stream_protocol::endpoint ep(socket_name);
+ boost::asio::local::stream_protocol::acceptor acceptor(io_context, ep);
+ acceptor.async_accept(connection_socket, accept_handler);
+
+ io_context.run();
+
+ boost::filesystem::remove(socket_name);
+ return 0;
+}
diff --git a/run/runner.cpp b/run/runner.cpp
new file mode 100644
index 0000000..8f19bfb
--- /dev/null
+++ b/run/runner.cpp
@@ -0,0 +1,94 @@
+
+#include <cstdio>
+#include <cerrno>
+#include <cstring>
+#include <cassert>
+#include <csignal>
+
+#include <iostream>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/mman.h>
+
+#include "common.hpp"
+#include "dos_emu.hpp"
+
+int loader_socket;
+
+enum ErrorCode {
+ ok,
+ socket_creation_failed,
+ connection_error
+};
+
+static ErrorCode connect_to_loader();
+static BinaryLoadMessage receive_message();
+static void load_binary(BinaryLoadMessage const& message);
+static void register_signal_handlers();
+
+int main(int, char*[]) {
+ if(connect_to_loader() != ok) {
+ return -1;
+ }
+ BinaryLoadMessage message = receive_message();
+ load_binary(message);
+ register_signal_handlers();
+
+ asm ("JMP *%0 \n\t"
+ :
+ : "r" (message.eip));
+}
+
+static ErrorCode connect_to_loader() {
+ if ((loader_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ perror("socket");
+ return socket_creation_failed;
+ }
+
+ sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ std::strncpy(addr.sun_path, socket_name.c_str(), sizeof addr.sun_path);
+
+ size_t len = strnlen(addr.sun_path, sizeof addr.sun_path) + sizeof(addr.sun_family);
+ if (connect(loader_socket, (struct sockaddr *)&addr, len) == -1) {
+ perror("connect");
+ return connection_error;
+ }
+ return ok;
+}
+
+static BinaryLoadMessage receive_message() {
+ BinaryLoadMessage message;
+ uint32_t bytes_received = recv(loader_socket, &message, sizeof message, 0);
+ assert((bytes_received == sizeof message) && "Didn't receive full BinaryLoadMessage");
+ return message;
+}
+
+static void load_binary(BinaryLoadMessage const& message) {
+ uint8_t* binary = static_cast<uint8_t*>(mmap((void*)message.base_address, message.binary_size - message.base_address, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+ if(binary == MAP_FAILED) {
+ std::cerr << "error during mmap: " << errno << " " << strerror(errno) << std::endl;
+ exit(1);
+ }
+
+ assert((binary == (void*)message.base_address) && "binary couldn't be loaded on the prefered address.");
+
+ uint8_t x[message.base_address];
+ recv(loader_socket, x, sizeof(x), 0);
+
+ size_t bytes_received = recv(loader_socket, binary, message.binary_size - message.base_address, 0);
+
+ assert((bytes_received == message.binary_size - (size_t)message.base_address) && "bytes_received did not match expected");
+}
+
+static void register_signal_handlers() {
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof sa);
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_sigaction = dos_emu_handler;
+
+ sigaction(SIGSEGV, &sa, NULL);
+}