diff options
| -rw-r--r-- | disasm/extractfunction.cpp | 1 | ||||
| -rw-r--r-- | emulate/emulator.cpp | 1 | ||||
| -rw-r--r-- | le/le_file.cpp | 2 | ||||
| -rw-r--r-- | le/le_file.hpp | 3 | ||||
| -rw-r--r-- | le/le_fixup_record_table.cpp | 9 | ||||
| -rw-r--r-- | le/le_fixup_record_table.hpp | 3 | ||||
| -rw-r--r-- | le/le_parse_util.cpp | 98 | ||||
| -rw-r--r-- | le/le_parse_util.hpp | 2 | ||||
| -rw-r--r-- | run/common.hpp | 10 | ||||
| -rw-r--r-- | run/dos_emu.cpp | 43 | ||||
| -rw-r--r-- | run/run.cpp | 16 | ||||
| -rw-r--r-- | run/runner.cpp | 73 |
12 files changed, 189 insertions, 72 deletions
diff --git a/disasm/extractfunction.cpp b/disasm/extractfunction.cpp index 288d78f..465f0ca 100644 --- a/disasm/extractfunction.cpp +++ b/disasm/extractfunction.cpp @@ -30,6 +30,7 @@ void extract_function(std::string file_path, binparse::Value32 object_id, binpar unsigned int decodedInstructionsCount = 0; std::vector<uint8_t> code_buf = load_binary(file); + relocate(file, code_buf); _CodeInfo ci; ci.code = code_buf.data() + function_offset; diff --git a/emulate/emulator.cpp b/emulate/emulator.cpp index e767446..1f0f349 100644 --- a/emulate/emulator.cpp +++ b/emulate/emulator.cpp @@ -627,6 +627,7 @@ void emulate(std::string file_path) { file_stream.unsetf(std::ios::skipws); auto file = le::parse_file(file_stream); auto binary = load_binary(file); + relocate(file, binary); _CodeInfo ci; _DecodeType dt = Decode32Bits; diff --git a/le/le_file.cpp b/le/le_file.cpp index 2e0a9d5..5fbb34a 100644 --- a/le/le_file.cpp +++ b/le/le_file.cpp @@ -78,4 +78,4 @@ std::ostream&operator<<(std::ostream& os, File const& file) return binparse::operator<<(os, file); } -}
\ No newline at end of file +} diff --git a/le/le_file.hpp b/le/le_file.hpp index 0807ea4..0e9a488 100644 --- a/le/le_file.hpp +++ b/le/le_file.hpp @@ -48,5 +48,4 @@ struct File File parse_file(std::istream& is); std::ostream& operator<<(std::ostream& os, File const& file); - -}
\ No newline at end of file +} diff --git a/le/le_fixup_record_table.cpp b/le/le_fixup_record_table.cpp index e909203..c4d7b58 100644 --- a/le/le_fixup_record_table.cpp +++ b/le/le_fixup_record_table.cpp @@ -227,9 +227,14 @@ FixupRecordTable parse_fixup_record_table(std::istream& is, Offset32 offset, Fix return table; } -std::ostream&operator<<(std::ostream& os, const FixupRecordTable& table) +std::ostream& operator<<(std::ostream& os, const FixupRecordTable& table) { - return binparse::operator<<(os, table.entries); + return binparse::operator<<(os, table.entries); +} + +std::ostream& operator<<(std::ostream& os, FixupRecordTable::Entry const& entry) +{ + return binparse::operator<<(os, entry); } } diff --git a/le/le_fixup_record_table.hpp b/le/le_fixup_record_table.hpp index 6a07da5..dff8ef5 100644 --- a/le/le_fixup_record_table.hpp +++ b/le/le_fixup_record_table.hpp @@ -52,5 +52,6 @@ FixupRecordTable::Entry parse(std::istream& is); FixupRecordTable parse_fixup_record_table(std::istream& is, Offset32 offset, FixupPageTable fixups); std::ostream& operator<<(std::ostream& os, FixupRecordTable const& table); +std::ostream& operator<<(std::ostream& os, FixupRecordTable::Entry const& entry); -}
\ No newline at end of file +} diff --git a/le/le_parse_util.cpp b/le/le_parse_util.cpp index 003c953..4455d24 100644 --- a/le/le_parse_util.cpp +++ b/le/le_parse_util.cpp @@ -1,5 +1,8 @@ #include "le_parse_util.hpp" +#include <sstream> +#include <iomanip> + #include <boost/assert.hpp> #include "parse.hpp" @@ -34,37 +37,65 @@ le::File parse_file(std::istream& is) return file; } -void relocate(std::vector<le::FixupRecordTable::Entry> fixups, uint8_t* binary, binparse::Value32 page_nr, le::File const& file) { - binparse::Offset32 page_offset; - for(auto&& object : file.object_table.entries) { - if(page_nr >= object.second.page_table_index && page_nr < object.second.page_table_index + object.second.nr_page_table_entries) { - page_offset = object.second.reloc_base_address; - page_offset += ((page_nr - 1) - object.second.page_table_index) * file.le_header.page_size; - break; - } - } - - for(auto&& fixup : fixups) { - auto internal = boost::get<le::FixupRecordTable::Entry::Internal>(fixup.data); - - auto source_offset = boost::get<binparse::Offset16>(fixup.source_offset_or_source_list_count); - - auto target_object = boost::get<binparse::Value8>(internal.object_number); - - auto binary_offset = page_offset + (int32_t) source_offset; - - binparse::Offset32 dest_offset; - if(bit(4, fixup.target_flags)) { - dest_offset = boost::get<binparse::Offset32>(internal.target_offset); - } else { - dest_offset = binparse::Offset32(boost::get<binparse::Offset16>(internal.target_offset)); - } - dest_offset += file.object_table.entries.at(target_object).reloc_base_address; - for(int i = 0; i < 4; ++i) { - uint8_t& byte = *(binary + binary_offset + i); - byte = ((dest_offset >> (i * 8)) & 255); - } - } +//works only for relocation type 7 (internal) (source flags == 7) +void relocate(le::File const& file, std::vector<uint8_t>& binary, binparse::Offset32 offset) { + for(auto&& entry : file.fixup_record_table.entries) { + auto&& page_nr = entry.first; + auto&& fixups = entry.second; + + std::cout << "page_nr: " << page_nr << std::endl; + binparse::Offset32 page_offset; + for(auto&& object : file.object_table.entries) { + if(page_nr >= object.second.page_table_index && page_nr < object.second.page_table_index + object.second.nr_page_table_entries) { + page_offset = object.second.reloc_base_address; + //both page_nr and page_table_index are 1-indexed so this subtraction works out. + page_offset += (page_nr - object.second.page_table_index) * file.le_header.page_size; + break; + } + } + + std::cout << "Page_offset: " << page_offset << std::endl; + + for(auto&& fixup : fixups) { + auto internal = boost::get<le::FixupRecordTable::Entry::Internal>(fixup.data); + + auto source_offset = boost::get<binparse::Offset16>(fixup.source_offset_or_source_list_count); + + auto target_object = boost::get<binparse::Value8>(internal.object_number); + + auto binary_offset = page_offset + source_offset; + + binparse::Offset32 dest_offset; + if(bit(4, fixup.target_flags)) { + dest_offset = boost::get<binparse::Offset32>(internal.target_offset); + } else { + dest_offset = binparse::Offset32(boost::get<binparse::Offset16>(internal.target_offset)); + } + dest_offset += file.object_table.entries.at(target_object).reloc_base_address; + dest_offset += offset; + + std::stringstream byte_stream; + std::stringstream fixup_stream; + + for(int i = 3; i >= 0; --i) { + uint8_t& byte = *(binary.data() + binary_offset + i); + const uint8_t fixup_byte = (dest_offset >> (i * 8)) & 255; + + byte_stream << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) byte; + fixup_stream << std::hex << std::setw(2) << std::setfill('0') << (unsigned int) fixup_byte; + + byte = fixup_byte; + } + + std::cout << fixup << std::endl; + + std::cout << + "Fixup (" + << std::hex << binary_offset << + "): " << byte_stream.str() << " => " << fixup_stream.str() << std::endl; + + } + } } size_t determine_binary_size(le::File const& file) { @@ -93,11 +124,6 @@ static void load_binary_into(le::File const& file, uint8_t* buffer, size_t buffe std::copy(page.begin(), page.end(), buffer + dest_offset); } } - - for(auto&& entry : file.fixup_record_table.entries) { - auto&& relocation = entry.second; - relocate(relocation, buffer, entry.first, file); - } } std::vector<uint8_t> load_binary(le::File const& file) diff --git a/le/le_parse_util.hpp b/le/le_parse_util.hpp index aea5e6e..2f0574a 100644 --- a/le/le_parse_util.hpp +++ b/le/le_parse_util.hpp @@ -10,7 +10,7 @@ std::vector<uint8_t> read_file_part(std::istream& is, std::streamsize offset, si std::vector<uint8_t> read_object(std::istream& is, le::File file, binparse::Value32 object_id); -std::vector<uint8_t> relocate(le::File& file, std::vector<uint8_t> page, size_t index); +void relocate(le::File const& file, std::vector<uint8_t>& binary, binparse::Offset32 offset = binparse::Offset32(0)); size_t determine_binary_size(le::File const& file); std::vector<uint8_t> load_binary(le::File const& file); void load_binary(le::File const& file, uint8_t* buffer, size_t buffer_size); diff --git a/run/common.hpp b/run/common.hpp index becd0c9..375bdf8 100644 --- a/run/common.hpp +++ b/run/common.hpp @@ -5,7 +5,13 @@ 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; }; + +struct __attribute__((packed, aligned(4))) BinarySizeMessage { + uint32_t binary_size; +}; + +struct __attribute__((packed, aligned(4))) BinaryBaseOffsetMessage { + uint32_t offset; +}; diff --git a/run/dos_emu.cpp b/run/dos_emu.cpp index f8e294d..c42df68 100644 --- a/run/dos_emu.cpp +++ b/run/dos_emu.cpp @@ -9,7 +9,7 @@ #include <ucontext.h> static void dos_functions(mcontext_t& mcontext); -static void dpmi_functions(mcontext_t& mcontext); +static void dpmi_functions(mcontext_t& mcontext, long unsigned int& flags); void dos_emu_handler(int, siginfo_t*, void* c) { ucontext_t* context = (ucontext_t*) c; @@ -27,7 +27,7 @@ void dos_emu_handler(int, siginfo_t*, void* c) { dos_functions(context->uc_mcontext); } if(instruction[1] == 0x31) { - dpmi_functions(context->uc_mcontext); + dpmi_functions(context->uc_mcontext, context->uc_flags); } //skip the interrupt and hopefully we handled it owk. @@ -40,10 +40,45 @@ void dos_emu_handler(int, siginfo_t*, void* c) { return; } -static void dos_functions(mcontext_t&) { +static void dos_functions(mcontext_t& mcontext) { + uint8_t ah = (mcontext.gregs[REG_EAX] & 0x0000FF00) >> 8; + uint8_t al = mcontext.gregs[REG_EAX] & 0x000000FF; + uint16_t ax = mcontext.gregs[REG_EAX] & 0x0000FFFF; + uint16_t dx = mcontext.gregs[REG_EDX] & 0x0000FFFF; + + //Get dos version + if(ah == 0x30) { + mcontext.gregs[REG_EAX] &= 0xFFFF0000; + mcontext.gregs[REG_EAX] |= 6 << 8; + mcontext.gregs[REG_EAX] |= 22; + + mcontext.gregs[REG_EBX] &= 0xFFFF0000; + mcontext.gregs[REG_EBX] |= 0x000000DE; + mcontext.gregs[REG_ECX] = 0xDEADBEAF; + + if(al == 1) { + mcontext.gregs[REG_EBX] |= 1 << 8; + } else { + mcontext.gregs[REG_EBX] |= 2 << 8; + } + } + + //Dos4gw install check + if(ax == 0xFF00 && dx == 0x0078) { + mcontext.gregs[REG_EAX] &= 0xFFFFFF00; + mcontext.gregs[REG_EAX] |= 1; + //should possible set GS... well fuck. + } } -static void dpmi_functions(mcontext_t&) { +static void dpmi_functions(mcontext_t& mcontext, long unsigned int& flags) { + uint16_t ax = mcontext.gregs[REG_EAX] & 0x0000FFFF; + //Get Segment base address + if (ax == 0x0006) { + mcontext.gregs[REG_ECX] &= 0xFFFF0000; + mcontext.gregs[REG_EDX] &= 0xFFFF0000; + flags = 0; + } } diff --git a/run/run.cpp b/run/run.cpp index 2f02a7b..b85e001 100644 --- a/run/run.cpp +++ b/run/run.cpp @@ -33,13 +33,21 @@ void accept_handler(boost::system::error_code const& error) { if(!error) { + uint32_t binary_size = determine_binary_size(file); + BinarySizeMessage size_message { + .binary_size = binary_size + }; + connection_socket.send(boost::asio::buffer(&size_message, sizeof size_message)); + + BinaryBaseOffsetMessage offset_message; + connection_socket.receive(boost::asio::buffer(&offset_message, sizeof offset_message)); + std::vector<uint8_t> binary = load_binary(file); + relocate(file, binary, binparse::Offset32(offset_message.offset)); + 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 + .eip = file.le_header.EIP + base_address + offset_message.offset }; connection_socket.send(boost::asio::buffer(&message, sizeof message)); diff --git a/run/runner.cpp b/run/runner.cpp index 8f19bfb..d8b9cad 100644 --- a/run/runner.cpp +++ b/run/runner.cpp @@ -4,40 +4,77 @@ #include <cstring> #include <cassert> #include <csignal> +#include <cmath> #include <iostream> +#include <memory> #include <sys/socket.h> #include <sys/un.h> #include <sys/mman.h> +#include <asm/ldt.h> + #include "common.hpp" #include "dos_emu.hpp" int loader_socket; +class mmap_deleter{ + size_t size; + +public: + mmap_deleter(size_t size) + : size(size) + {} + + void operator()(void* ptr) const { + munmap(ptr, size); + } +}; + enum ErrorCode { ok, socket_creation_failed, connection_error }; +using mmap_pointer_t = std::unique_ptr<void, mmap_deleter>; + static ErrorCode connect_to_loader(); -static BinaryLoadMessage receive_message(); -static void load_binary(BinaryLoadMessage const& message); + +template<typename T> +static T receive_message(); +static mmap_pointer_t map_memory(BinarySizeMessage const& message); +static void load_binary(mmap_pointer_t& binary, uint32_t binary_size); static void register_signal_handlers(); int main(int, char*[]) { if(connect_to_loader() != ok) { return -1; } - BinaryLoadMessage message = receive_message(); - load_binary(message); + auto size_message = receive_message<BinarySizeMessage>(); + auto binary = map_memory(size_message); + + BinaryBaseOffsetMessage offset_message + { + .offset = (uint32_t)binary.get() + }; + + send(loader_socket, &offset_message, sizeof offset_message, 0); + + auto binary_load_message = receive_message<BinaryLoadMessage>(); + load_binary(binary, size_message.binary_size); + register_signal_handlers(); - asm ("JMP *%0 \n\t" + std::cout << std::hex << "Binary base: " << offset_message.offset << std::endl; + + asm ( + "jmp *%0 \n\t" : - : "r" (message.eip)); + : "r" (binary_load_message.eip) + ); } static ErrorCode connect_to_loader() { @@ -58,28 +95,26 @@ static ErrorCode connect_to_loader() { return ok; } -static BinaryLoadMessage receive_message() { - BinaryLoadMessage message; +template <typename T> +static T receive_message() { + T message; uint32_t bytes_received = recv(loader_socket, &message, sizeof message, 0); - assert((bytes_received == sizeof message) && "Didn't receive full BinaryLoadMessage"); + assert((bytes_received == sizeof message) && "Didn't receive message"); 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)); +static mmap_pointer_t map_memory(BinarySizeMessage const& message) { + void* binary = mmap(NULL, message.binary_size, 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); } + return mmap_pointer_t(binary, message.binary_size); +} - 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 load_binary(mmap_pointer_t& binary, uint32_t binary_size) { + size_t bytes_received = recv(loader_socket, binary.get(), binary_size, 0); + assert((bytes_received == binary_size) && "bytes_received did not match expected"); } static void register_signal_handlers() { |
