summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Brentjes <d.brentjes@gmail.com>2021-05-28 21:45:07 +0200
committerDennis Brentjes <d.brentjes@gmail.com>2021-05-28 21:45:07 +0200
commitb81ca2c41ff4d48ca03d9c0e9bb53dd39bdd0a48 (patch)
tree6c701da77966e567db7c9b2651eb0797b1868d26
parent67bfeba1035dedf98d67cb00ea89e550de673aa4 (diff)
downloadopenwar-b81ca2c41ff4d48ca03d9c0e9bb53dd39bdd0a48.tar.gz
openwar-b81ca2c41ff4d48ca03d9c0e9bb53dd39bdd0a48.tar.bz2
openwar-b81ca2c41ff4d48ca03d9c0e9bb53dd39bdd0a48.zip
Fixes relocation and slowly starts implmenting base DOS and DPMI interrupts.
-rw-r--r--disasm/extractfunction.cpp1
-rw-r--r--emulate/emulator.cpp1
-rw-r--r--le/le_file.cpp2
-rw-r--r--le/le_file.hpp3
-rw-r--r--le/le_fixup_record_table.cpp9
-rw-r--r--le/le_fixup_record_table.hpp3
-rw-r--r--le/le_parse_util.cpp98
-rw-r--r--le/le_parse_util.hpp2
-rw-r--r--run/common.hpp10
-rw-r--r--run/dos_emu.cpp43
-rw-r--r--run/run.cpp16
-rw-r--r--run/runner.cpp73
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() {