first commit

This commit is contained in:
Ash Wolf 2022-06-13 02:20:18 +02:00
commit d1a4fd35a7
7 changed files with 718 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Ash Wolf
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

20
README.md Normal file
View File

@ -0,0 +1,20 @@
# WiBo
An experiment to try and write a minimal, low-fuss wrapper that can run really simple command-line 32-bit Windows binaries on Linux - with less faff and less dependencies than WINE.
Don't run this on any untrusted executables, I implore you. (Or probably just don't run it at all... :p)
g++ -g -m32 -std=c++20 -lstdc++ main.cpp kernel32.cpp advapi32.cpp loader.cpp
If you need something like this project (but more mature), you might find [taviso/loadlibrary](https://github.com/taviso/loadlibrary) more interesting.
---
Rough to-do list:
- Implement more APIs
- Do something intelligent with Windows `HANDLE`s
- Pass the command line properly
- Convert paths in environment variables (and the structure of `PATH` itself, maybe) to Windows format
- Implement PE relocations rather than just failing unceremoniously
- Make the PE loader work for DLLs as well in case we ever want to load some

14
advapi32.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "common.h"
namespace advapi32 {
unsigned int WIN_FUNC RegOpenKeyExA(void *hKey, const char *lpSubKey, unsigned int ulOptions, void *samDesired, void **phkResult) {
printf("RegOpenKeyExA(key=%p, subkey=%s, ...)\n", hKey, lpSubKey);
return 1; // screw them for now
}
}
void *wibo::resolveAdvApi32(const char *name) {
if (strcmp(name, "RegOpenKeyExA") == 0) return (void *) advapi32::RegOpenKeyExA;
return 0;
}

37
common.h Normal file
View File

@ -0,0 +1,37 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define WIN_FUNC __attribute__((stdcall))
namespace wibo {
extern uint32_t lastError;
extern char *commandLine;
void *resolveKernel32(const char *name);
void *resolveAdvApi32(const char *name);
void *resolveStubByName(const char *dllName, const char *funcName);
void *resolveStubByOrdinal(const char *dllName, uint16_t ordinal);
struct Executable {
Executable();
~Executable();
bool loadPE(FILE *file);
void *imageBuffer;
size_t imageSize;
void *entryPoint;
template <typename T>
T *fromRVA(uint32_t rva) {
return (T *) (rva + (uint8_t *) imageBuffer);
}
template <typename T>
T *fromRVA(T *rva) {
return fromRVA<T>((uint32_t) rva);
}
};
}

322
kernel32.cpp Normal file
View File

@ -0,0 +1,322 @@
#include "common.h"
#include <algorithm>
#include <ctype.h>
#include <filesystem>
#include <string>
namespace kernel32 {
uint32_t WIN_FUNC GetLastError() {
return wibo::lastError;
}
void *WIN_FUNC GetCurrentProcess() {
return (void *) 0xFFFFFFFF;
}
void WIN_FUNC InitializeCriticalSection(void *param) {
// printf("InitializeCriticalSection(...)\n");
}
void WIN_FUNC DeleteCriticalSection(void *param) {
// printf("DeleteCriticalSection(...)\n");
}
void WIN_FUNC EnterCriticalSection(void *param) {
// printf("EnterCriticalSection(...)\n");
}
void WIN_FUNC LeaveCriticalSection(void *param) {
// printf("LeaveCriticalSection(...)\n");
}
/*
* TLS (Thread-Local Storage)
*/
enum { MAX_TLS_VALUES = 100 };
static bool tlsValuesUsed[MAX_TLS_VALUES] = { false };
static void *tlsValues[MAX_TLS_VALUES];
unsigned int WIN_FUNC TlsAlloc() {
printf("TlsAlloc()\n");
for (int i = 0; i < MAX_TLS_VALUES; i++) {
if (tlsValuesUsed[i] == false) {
tlsValuesUsed[i] = true;
tlsValues[i] = 0;
printf("...returning %d\n", i);
return i;
}
}
printf("...returning nothing\n");
return 0xFFFFFFFF;
}
unsigned int WIN_FUNC TlsFree(unsigned int dwTlsIndex) {
printf("TlsFree(%u)\n", dwTlsIndex);
if (dwTlsIndex >= 0 && dwTlsIndex < MAX_TLS_VALUES && tlsValuesUsed[dwTlsIndex]) {
tlsValuesUsed[dwTlsIndex] = false;
return 1;
} else {
return 0;
}
}
void *WIN_FUNC TlsGetValue(unsigned int dwTlsIndex) {
// printf("TlsGetValue(%u)\n", dwTlsIndex);
if (dwTlsIndex >= 0 && dwTlsIndex < MAX_TLS_VALUES && tlsValuesUsed[dwTlsIndex])
return tlsValues[dwTlsIndex];
else
return 0;
}
unsigned int WIN_FUNC TlsSetValue(unsigned int dwTlsIndex, void *lpTlsValue) {
// printf("TlsSetValue(%u, %p)\n", dwTlsIndex, lpTlsValue);
if (dwTlsIndex >= 0 && dwTlsIndex < MAX_TLS_VALUES && tlsValuesUsed[dwTlsIndex]) {
tlsValues[dwTlsIndex] = lpTlsValue;
return 1;
} else {
return 0;
}
}
/*
* Memory
*/
void *WIN_FUNC GlobalAlloc(uint32_t uFlags, size_t dwBytes) {
printf("GlobalAlloc(flags=%x, size=%x)\n", uFlags, dwBytes);
if (uFlags & 2) {
// GMEM_MOVEABLE - not implemented rn
return 0;
} else {
// GMEM_FIXED - this is simpler
void *buffer = malloc(dwBytes);
if (buffer && (uFlags & 0x40)) {
// GMEM_ZEROINT
memset(buffer, 0, dwBytes);
}
return buffer;
}
}
void *WIN_FUNC GlobalFree(void *hMem) {
free(hMem);
return 0;
}
/*
* Environment
*/
char *WIN_FUNC GetCommandLineA() {
return wibo::commandLine;
}
char *WIN_FUNC GetEnvironmentStrings() {
// Step 1, figure out the size of the buffer we need.
size_t bufSize = 0;
char **work = environ;
while (*work) {
bufSize += strlen(*work) + 1;
work++;
}
bufSize++;
// Step 2, actually build that buffer
char *buffer = (char *) malloc(bufSize);
char *ptr = buffer;
work = environ;
while (*work) {
size_t strSize = strlen(*work);
memcpy(ptr, *work, strSize);
ptr[strSize] = 0;
ptr += strSize + 1;
work++;
}
*ptr = 0; // an extra null at the end
return buffer;
}
void WIN_FUNC FreeEnvironmentStringsA(char *buffer) {
free(buffer);
}
/*
* I/O
*/
void *WIN_FUNC GetStdHandle(uint32_t nStdHandle) {
switch (nStdHandle) {
case ((uint32_t) -10): // STD_INPUT_HANDLE
return stdin;
case ((uint32_t) -11): // STD_OUTPUT_HANDLE
return stdout;
case ((uint32_t) -12): // STD_ERROR_HANDLE
return stderr;
default:
return (void *) 0xFFFFFFFF;
}
}
unsigned int WIN_FUNC DuplicateHandle(void *hSourceProcessHandle, void *hSourceHandle, void *hTargetProcessHandle, void **lpTargetHandle, unsigned int dwDesiredAccess, unsigned int bInheritHandle, unsigned int dwOptions) {
// This is kinda silly...
if (hSourceHandle == stdin || hSourceHandle == stdout || hSourceHandle == stderr) {
// Just pretend we duplicated it, why not
*lpTargetHandle = hSourceHandle;
return 1;
}
// This probably won't come up
printf("Unhandled DuplicateHandle(source=%p)\n", hSourceHandle);
return 0;
}
std::filesystem::path pathFromWindows(const char *inStr) {
// Convert to forward slashes
std::string str = inStr;
std::replace(str.begin(), str.end(), '\\', '/');
// Remove the drive letter
if (str.starts_with("c:/") || str.starts_with("C:/")) {
str.erase(0, 2);
}
return std::filesystem::path(str);
}
std::string pathToWindows(const std::filesystem::path &path) {
std::string str = path;
if (path.is_absolute()) {
str.insert(0, "C:");
}
std::replace(str.begin(), str.end(), '/', '\\');
return str;
}
unsigned int WIN_FUNC GetFullPathNameA(const char *lpFileName, unsigned int nBufferLength, char *lpBuffer, char **lpFilePart) {
printf("GetFullPathNameA(%s)...\n", lpFileName);
std::filesystem::path absPath = std::filesystem::absolute(pathFromWindows(lpFileName));
std::string absStr = pathToWindows(absPath);
printf("AbsPath: %s - %s\n", absPath.c_str(), absStr.c_str());
// Enough space?
if ((absStr.size() + 1) <= nBufferLength) {
strcpy(lpBuffer, absStr.c_str());
// Do we need to fill in FilePart?
if (lpFilePart) {
*lpFilePart = 0;
if (!std::filesystem::is_directory(absPath)) {
*lpFilePart = strrchr(lpBuffer, '\\');
if (*lpFilePart)
*lpFilePart += 1;
}
}
return absStr.size();
} else {
return absStr.size() + 1;
}
}
unsigned int WIN_FUNC GetFileAttributesA(const char *lpFileName) {
auto path = pathFromWindows(lpFileName);
printf("GetFileAttributesA(%s)... (%s)\n", lpFileName, path.c_str());
auto status = std::filesystem::status(path);
wibo::lastError = 0;
switch (status.type()) {
case std::filesystem::file_type::regular:
printf("File exists\n");
return 0x80; // FILE_ATTRIBUTE_NORMAL
case std::filesystem::file_type::directory:
return 0x10; // FILE_ATTRIBUTE_DIRECTORY
case std::filesystem::file_type::not_found:
default:
printf("File does not exist\n");
wibo::lastError = 2; // ERROR_FILE_NOT_FOUND
return 0xFFFFFFFF; // INVALID_FILE_ATTRIBUTES
}
}
unsigned int WIN_FUNC WriteFile(void *hFile, const void *lpBuffer, unsigned int nNumberOfBytesToWrite, unsigned int *lpNumberOfBytesWritten, void *lpOverlapped) {
// for now, we VERY naively assume that the handle is a FILE*
// haha this is gonna come back and bite me, isn't it
wibo::lastError = 0;
size_t written = fwrite(lpBuffer, 1, nNumberOfBytesToWrite, (FILE *) hFile);
if (lpNumberOfBytesWritten)
*lpNumberOfBytesWritten = written;
if (written == 0)
wibo::lastError = 29; // ERROR_WRITE_FAULT
return (written == nNumberOfBytesToWrite);
}
/*
* Console Nonsense
*/
unsigned int WIN_FUNC SetConsoleCtrlHandler(void *HandlerRoutine, unsigned int Add) {
// This is a function that gets called when doing ^C
// We might want to call this later (being mindful that it'll be stdcall I think)
// For now, just pretend we did the thing
return 1;
}
struct CONSOLE_SCREEN_BUFFER_INFO {
int16_t dwSize_x;
int16_t dwSize_y;
int16_t dwCursorPosition_x;
int16_t dwCursorPosition_y;
uint16_t wAttributes;
int16_t srWindow_left;
int16_t srWindow_top;
int16_t srWindow_right;
int16_t srWindow_bottom;
int16_t dwMaximumWindowSize_x;
int16_t dwMaximumWindowSize_y;
};
unsigned int WIN_FUNC GetConsoleScreenBufferInfo(void *hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO *lpConsoleScreenBufferInfo) {
// Tell a lie
// mwcc doesn't care about anything else
lpConsoleScreenBufferInfo->dwSize_x = 80;
lpConsoleScreenBufferInfo->dwSize_y = 25;
return 1;
}
unsigned int WIN_FUNC GetSystemDirectoryA(char *lpBuffer, unsigned int uSize) {
strcpy(lpBuffer, "C:\\Windows\\System32");
return strlen(lpBuffer);
}
unsigned int WIN_FUNC GetWindowsDirectoryA(char *lpBuffer, unsigned int uSize) {
strcpy(lpBuffer, "C:\\Windows");
return strlen(lpBuffer);
}
}
void *wibo::resolveKernel32(const char *name) {
if (strcmp(name, "GetLastError") == 0) return (void *) kernel32::GetLastError;
if (strcmp(name, "GetCurrentProcess") == 0) return (void *) kernel32::GetCurrentProcess;
if (strcmp(name, "InitializeCriticalSection") == 0) return (void *) kernel32::InitializeCriticalSection;
if (strcmp(name, "DeleteCriticalSection") == 0) return (void *) kernel32::DeleteCriticalSection;
if (strcmp(name, "EnterCriticalSection") == 0) return (void *) kernel32::EnterCriticalSection;
if (strcmp(name, "LeaveCriticalSection") == 0) return (void *) kernel32::LeaveCriticalSection;
if (strcmp(name, "GlobalAlloc") == 0) return (void *) kernel32::GlobalAlloc;
if (strcmp(name, "GlobalFree") == 0) return (void *) kernel32::GlobalFree;
if (strcmp(name, "TlsAlloc") == 0) return (void *) kernel32::TlsAlloc;
if (strcmp(name, "TlsFree") == 0) return (void *) kernel32::TlsFree;
if (strcmp(name, "TlsGetValue") == 0) return (void *) kernel32::TlsGetValue;
if (strcmp(name, "TlsSetValue") == 0) return (void *) kernel32::TlsSetValue;
if (strcmp(name, "GetCommandLineA") == 0) return (void *) kernel32::GetCommandLineA;
if (strcmp(name, "GetEnvironmentStrings") == 0) return (void *) kernel32::GetEnvironmentStrings;
if (strcmp(name, "FreeEnvironmentStringsA") == 0) return (void *) kernel32::FreeEnvironmentStringsA;
if (strcmp(name, "GetStdHandle") == 0) return (void *) kernel32::GetStdHandle;
if (strcmp(name, "DuplicateHandle") == 0) return (void *) kernel32::DuplicateHandle;
if (strcmp(name, "GetFullPathNameA") == 0) return (void *) kernel32::GetFullPathNameA;
if (strcmp(name, "GetFileAttributesA") == 0) return (void *) kernel32::GetFileAttributesA;
if (strcmp(name, "WriteFile") == 0) return (void *) kernel32::WriteFile;
if (strcmp(name, "SetConsoleCtrlHandler") == 0) return (void *) kernel32::SetConsoleCtrlHandler;
if (strcmp(name, "GetConsoleScreenBufferInfo") == 0) return (void *) kernel32::GetConsoleScreenBufferInfo;
if (strcmp(name, "GetSystemDirectoryA") == 0) return (void *) kernel32::GetSystemDirectoryA;
if (strcmp(name, "GetWindowsDirectoryA") == 0) return (void *) kernel32::GetWindowsDirectoryA;
return 0;
}

207
loader.cpp Normal file
View File

@ -0,0 +1,207 @@
#include "common.h"
#include <errno.h>
#include <memory>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
struct PEHeader {
uint8_t magic[4]; // "PE\0\0"
uint16_t machine;
uint16_t numberOfSections;
uint32_t timeDateStamp;
uint32_t pointerToSymbolTable;
uint32_t numberOfSymbols;
uint16_t sizeOfOptionalHeader;
uint16_t characteristics;
};
struct PEImageDataDirectory {
uint32_t virtualAddress;
uint32_t size;
};
struct PE32Header {
uint16_t magic; // 0x10B for PE32
uint8_t majorLinkerVersion;
uint8_t minorLinkerVersion;
uint32_t sizeOfCode;
uint32_t sizeOfInitializedData;
uint32_t sizeOfUninitializedData;
uint32_t addressOfEntryPoint;
uint32_t baseOfCode;
uint32_t baseOfData;
uint32_t imageBase;
uint32_t sectionAlignment;
uint32_t fileAlignment;
uint16_t majorOperatingSystemVersion;
uint16_t minorOperatingSystemVersion;
uint16_t majorImageVersion;
uint16_t minorImageVersion;
uint16_t majorSubsystemVersion;
uint16_t minorSubsystemVersion;
uint32_t win32VersionValue;
uint32_t sizeOfImage;
uint32_t sizeOfHeaders;
uint32_t checkSum;
uint16_t subsystem;
uint16_t dllCharacteristics;
uint32_t sizeOfStackReserve;
uint32_t sizeOfStackCommit;
uint32_t sizeOfHeapReserve;
uint32_t sizeOfHeapCommit;
uint32_t loaderFlags;
uint32_t numberOfRvaAndSizes;
PEImageDataDirectory exportTable;
PEImageDataDirectory importTable; // *
PEImageDataDirectory resourceTable; // *
PEImageDataDirectory exceptionTable;
PEImageDataDirectory certificateTable;
PEImageDataDirectory baseRelocationTable; // *
PEImageDataDirectory debug; // *
PEImageDataDirectory architecture;
PEImageDataDirectory globalPtr;
PEImageDataDirectory tlsTable;
PEImageDataDirectory loadConfigTable;
PEImageDataDirectory boundImport;
PEImageDataDirectory iat;
PEImageDataDirectory delayImportDescriptor;
PEImageDataDirectory clrRuntimeHeader;
PEImageDataDirectory reserved;
};
struct PESectionHeader {
char name[8];
uint32_t virtualSize;
uint32_t virtualAddress;
uint32_t sizeOfRawData;
uint32_t pointerToRawData;
uint32_t pointerToRelocations;
uint32_t pointerToLinenumbers;
uint16_t numberOfRelocations;
uint16_t numberOfLinenumbers;
uint32_t characteristics;
};
struct PEImportDirectoryEntry {
uint32_t *importLookupTable;
uint32_t timeDateStamp;
uint32_t forwarderChain;
char *name;
uint32_t *importAddressTable;
};
struct PEHintNameTableEntry {
uint16_t hint;
char name[1]; // variable length
};
uint16_t read16(FILE *file) {
uint16_t v = 0;
fread(&v, 2, 1, file);
return v;
}
uint32_t read32(FILE *file) {
uint32_t v = 0;
fread(&v, 4, 1, file);
return v;
}
wibo::Executable::Executable() {
imageBuffer = nullptr;
imageSize = 0;
}
wibo::Executable::~Executable() {
if (imageBuffer) {
munmap(imageBuffer, imageSize);
}
}
bool wibo::Executable::loadPE(FILE *file) {
// Skip to PE header
fseek(file, 0x3C, SEEK_SET);
uint32_t offsetToPE = read32(file);
fseek(file, offsetToPE, SEEK_SET);
// Read headers
PEHeader header;
fread(&header, sizeof header, 1, file);
if (memcmp(header.magic, "PE\0\0", 4) != 0)
return false;
if (header.machine != 0x14C) // i386
return false;
printf("Sections: %d / Size of optional header: %x\n", header.numberOfSections, header.sizeOfOptionalHeader);
PE32Header header32;
memset(&header32, 0, sizeof header32);
fread(&header32, std::min(sizeof(header32), (size_t) header.sizeOfOptionalHeader), 1, file);
if (header32.magic != 0x10B)
return false;
printf("Image Base: %x / Size: %x\n", header32.imageBase, header32.sizeOfImage);
long pageSize = sysconf(_SC_PAGE_SIZE);
printf("Page size: %x\n", pageSize);
// Build buffer
imageSize = header32.sizeOfImage;
imageBuffer = mmap((void *) header32.imageBase, header32.sizeOfImage, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_FIXED|MAP_PRIVATE, -1, 0);
if (imageBuffer == MAP_FAILED) {
perror("Image mapping failed!");
imageBuffer = 0;
return false;
}
// Read the sections
fseek(file, offsetToPE + sizeof header + header.sizeOfOptionalHeader, SEEK_SET);
for (int i = 0; i < header.numberOfSections; i++) {
PESectionHeader section;
fread(&section, sizeof section, 1, file);
char name[9];
memcpy(name, section.name, 8);
name[8] = 0;
printf("Section %d: name=%s addr=%x size=%x (raw=%x) ptr=%x\n", i, name, section.virtualAddress, section.virtualSize, section.sizeOfRawData, section.pointerToRawData);
if (section.sizeOfRawData > 0) {
// Grab this data
long savePos = ftell(file);
fseek(file, section.pointerToRawData, SEEK_SET);
void *sectionBase = (void *) (header32.imageBase + section.virtualAddress);
fread(sectionBase, section.virtualSize, 1, file);
fseek(file, savePos, SEEK_SET);
}
}
// Handle imports
PEImportDirectoryEntry *dir = fromRVA<PEImportDirectoryEntry>(header32.importTable.virtualAddress);
while (dir->name) {
char *name = fromRVA(dir->name);
printf("DLL Name: %s\n", name);
uint32_t *lookupTable = fromRVA(dir->importLookupTable);
uint32_t *addressTable = fromRVA(dir->importAddressTable);
while (*lookupTable) {
uint32_t lookup = *lookupTable;
if (lookup & 0x80000000) {
// Import by ordinal
uint16_t ordinal = lookup & 0xFFFF;
printf(" Ordinal: %d\n", ordinal);
*addressTable = (uint32_t) resolveStubByOrdinal(name, ordinal);
} else {
// Import by name
PEHintNameTableEntry *hintName = fromRVA<PEHintNameTableEntry>(lookup);
printf(" Name: %s\n", hintName->name);
*addressTable = (uint32_t) resolveStubByName(name, hintName->name);
}
++lookupTable;
++addressTable;
}
++dir;
}
entryPoint = fromRVA<void>(header32.addressOfEntryPoint);
return true;
}

97
main.cpp Normal file
View File

@ -0,0 +1,97 @@
#include "common.h"
#include <asm/ldt.h>
#include <errno.h>
#include <memory>
#include <sys/mman.h>
#include <sys/syscall.h>
uint32_t wibo::lastError = 0;
char *wibo::commandLine;
void stub() {
// should go through all the functions imported by mwcceppc.exe
// and create template stubs for them, at least...
printf("Unhandled function\n");
exit(0);
}
uint32_t __attribute__((stdcall)) CoInitialize(void *pvReserved) {
printf("CoInitialize(...)\n");
return 0; // S_OK I think?
}
void *wibo::resolveStubByName(const char *dllName, const char *funcName) {
if (strcmp(dllName, "KERNEL32.dll") == 0) {
void *func = wibo::resolveKernel32(funcName);
if (func)
return func;
}
if (strcmp(dllName, "ADVAPI32.dll") == 0) {
void *func = wibo::resolveAdvApi32(funcName);
if (func)
return func;
}
if (strcmp(dllName, "ole32.dll") == 0) {
if (strcmp(funcName, "CoInitialize") == 0) return (void *) CoInitialize;
}
printf("Missing function: %s (%s)\n", dllName, funcName);
return (void *) stub;
}
void *wibo::resolveStubByOrdinal(const char *dllName, uint16_t ordinal) {
return (void *) stub;
}
// Windows Thread Information Block
struct TIB {
void *sehFrame;
void *stackBase;
void *stackLimit;
void *subSystemTib;
void *fiberData;
void *arbitraryDataSlot;
TIB *tib;
};
int main(int argc, char **argv) {
// Create TIB
TIB tib;
tib.tib = &tib;
struct user_desc tibDesc;
tibDesc.entry_number = 0;
tibDesc.base_addr = (unsigned int) &tib;
tibDesc.limit = 0x1000;
tibDesc.seg_32bit = 1;
tibDesc.contents = 0; // hopefully this is ok
tibDesc.read_exec_only = 0;
tibDesc.limit_in_pages = 0;
tibDesc.seg_not_present = 0;
tibDesc.useable = 1;
if (syscall(SYS_modify_ldt, 1, &tibDesc, sizeof tibDesc) != 0) {
perror("Failed to modify LDT\n");
return 1;
}
// Build a command line (todo, fill this with argv etc)
wibo::commandLine = new char[1024];
strcpy(wibo::commandLine, "mwcceppc.exe");
wibo::Executable exec;
FILE *f = fopen("mwcceppc.exe", "rb");
exec.loadPE(f);
fclose(f);
uint16_t tibSegment = (tibDesc.entry_number << 3) | 7;
// Invoke the damn thing
asm(
"movw %0, %%fs; call *%1"
:
: "r"(tibSegment), "r"(exec.entryPoint)
);
printf("We came back\n");
return 0;
}