revolutionary crash dump, msvcrt.dll redirect, text editor, some win32 functions
This commit is contained in:
1 parent
923e8792b4
commit
603fbdfab1
9 files changed
+1432
-160
No files matched your search
+269
-26
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user