revolutionary crash dump, msvcrt.dll redirect, text editor, some win32 functions

This commit is contained in:
maksw committed 2026-05-24 09:49:01 +02:00
1 parent 923e8792b4
commit 603fbdfab1
9 files changed
+1432 -160

No files matched your search

+269 -26
View File
@@ -43,6 +43,29 @@ typedef struct { LONG x; LONG y; } POINT;
#define INVALID_HANDLE_VALUE ((HANDLE)(intptr_t)-1)
#define MEM_COMMIT 0x00001000UL
#define MEM_RESERVE 0x00002000UL
#define MEM_RELEASE 0x00008000UL
#define MEM_FREE 0x00010000UL
#define MEM_PRIVATE 0x00020000UL
#define PAGE_NOACCESS 0x01UL
#define PAGE_READONLY 0x02UL
#define PAGE_READWRITE 0x04UL
#define PAGE_WRITECOPY 0x08UL
#define PAGE_EXECUTE 0x10UL
#define PAGE_EXECUTE_READ 0x20UL
#define PAGE_EXECUTE_READWRITE 0x40UL
typedef struct _MEMORY_BASIC_INFORMATION {
void* BaseAddress;
void* AllocationBase;
DWORD AllocationProtect;
size_t RegionSize;
DWORD State;
DWORD Protect;
DWORD Type;
} MEMORY_BASIC_INFORMATION;
// File-find structures
typedef struct _FILETIME {
DWORD dwLowDateTime;
@@ -110,12 +133,12 @@ static void TranslatePath(const char* input, char* output) {
if (!input) { output[0] = '\0'; return; }
if (input[0] != '\0' && input[1] == ':' && (input[2] == '\\' || input[2] == '/')) {
// Translate "C:\" -> "0:/" (assuming 'C' maps to '0', etc.)
// Map drive letter to index: 'C' or 'c' -> '0'
// Translate "C:\" -> "0:/". Native nt-lite paths such as
// "0:/system/foo.dll" are already drive-indexed and pass through.
char drive = input[0];
if (drive >= 'a') drive -= ('a' - 'A'); // To uppercase
output[0] = (char)('0' + (drive - 'C'));
if (drive >= 'a' && drive <= 'z') drive -= ('a' - 'A'); // To uppercase
output[0] = (drive >= '0' && drive <= '7') ? drive : (char)('0' + (drive - 'C'));
output[1] = ':';
output[2] = '/';
@@ -137,11 +160,88 @@ static void TranslatePath(const char* input, char* output) {
}
}
static DWORD gLastError = 0;
static BOOL KiFileExistsA(const char* path) {
if (!path || !*path) return FALSE;
char native[MAX_PATH];
TranslatePath(path, native);
uint32_t h = 0;
if (SysOpenFile(native, &h) != 0) return FALSE;
SysCloseHandle(h);
return TRUE;
}
static DWORD KiCopySearchPathResult(char* out, DWORD outChars, const char* text, char** filePart) {
DWORD len = (DWORD)strlen(text);
if (out && outChars) {
DWORD copy = (len < outChars - 1) ? len : outChars - 1;
memcpy(out, text, copy);
out[copy] = '\0';
if (filePart) {
char* slash1 = strrchr(out, '/');
char* slash2 = strrchr(out, '\\');
char* slash = slash1 > slash2 ? slash1 : slash2;
*filePart = slash ? slash + 1 : out;
}
}
return len;
}
__declspec(dllexport) DWORD SearchPathA(const char* lpPath, const char* lpFileName,
const char* lpExtension, DWORD nBufferLength,
char* lpBuffer, char** lpFilePart) {
if (!lpFileName || !*lpFileName) { gLastError = 87; return 0; }
char candidate[MAX_PATH];
size_t nameLen = strlen(lpFileName);
bool hasExt = (strrchr(lpFileName, '.') != NULL);
bool rooted = (lpFileName[0] == '/' || lpFileName[0] == '\\' ||
(lpFileName[0] && lpFileName[1] == ':'));
if (rooted || strchr(lpFileName, '/') || strchr(lpFileName, '\\')) {
strncpy(candidate, lpFileName, sizeof(candidate) - 1);
candidate[sizeof(candidate) - 1] = '\0';
if (!hasExt && lpExtension && nameLen + strlen(lpExtension) + 1 < sizeof(candidate))
strcat(candidate, lpExtension);
if (KiFileExistsA(candidate))
return KiCopySearchPathResult(lpBuffer, nBufferLength, candidate, lpFilePart);
}
const char* paths = lpPath && *lpPath ? lpPath : ".";
const char* p = paths;
while (*p) {
char dir[MAX_PATH];
size_t di = 0;
while (*p && *p != ';' && di + 1 < sizeof(dir)) dir[di++] = *p++;
while (*p == ';') p++;
dir[di] = '\0';
size_t pos = 0;
if (strcmp(dir, ".") != 0) {
while (dir[pos] && pos + 1 < sizeof(candidate)) { candidate[pos] = dir[pos]; pos++; }
if (pos && candidate[pos - 1] != '/' && candidate[pos - 1] != '\\' && pos + 1 < sizeof(candidate))
candidate[pos++] = '/';
}
for (size_t i = 0; lpFileName[i] && pos + 1 < sizeof(candidate); i++) candidate[pos++] = lpFileName[i];
if (!hasExt && lpExtension) {
for (size_t i = 0; lpExtension[i] && pos + 1 < sizeof(candidate); i++) candidate[pos++] = lpExtension[i];
}
candidate[pos] = '\0';
if (KiFileExistsA(candidate))
return KiCopySearchPathResult(lpBuffer, nBufferLength, candidate, lpFilePart);
}
gLastError = 2; // ERROR_FILE_NOT_FOUND
if (lpBuffer && nBufferLength) lpBuffer[0] = '\0';
if (lpFilePart) *lpFilePart = NULL;
return 0;
}
// ---------------------------------------------------------------------------
// GetLastError / SetLastError (single-threaded stub)
// ---------------------------------------------------------------------------
static DWORD gLastError = 0;
static SYS_PEB* gProcessPeb = NULL;
static SYS_PEB* Win32Peb(void) {
@@ -215,6 +315,49 @@ __declspec(dllexport) void* GetProcessHeap(void) {
return (void*)1;
}
// ---------------------------------------------------------------------------
// Virtual memory compatibility
// ---------------------------------------------------------------------------
__declspec(dllexport) void* VirtualAlloc(void* lpAddress, size_t dwSize,
DWORD flAllocationType, DWORD flProtect) {
(void)lpAddress; (void)flAllocationType; (void)flProtect;
if (!dwSize) return NULL;
void* ptr = SysAlloc(dwSize);
if (!ptr) gLastError = 8; // ERROR_NOT_ENOUGH_MEMORY
return ptr;
}
__declspec(dllexport) BOOL VirtualFree(void* lpAddress, size_t dwSize, DWORD dwFreeType) {
(void)dwSize; (void)dwFreeType;
if (lpAddress) SysFree(lpAddress);
return TRUE;
}
__declspec(dllexport) BOOL VirtualProtect(void* lpAddress, size_t dwSize,
DWORD flNewProtect, DWORD* lpflOldProtect) {
(void)lpAddress; (void)dwSize; (void)flNewProtect;
if (lpflOldProtect) *lpflOldProtect = PAGE_EXECUTE_READWRITE;
return TRUE;
}
__declspec(dllexport) size_t VirtualQuery(const void* lpAddress,
MEMORY_BASIC_INFORMATION* lpBuffer,
size_t dwLength) {
if (!lpAddress || !lpBuffer || dwLength < sizeof(MEMORY_BASIC_INFORMATION)) {
gLastError = 87; // ERROR_INVALID_PARAMETER
return 0;
}
uintptr_t base = (uintptr_t)lpAddress & ~(uintptr_t)0xFFF;
lpBuffer->BaseAddress = (void*)base;
lpBuffer->AllocationBase = (void*)base;
lpBuffer->AllocationProtect = PAGE_EXECUTE_READWRITE;
lpBuffer->RegionSize = 0x1000;
lpBuffer->State = MEM_COMMIT;
lpBuffer->Protect = PAGE_EXECUTE_READWRITE;
lpBuffer->Type = MEM_PRIVATE;
return sizeof(MEMORY_BASIC_INFORMATION);
}
// --- Win32 API ---
// Updated GetAsyncKeyState implementation
@@ -335,6 +478,11 @@ __declspec(dllexport) int WideCharToMultiByte(unsigned int cp, DWORD flags,
__declspec(dllexport) DWORD GetACP(void) { return 1252; } // Windows-1252
__declspec(dllexport) DWORD GetOEMCP(void) { return 437; } // DOS Latin US
__declspec(dllexport) BOOL IsDBCSLeadByteEx(unsigned int CodePage, BYTE TestChar) {
(void)CodePage; (void)TestChar;
return FALSE;
}
// ---------------------------------------------------------------------------
// File I/O
// ---------------------------------------------------------------------------
@@ -599,32 +747,104 @@ __declspec(dllexport) HANDLE GetCurrentThread(void) {
__declspec(dllexport) DWORD GetCurrentThreadId(void) { return (DWORD)SysGetCurrentTid(); }
__declspec(dllexport) DWORD GetCurrentProcessId(void) { return (DWORD)SysGetCurrentPid(); }
// GetModuleHandleA/W - no PE map; return NULL so callers that check can fail
// gracefully. GetModuleHandleA(NULL) on Windows returns the exe base; we
// return a recognisable non-NULL sentinel so code that just passes it to
// GetProcAddress doesn't immediately crash.
// Tiny TLS table; enough for MSVCRT/TCC compatibility paths that probe TLS.
#define WIN32_TLS_SLOTS 64
static void* gTlsSlots[WIN32_TLS_SLOTS];
static uint64_t gTlsBitmap = 1; // reserve slot 0
__declspec(dllexport) DWORD TlsAlloc(void) {
for (DWORD i = 1; i < WIN32_TLS_SLOTS; i++) {
uint64_t bit = 1ULL << i;
if (!(gTlsBitmap & bit)) { gTlsBitmap |= bit; gTlsSlots[i] = NULL; return i; }
}
gLastError = 8;
return 0xFFFFFFFFUL;
}
__declspec(dllexport) BOOL TlsFree(DWORD dwTlsIndex) {
if (dwTlsIndex >= WIN32_TLS_SLOTS || !(gTlsBitmap & (1ULL << dwTlsIndex))) { gLastError = 87; return FALSE; }
gTlsSlots[dwTlsIndex] = NULL;
gTlsBitmap &= ~(1ULL << dwTlsIndex);
return TRUE;
}
__declspec(dllexport) void* TlsGetValue(DWORD dwTlsIndex) {
if (dwTlsIndex >= WIN32_TLS_SLOTS || !(gTlsBitmap & (1ULL << dwTlsIndex))) { gLastError = 87; return NULL; }
gLastError = 0;
return gTlsSlots[dwTlsIndex];
}
__declspec(dllexport) BOOL TlsSetValue(DWORD dwTlsIndex, void* lpTlsValue) {
if (dwTlsIndex >= WIN32_TLS_SLOTS || !(gTlsBitmap & (1ULL << dwTlsIndex))) { gLastError = 87; return FALSE; }
gTlsSlots[dwTlsIndex] = lpTlsValue;
return TRUE;
}
// Pseudo HMODULEs for callers that probe already-linked personality DLLs.
#define WIN32_HMODULE_EXE ((HANDLE)(uintptr_t)0x00400000UL)
#define WIN32_HMODULE_WIN32 ((HANDLE)(uintptr_t)0x57333232UL) // W322
static int KiStricmpA(const char* a, const char* b) {
while (*a && (((unsigned char)*a | 0x20) == ((unsigned char)*b | 0x20))) { a++; b++; }
return ((unsigned char)*a | 0x20) - ((unsigned char)*b | 0x20);
}
static BOOL KiIsWin32DllNameA(const char* name) {
return name && (
!KiStricmpA(name, "kernel32.dll") || !KiStricmpA(name, "user32.dll") ||
!KiStricmpA(name, "gdi32.dll") || !KiStricmpA(name, "ole32.dll") ||
!KiStricmpA(name, "winmm.dll") || !KiStricmpA(name, "win32.dll"));
}
static void KiDbgWriteA(const char* s) {
if (s) SysWriteConsole(s, strlen(s));
}
__declspec(dllexport) HANDLE GetModuleHandleA(const char* lpModuleName) {
return lpModuleName ? NULL : (HANDLE)(uintptr_t)0x00400000UL;
}
__declspec(dllexport) HANDLE GetModuleHandleW(const unsigned short* lpModuleName) {
return lpModuleName ? NULL : (HANDLE)(uintptr_t)0x00400000UL;
}
// GetProcAddress - no dynamic linker; always fail.
__declspec(dllexport) void* GetProcAddress(HANDLE hModule, const char* lpProcName) {
(void)hModule; (void)lpProcName;
gLastError = 127; // ERROR_PROC_NOT_FOUND
if (!lpModuleName) return WIN32_HMODULE_EXE;
if (KiIsWin32DllNameA(lpModuleName)) return WIN32_HMODULE_WIN32;
gLastError = 126; // ERROR_MOD_NOT_FOUND
return NULL;
}
// LoadLibraryA - no dynamic loader; always fail.
__declspec(dllexport) HANDLE GetModuleHandleW(const unsigned short* lpModuleName) {
return lpModuleName ? NULL : WIN32_HMODULE_EXE;
}
__declspec(dllexport) HANDLE LoadLibraryA(const char* lpLibFileName) {
(void)lpLibFileName;
if (KiIsWin32DllNameA(lpLibFileName)) return WIN32_HMODULE_WIN32;
gLastError = 2; // ERROR_FILE_NOT_FOUND
return NULL;
}
// Minimal GetProcAddress for code that probes kernel32 functions already present
// in this win32.dll image. Full dynamic DLL loading remains a kernel-loader job.
__declspec(dllexport) BOOL FreeLibrary(HANDLE hLibModule);
__declspec(dllexport) void Sleep(DWORD dwMilliseconds);
__declspec(dllexport) void* GetProcAddress(HANDLE hModule, const char* lpProcName) {
if (hModule != WIN32_HMODULE_WIN32 || !lpProcName) { gLastError = 127; return NULL; }
// Ordinal probes are represented as small integer pointers. Do not treat
// them as strings while debugging misses.
if ((uintptr_t)lpProcName < 0x10000) {
KiDbgWriteA("GetProcAddress ordinal miss\n");
gLastError = 127;
return NULL;
}
#define GP(name) if (strcmp(lpProcName, #name) == 0) return (void*)&name
GP(GetLastError); GP(SetLastError); GP(LoadLibraryA); GP(GetProcAddress);
GP(FreeLibrary); GP(VirtualAlloc); GP(VirtualFree); GP(VirtualProtect);
GP(VirtualQuery); GP(GetTickCount); GP(GetTickCount64); GP(Sleep);
GP(TlsAlloc); GP(TlsFree); GP(TlsGetValue); GP(TlsSetValue);
#undef GP
KiDbgWriteA("GetProcAddress miss: ");
KiDbgWriteA(lpProcName);
KiDbgWriteA("\n");
gLastError = 127; // ERROR_PROC_NOT_FOUND
return NULL;
}
__declspec(dllexport) BOOL FreeLibrary(HANDLE hLibModule) {
(void)hLibModule;
return TRUE;
@@ -633,8 +853,19 @@ __declspec(dllexport) BOOL FreeLibrary(HANDLE hLibModule) {
__declspec(dllexport) DWORD GetModuleFileNameA(HANDLE hModule,
char* lpFilename, DWORD nSize) {
(void)hModule;
if (lpFilename && nSize) lpFilename[0] = '\0';
return 0;
if (!lpFilename || !nSize) return 0;
SYS_PEB* peb = Win32Peb();
const char* src = (peb && peb->Magic == SYS_PEB_MAGIC && peb->ImagePath)
? peb->ImagePath
: "";
DWORD len = (DWORD)strlen(src);
DWORD copy = (len < nSize - 1) ? len : nSize - 1;
memcpy(lpFilename, src, copy);
lpFilename[copy] = '\0';
if (copy < len) gLastError = 122; // ERROR_INSUFFICIENT_BUFFER
return copy;
}
__declspec(dllexport) BOOL TerminateProcess(HANDLE hProcess, unsigned int uExitCode) {
@@ -1565,6 +1796,18 @@ typedef struct _RUNTIME_FUNCTION {
unsigned int UnwindInfoAddress;
} RUNTIME_FUNCTION;
__declspec(dllexport) BOOL RtlAddFunctionTable(RUNTIME_FUNCTION* FunctionTable,
DWORD EntryCount,
unsigned long long BaseAddress) {
(void)FunctionTable; (void)EntryCount; (void)BaseAddress;
return TRUE;
}
__declspec(dllexport) BOOL RtlDeleteFunctionTable(RUNTIME_FUNCTION* FunctionTable) {
(void)FunctionTable;
return TRUE;
}
// We have no runtime function table, so RtlLookupFunctionEntry always fails.
__declspec(dllexport) RUNTIME_FUNCTION*
RtlLookupFunctionEntry(unsigned long long ControlPc,