/* (C) 2003 XDA Developers itsme@xs4all.nl * * $Header$ */ // program to dump lowlevel/internal window structures /* nextsibA parentA 1stchldA magic parentB 1stchldB nextsibB wrect crect ----------pw1------------- --pw2-- --pw2-- wtext msgq IME style exstyle CLS usrdata pid tid pid wndproc window 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13141516 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d extra brush pid wndproc style name icon? icon? cursor atom class 00 01 02 03 04 05 06 07 08 09 0a next magic pid tid msgq 00 01 02 03 04 05 06 07 08 hold this next to a hexdump -4, to get the fields. nextsibA parentA 1stchldA magic parentB 1stchldB nextsibB ---------------wrect---------------- ---------------crect---------------- ----------pw1------------- --pw2-- --pw2-- wtext msgq IME style exstyle CLS usrdata pid tid pid wndproc */ // for an idea about what kind of stuff is in the WND struct, see these files: // S:/archive/software/wnt/nt4/private/mvdm/wow16/user/user.h // S:/archive/software/wnt/nt4/private/ntos/w32/ntuser/inc/user.h // S:/archive/software/wnt/win2k/private/ntos/w32/ntuser/client/nt6/user.h // S:/archive/software/wnt/win2k/private/ntos/w32/ntuser/inc/user.h // #include #include "debug.h" #include "stringutils.h" #include "vectorutils.h" #include "cenk.h" #include "kernelmisc.h" #include "cever_deps.h" #include #include #include typedef std::map ptrmap; // globals std::set ptrhistory; HANDLE g_hGwes; // forward decls bool DumpWND(DWORD dwOffset, int level= 0); bool isSanePtr(DWORD dwAddr) { return dwAddr>=0x10000 && dwAddr<=0x40000000 && (dwAddr&3)==0 && (dwAddr&0xfffff)!=0; } DWORD GetGwesVMbase() { static DWORD gwesbase= 0; if (gwesbase) return gwesbase; int gwesslot= FindProcessSlotForName(L"gwes.exe"); if (gwesslot==-1) return 0; gwesbase= getProcessSlotVMBase(gwesslot); return gwesbase; } DWORD ReadGwesDword(DWORD pdw) { pdw= (DWORD)MapPtrWithBits(pdw, GetGwesVMbase()); if (!isValidPtr(pdw)) return 0; return *(DWORD*)(pdw&~3); } template bool ReadGwesVector(DWORD dwOffset, T& dwv, DWORD nDwords) { dwOffset= (DWORD)MapPtrWithBits(dwOffset, GetGwesVMbase()); if (!isValidPtr(dwOffset)) return false; dwv.resize(nDwords); memcpy(vectorptr(dwv), (void*)(dwOffset&~3), sizeof(T::value_type)*dwv.size()); return true; } bool isasciistring(BYTE *p) { while (1) { if (IsBadReadPtr(p,1)) return false; if (p[0]==0) return true; if (!isprint(p[0])) return false; p+=1; } } bool isunicodestring(BYTE *p) { while (1) { if (IsBadReadPtr(p,2)) return false; if (p[1]) return false; if (p[0]==0) return true; if (!isprint(p[0])) return false; p+=2; } } DWORD FindDataLen(BYTE *p, DWORD dwMax) { for (DWORD dwI= 0 ; dwI < dwMax ; dwI++) { if (IsBadReadPtr(p+dwI, 1)) return dwI; } return dwMax; } std::string stringofdata(HANDLE hData) { if (!IsBadReadPtr(hData, 4)) { if (isunicodestring((BYTE*)hData)) return stringformat("L'%ls'", hData); else if (isasciistring((BYTE*)hData)) return stringformat("'%s'", hData); else { BYTE *p= (BYTE*)hData; DWORD dwLen= FindDataLen(p, 16); return stringformat("%08lx: ", hData) + ascdump(ByteVector(p, p+dwLen), "\r\n\t\"'"); } } else return stringformat("%08lx", hData); } std::string stringofdata(const TCHAR *pStr) { return stringofdata((HANDLE)pStr); } BOOL CALLBACK enumprop(HWND hWnd, TCHAR *lpszString, HANDLE hData, ULONG_PTR dwData) { debug(" wnd_%08lx property %s=%s\n", hWnd, stringofdata(lpszString).c_str(), stringofdata(hData).c_str()); return TRUE; } std::string stringofwclass(HWND hWnd) { TCHAR szClassName[1024]; if (GetClassName(hWnd, szClassName, 1024)) return stringofdata(szClassName); else return "-"; } std::string stringofwtext(HWND hWnd) { TCHAR text[1024]; if (GetWindowText(hWnd, text, 1024)) return stringofdata(text); else return "-"; } void DumpClassInfo(HWND hWnd, const WNDCLASS &wc) { debug(" wnd_%08lx: style=%08lx inst=%08lx ico=%08lx cursor=%08lx bkg=%08lx menu=%ls, class=%ls\n", hWnd, wc.style, wc.hInstance, wc.hIcon, wc.hCursor, wc.hbrBackground, stringofdata(wc.lpszMenuName).c_str(), stringofdata(wc.lpszClassName).c_str()); if (wc.cbWndExtra) { debug("wndextra(%d bytes) : ", wc.cbWndExtra); for (int i=0 ; i>16 = cbWndExtra #define CLSOFS_EXTRA 0x00 #define CLSOFS_BRUSH 0x01 #define CLSOFS_PID 0x02 #define CLSOFS_WNDPROC 0x03 #define CLSOFS_STYLE 0x04 #define CLSOFS_NAME 0x05 // 6 - icon .. 0x2c bytes large struct 'pc1' // 7 - icon .. 0x2c bytes large struct 'pc1' #define CLSOFS_CURSOR 0x08 #define CLSOFS_NRWINDOWS 0x09 // low word is atom #define CLSOFS_ATOM 0x0a #define CLS_NDWORDS 11 bool DumpCLS(DWORD dwOffset) { if (dwOffset==0) return false; if (ptrhistory.find(dwOffset)!=ptrhistory.end()) return false; ptrhistory.insert(dwOffset); DwordVector cls; debug(" cls:%08lx: ", dwOffset); if (!ReadGwesVector(dwOffset, cls, CLS_NDWORDS)) { debug("ERROR\n"); return false; } DWORD dwClsExtra= (cls[CLSOFS_EXTRA]&0xffff)/sizeof(DWORD); if (!ReadGwesVector(dwOffset, cls, CLS_NDWORDS+dwClsExtra)) { cls.resize(CLS_NDWORDS); } ptrmap ptrs; for (size_t i=0 ; i>16); } else if (isSanePtr(cls[i]) && isValidPtr((DWORD)MapPtrWithBits(cls[i], GetGwesVMbase()))) { ptrs[cls[i]]= i; debug(" %08lx", cls[i]); } else { debug(" %08lx", cls[i]); } } debug("\n"); if (cls[CLSOFS_NAME]) { debug(" str:%08lx: cls:%08lx: name=", cls[CLSOFS_NAME], dwOffset); TCharVector cn; cn.resize(64); if (ReadGwesVector(cls[CLSOFS_NAME], cn, 64)) { cn.resize(65); debug("%s\n", stringofdata(vectorptr(cn)).c_str()); } else debug("-\n"); } for (ptrmap::iterator pi= ptrs.begin() ; pi!=ptrs.end() ; ++pi) DumpPtr("c", (*pi).second, (*pi).first); return true; } #define WNDOFS_pNEXT 0x00 #define WNDOFS_pPARENT 0x01 #define WNDOFS_pCHILD 0x02 #define WNDOFS_MAGIC 0x03 // 04 wnd // 05 wnd // 06 always 0 ? // 07 wnd #define WNDOFS_WINDOWRECT 0x08 // 8..b window rect #define WNDOFS_CLIENTRECT 0x0c // c..f client rect // 10 ptr 0x50 bytes large 'pw1' // 11 ptr 0x50 bytes large 'pw1' // 12 ptr 0x50 bytes large 'pw1' // 13..16 // 17 ptr 0x70 bytes large 'pw2' // 18 // 19 ptr 0x70 bytes large 'pw2' #define WNDOFS_WINDOWTEXT 0x1A // 1b ptr 0x100 bytes large 'pw3' == msgq #define WNDOFS_MESSAGEQUEUE 0x1B // 1c ptr 0x20 bytes large 'pw4' == ime #define WNDOFS_STYLE 0x1D #define WNDOFS_EXTSTYLE 0x1E #define WNDOFS_pCLS 0x1F #define WNDOFS_ID 0x20 #define WNDOFS_pUSERDATA 0x21 #define WNDOFS_PID 0x22 #define WNDOFS_TID 0x23 #define WNDOFS_PID2 0x24 #define WNDOFS_WNDPROC 0x25 // 26 // 27 // 28 // 29 // 2a // 2b // 2c // 2d #define WND_NDWORDS 0x2e BOOL CALLBACK EnumWinProc(HWND hWnd, LPARAM lParam); bool DumpWND(DWORD dwOffset, int level /*= 0*/) { if (dwOffset==0) return false; if (ptrhistory.find(dwOffset)!=ptrhistory.end()) return false; ptrhistory.insert(dwOffset); debug(" wnd_%08lx: %s %s\n", dwOffset, stringofwclass((HWND)dwOffset).c_str(), stringofwtext((HWND)dwOffset).c_str()); debug(" wnd:%08lx: ", dwOffset); DwordVector wnd; if (!ReadGwesVector(dwOffset, wnd, WND_NDWORDS)) { debug("ERROR\n"); return false; } DWORD dwWndExtra= (ReadGwesDword(wnd[WNDOFS_pCLS]) >> 16)/sizeof(DWORD); if (!ReadGwesVector(dwOffset, wnd, WND_NDWORDS+dwWndExtra)) { wnd.resize(WND_NDWORDS); } ptrmap ptrs; for (size_t i=0 ; i=WNDOFS_WINDOWRECT && i=19 && i<23) { debug(" %x", wnd[i]); } else if (i==WNDOFS_MAGIC || i==WNDOFS_STYLE|| i==WNDOFS_EXTSTYLE || i==WNDOFS_PID || i==WNDOFS_TID || i==WNDOFS_PID2 || i==WNDOFS_WNDPROC || i==WNDOFS_pCLS || i>=WND_NDWORDS || i==WNDOFS_pUSERDATA || i==WNDOFS_WINDOWTEXT || i>=0x20) { debug(" %08lx", wnd[i]); } else if (isSanePtr(wnd[i]) && isValidPtr((DWORD)MapPtrWithBits(wnd[i], GetGwesVMbase()))) { ptrs[wnd[i]]= i; debug(" %08lx", wnd[i]); } else { debug(" %08lx", wnd[i]); } } debug("\n"); if (wnd[WNDOFS_WINDOWTEXT]) { debug(" str:%08lx wnd:%08lx: wintext=", wnd[WNDOFS_WINDOWTEXT], dwOffset); TCharVector wn; wn.resize(64); if (ReadGwesVector(wnd[WNDOFS_WINDOWTEXT], wn, 64)) { wn.resize(65); debug("%s\n", stringofdata(vectorptr(wn)).c_str()); } else debug("-\n"); } DumpCLS(wnd[WNDOFS_pCLS]); for (ptrmap::iterator pi= ptrs.begin() ; pi!=ptrs.end() ; ++pi) DumpPtr("w", (*pi).second, (*pi).first); /* for (DWORD wndofs= wnd[WNDOFS_pCHILD] ; wndofs ; wndofs= wnd[WNDOFS_pNEXT]) { if (!ReadGwesVector(wndofs, wnd, 0x27)) return false; EnumWinProc((HWND)wndofs, level+1); } */ if (wnd[WNDOFS_pCHILD]) DumpWND(wnd[WNDOFS_pCHILD]); if (wnd[WNDOFS_pNEXT]) DumpWND(wnd[WNDOFS_pNEXT]); return true; } void DumpWndClass(HWND hWnd, DWORD pid) { TCHAR szClassName[1024]; if (0==GetClassName(hWnd, szClassName, 1024)) return; WNDCLASS wc; if (GetClassInfo(NULL, szClassName, &wc)) { DumpClassInfo(hWnd, wc); } else if (GetClassInfo((HINSTANCE)pid, szClassName, &wc)) { DumpClassInfo(hWnd, wc); } } BOOL CALLBACK EnumWinProc(HWND hWnd, LPARAM lParam) { if (hWnd==NULL) return TRUE; EnumPropsEx(hWnd, &enumprop, (LPARAM)0); DumpWND((DWORD)hWnd, lParam); /* //DumpWndClass(hWnd, pid); bool bHasItems= false; for (int i=-65536 ; i<65536 ; i++) { TCHAR txt[1024]; HWND hItem= GetDlgItem(hWnd, i); if (hItem) { if (!bHasItems) debug("dialog: "); bHasItems= true; if (GetDlgItemText(hWnd, i, txt, 1024)) { debug(" %08lx:%s", hItem, stringofdata(txt).c_str()); } else { debug(" %08lx:?", hItem); } } } if (bHasItems) debug("\n"); */ /* DWORD dwCount= SendMessage(hWnd, LB_GETCOUNT, 0, 0); if (dwCount) { debug("LB: GETCOUNT=%08lx", dwCount); debug("LB: GETANCHORINDEX=%08lx", SendMessage(hWnd, LB_GETANCHORINDEX, 0, 0)); debug("LB: GETCARETINDEX=%08lx", SendMessage(hWnd, LB_GETCARETINDEX, 0, 0)); debug("LB: GETCURSEL=%08lx", SendMessage(hWnd, LB_GETCURSEL, 0, 0)); debug("LB: GETHORIZONTALEXTENT=%08lx", SendMessage(hWnd, LB_GETHORIZONTALEXTENT, 0, 0)); debug("LB: GETLOCALE=%08lx", SendMessage(hWnd, LB_GETLOCALE, 0, 0)); debug("LB: GETSELCOUNT=%08lx", SendMessage(hWnd, LB_GETSELCOUNT, 0, 0)); DWORD itemList[8]; DWORD selItemCount= SendMessage(hWnd, LB_GETSELITEMS, 8, (LPARAM)itemList); debug("LB: GETSELITEMS=%08lx: %08lx %08lx", selItemCount, itemList[0], itemList[1]); debug("LB: GETTOPINDEX=%08lx", SendMessage(hWnd, LB_GETTOPINDEX, 0, 0)); for (DWORD dwItem= 0 ; dwItem < dwCount ; dwItem++) { debug("LB: GETITEMDATA(%d)=%08lx", dwItem, SendMessage(hWnd, LB_GETITEMDATA, dwItem, 0)); debug("LB: GETITEMHEIGHT(%d)=%08lx", dwItem, SendMessage(hWnd, LB_GETITEMHEIGHT, dwItem, 0)); debug("LB: GETSEL(%d)=%08lx", dwItem, SendMessage(hWnd, LB_GETSEL, dwItem, 0)); RECT rc; DWORD rcResult= SendMessage(hWnd, LB_GETITEMRECT, dwItem, (LPARAM)&rc); debug("LB: GETITEMRECT(%d)=%08lx", dwItem, rcResult); DWORD dwTxtLen= SendMessage(hWnd, LB_GETTEXTLEN, dwItem, 0); debug("LB: GETTEXTLEN(%d)=%08lx", dwItem, dwTxtLen); TCHAR itemtext[1024]; itemtext[0]= 0; DWORD txtResult= SendMessage(hWnd, LB_GETTEXT, dwItem, (LPARAM)itemtext); debug("LB: GETTEXT(%d)=%08lx", dwItem, txtResult); } } */ return TRUE; } std::string GetFontTypeString(DWORD dwType) { if (dwType==RASTER_FONTTYPE) return "RASTER"; if (dwType==TRUETYPE_FONTTYPE) return "TRUETYPE"; return stringformat("FONTTYPE_%08lx", dwType); } std::string GetLogFontString(const LOGFONT* plf) { return stringformat("name='%ls' %dx%d esc=%d o=%d w=%d i=%d u=%d so=%d ch=%d out=%d cli=%d q=%d pitch=%d", plf->lfFaceName, plf->lfHeight, plf->lfWidth, plf->lfEscapement, plf->lfOrientation, plf->lfWeight, plf->lfItalic, plf->lfUnderline, plf->lfStrikeOut, plf->lfCharSet, plf->lfOutPrecision, plf->lfClipPrecision, plf->lfQuality, plf->lfPitchAndFamily); } std::string GetTextMetrixString(const TEXTMETRIC* ptm) { return stringformat("tm"); } int EnumFontsProc(const LOGFONT* lplf, const TEXTMETRIC* lptm, DWORD dwType, LPARAM lpData) { debug("font: %08lx %hs %hs\n", GetFontTypeString(dwType).c_str(), GetLogFontString(lplf).c_str(), GetTextMetrixString(lptm).c_str()); return TRUE; } HANDLE GetProcessHandle(WCHAR *wszProcessName) { HANDLE hTH= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS|TH32CS_SNAPNOHEAPS, 0); PROCESSENTRY32 pe; pe.dwSize= sizeof(PROCESSENTRY32); HANDLE hProc= INVALID_HANDLE_VALUE; if (Process32First(hTH, &pe)) { do { if (wcsicmp(wszProcessName, pe.szExeFile)==0) { hProc= OpenProcess(0, 0, pe.th32ProcessID); if (hProc != INVALID_HANDLE_VALUE && hProc!=NULL) break; } } while (Process32Next(hTH, &pe)); } CloseToolhelp32Snapshot(hTH); return hProc; } LRESULT CALLBACK tst_winproc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { LRESULT l= DefWindowProc(wnd, msg, wParam, lParam); debug("msg:wnd:%08lx msg:%08lx w=%08lx l=%08lx -> %08lx\n", wnd, msg, wParam, lParam, l); return l; } #define ITSMECLASS L"itsmewndtest" #define ITSMETITLE L"itsmewndtitle" HWND createtstwindow(HINSTANCE hInst) { HCURSOR cursor = LoadCursor (NULL, IDC_ARROW); HBRUSH brush = CreateSolidBrush(0x00112233); debug("cursor=%08lx brush=%08lx\n", cursor, brush); WNDCLASS wc; /* Register window-class */ wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)tst_winproc; wc.cbClsExtra = 8; wc.cbWndExtra = 12; wc.hInstance = hInst; wc.hIcon = (HICON)0; wc.hCursor = cursor; wc.hbrBackground = brush; wc.lpszClassName = ITSMECLASS; wc.lpszMenuName = MAKEINTRESOURCE(0); ATOM a = RegisterClass (&wc); if (a==0) { error("RegisterClass"); return 0; } debug("registered class a=%08lx\n", a); HWND hWnd= CreateWindowEx (0, ITSMECLASS, ITSMETITLE, 0, 20, 30, 40, 50, (HWND)0, (HMENU)0, hInst, (LPVOID)0x01237777); if (hWnd==NULL) { error("CreateWindowEx"); return 0; } SetWindowLong(hWnd, 0, 0x12348888); SetWindowLong(hWnd, 4, 0x23419999); SetWindowLong(hWnd, 8, 0x3412aaaa); SetClassLong(hWnd, 0, 0x5678bbbb); SetClassLong(hWnd, 4, 0x7856cccc); return hWnd; } void deletetstwindow(HINSTANCE hInst, HWND hWnd) { UnregisterClass (ITSMECLASS, hInst); } DWORD FindWndRoot(DWORD hWnd) { DWORD hParent; while (hParent=ReadGwesDword(hWnd+4)) hWnd= hParent; return hWnd; } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { DebugSetLogfile("tstwnd.log"); BOOL bMode = SetKMode(TRUE); DWORD dwPerm = SetProcPermissions(0xFFFFFFFF); g_hGwes= GetProcessHandle(L"gwes.exe"); HWND hTstWnd= createtstwindow(hInstance); HWND hWnd= GetForegroundWindow(); DWORD tid, pid; tid= GetWindowThreadProcessId(hWnd, &pid); debug("foregnd: hw=%08lx pid=%08lx tid=%08lx\n", hWnd, pid, tid); DWORD hRoot= FindWndRoot((DWORD)hWnd); DumpWND(hRoot); /* debug("----------- start enum windows\n"); if (!EnumWindows(&EnumWinProc, (LPARAM)0)) error("EnumWindows"); debug("----------- end enum windows\n"); HDC hdc= CreateDC(NULL, NULL, NULL, NULL); if (hdc) { debug("----------- start enum fonts\n"); if (!EnumFonts(hdc, NULL, &EnumFontsProc, (LPARAM)0)) error("EnumFonts"); debug("----------- end enum fonts\n"); DeleteDC(hdc); } else { error("CreateDC"); } */ deletetstwindow(hInstance, hTstWnd); SetProcPermissions(dwPerm); SetKMode(bMode); MessageBeep(-1); return 0; }