From 1a9d5d5a864aa8e828cdf1988bb8adf6a7123101 Mon Sep 17 00:00:00 2001 From: Simon Lindholm Date: Wed, 29 Jun 2022 13:19:45 +0200 Subject: [PATCH] resources --- common.h | 7 ++-- kernel32.cpp | 3 +- loader.cpp | 7 +++- main.cpp | 2 ++ user32.cpp | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 108 insertions(+), 6 deletions(-) diff --git a/common.h b/common.h index 76db4e4..e944f4b 100644 --- a/common.h +++ b/common.h @@ -6,8 +6,8 @@ #include #define WIN_FUNC __attribute__((stdcall)) -#define DEBUG_LOG(...) /* nothing */ -// #define DEBUG_LOG(...) wibo::debug_log(__VA_ARGS__) +// inline void DEBUG_LOG(const char *fmt, ...) {} +#define DEBUG_LOG(...) wibo::debug_log(__VA_ARGS__) namespace wibo { extern uint32_t lastError; @@ -31,6 +31,7 @@ namespace wibo { void *imageBuffer; size_t imageSize; void *entryPoint; + void *rsrcBase; template T *fromRVA(uint32_t rva) { @@ -42,4 +43,6 @@ namespace wibo { return fromRVA((uint32_t) rva); } }; + + extern Executable *mainModule; } diff --git a/kernel32.cpp b/kernel32.cpp index 7b7e2a4..0414795 100644 --- a/kernel32.cpp +++ b/kernel32.cpp @@ -79,9 +79,10 @@ namespace kernel32 { * Memory */ void *WIN_FUNC GlobalAlloc(uint32_t uFlags, size_t dwBytes) { - DEBUG_LOG("GlobalAlloc(flags=%x, size=%x)\n", uFlags, dwBytes); + // DEBUG_LOG("GlobalAlloc(flags=%x, size=%x)\n", uFlags, dwBytes); if (uFlags & 2) { // GMEM_MOVEABLE - not implemented rn + assert(0); return 0; } else { // GMEM_FIXED - this is simpler diff --git a/loader.cpp b/loader.cpp index 8f94404..121a09e 100644 --- a/loader.cpp +++ b/loader.cpp @@ -106,6 +106,7 @@ uint32_t read32(FILE *file) { wibo::Executable::Executable() { imageBuffer = nullptr; imageSize = 0; + rsrcBase = 0; } wibo::Executable::~Executable() { @@ -162,14 +163,18 @@ bool wibo::Executable::loadPE(FILE *file) { name[8] = 0; DEBUG_LOG("Section %d: name=%s addr=%x size=%x (raw=%x) ptr=%x\n", i, name, section.virtualAddress, section.virtualSize, section.sizeOfRawData, section.pointerToRawData); + void *sectionBase = (void *) (header32.imageBase + section.virtualAddress); 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); } + + if (strcmp(name, ".rsrc") == 0) { + rsrcBase = sectionBase; + } } // Handle imports diff --git a/main.cpp b/main.cpp index 309dba5..aafba18 100644 --- a/main.cpp +++ b/main.cpp @@ -8,6 +8,7 @@ uint32_t wibo::lastError = 0; char *wibo::commandLine; +wibo::Executable *wibo::mainModule = 0; void wibo::debug_log(const char *fmt, ...) { va_list args; @@ -168,6 +169,7 @@ int main(int argc, char **argv) { DEBUG_LOG("Command line: %s\n", wibo::commandLine); wibo::Executable exec; + wibo::mainModule = &exec; FILE *f = fopen(argv[1], "rb"); exec.loadPE(f); diff --git a/user32.cpp b/user32.cpp index 400d058..2b7b02a 100644 --- a/user32.cpp +++ b/user32.cpp @@ -1,10 +1,101 @@ #include "common.h" namespace user32 { + struct Resource { + uint32_t id; + uint32_t value; + }; + + struct ResourceTable { + char pad[12]; + uint16_t nameEntryCount; + uint16_t idEntryCount; + Resource resources[]; + }; + + static unsigned int searchResourceTableByID(const char *tableAddr, unsigned int id) { + ResourceTable* table = (ResourceTable*)tableAddr; + for (int i = 0; i < table->idEntryCount; i++) { + const Resource& r = table->resources[table->nameEntryCount + i]; + if (r.id == id) { + return r.value; + } + } + return 0; + } + + static unsigned int* getResourceByID(wibo::Executable *mod, unsigned int typeID, unsigned int nameID, unsigned int languageID) { + const char *rsrcBase = (const char *)mod->rsrcBase; + + if (rsrcBase == 0) { + DEBUG_LOG("getResourceByID: no .rsrc section\n"); + wibo::lastError = 1812; // ERROR_RESOURCE_DATA_NOT_FOUND + return 0; + } + + unsigned int typeTable = searchResourceTableByID(rsrcBase, typeID) & 0x7FFFFFFFu; + if (typeTable == 0) { + DEBUG_LOG("getResourceByID: no type table with id = %s\n", typeID); + wibo::lastError = 1813; // ERROR_RESOURCE_TYPE_NOT_FOUND + return 0; + } + + unsigned int nameTable = searchResourceTableByID(rsrcBase + typeTable, nameID) & 0x7FFFFFFFu; + if (nameTable == 0) { + DEBUG_LOG("getResourceByID: no name table with id = %s\n", nameID); + wibo::lastError = 1814; // ERROR_RESOURCE_NAME_NOT_FOUND + return 0; + } + + unsigned int langEntry = searchResourceTableByID(rsrcBase + nameTable, languageID); + if (langEntry == 0) { + DEBUG_LOG("getResourceByID: no lang entry with id = %s\n", languageID); + wibo::lastError = 1814; // ERROR_RESOURCE_NAME_NOT_FOUND + return 0; + } + + return (unsigned int*)(rsrcBase + langEntry); + } + + static const char *getStringFromTable(unsigned int uID) { + wibo::Executable *mod = wibo::mainModule; + unsigned int tableID = (uID >> 4) + 1; + unsigned int entryID = uID & 15; + unsigned int* stringTable = getResourceByID(mod, 6, tableID, 1033); + if (stringTable == 0) + return 0; + + // what's in here? + const char *str = mod->fromRVA(stringTable[0]); + unsigned int size = stringTable[1]; + assert(entryID < size); + + // skip over strings to get to the one we want + for (unsigned int i = 0; i < entryID; i++) { + int stringSize = *(uint16_t*)str; + str += 2; + str += stringSize * 2; + } + + return str; + } + int WIN_FUNC LoadStringA(void* hInstance, unsigned int uID, char* lpBuffer, int cchBufferMax) { DEBUG_LOG("LoadStringA %p %d %d\n", hInstance, uID, cchBufferMax); - strcpy(lpBuffer, "hello"); - return 5; + const char* s = getStringFromTable(uID); + if (!s) { + return 0; + } + int len = *(int16_t*)s; + s += 2; + assert(cchBufferMax != 0); + len = (len < cchBufferMax - 1 ? len : cchBufferMax - 1); + for (int i = 0; i < len; i++) { + lpBuffer[i] = s[i * 2]; + } + lpBuffer[len] = 0; + DEBUG_LOG("returning: %s\n", lpBuffer); + return len; } }