diff options
| author | Dennis Brentjes <d.brentjes@gmail.com> | 2021-01-25 23:23:42 +0100 |
|---|---|---|
| committer | Dennis Brentjes <d.brentjes@gmail.com> | 2021-01-25 23:23:42 +0100 |
| commit | 67bfeba1035dedf98d67cb00ea89e550de673aa4 (patch) | |
| tree | 547928f5efd4098f73f045e914dc7c38ca10e330 | |
| parent | 3cb35ec664734cfe04bf788b3a9c11402fd0f878 (diff) | |
| download | openwar-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.txt | 41 | ||||
| -rw-r--r-- | run/common.hpp | 11 | ||||
| -rw-r--r-- | run/dos_emu.cpp | 49 | ||||
| -rw-r--r-- | run/dos_emu.hpp | 5 | ||||
| -rw-r--r-- | run/run.cpp | 111 | ||||
| -rw-r--r-- | run/runner.cpp | 94 |
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); +} |
