// a kernel library which writes a stackdump for each exception // // printf "#\"loadklib\"stackdumper.dll" | pput -f -c "%CSIDL_STARTUP%\stackdumper.lnk" // area free in kaiser rom // 802fa000-802fb000 // 802fc000-80300000 // 80308000-8031f000 #include #include "cenk.h" #include "printfformat.h" //#include "kernelmisc.h" DWORD PhysToVirt(DWORD dwPhysOffset) { // KSEG0_BASE .. KSEG1_BASE = cached kernel physical for (DWORD ixPage= 0x800 ; ixPage < 0xa00 ; ixPage++) { DWORD dwEntry= FirstPT[ixPage]; // FirstPT is defined in nkarm.h if (((dwEntry&3)==2) && ((dwEntry&0xfff00000)==(dwPhysOffset&0xfff00000))) return (dwPhysOffset&0xfffff)|(ixPage<<20); } // debug("Physical address %08lx is not mapped\n", dwPhysOffset); return 0; } void dummy() { } #define DECLARE_API(name, result, params) \ typedef result (*name##_fn) params; \ name##_fn name##_orig=(name##_fn)dummy; #define GETAPI(apinr,callnr,name) \ name##_orig = (name##_fn)SystemApiSets[apinr]->ppfnMethods[callnr]; #define HOOKFUNCTION(name,result,params) \ result name##_hook params #define SETAPI(apinr,callnr,name) \ set_api_method(apinr, callnr, (PFNVOID)name##_hook); \ NKDbgPrintf(L"hooked api(%d,%d) : %s\n", apinr, callnr, L#name); // note: all functions need to use the same nr of macro levels // otherwise one will use the name -as-is-, while the other will use // the name redefined to nameW ( as often done in windows.h for UNICODE apis ) #define DECLARE_HOOK(name, result, params) \ DECLARE_API(name,result,params) \ HOOKFUNCTION(name,result,params) #define HOOKAPI(apinr,callnr,name) \ GETAPI(apinr,callnr,name) \ SETAPI(apinr,callnr,name) #define ORIGAPIX(name) name##_orig #define ORIGAPI(name) ORIGAPIX(name) // use kernel versions of : // SetLastError 0 88 f000fea0 DECLARE_API(SetLastError,void,(DWORD)) // GetLastError 0 89 f000fe9c DECLARE_API(GetLastError,DWORD,()) // LeaveCriticalSection f000ff1c 0 57 LeaveCritSec DECLARE_API(LeaveCriticalSection,void, (LPCRITICAL_SECTION)) // EnterCriticalSection f000ff20 0 56 TakeCritSec DECLARE_API(EnterCriticalSection,void, (LPCRITICAL_SECTION)) // InitializeCriticalSection f000fec8 0 78 CreateCrit DECLARE_API(InitializeCriticalSection,HANDLE, (LPCRITICAL_SECTION)) // AllocPhysMem 0 168 f000fd60 DECLARE_API(AllocPhysMem,LPVOID,(DWORD cbSize, DWORD fdwProtect, DWORD dwAlignmentMask, DWORD dwFlags, PULONG pPhysicalAddress)) // memcpy - use compiler intrinsic ... how? void mymemcpy(BYTE *dst, BYTE *src, DWORD n) { while (n--) *dst++ = *src++; } #define SystemApiSets ((CINFO**)(KData.aInfo[KINX_APISETS])) // f000fef0 0 68 DECLARE_API(GetCallerProcess, HANDLE, ()) // f000ff08 0 62 DECLARE_API(IsBadPtr, BOOL, (DWORD flag, LPBYTE ptr, DWORD len)) #if 0 typedef HANDLE (*CreateFile_t)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); CreateFile_t MyCreateFile; typedef BOOL (*CloseHandle_t)(HANDLE h); CloseHandle_t MyCloseHandle; typedef BOOL (*WriteFile_t)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); WriteFile_t MyWriteFile; typedef BOOL (*SetFilePointer_t)(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); SetFilePointer_t MySetFilePointer; #endif //#define NKvDbgPrintf (*(void (*)(const WCHAR*msg, const void *lpParms))0xF000FFA4) void init(); #define dwptr(p) ((DWORD*)(p)) #define ProcessHandle(p) ((p)?(p)->hProc:0) #define ThreadHandle(p) ((p)?(p)->hTh:0) void NKDbgPrintf(const WCHAR *msg, ...); struct bufferinfo { DWORD wrptr; DWORD rdptr; DWORD logsize; bool full; DWORD droppedbytes; DWORD encodingerror; DWORD totalsize; BYTE *vdata; // virtual (ptr into loadklib process space) BYTE *pdata; // physical BYTE *vpdata; // physical (ptr into kernel process space) CRITICAL_SECTION readlock; }; static bufferinfo g_log; void initlogging(DWORD bufsize) { g_log.vdata= (BYTE*)ORIGAPI(AllocPhysMem)(bufsize, PAGE_READWRITE, 0, 0, (PULONG)&g_log.pdata); g_log.vpdata= (BYTE*)PhysToVirt((DWORD)g_log.pdata); g_log.wrptr= 0; g_log.rdptr= 0; g_log.logsize= 0; g_log.full= false; g_log.droppedbytes=0; g_log.encodingerror=0; g_log.totalsize= g_log.vdata ? bufsize : 0; ORIGAPI(InitializeCriticalSection)(&g_log.readlock); if (g_log.vdata==0) { NKDbgPrintf(L"debug logger: ERROR allocating log buffer: %08lx\n", ORIGAPI(GetLastError)()); } else { NKDbgPrintf(L"debug logger: buffer = v:%08lx, p:%08lx\n", g_log.vdata, g_log.pdata); } } void log_byte(DWORD b) { g_log.vpdata[g_log.wrptr]= (BYTE)b; g_log.wrptr++; if (g_log.wrptr>=g_log.totalsize) g_log.wrptr= 0; } DWORD readlogsize() { return g_log.logsize; } void updatelogsize(int change) { InterlockedExchangeAdd((long*)&g_log.logsize, change); } bool check_room(int req) { if (readlogsize()+8+req req) want= req; if (want > g_log.totalsize-g_log.rdptr) want= g_log.totalsize-g_log.rdptr; mymemcpy(buf, g_log.vpdata+g_log.rdptr, want); req -= want; *nread += want; g_log.rdptr += want; if (g_log.rdptr==g_log.totalsize) g_log.rdptr= 0; logsize -= want; } updatelogsize(-(int)*nread); unlockreader(); return true; } DWORD calcmsgsize(const WCHAR*msg) { DWORD n=0; while (*msg) { WCHAR c= *msg++; if (c<0x80) { n++; } else if (c<0x800) { n+=2; } else if (c<0x10000) { n+=3; } else if (c<0x110000) { n+=4; } else { n++; } } return n; } bool logmsg(const WCHAR*msg) { if (g_log.vdata==0) return false; DWORD msgsize= calcmsgsize(msg); if (!check_room(msgsize)) return false; while (*msg) { DWORD c= *msg++; // convert to utf-8 if (c<0x80) { log_byte(c); } else if (c<0x800) { log_byte(0xc0|(c>>6)); log_byte(0x80|(c&0x3f)); } else if (c<0x10000) { log_byte(0xe0|(c>>12)); log_byte(0x80|((c>>6)&0x3f)); log_byte(0x80|(c&0x3f)); } else if (c<0x110000) { log_byte(0xf0|(c>>18)); log_byte(0x80|((c>>12)&0x3f)); log_byte(0x80|((c>>6)&0x3f)); log_byte(0x80|(c&0x3f)); } else { g_log.encodingerror++; // mark as error log_byte(0xFF); } } g_log.vpdata[g_log.wrptr]= 0; updatelogsize(msgsize); return true; } bool vlogmsg(const WCHAR*msg, const void *lpParms) { WCHAR buf[10240]; NKwvsprintfW(buf, msg, (va_list)lpParms, 10240); return logmsg(buf); } BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { logmsg(L"DllMain\n"); if (ul_reason_for_call==0) { init(); } NKDbgPrintf(L"libklog: hmod=%08lx reason=%d res=%08lx\n", hModule, ul_reason_for_call, lpReserved); return TRUE; } extern "C" __declspec(dllexport) void dumpstack(int r0, ...) { DWORD esp= (DWORD)(&esp)&~0x1F; DWORD stacktop= (esp|0xFFFF)+1; NKDbgPrintf(L"stackdump: r0=%08lx, &r0=%08lx, stack=%08lx-%08lx curproc=%08lx:%08lx, curthread=%08lx:%08lx\n", r0, &r0, esp, stacktop, KData.pCurPrc, ProcessHandle(KData.pCurPrc), KData.pCurThd, ThreadHandle(KData.pCurThd)); if (KData.pCurThd) { NKDbgPrintf(L"callstack: \n"); for (CALLSTACK *cs= KData.pCurThd->pcstkTop ; cs ; cs= cs->pcstkNext) { NKDbgPrintf(L" %08lx %08lx:%08lx %08lx %08lx %08lx %08lx:", cs->retAddr, cs->pprcLast,ProcessHandle(cs->pprcLast), cs->akyLast, cs->extra, cs->dwPrevSP, cs->dwPrcInfo); if (cs->dwPrevSP) NKDbgPrintf(L" %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", dwptr(cs->dwPrevSP)[0], dwptr(cs->dwPrevSP)[1], dwptr(cs->dwPrevSP)[2], dwptr(cs->dwPrevSP)[3], dwptr(cs->dwPrevSP)[4], dwptr(cs->dwPrevSP)[5], dwptr(cs->dwPrevSP)[6], dwptr(cs->dwPrevSP)[7]); else NKDbgPrintf(L" -\n"); } } while (esp%08lx" #define APIHOOKARGS() ORIGAPI(GetCallerProcess)(), hCurProc // f000ff2c 0 53 DECLARE_HOOK(CreateProcess, BOOL, (LPCWSTR lpszImageName, LPCWSTR lpszCommandLine, LPSECURITY_ATTRIBUTES lpsaProcess, LPSECURITY_ATTRIBUTES lpsaThread, BOOL fInheritHandles, DWORD fdwCreate, LPVOID lpvEnvironment, LPWSTR lpszCurDir, LPSTARTUPINFO lpsiStartInfo, LPPROCESS_INFORMATION lppiProcInfo)) { BOOL result= ORIGAPI(CreateProcess)(lpszImageName, lpszCommandLine, lpsaProcess, lpsaThread, fInheritHandles, fdwCreate, lpvEnvironment, lpszCurDir, lpsiStartInfo, lppiProcInfo); NKDbgPrintf(APIHOOKFMT L" CreateProcess('%ls', '%ls' -> %08lx)= %08lx\n", APIHOOKARGS(), lpszImageName, lpszCommandLine, lppiProcInfo?lppiProcInfo->hProcess:0, result); return result; } // f000ffe0 0 8 LoadLibraryW // f000fdb0 0 148 LoadLibraryEx DECLARE_HOOK(LoadLibraryEx, HMODULE, (LPCSTR lpLibFileName, DWORD dwFlags, LPDWORD pdwCnt)) { HMODULE result= ORIGAPI(LoadLibraryEx)(lpLibFileName, dwFlags, pdwCnt); NKDbgPrintf(APIHOOKFMT L" LoadLibraryEx('%ls', %08lx, %08lx=%08lx)= %08lx\n", APIHOOKARGS(), lpLibFileName, dwFlags, pdwCnt, pdwCnt?*pdwCnt:0, result); return result; } // f000ffd8 0 10 GetProcAddressW // f000ff04 0 63 GetProcAddrBits // f000fdc0 0 144 GetProcAddressA DECLARE_HOOK(GetProcAddress, LPVOID, (HMODULE hMod, LPCWSTR szProcname)) { LPVOID result= ORIGAPI(GetProcAddress)(hMod, szProcname); if (DWORD(szProcname)<0x10000) NKDbgPrintf(APIHOOKFMT L" GetProcAddress(%08lx, ord_%04d)= %08lx\n", APIHOOKARGS(), hMod, szProcname, result); else NKDbgPrintf(APIHOOKFMT L" GetProcAddress(%08lx, '%ls')= %08lx\n", APIHOOKARGS(), hMod, szProcname, result); return result; } // f000fe84 0 95 DECLARE_HOOK(CreateFileMapping, HANDLE, (HANDLE hFile, LPSECURITY_ATTRIBUTES lpsa, DWORD flProtect, DWORD dwMaxSizeHigh, DWORD dwMaxSizeLow, LPCWSTR lpName)) { HANDLE result= ORIGAPI(CreateFileMapping)(hFile, lpsa, flProtect, dwMaxSizeHigh, dwMaxSizeLow, lpName); NKDbgPrintf(APIHOOKFMT L" CreateFileMapping(%08lx, %08lx, %08lx, %08lx, %08lx, %08lx:'%ls')= %08lx\n", APIHOOKARGS(), hFile, lpsa, flProtect, dwMaxSizeHigh, dwMaxSizeLow, lpName, lpName?lpName:L"", result); return result; } // f000ff48 0 46 DECLARE_HOOK(CloseProcOE, void, (DWORD bClose)) { ORIGAPI(CloseProcOE)(bClose); NKDbgPrintf(APIHOOKFMT L" CloseProcOE(%08lx)\n", APIHOOKARGS(), bClose); } // f000fef8 0 66 DECLARE_HOOK(KillAllOtherThreads, VOID, (void)) { ORIGAPI(KillAllOtherThreads)(); NKDbgPrintf(APIHOOKFMT L" KillAllOtherThreads\n", APIHOOKARGS()); } // f000fea4 0 87 DECLARE_HOOK(NKTerminateThread, void, (DWORD dwExitCode)) { ORIGAPI(NKTerminateThread)(dwExitCode); NKDbgPrintf(APIHOOKFMT L" NKTerminateThread(%08lx)\n", APIHOOKARGS(), dwExitCode); } // f000fe90 0 92 DECLARE_HOOK(CloseAllHandles, void, (void)) { ORIGAPI(CloseAllHandles)(); NKDbgPrintf(APIHOOKFMT L" CloseAllHandles\n", APIHOOKARGS()); } // f000fda4 0 151 DECLARE_HOOK(KillThreadIfNeeded, void, (void)) { ORIGAPI(KillThreadIfNeeded)(); NKDbgPrintf(APIHOOKFMT L" KillThreadIfNeeded\n", APIHOOKARGS()); } // f000ff28 0 54 DECLARE_HOOK(CreateThread, HANDLE, (LPSECURITY_ATTRIBUTES lpsa, DWORD cbStack, LPTHREAD_START_ROUTINE lpStartAddr, LPVOID lpvThreadParm, DWORD fdwCreate, LPDWORD lpIDThread)) { HANDLE result= ORIGAPI(CreateThread)(lpsa, cbStack, lpStartAddr, lpvThreadParm, fdwCreate, lpIDThread); NKDbgPrintf(APIHOOKFMT L" CreateThread(%08lx, %08lx, %08lx, %08lx, %08lx, %08lx)= %08lx\n", APIHOOKARGS(), lpsa, cbStack, lpStartAddr, lpvThreadParm, fdwCreate, lpIDThread, result); return result; } // f000ffdc 0 9 DECLARE_HOOK(FreeLibrary, BOOL, (HANDLE hInst, LPDWORD pdwCnt)) { BOOL result= ORIGAPI(FreeLibrary)(hInst, pdwCnt); NKDbgPrintf(APIHOOKFMT L" FreeLibrary(%08lx, %08lx:%08lx)=%08lx\n", APIHOOKARGS(), hInst, pdwCnt, pdwCnt?*pdwCnt:0, result); return result; } // f000fbdc 1 9 DECLARE_HOOK(TerminateThread,BOOL,(HANDLE hThread, DWORD dwExitCode)) { BOOL result= ORIGAPI(TerminateThread)(hThread, dwExitCode); NKDbgPrintf(APIHOOKFMT L" TerminateThread(%08lx,%08lx)=%08lx\n", APIHOOKARGS(), hThread, dwExitCode, result); return result; } // f000f800 2 0 DECLARE_HOOK(ProcCloseHandle,BOOL,(HANDLE hProc)) { BOOL result= ORIGAPI(ProcCloseHandle)(hProc); NKDbgPrintf(APIHOOKFMT L" ProcCloseHandle(%08lx)=%08lx\n", APIHOOKARGS(), hProc, result); return result; } // f000f7f8 2 2 DECLARE_HOOK(TerminateProcess,BOOL,(HANDLE hProc, DWORD dwExitCode)) { BOOL result= ORIGAPI(TerminateProcess)(hProc, dwExitCode); NKDbgPrintf(APIHOOKFMT L" TerminateProcess(%08lx,%08lx)=%08lx\n", APIHOOKARGS(), hProc, dwExitCode, result); return result; } // f000ffc8 0 14 DECLARE_HOOK(OutputDebugString, void, (const WCHAR*msg)) { logmsg(msg); ORIGAPI(OutputDebugString)(msg); } // f000ffa4 0 23 DECLARE_HOOK(NKvDbgPrintf, void, (const WCHAR*msg, const void *lpParms)) { vlogmsg(msg, lpParms); ORIGAPI(NKvDbgPrintf)(msg, lpParms); } // f000fed8 0 74 DECLARE_HOOK(ReadDebugLog, BOOL, (BYTE *pBuf, DWORD dwBufSize, DWORD *pnRead)) { // todo: translate pbuf and pnread to kspace //NKDbgPrintf(L"ReadDebugLog(%p, 0x%x, %p)\n", pBuf, dwBufSize, pnRead); return readlog(pBuf, dwBufSize, pnRead); } // see line 1020 in ~/sources/wince500/PRIVATE/WINCEOS/COREOS/NK/KERNEL/ARM/mdarm.c const WCHAR akystring[]= { 'A','K','Y','=','%','8','.','8','l','x',' ','P','C','=','%','8','.','8','l','x','(','%','s','+','0','x','%','8','.','8','l','x',')',' ','R','A','=','%','8','.','8','l','x','(', //'%','s','+','0','x','%','8','.','8','l','x',')',' ','B','V','A','=','%','8','.','8','l','x',' ','F','S','R','=','%','8','.','8','l','x', }; template int compare(const T*p1, const T*p2, size_t n) { while (n && *p1==*p2) { n--; p1++; p2++; } if (n==0) return 0; if (*p1<*p2) return -1; if (*p1>*p2) return +1; return 0; } void NKDbgPrintf(const WCHAR *msg, ...) { va_list ap; va_start(ap, msg); vlogmsg(msg, (const void *)ap); if (ORIGAPI(NKvDbgPrintf)) ORIGAPI(NKvDbgPrintf)(msg, ap); va_end(ap); } void set_api_method(int set, int mth, PFNVOID func) { const_cast(SystemApiSets[set]->ppfnMethods[mth])= func; } //------- hd interface ULONG MyHDException( PEXCEPTION_RECORD ExceptionRecord, CONTEXT *ContextRecord, BOOLEAN SecondChance ) { dumpstack(0); return FALSE; } /* static void HDPageIn (DWORD dw, BOOL f) { } static void HDModLoad (DWORD dw) { } static void HDModUnload (DWORD dw) { } */ void init() { GETAPI(0, 88, SetLastError) GETAPI(0, 89, GetLastError) GETAPI(0, 57, LeaveCriticalSection) GETAPI(0, 56, EnterCriticalSection) GETAPI(0, 78, InitializeCriticalSection) GETAPI(0, 168, AllocPhysMem) GETAPI(0, 68, GetCallerProcess) GETAPI(0, 62, IsBadPtr) // HOOKAPI(0,14,OutputDebugString); HOOKAPI(0,23,NKvDbgPrintf); initlogging(0x800000); // MyCreateFile= (CreateFile_t)SystemApiSets[20]->ppfnMethods[9]; // // problem: the following 3 ptrs are NULL // MyCloseHandle= (CloseHandle_t)SystemApiSets[7]->ppfnMethods[0]; // MyWriteFile= (WriteFile_t)SystemApiSets[7]->ppfnMethods[3]; // MySetFilePointer= (SetFilePointer_t)SystemApiSets[7]->ppfnMethods[5]; // see ~/sources/wince500/PRIVATE/WINCEOS/COREOS/NK/KERNEL/kwin32.c HOOKAPI(0,53,CreateProcess); HOOKAPI(0,148,LoadLibraryEx); HOOKAPI(0,9,FreeLibrary); HOOKAPI(0,10,GetProcAddress); HOOKAPI(0,95,CreateFileMapping); HOOKAPI(0,46,CloseProcOE); HOOKAPI(0,66,KillAllOtherThreads); HOOKAPI(0,87,NKTerminateThread); HOOKAPI(0,92,CloseAllHandles); // HOOKAPI(0,151,KillThreadIfNeeded); ... called very often HOOKAPI(0,54,CreateThread); HOOKAPI(0,74,ReadDebugLog); // hack: hook hd.dll exception handler, note: this only works // for the htc kaiser v1.82 rom if (((DWORD)ORIGAPI(LoadLibraryEx))==0x8003ABCC) *(DWORD*)0x80306050= (DWORD)MyHDException; // for the htc viva v1.27 rom else if (((DWORD)ORIGAPI(LoadLibraryEx))==0x8C12FB64) *(DWORD*)0x8C3D6050= (DWORD)MyHDException; // for the htc startrek v1.02 rom else if (((DWORD)ORIGAPI(LoadLibraryEx))==0x8C0AC178) *(DWORD*)0x8C2C6050= (DWORD)MyHDException; // for the hrc herald v5.4.405.1 rom else if (((DWORD)ORIGAPI(LoadLibraryEx))==0x8C12DD40) *(DWORD*)0x8C386050= (DWORD)MyHDException; else { NKDbgPrintf(L"stackdumper::init: did not patch HDException: loadlib=%08lx nkdbgprintf=%08lx createproc=%08lx getproc=%08lx\n", ORIGAPI(LoadLibraryEx), ORIGAPI(NKvDbgPrintf), ORIGAPI(CreateProcess), ORIGAPI(GetProcAddress)); } }