2022-06-13 00:20:18 +00:00
|
|
|
#include "common.h"
|
2022-07-03 22:40:12 +00:00
|
|
|
#include "files.h"
|
2022-06-13 00:20:18 +00:00
|
|
|
#include <asm/ldt.h>
|
2022-06-30 19:23:00 +00:00
|
|
|
#include <filesystem>
|
2022-06-13 00:20:18 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <memory>
|
2023-09-22 00:13:56 +00:00
|
|
|
#include "strutil.h"
|
2022-06-13 00:20:18 +00:00
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/syscall.h>
|
2022-06-28 23:07:04 +00:00
|
|
|
#include <stdarg.h>
|
2023-06-02 19:30:45 +00:00
|
|
|
#include <iostream>
|
2023-09-10 03:07:23 +00:00
|
|
|
#include <fstream>
|
2023-09-22 00:13:56 +00:00
|
|
|
#include <vector>
|
2022-06-13 00:20:18 +00:00
|
|
|
|
|
|
|
uint32_t wibo::lastError = 0;
|
2023-09-10 03:07:23 +00:00
|
|
|
char** wibo::argv;
|
|
|
|
int wibo::argc;
|
2023-09-18 06:05:47 +00:00
|
|
|
char *wibo::executableName;
|
2022-06-13 00:20:18 +00:00
|
|
|
char *wibo::commandLine;
|
2023-09-22 00:13:56 +00:00
|
|
|
std::vector<uint16_t> wibo::commandLineW;
|
2022-06-29 11:19:45 +00:00
|
|
|
wibo::Executable *wibo::mainModule = 0;
|
2022-06-29 13:24:58 +00:00
|
|
|
bool wibo::debugEnabled = false;
|
2023-09-18 06:05:47 +00:00
|
|
|
unsigned int wibo::debugIndent = 0;
|
2022-06-13 00:20:18 +00:00
|
|
|
|
2022-06-28 23:07:04 +00:00
|
|
|
void wibo::debug_log(const char *fmt, ...) {
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2023-09-18 06:05:47 +00:00
|
|
|
if (wibo::debugEnabled) {
|
|
|
|
for (size_t i = 0; i < wibo::debugIndent; i++)
|
|
|
|
fprintf(stderr, "\t");
|
|
|
|
|
2022-07-26 10:38:21 +00:00
|
|
|
vfprintf(stderr, fmt, args);
|
2023-09-18 06:05:47 +00:00
|
|
|
}
|
|
|
|
|
2022-06-28 23:07:04 +00:00
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
2022-07-14 22:45:35 +00:00
|
|
|
#define FOR_256_3(a, b, c, d) FOR_ITER((a << 6 | b << 4 | c << 2 | d))
|
|
|
|
#define FOR_256_2(a, b) \
|
|
|
|
FOR_256_3(a, b, 0, 0) FOR_256_3(a, b, 0, 1) FOR_256_3(a, b, 0, 2) FOR_256_3(a, b, 0, 3) \
|
|
|
|
FOR_256_3(a, b, 1, 0) FOR_256_3(a, b, 1, 1) FOR_256_3(a, b, 1, 2) FOR_256_3(a, b, 1, 3) \
|
|
|
|
FOR_256_3(a, b, 2, 0) FOR_256_3(a, b, 2, 1) FOR_256_3(a, b, 2, 2) FOR_256_3(a, b, 2, 3) \
|
|
|
|
FOR_256_3(a, b, 3, 0) FOR_256_3(a, b, 3, 1) FOR_256_3(a, b, 3, 2) FOR_256_3(a, b, 3, 3)
|
|
|
|
#define FOR_256 \
|
|
|
|
FOR_256_2(0, 0) FOR_256_2(0, 1) FOR_256_2(0, 2) FOR_256_2(0, 3) \
|
|
|
|
FOR_256_2(1, 0) FOR_256_2(1, 1) FOR_256_2(1, 2) FOR_256_2(1, 3) \
|
|
|
|
FOR_256_2(2, 0) FOR_256_2(2, 1) FOR_256_2(2, 2) FOR_256_2(2, 3) \
|
|
|
|
FOR_256_2(3, 0) FOR_256_2(3, 1) FOR_256_2(3, 2) FOR_256_2(3, 3) \
|
|
|
|
|
2022-06-28 21:08:23 +00:00
|
|
|
static int stubIndex = 0;
|
|
|
|
static char stubDlls[0x100][0x100];
|
|
|
|
static char stubFuncNames[0x100][0x100];
|
|
|
|
|
|
|
|
static void stubBase(int index) {
|
2022-06-29 13:24:58 +00:00
|
|
|
printf("Unhandled function %s (%s)\n", stubFuncNames[index], stubDlls[index]);
|
|
|
|
exit(1);
|
2022-06-13 00:20:18 +00:00
|
|
|
}
|
|
|
|
|
2022-06-28 21:08:23 +00:00
|
|
|
void (*stubFuncs[0x100])(void) = {
|
2022-07-14 22:45:35 +00:00
|
|
|
#define FOR_ITER(i) []() { stubBase(i); },
|
|
|
|
FOR_256
|
|
|
|
#undef FOR_ITER
|
2022-06-28 21:08:23 +00:00
|
|
|
};
|
|
|
|
|
2022-07-14 22:45:35 +00:00
|
|
|
#undef FOR_256_3
|
|
|
|
#undef FOR_256_2
|
|
|
|
#undef FOR_256
|
2022-06-13 00:20:18 +00:00
|
|
|
|
2023-09-10 03:07:23 +00:00
|
|
|
static void *resolveMissingFuncName(const char *dllName, const char *funcName) {
|
2022-06-28 23:07:04 +00:00
|
|
|
DEBUG_LOG("Missing function: %s (%s)\n", dllName, funcName);
|
2022-06-28 21:08:23 +00:00
|
|
|
assert(stubIndex < 0x100);
|
|
|
|
assert(strlen(dllName) < 0x100);
|
|
|
|
assert(strlen(funcName) < 0x100);
|
|
|
|
strcpy(stubFuncNames[stubIndex], funcName);
|
|
|
|
strcpy(stubDlls[stubIndex], dllName);
|
2023-09-10 03:07:23 +00:00
|
|
|
return (void *)stubFuncs[stubIndex++];
|
2022-06-13 00:20:18 +00:00
|
|
|
}
|
|
|
|
|
2023-09-10 03:07:23 +00:00
|
|
|
static void *resolveMissingFuncOrdinal(const char *dllName, uint16_t ordinal) {
|
|
|
|
char buf[16];
|
|
|
|
sprintf(buf, "%d", ordinal);
|
|
|
|
return resolveMissingFuncName(dllName, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern const wibo::Module lib_advapi32;
|
|
|
|
extern const wibo::Module lib_bcrypt;
|
|
|
|
extern const wibo::Module lib_crt;
|
|
|
|
extern const wibo::Module lib_kernel32;
|
|
|
|
extern const wibo::Module lib_lmgr;
|
2023-09-12 13:44:56 +00:00
|
|
|
extern const wibo::Module lib_mscoree;
|
2023-09-10 19:22:01 +00:00
|
|
|
extern const wibo::Module lib_msvcrt;
|
2023-09-10 03:07:23 +00:00
|
|
|
extern const wibo::Module lib_ntdll;
|
|
|
|
extern const wibo::Module lib_ole32;
|
|
|
|
extern const wibo::Module lib_user32;
|
|
|
|
extern const wibo::Module lib_vcruntime;
|
|
|
|
extern const wibo::Module lib_version;
|
|
|
|
const wibo::Module * wibo::modules[] = {
|
|
|
|
&lib_advapi32,
|
|
|
|
&lib_bcrypt,
|
|
|
|
&lib_crt,
|
|
|
|
&lib_kernel32,
|
|
|
|
&lib_lmgr,
|
2023-09-12 13:44:56 +00:00
|
|
|
&lib_mscoree,
|
2023-09-10 19:22:01 +00:00
|
|
|
&lib_msvcrt,
|
2023-09-10 03:07:23 +00:00
|
|
|
&lib_ntdll,
|
|
|
|
&lib_ole32,
|
|
|
|
&lib_user32,
|
|
|
|
&lib_vcruntime,
|
|
|
|
&lib_version,
|
|
|
|
nullptr,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ModuleInfo {
|
|
|
|
std::string name;
|
|
|
|
const wibo::Module* module = nullptr;
|
|
|
|
};
|
2022-07-14 22:45:35 +00:00
|
|
|
|
2023-09-10 03:07:23 +00:00
|
|
|
HMODULE wibo::loadModule(const char *dllName) {
|
|
|
|
auto *result = new ModuleInfo;
|
|
|
|
result->name = dllName;
|
|
|
|
for (int i = 0; modules[i]; i++) {
|
|
|
|
for (int j = 0; modules[i]->names[j]; j++) {
|
|
|
|
if (strcasecmp(dllName, modules[i]->names[j]) == 0) {
|
|
|
|
result->module = modules[i];
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
2022-07-14 22:45:35 +00:00
|
|
|
}
|
|
|
|
|
2023-09-10 03:07:23 +00:00
|
|
|
void wibo::freeModule(HMODULE module) { delete static_cast<ModuleInfo *>(module); }
|
|
|
|
|
|
|
|
void *wibo::resolveFuncByName(HMODULE module, const char *funcName) {
|
|
|
|
auto *info = static_cast<ModuleInfo *>(module);
|
|
|
|
if (info && info->module && info->module->byName) {
|
|
|
|
void *func = info->module->byName(funcName);
|
|
|
|
if (func)
|
|
|
|
return func;
|
2022-06-28 23:07:04 +00:00
|
|
|
}
|
2023-09-10 03:07:23 +00:00
|
|
|
return resolveMissingFuncName(info->name.c_str(), funcName);
|
|
|
|
}
|
2022-07-14 22:45:35 +00:00
|
|
|
|
2023-09-10 03:07:23 +00:00
|
|
|
void *wibo::resolveFuncByOrdinal(HMODULE module, uint16_t ordinal) {
|
|
|
|
auto *info = static_cast<ModuleInfo *>(module);
|
|
|
|
if (info && info->module && info->module->byOrdinal) {
|
|
|
|
void *func = info->module->byOrdinal(ordinal);
|
|
|
|
if (func)
|
|
|
|
return func;
|
|
|
|
}
|
|
|
|
return resolveMissingFuncOrdinal(info->name.c_str(), ordinal);
|
2022-06-13 00:20:18 +00:00
|
|
|
}
|
|
|
|
|
2022-07-27 22:13:36 +00:00
|
|
|
struct UNICODE_STRING {
|
|
|
|
unsigned short Length;
|
|
|
|
unsigned short MaximumLength;
|
|
|
|
uint16_t *Buffer;
|
|
|
|
};
|
|
|
|
|
2023-04-01 09:13:21 +00:00
|
|
|
// Run Time Library (RTL)
|
2022-07-27 22:13:36 +00:00
|
|
|
struct RTL_USER_PROCESS_PARAMETERS {
|
|
|
|
char Reserved1[16];
|
|
|
|
void *Reserved2[10];
|
|
|
|
UNICODE_STRING ImagePathName;
|
|
|
|
UNICODE_STRING CommandLine;
|
|
|
|
};
|
|
|
|
|
2023-04-01 09:13:21 +00:00
|
|
|
// Windows Process Environment Block (PEB)
|
2022-07-27 22:13:36 +00:00
|
|
|
struct PEB {
|
|
|
|
char Reserved1[2];
|
|
|
|
char BeingDebugged;
|
|
|
|
char Reserved2[1];
|
|
|
|
void *Reserved3[2];
|
|
|
|
void *Ldr;
|
|
|
|
RTL_USER_PROCESS_PARAMETERS *ProcessParameters;
|
|
|
|
char Reserved4[104];
|
|
|
|
void *Reserved5[52];
|
|
|
|
void *PostProcessInitRoutine;
|
|
|
|
char Reserved6[128];
|
|
|
|
void *Reserved7[1];
|
|
|
|
unsigned int SessionId;
|
|
|
|
};
|
|
|
|
|
2023-04-01 09:13:21 +00:00
|
|
|
// Windows Thread Information Block (TIB)
|
2022-06-13 00:20:18 +00:00
|
|
|
struct TIB {
|
2022-07-27 22:13:36 +00:00
|
|
|
/* 0x00 */ void *sehFrame;
|
|
|
|
/* 0x04 */ void *stackBase;
|
|
|
|
/* 0x08 */ void *stackLimit;
|
|
|
|
/* 0x0C */ void *subSystemTib;
|
|
|
|
/* 0x10 */ void *fiberData;
|
|
|
|
/* 0x14 */ void *arbitraryDataSlot;
|
|
|
|
/* 0x18 */ TIB *tib;
|
|
|
|
/* */ char pad[0x14];
|
|
|
|
/* 0x30 */ PEB *peb;
|
|
|
|
/* */ char pad2[0x1000];
|
2022-06-13 00:20:18 +00:00
|
|
|
};
|
|
|
|
|
2022-07-29 21:39:31 +00:00
|
|
|
// Make this global to ease debugging
|
|
|
|
TIB tib;
|
|
|
|
|
2022-06-13 00:20:18 +00:00
|
|
|
int main(int argc, char **argv) {
|
2022-06-28 23:29:26 +00:00
|
|
|
if (argc <= 1) {
|
|
|
|
printf("Usage: ./wibo program.exe ...\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-06-29 13:24:58 +00:00
|
|
|
if (getenv("WIBO_DEBUG")) {
|
|
|
|
wibo::debugEnabled = true;
|
|
|
|
}
|
|
|
|
|
2023-09-18 06:05:47 +00:00
|
|
|
if (getenv("WIBO_DEBUG_INDENT")) {
|
|
|
|
wibo::debugIndent = std::stoul(getenv("WIBO_DEBUG_INDENT"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-07-03 22:40:12 +00:00
|
|
|
files::init();
|
|
|
|
|
2022-06-13 00:20:18 +00:00
|
|
|
// Create TIB
|
2022-07-27 22:13:36 +00:00
|
|
|
memset(&tib, 0, sizeof(tib));
|
2022-06-13 00:20:18 +00:00
|
|
|
tib.tib = &tib;
|
2022-07-27 22:13:36 +00:00
|
|
|
tib.peb = (PEB*)calloc(sizeof(PEB), 1);
|
|
|
|
tib.peb->ProcessParameters = (RTL_USER_PROCESS_PARAMETERS*)calloc(sizeof(RTL_USER_PROCESS_PARAMETERS), 1);
|
2022-06-13 00:20:18 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-06-28 23:29:26 +00:00
|
|
|
// Build a command line
|
|
|
|
std::string cmdLine;
|
|
|
|
for (int i = 1; i < argc; i++) {
|
2023-01-23 15:35:50 +00:00
|
|
|
std::string arg;
|
|
|
|
if (i == 1) {
|
|
|
|
arg = files::pathToWindows(std::filesystem::absolute(argv[1]));
|
|
|
|
} else {
|
|
|
|
cmdLine += ' ';
|
|
|
|
arg = argv[i];
|
|
|
|
}
|
2022-06-28 23:29:26 +00:00
|
|
|
bool needQuotes = arg.find_first_of("\\\" \t\n") != std::string::npos;
|
|
|
|
if (needQuotes)
|
|
|
|
cmdLine += '"';
|
|
|
|
int backslashes = 0;
|
|
|
|
for (const char *p = arg.c_str(); ; p++) {
|
|
|
|
char c = *p;
|
|
|
|
if (c == '\\') {
|
|
|
|
backslashes++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Backslashes are doubled *before quotes*
|
|
|
|
for (int j = 0; j < backslashes; j++) {
|
|
|
|
cmdLine += '\\';
|
|
|
|
if (c == '\0' || c == '"')
|
|
|
|
cmdLine += '\\';
|
|
|
|
}
|
2022-07-31 11:17:14 +00:00
|
|
|
backslashes = 0;
|
2022-06-28 23:29:26 +00:00
|
|
|
|
|
|
|
if (c == '\0')
|
|
|
|
break;
|
|
|
|
if (c == '\"')
|
|
|
|
cmdLine += '\\';
|
|
|
|
cmdLine += c;
|
|
|
|
}
|
|
|
|
if (needQuotes)
|
|
|
|
cmdLine += '"';
|
|
|
|
}
|
|
|
|
cmdLine += '\0';
|
|
|
|
|
|
|
|
wibo::commandLine = cmdLine.data();
|
2023-09-22 00:13:56 +00:00
|
|
|
wibo::commandLineW = stringToWideString(wibo::commandLine);
|
2022-06-28 23:29:26 +00:00
|
|
|
DEBUG_LOG("Command line: %s\n", wibo::commandLine);
|
2022-06-13 00:20:18 +00:00
|
|
|
|
2023-09-18 06:05:47 +00:00
|
|
|
wibo::executableName = argv[0];
|
2023-09-10 03:07:23 +00:00
|
|
|
wibo::argv = argv + 1;
|
|
|
|
wibo::argc = argc - 1;
|
|
|
|
|
2022-06-13 00:20:18 +00:00
|
|
|
wibo::Executable exec;
|
2022-06-29 11:19:45 +00:00
|
|
|
wibo::mainModule = &exec;
|
2022-06-13 00:20:18 +00:00
|
|
|
|
2022-06-30 19:23:00 +00:00
|
|
|
char* pe_path = argv[1];
|
|
|
|
FILE *f = fopen(pe_path, "rb");
|
|
|
|
if (!f) {
|
|
|
|
std::string mesg = std::string("Failed to open file ") + pe_path;
|
|
|
|
perror(mesg.c_str());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-06-13 00:20:18 +00:00
|
|
|
exec.loadPE(f);
|
|
|
|
fclose(f);
|
|
|
|
|
2023-06-02 19:30:45 +00:00
|
|
|
// 32-bit windows only reserves the lowest 2GB of memory for use by a process (https://www.tenouk.com/WinVirtualAddressSpace.html)
|
|
|
|
// Linux, on the other hand, will happily allow nearly the entire 4GB address space to be used.
|
|
|
|
// In order to prevent windows programs from being very confused as to why it's being handed
|
|
|
|
// addresses in "invalid" memory, let's map the upper 2GB of memory to ensure libc can't allocate
|
|
|
|
// anything there.
|
|
|
|
std::ifstream procMap("/proc/self/maps");
|
|
|
|
std::string procLine;
|
|
|
|
unsigned int lastMapEnd = 0;
|
|
|
|
|
|
|
|
const unsigned int FILL_MEMORY_ABOVE = 0x80000000; // 2GB
|
|
|
|
|
|
|
|
while (getline(procMap, procLine)) {
|
|
|
|
std::size_t idx = 0;
|
|
|
|
unsigned int mapStart = std::stoul(procLine, &idx, 16);
|
|
|
|
unsigned int mapEnd = std::stoul(procLine.substr(idx + 1), nullptr, 16);
|
|
|
|
|
|
|
|
// The empty space we want to map out is now between lastMapEnd and mapStart
|
|
|
|
unsigned int holdingMapStart = lastMapEnd;
|
|
|
|
unsigned int holdingMapEnd = mapStart;
|
|
|
|
|
|
|
|
if ((holdingMapEnd - holdingMapStart) != 0 && holdingMapEnd > FILL_MEMORY_ABOVE) {
|
|
|
|
holdingMapStart = std::max(holdingMapStart, FILL_MEMORY_ABOVE);
|
|
|
|
|
|
|
|
void* holdingMap = mmap((void*) holdingMapStart, holdingMapEnd - holdingMapStart, PROT_READ, MAP_ANONYMOUS|MAP_FIXED|MAP_PRIVATE, -1, 0);
|
2023-09-10 03:07:23 +00:00
|
|
|
|
2023-06-02 19:30:45 +00:00
|
|
|
if (holdingMap == MAP_FAILED) {
|
|
|
|
perror("Failed to create holding map");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2023-09-10 03:07:23 +00:00
|
|
|
|
2023-06-02 19:30:45 +00:00
|
|
|
lastMapEnd = mapEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
procMap.close();
|
|
|
|
|
2022-06-13 00:20:18 +00:00
|
|
|
uint16_t tibSegment = (tibDesc.entry_number << 3) | 7;
|
|
|
|
// Invoke the damn thing
|
|
|
|
asm(
|
|
|
|
"movw %0, %%fs; call *%1"
|
|
|
|
:
|
|
|
|
: "r"(tibSegment), "r"(exec.entryPoint)
|
|
|
|
);
|
2022-06-28 23:07:04 +00:00
|
|
|
DEBUG_LOG("We came back\n");
|
2022-06-13 00:20:18 +00:00
|
|
|
|
2022-06-28 23:29:26 +00:00
|
|
|
return 1;
|
2022-06-13 00:20:18 +00:00
|
|
|
}
|