00001
00007 #include "stdafx.h"
00008 #include "resource.h"
00009 #include <bzscmn/bzscmn.h>
00010 #include <bzswin/findproc.h>
00011 #include <bzswin/registry.h>
00012 #include <bzsnet/ratecalc.h>
00013 #include <bzswin/wow64.h>
00014
00015 #include "MainDlg.h"
00016 #include "trparams.h"
00017
00018 #include "../kdclient/patchapi.h"
00019 #include "../rpcdispatch/permdesc.h"
00020
00021 enum
00022 {
00023 ProcessInactive,
00024 ProcessPending,
00025 ProcessPatched,
00026 ProcessFailed
00027 };
00028
00029 using namespace BazisLib;
00030
00031 static const TCHAR tszRegistryPath[] = _T("SOFTWARE\\BazisSoft\\KdVMWare\\Monitor");
00032
00034 HANDLE CreateLogPipe(unsigned PID)
00035 {
00036 PermissiveSecurityDescriptor desc;
00037 TCHAR tszPipeName[MAX_PATH];
00038 _sntprintf_s(tszPipeName, __countof(tszPipeName), _TRUNCATE, tszLogPipeNameFormat, PID);
00039 return CreateNamedPipe(tszPipeName, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE, 2, 65536, 65536, 1000, desc);
00040 }
00041
00042 static LPCTSTR GetVMTypeName(VMType type)
00043 {
00044 switch (type)
00045 {
00046 case kVMWare32:
00047 return _T("VMWare");
00048 case kVBox32:
00049 return _T("VirtualBox");
00050 case kVMWare64:
00051 return _T("VMWare x64");
00052 case kVBox64:
00053 return _T("VirtualBox x64");
00054 default:
00055 return _T("Unknown");
00056 }
00057 }
00058
00059 static void EnableDebugPrivilege()
00060 {
00061 HANDLE hToken;
00062 LUID sedebugnameValue;
00063 TOKEN_PRIVILEGES tkp;
00064
00065 OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
00066
00067
00068 LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue);
00069
00070 tkp.PrivilegeCount = 1;
00071 tkp.Privileges[0].Luid = sedebugnameValue;
00072 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
00073
00074 AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL);
00075
00076 CloseHandle(hToken);
00077 }
00078
00079 CMainDlg::CMainDlg()
00080 : m_DbgToolsPath(_T(""))
00081 {
00082 EnableDebugPrivilege();
00083 SYSTEM_INFO sysinfo;
00084 GetSystemInfo(&sysinfo);
00085 m_ProcessorCount = sysinfo.dwNumberOfProcessors;
00086
00087 RegistryKey key(HKEY_LOCAL_MACHINE, tszRegistryPath);
00088 key.DeserializeObject(m_Params);
00089
00090 FilePath toolsPath(_T(""));
00091 if (m_Params.ToolsPath.empty())
00092 {
00093 RegistryKey key2(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"));
00094 toolsPath = (String)key2[_T("ProgramFilesDir")];
00095 toolsPath = toolsPath + (FilePath)_T("Debugging Tools for Windows");
00096 }
00097 else
00098 toolsPath = m_Params.ToolsPath;
00099 if (File::Exists(toolsPath + (FilePath)_T("windbg.exe")) && File::Exists(toolsPath + (FilePath)_T("kd.exe")))
00100 m_DbgToolsPath = toolsPath;
00101 }
00102
00103 LRESULT CMainDlg::OnInitDialog(UINT , WPARAM , LPARAM , BOOL& bHandled)
00104 {
00105
00106 CenterWindow();
00107
00108
00109 HICON hIcon = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME),
00110 IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);
00111 SetIcon(hIcon, TRUE);
00112 HICON hIconSmall = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME),
00113 IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
00114 SetIcon(hIconSmall, FALSE);
00115
00116 m_ListView.m_hWnd = GetDlgItem(IDC_LIST1);
00117 m_StatsView.m_hWnd = GetDlgItem(IDC_STATS);
00118 m_DebugLevel.m_hWnd = GetDlgItem(IDC_DBGLEVEL);
00119
00120 DlgResize_Init();
00121
00122
00123 m_DebugLevel.InsertString(-1, _T("No debug messages"));
00124 m_DebugLevel.InsertString(-1, _T("Patcher debug messages"));
00125
00126
00127 #ifdef _DEBUG
00128 m_DebugLevel.InsertString(-1, _T("Patcher and KDCOM protocol messages (normal)"));
00129 m_DebugLevel.InsertString(-1, _T("Patcher and KDCOM protocol messages (detailed)"));
00130 #endif
00131
00132 if (m_Params.DebugLevel < (unsigned)m_DebugLevel.GetCount())
00133 m_DebugLevel.SetCurSel(m_Params.DebugLevel);
00134
00135 m_ListView.AddColumn(_T("PID"), 0);
00136 m_ListView.AddColumn(_T("VM type"), 1);
00137 m_ListView.AddColumn(_T("Uptime"), 2);
00138 m_ListView.AddColumn(_T("CPU"), 3);
00139 m_ListView.AddColumn(_T("Pipe name"), 4);
00140 m_ListView.AddColumn(_T("Packets"), 5);
00141 m_ListView.AddColumn(_T("Resets"), 6);
00142 m_ListView.AddColumn(_T("OS"), 7);
00143 m_ListView.AddColumn(_T("Debugger"), 8);
00144
00145 m_ImageList.Create(16, 16, ILC_COLOR4 | ILC_MASK, 4, 0);
00146 m_ImageList.AddIcon(LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_GREY)));
00147 m_ImageList.AddIcon(LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_YELLOW)));
00148 m_ImageList.AddIcon(LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_GREEN)));
00149 m_ImageList.AddIcon(LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_RED)));
00150
00151 m_ListView.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT);
00152 m_ListView.ModifyStyle(0, LVS_SINGLESEL);
00153
00154 m_ListView.SetColumnWidth(0, 60);
00155 m_ListView.SetColumnWidth(1, 100);
00156 m_ListView.SetColumnWidth(2, 60);
00157 m_ListView.SetColumnWidth(3, 40);
00158 m_ListView.SetColumnWidth(4, 100);
00159 m_ListView.SetColumnWidth(5, 70);
00160
00161 m_ListView.SetImageList(m_ImageList, LVSIL_SMALL);
00162
00163 SendDlgItemMessage(IDC_STARTDBG, BM_SETCHECK, m_Params.AutoInvokeDebugger ? BST_CHECKED : 0, 0);
00164 SendDlgItemMessage(IDC_STOPDBG, BM_SETCHECK, m_Params.AutoCloseDebugger? BST_CHECKED : 0, 0);
00165 SendDlgItemMessage(IDC_BREAKIN, BM_SETCHECK, m_Params.InitialBreakIn ? BST_CHECKED : 0, 0);
00166 switch(m_Params.DebuggerType)
00167 {
00168 case 0:
00169 SendDlgItemMessage(IDC_USEKD, BM_SETCHECK, BST_CHECKED);
00170 break;
00171 case 1:
00172 SendDlgItemMessage(IDC_USEWINDBG, BM_SETCHECK, BST_CHECKED);
00173 break;
00174 case 2:
00175 SendDlgItemMessage(IDC_USECUSTOM, BM_SETCHECK, BST_CHECKED);
00176 break;
00177 }
00178
00179 OnDebuggerPathChanged();
00180
00181 SetTimer(0, 200);
00182
00183 CFont font((HFONT)GetStockObject(SYSTEM_FONT));
00184 LOGFONT logFont;
00185 font.GetLogFont(logFont);
00186 _tcsncpy(logFont.lfFaceName, _T("Courier New"), __countof(logFont.lfFaceName));
00187 HFONT hFont = CreateFontIndirect(&logFont);
00188 GetDlgItem(IDC_EDIT1).SetFont(hFont, TRUE);
00189
00190 SetDlgItemText(IDC_DBGTEMPLATE, m_Params.CustomDebuggerTemplate.c_str());
00191 UpdateParamControls();
00192
00193 m_StatsView.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
00194 m_StatsView.AddColumn(_T("Parameter"), 0);
00195 m_StatsView.AddColumn(_T("Value"), 1);
00196
00197 int i = 0;
00198 m_StatsView.InsertItem(i++, _T("Bytes received"));
00199 m_StatsView.InsertItem(i++, _T("Bytes send"));
00200 m_StatsView.InsertItem(i++, _T("Packets received"));
00201 m_StatsView.InsertItem(i++, _T("Packets sent"));
00202 m_StatsView.InsertItem(i++, _T("IN packet rate"));
00203 m_StatsView.InsertItem(i++, _T("OUT packet rate"));
00204 m_StatsView.InsertItem(i++, _T("Reset count"));
00205 m_StatsView.InsertItem(i++, _T("Send rate"));
00206 m_StatsView.InsertItem(i++, _T("Receive rate"));
00207 m_StatsView.InsertItem(i++, _T("Max. send rate"));
00208 m_StatsView.InsertItem(i++, _T("Max. recv. rate"));
00209 m_StatsView.InsertItem(i++, _T("CPU usage"));
00210 m_StatsView.InsertItem(i++, _T("Avg. CPU usage"));
00211
00212 m_StatsView.SetColumnWidth(0, 100);
00213 m_StatsView.SetColumnWidth(1, 65);
00214
00215 #ifdef KDVMWARE_USE_PROXY
00216 SetWindowText(_T("Virtual Machine monitor (proxy mode)"));
00217 #endif
00218
00219 if (BazisLib::WOW64APIProvider::sIsWow64Process())
00220 {
00221 SetWindowText(_T("Virtual Machine monitor (32-bit version on 64-bit windows). Use VMMON64.EXE instead."));
00222 }
00223
00224 return bHandled = FALSE;
00225 }
00226
00227 void CMainDlg::UpdateParamControls()
00228 {
00229 GetDlgItem(IDC_DBGTEMPLATE).EnableWindow((m_Params.DebuggerType == 2));
00230 }
00231
00232 LRESULT CMainDlg::OnParamsChanged(WORD , WORD wID, HWND , BOOL& )
00233 {
00234 m_Params.AutoInvokeDebugger = ((SendDlgItemMessage(IDC_STARTDBG, BM_GETCHECK) & BST_CHECKED) != 0);
00235 m_Params.AutoCloseDebugger = ((SendDlgItemMessage(IDC_STOPDBG, BM_GETCHECK) & BST_CHECKED) != 0);
00236 m_Params.InitialBreakIn = ((SendDlgItemMessage(IDC_BREAKIN, BM_GETCHECK) & BST_CHECKED) != 0);
00237 if ((SendDlgItemMessage(IDC_USEKD, BM_GETCHECK) & BST_CHECKED) != 0)
00238 m_Params.DebuggerType = 0;
00239 else if ((SendDlgItemMessage(IDC_USEWINDBG, BM_GETCHECK) & BST_CHECKED) != 0)
00240 m_Params.DebuggerType = 1;
00241 else if ((SendDlgItemMessage(IDC_USECUSTOM, BM_GETCHECK) & BST_CHECKED) != 0)
00242 m_Params.DebuggerType = 2;
00243 TCHAR tsz[MAX_PATH * 2];
00244 GetDlgItemText(IDC_DBGTEMPLATE, tsz, __countof(tsz));
00245 m_Params.CustomDebuggerTemplate = tsz;
00246 UpdateParamControls();
00247 SaveParamsToRegistry();
00248 return 0;
00249 }
00250
00251 void CMainDlg::SaveParamsToRegistry()
00252 {
00253 RegistryKey key(HKEY_LOCAL_MACHINE, tszRegistryPath);
00254 key.SerializeObject(m_Params);
00255 }
00256
00257 LRESULT CMainDlg::OnAppAbout(WORD , WORD , HWND , BOOL& )
00258 {
00259 return 0;
00260 }
00261
00262 LRESULT CMainDlg::OnOK(WORD , WORD wID, HWND , BOOL& )
00263 {
00264
00265 EndDialog(wID);
00266 return 0;
00267 }
00268
00269 LRESULT CMainDlg::OnCancel(WORD , WORD wID, HWND , BOOL& )
00270 {
00271 EndDialog(wID);
00272 return 0;
00273 }
00274
00275 LRESULT CMainDlg::OnTimer(UINT , WPARAM , LPARAM , BOOL& )
00276 {
00277 SearchForNewProcesses();
00278 UpdateProcessInfo();
00279 return 0;
00280 }
00281
00282 static inline bool UpdateProcessStats(PatchedProcess &proc, unsigned PID, unsigned ProcessorCount)
00283 {
00284 HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, PID);
00285 if (hProc == INVALID_HANDLE_VALUE)
00286 {
00287 proc.StillRunning = false;
00288 return false;
00289 }
00290 DateTime now = DateTime::Now();
00291 FILETIME StartTime = {0,}, EndTime = {0,};
00292 FILETIME KernelTime = {0,}, UserTime = {0,};
00293 GetProcessTimes(hProc, &StartTime, &EndTime, &KernelTime, &UserTime);
00294 if (WaitForSingleObject(hProc, 0) == WAIT_OBJECT_0)
00295 {
00296 proc.StillRunning = false;
00297 proc.StopTime = EndTime;
00298 }
00299 else
00300 {
00301 proc.StillRunning = true;
00302 proc.StopTime = now;
00303 }
00304 ULONGLONG sum = (*((ULONGLONG*)&KernelTime) + *((ULONGLONG*)&UserTime));
00305 FILETIME CPUTime = *((FILETIME *)&sum);
00306 CloseHandle(hProc);
00307 proc.PID = PID;
00308 proc.StartTime = StartTime;
00309
00310 ULONGLONG timeReal = (now - proc.PreviousSampleTime).GetTotalMilliseconds();
00311 ULONGLONG timeSinceStart = (now - proc.StartTime).GetTotalMilliseconds();
00312 if (!timeReal)
00313 timeReal++;
00314 if (proc.CpuUsage != -1)
00315 {
00316 ULONGLONG timeCPU = (DateTime(CPUTime) - proc.PreviousCPUTime).GetTotalMilliseconds();
00317 proc.CpuUsage = ((int)((timeCPU * 1000) / timeReal)) / ProcessorCount;
00318 }
00319 else
00320 proc.CpuUsage = 0;
00321
00322 proc.AvgCpuUsage = (unsigned)((TimeSpan(sum).GetTotalMilliseconds() * 1000) / (timeSinceStart * ProcessorCount));
00323 if (proc.pStatus)
00324 {
00325 if (proc.PrevRecvd > proc.pStatus->BytesReceived)
00326 proc.PrevRecvd = proc.pStatus->BytesReceived;
00327 if (proc.PrevSent > proc.pStatus->BytesSent)
00328 proc.PrevSent = proc.pStatus->BytesSent;
00329 if (proc.PrevPacketsRecvd > proc.pStatus->PacketsReceived)
00330 proc.PrevPacketsRecvd = proc.pStatus->PacketsReceived;
00331 if (proc.PrevPacketsSent > proc.pStatus->PacketsSent)
00332 proc.PrevPacketsSent = proc.pStatus->PacketsSent;
00333
00334 if (timeReal > 10)
00335 {
00336 if (proc.PrevRecvd)
00337 proc.RecvRate = (unsigned)(((ULONGLONG)(proc.pStatus->BytesReceived - proc.PrevRecvd) * 1000) / timeReal);
00338 if (proc.PrevSent)
00339 proc.SendRate = (unsigned)(((ULONGLONG)(proc.pStatus->BytesSent- proc.PrevSent) * 1000) / timeReal);
00340
00341 if (proc.PrevPacketsRecvd)
00342 proc.PacketRecvRate = (unsigned)(((ULONGLONG)(proc.pStatus->PacketsReceived - proc.PrevPacketsRecvd) * 1000) / timeReal);
00343 if (proc.PrevPacketsSent)
00344 proc.PacketSendRate = (unsigned)(((ULONGLONG)(proc.pStatus->PacketsSent - proc.PrevPacketsSent) * 1000) / timeReal);
00345 }
00346
00347 proc.PrevRecvd = proc.pStatus->BytesReceived;
00348 proc.PrevSent = proc.pStatus->BytesSent;
00349
00350 proc.PrevPacketsRecvd = proc.pStatus->PacketsReceived;
00351 proc.PrevPacketsSent = proc.pStatus->PacketsSent;
00352
00353 if (proc.RecvRate > proc.MaxRecvRate)
00354 proc.MaxRecvRate = proc.RecvRate;
00355 if (proc.SendRate > proc.MaxSendRate)
00356 proc.MaxSendRate = proc.SendRate;
00357 }
00358
00359 proc.PreviousSampleTime = now;
00360 proc.PreviousCPUTime = CPUTime;
00361 return true;
00362 }
00363
00364 void CMainDlg::SearchForNewProcesses()
00365 {
00366 HANDLE hList = CreateVMSessionList();
00367 unsigned PID = 0;
00368 VMType vmType = kVMUnknown;
00369
00370 while (PID = GetNextVMSessionPIDEx(hList, &vmType))
00371 {
00372 if (m_PatchedSet.find(PID) == m_PatchedSet.end())
00373 {
00374 PatchedProcess proc;
00375 proc.State = PatchPending;
00376 proc.vmType = vmType;
00377 if (UpdateProcessStats(proc, PID, m_ProcessorCount))
00378 {
00379 m_PatchedSet.insert(PID);
00380 TCHAR tsz[32];
00381 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%d"), proc.PID);
00382 if (IsVMSessionPatched(PID))
00383 {
00384 proc.State = PatchSuccessful;
00385 CreateStatusMapping(proc, false);
00386 }
00387 wchar_t szName[MAX_PATH] = {0,};
00388 GetVMSessionNameW(PID, szName, _countof(szName));
00389 if (szName[0])
00390 proc.SessionNameRetreived = true;
00391 m_Processes.push_back(proc);
00392 size_t idx = m_Processes.size() - 1;
00393
00394 m_ListView.InsertItem((UINT)idx, tsz, ProcessPending);
00395 m_ListView.SetItem((UINT)idx, 1, LVIF_TEXT, GetVMTypeName(proc.vmType), 0, 0, 0, 0);
00396 }
00397 }
00398 };
00399 CloseVMSessionList(hList);
00400 }
00401
00402 static BOOL CALLBACK CloseEnumWndProc(HWND hWnd, LPARAM lParam)
00403 {
00404 DWORD dwProcessID = 0;
00405 GetWindowThreadProcessId(hWnd, &dwProcessID);
00406 if (dwProcessID == lParam)
00407 {
00408 TCHAR tsz[512] = {0,};
00409 RealGetWindowClass(hWnd, tsz, __countof(tsz));
00410 if (!_tcscmp(tsz, _T("WinDbgFrameClass")) || !_tcscmp(tsz, _T("ConsoleWindowClass")))
00411 {
00412 ::SendMessage(hWnd, WM_CLOSE, 0, 0);
00413 return FALSE;
00414 }
00415 }
00416 return TRUE;
00417 }
00418
00419 static bool CloseDebugger(unsigned PID)
00420 {
00421 if (!EnumWindows(CloseEnumWndProc, PID))
00422 return true;
00423 return false;
00424 }
00425
00426 void CMainDlg::CleanupProcessEntry(PatchedProcess &proc)
00427 {
00428 if (proc.hLogPipe != INVALID_HANDLE_VALUE)
00429 {
00430 CloseHandle(proc.hLogPipe);
00431 proc.hLogPipe = INVALID_HANDLE_VALUE;
00432 }
00433 if (proc.hMapping != INVALID_HANDLE_VALUE)
00434 {
00435 if (proc.pStatus)
00436 {
00437 UnmapViewOfFile(proc.pStatus);
00438 proc.pStatus = NULL;
00439 }
00440 CloseHandle(proc.hMapping);
00441 proc.hMapping = INVALID_HANDLE_VALUE;
00442 }
00443 }
00444
00445 void CMainDlg::CreateStatusMapping(PatchedProcess &proc, bool Reset)
00446 {
00447 TCHAR tszMappingName[MAX_PATH];
00448 _sntprintf_s(tszMappingName, __countof(tszMappingName), _TRUNCATE, tszMappingNameFormat, proc.PID);
00449 PermissiveSecurityDescriptor descriptor;
00450 proc.hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, descriptor, PAGE_READWRITE, 0, sizeof(KdClientStatus), tszMappingName);
00451 if (GetLastError() == ERROR_ALREADY_EXISTS)
00452 Reset = false;
00453 if (proc.hMapping != INVALID_HANDLE_VALUE)
00454 {
00455 proc.pStatus = (KdClientStatus *)MapViewOfFile(proc.hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
00456 if (!proc.pStatus)
00457 {
00458 CloseHandle(proc.hMapping);
00459 proc.hMapping = INVALID_HANDLE_VALUE;
00460 }
00461 else
00462 {
00463 if (Reset)
00464 memset(proc.pStatus, 0, sizeof(KdClientStatus));
00465 proc.pStatus->DebugLevel = m_Params.DebugLevel;
00466 proc.pStatus->LogAllPackets = ((SendDlgItemMessage(IDC_LOGPACKETS, BM_GETCHECK) & BST_CHECKED) != 0);
00467 }
00468 }
00469 if (proc.hMapping == INVALID_HANDLE_VALUE)
00470 {
00471 MessageBox(MAKE_STATUS(ActionStatus::FromLastError()).GetErrorText().c_str(),
00472 _T("Cannot create shared parameter block"),
00473 MB_ICONERROR);
00474 }
00475 }
00476
00477 bool CMainDlg::InitiatePatching(PatchedProcess &proc)
00478 {
00479 CreateStatusMapping(proc, true);
00480 if (proc.hLogPipe == INVALID_HANDLE_VALUE)
00481 proc.hLogPipe = CreateLogPipe(proc.PID);
00482 proc.hRemoteThread = StartVMSessionPatching(proc.PID);
00483 if (!proc.hRemoteThread)
00484 {
00485 proc.State = PatchSuccessful;
00486 return true;
00487 }
00488 else if (proc.hRemoteThread == INVALID_HANDLE_VALUE)
00489 {
00490 proc.State = PatchFailed;
00491 return false;
00492 }
00493 else
00494 {
00495 proc.State = PatchInProgress;
00496 return true;
00497 }
00498 }
00499
00500 void CMainDlg::UpdateLog(PatchedProcess &proc)
00501 {
00502 if (proc.hLogPipe != INVALID_HANDLE_VALUE)
00503 {
00504 DWORD bytesAvailable = 0;
00505 PeekNamedPipe(proc.hLogPipe, NULL, 0, NULL, &bytesAvailable, NULL);
00506 if (bytesAvailable)
00507 {
00508 CBuffer buf;
00509 buf.EnsureSize(bytesAvailable);
00510 DWORD dwOk = 0;
00511 ReadFile(proc.hLogPipe, buf.GetData(), bytesAvailable, &dwOk, NULL);
00512 if (dwOk == bytesAvailable)
00513 {
00514 proc.Log.append((TCHAR *)buf.GetData(), bytesAvailable / sizeof(TCHAR));
00515 proc.LogChanged = true;
00516 }
00517 }
00518 }
00519 }
00520
00521 void CMainDlg::PerformProcessActions(PatchedProcess &proc, TimeSpan &runTime, bool *pPatchingStarted)
00522 {
00523 if ((proc.State == PatchProcessTerminated) || (proc.State == Unpatched))
00524 CleanupProcessEntry(proc);
00525 else
00526 {
00527 if (proc.hLogPipe == INVALID_HANDLE_VALUE)
00528 proc.hLogPipe = CreateLogPipe(proc.PID);
00529 }
00530
00531 if (proc.State == PatchPending)
00532 {
00533 if (runTime.GetTotalSeconds() > m_Params.PatchDelay)
00534 {
00535 bool started = InitiatePatching(proc);
00536 if (pPatchingStarted)
00537 *pPatchingStarted = started;
00538 }
00539 }
00540
00541 if (proc.State == PatchInProgress)
00542 {
00543 if (WaitForSingleObject(proc.hRemoteThread, 0) == WAIT_OBJECT_0)
00544 {
00545 DWORD dwCode = 0;
00546 GetExitCodeThread(proc.hRemoteThread, &dwCode);
00547 if (dwCode)
00548 proc.State = PatchInProgress2;
00549 else
00550 proc.State = PatchFailed;
00551 CloseHandle(proc.hRemoteThread);
00552 proc.hRemoteThread = INVALID_HANDLE_VALUE;
00553 }
00554 }
00555
00556 if ((proc.State == PatchInProgress2) || (proc.State == PatchSuccessful))
00557 {
00558 if (proc.pStatus)
00559 {
00560 switch (proc.pStatus->PatchErrorPlus1 - 1)
00561 {
00562 case ERROR_SUCCESS:
00563 proc.State = PatchSuccessful;
00564 break;
00565 case -1:
00566 proc.State = PatchInProgress2;
00567 break;
00568 default:
00569 proc.State = PatchFailed;
00570 }
00571 }
00572 if (proc.pStatus->ProtocolMismatchStatus)
00573 {
00574 proc.State = ProtocolMismatch;
00575 WORD expected = HIWORD(proc.pStatus->ProtocolMismatchStatus), found = LOWORD(proc.pStatus->ProtocolMismatchStatus);
00576 proc.pStatus->ProtocolMismatchStatus = 0;
00577 TCHAR tsz[256];
00578 _sntprintf(tsz, __countof(tsz), _T("Warning! KDVMWARE.DLL version %x.%02x was loaded by virtual machine, while version %x.%02x was expected. Debugging functions disabled!"),
00579 HIBYTE(found), LOBYTE(found), HIBYTE(expected), LOBYTE(expected));
00580 MessageBox(tsz, _T("Invalid KDVMWARE.DLL version"), MB_ICONWARNING);
00581 }
00582 }
00583
00584 if (proc.State == UnpatchInProgress)
00585 {
00586 if (WaitForSingleObject(proc.hRemoteThread, 0) == WAIT_OBJECT_0)
00587 {
00588 CloseHandle(proc.hRemoteThread);
00589 proc.hRemoteThread = INVALID_HANDLE_VALUE;
00590 proc.State = Unpatched;
00591 UpdateLog(proc);
00592 CleanupProcessEntry(proc);
00593 }
00594 }
00595
00596 UpdateLog(proc);
00597 }
00598
00599 void CMainDlg::UpdateProcessInfo()
00600 {
00601 DateTime now = DateTime::Now();
00602 int idx = m_ListView.GetSelectedIndex();
00603 for (unsigned i = 0; i < (unsigned)m_Processes.size(); i++)
00604 {
00605 PatchedProcess &proc = m_Processes[i];
00606 if (proc.StillRunning)
00607 UpdateProcessStats(proc, proc.PID, m_ProcessorCount);
00608
00609 if (!proc.StillRunning)
00610 proc.State = PatchProcessTerminated;
00611 TimeSpan runTime = now - proc.StartTime;
00612 if (!proc.StillRunning)
00613 runTime = proc.StopTime - proc.StartTime;
00614 m_ListView.AddItem(i, 2, runTime.ToString().c_str());
00615 TCHAR tsz[128];
00616 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%d%%"), proc.CpuUsage / 10);
00617 m_ListView.AddItem(i, 3, tsz);
00618 bool patchStarted = false;
00619 PerformProcessActions(proc, runTime, &patchStarted);
00620
00621 if (patchStarted)
00622 m_ListView.SelectItem(i), idx = i;
00623
00624 if (idx == i)
00625 {
00626 if (proc.LogChanged)
00627 {
00628 SetDlgItemText(IDC_EDIT1, proc.Log.c_str());
00629 SendDlgItemMessage(IDC_EDIT1, WM_VSCROLL, SB_BOTTOM, 0);
00630 proc.LogChanged = false;
00631 }
00632 if (proc.State == PatchSuccessful)
00633 {
00634 m_StatsView.EnableWindow(TRUE);
00635 DisplayStats(proc);
00636 }
00637 else
00638 m_StatsView.EnableWindow(FALSE);
00639 }
00640
00641 switch (proc.State)
00642 {
00643 case PatchInProgress:
00644 case PatchInProgress2:
00645 m_ListView.SetItem(i, 0, LVIF_IMAGE, NULL, ProcessPending, 0, 0, 0);
00646 m_ListView.AddItem(i, 4, _T("loading..."));
00647 break;
00648 case UnpatchInProgress:
00649 m_ListView.SetItem(i, 0, LVIF_IMAGE, NULL, ProcessPending, 0, 0, 0);
00650 m_ListView.AddItem(i, 4, _T("unloading..."));
00651 break;
00652 case PatchPending:
00653 m_ListView.SetItem(i, 0, LVIF_IMAGE, NULL, ProcessPending, 0, 0, 0);
00654 m_ListView.AddItem(i, 4, _T(""));
00655 break;
00656 case PatchSuccessful:
00657 m_ListView.SetItem(i, 0, LVIF_IMAGE, NULL, ProcessPatched, 0, 0, 0);
00658 if (proc.pStatus)
00659 {
00660 const KdClientStatus &status = *proc.pStatus;
00661 m_ListView.AddItem(i, 4, status.PipeName + 9);
00662 proc.PipeName = status.PipeName;
00663
00664 #ifdef _DEBUG
00665 {
00666 wchar_t wszT[MAX_PATH] = {0,};
00667 GetVMPipeNameW(proc.PID, wszT, __countof(wszT), true);
00668 ASSERT(!wcscmp(wszT, status.PipeName));
00669 }
00670 #endif
00671
00672 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%d/%d"), status.PacketsSent, status.PacketsReceived);
00673 m_ListView.AddItem(i, 5, tsz);
00674 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%d"), status.ResyncCount);
00675 m_ListView.AddItem(i, 6, tsz);
00676 m_ListView.AddItem(i, 7, status.OSDetected ? _T("yes") : _T(""));
00677 m_ListView.AddItem(i, 8, status.DebuggerConnected ? _T("yes") : _T(""));
00678 if (!proc.idDebuggerProcess)
00679 {
00680 if ((m_Params.AutoInvokeDebugger && status.PipeName[0]) && (!m_Params.WaitForOS || status.OSDetected))
00681 {
00682 RunDebugger(i);
00683 }
00684 }
00685 }
00686 else
00687 {
00688 m_ListView.AddItem(i, 4, _T("loading..."));
00689 m_ListView.AddItem(i, 7, _T(""));
00690 m_ListView.AddItem(i, 8, _T(""));
00691 }
00692 break;
00693 case PatchFailed:
00694 m_ListView.SetItem(i, 0, LVIF_IMAGE, NULL, ProcessFailed, 0, 0, 0);
00695 m_ListView.AddItem(i, 4, _T(""));
00696 break;
00697 case ProtocolMismatch:
00698 m_ListView.SetItem(i, 0, LVIF_IMAGE, NULL, ProcessFailed, 0, 0, 0);
00699 m_ListView.AddItem(i, 4, _T("Old KDVMWARE.DLL loaded in guest"));
00700 break;
00701 case PatchProcessTerminated:
00702 case Unpatched:
00703 m_ListView.SetItem(i, 0, LVIF_IMAGE, NULL, ProcessInactive, 0, 0, 0);
00704 m_ListView.AddItem(i, 4, (proc.State == Unpatched) ? _T("(KDCLIENT.DLL unloaded)") : _T("(terminated)"));
00705 if (proc.idDebuggerProcess)
00706 {
00707 if (m_Params.AutoCloseDebugger)
00708 {
00709 if (CloseDebugger(proc.idDebuggerProcess))
00710 proc.idDebuggerProcess = 0;
00711 }
00712 }
00713 break;
00714 }
00715 if (proc.State != proc.PreviousState)
00716 {
00717 if (idx == i)
00718 UpdateUnpatchButton(i);
00719 proc.PreviousState = proc.State;
00720 }
00721 if ((proc.State != PatchProcessTerminated) && !proc.SessionNameRetreived)
00722 {
00723 wchar_t szName[MAX_PATH] = {0,};
00724 GetVMSessionNameW(proc.PID, szName, _countof(szName));
00725
00726 if (szName[0])
00727 proc.SessionNameRetreived = true;
00728 }
00729 }
00730 }
00731
00732 static inline void FindAndReplace(String &src, const String& find, const String& replace)
00733 {
00734 size_t pos;
00735 for (;(pos = src.find( find )) != std::string::npos;)
00736 {
00737 src.replace( pos, find.length(), replace );
00738 }
00739 }
00740
00741 void CMainDlg::RunDebugger(unsigned entryIndex)
00742 {
00743 PatchedProcess &proc = m_Processes[entryIndex];
00744 if (proc.PipeName.empty())
00745 return;
00746 FilePath debugger(_T(""));
00747 TCHAR tszCmdLine[MAX_PATH * 2] = {0,};
00748 if (m_Params.DebuggerType < 2)
00749 {
00750 debugger = m_DbgToolsPath + (FilePath)(m_Params.DebuggerType ? _T("windbg.exe") : _T("kd.exe"));
00751 LPCTSTR lpFormat = _T("\"%s\" %s-k com:pipe,resets=0,reconnect,port=%s");
00752 _sntprintf_s(tszCmdLine, __countof(tszCmdLine), _TRUNCATE, lpFormat, debugger.c_str(), m_Params.InitialBreakIn ? _T("-b ") : _T(""), proc.PipeName.c_str());
00753 }
00754 else
00755 {
00756 String cmdLine = m_Params.CustomDebuggerTemplate;
00757 FindAndReplace(cmdLine, _T("$(toolspath)"), m_DbgToolsPath);
00758 FindAndReplace(cmdLine, _T("$(pipename)"), proc.PipeName.c_str());
00759 _tcsncpy(tszCmdLine, cmdLine.c_str(), __countof(tszCmdLine));
00760 }
00761 STARTUPINFO startupInfo = {0,};
00762 startupInfo.cb = sizeof(startupInfo);
00763 PROCESS_INFORMATION processInfo = {0,};
00764 CreateProcess(debugger.empty() ? NULL : debugger.c_str(), tszCmdLine, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, m_DbgToolsPath.c_str(), &startupInfo, &processInfo);
00765 CloseHandle(processInfo.hProcess);
00766 CloseHandle(processInfo.hThread);
00767 proc.idDebuggerProcess = processInfo.dwProcessId;
00768 }
00769
00770
00771 LRESULT CMainDlg::OnRunDebugger(WORD , WORD wID, HWND , BOOL& )
00772 {
00773 int idx = m_ListView.GetSelectedIndex();
00774 if ((idx != -1) && ((size_t)idx < m_Processes.size()))
00775 RunDebugger(idx);
00776 else
00777 MessageBox(_T("No Virtual Machine selected"), _T("Error"), MB_ICONERROR);
00778 return 0;
00779 }
00780
00781 LRESULT CMainDlg::OnSelChanged(int , LPNMHDR , BOOL& )
00782 {
00783 int idx = m_ListView.GetSelectedIndex();
00784 if (idx != -1)
00785 {
00786 PatchedProcess &proc = m_Processes[idx];
00787 SetDlgItemText(IDC_EDIT1, proc.Log.c_str());
00788 proc.LogChanged = false;
00789 if (proc.pStatus && proc.pStatus->DebugLevel)
00790 m_DebugLevel.SetCurSel(proc.pStatus->DebugLevel);
00791 UpdateUnpatchButton(idx);
00792
00793 if (proc.pStatus)
00794 {
00795 if (proc.pStatus->LogAllPackets)
00796 SendDlgItemMessage(IDC_LOGPACKETS, BM_SETCHECK, BST_CHECKED);
00797 else
00798 SendDlgItemMessage(IDC_LOGPACKETS, BM_SETCHECK, BST_UNCHECKED);
00799 }
00800
00801 DisplayStats(proc);
00802 }
00803 else
00804 m_StatsView.EnableWindow(FALSE);
00805 return 0;
00806 }
00807
00808 LRESULT CMainDlg::OnDebugLevelChanged(WORD , WORD wID, HWND , BOOL& )
00809 {
00810 m_Params.DebugLevel = m_DebugLevel.GetCurSel();
00811 int idx = m_ListView.GetSelectedIndex();
00812 if (idx != -1)
00813 {
00814 PatchedProcess &proc = m_Processes[idx];
00815 if ((proc.State == PatchSuccessful) && (proc.pStatus))
00816 proc.pStatus->DebugLevel = m_Params.DebugLevel;
00817 }
00818 SaveParamsToRegistry();
00819 return 0;
00820 }
00821
00822 LRESULT CMainDlg::OnBnClickedClearlog(WORD , WORD , HWND , BOOL& )
00823 {
00824 int idx = m_ListView.GetSelectedIndex();
00825 if (idx != -1)
00826 {
00827 PatchedProcess &proc = m_Processes[idx];
00828 proc.Log.clear();
00829 SetDlgItemText(IDC_EDIT1, proc.Log.c_str());
00830 proc.LogChanged = false;
00831 }
00832 return 0;
00833 }
00834
00835 LRESULT CMainDlg::OnBnClickedUnpatch(WORD , WORD , HWND , BOOL& )
00836 {
00837 int idx = m_ListView.GetSelectedIndex();
00838 if (idx != -1)
00839 {
00840 PatchedProcess &proc = m_Processes[idx];
00841 if (proc.State == PatchSuccessful)
00842 {
00843 proc.hRemoteThread = (HANDLE)StartVMSessionUnpatching(proc.PID);
00844 if (proc.hRemoteThread == INVALID_HANDLE_VALUE)
00845 MessageBox(_T("Cannot unpatch process"), _T("Error"), MB_ICONERROR);
00846 else
00847 {
00848 if (proc.hRemoteThread)
00849 proc.State = UnpatchInProgress;
00850 else
00851 proc.State = Unpatched;
00852 }
00853 }
00854 else if (proc.State == Unpatched)
00855 {
00856 proc.State = PatchPending;
00857 }
00858 UpdateUnpatchButton(idx);
00859 }
00860 return 0;
00861 }
00862
00863 void CMainDlg::UpdateUnpatchButton(int SelectionIndex)
00864 {
00865 if (SelectionIndex == -1)
00866 return;
00867 PatchedProcess &proc = m_Processes[SelectionIndex];
00868 switch (proc.State)
00869 {
00870 case PatchSuccessful:
00871 SetDlgItemText(IDC_UNPATCH, _T("Unpatch process"));
00872 GetDlgItem(IDC_UNPATCH).EnableWindow();
00873 break;
00874 case Unpatched:
00875 SetDlgItemText(IDC_UNPATCH, _T("Repatch process"));
00876 GetDlgItem(IDC_UNPATCH).EnableWindow();
00877 break;
00878 default:
00879 GetDlgItem(IDC_UNPATCH).EnableWindow(FALSE);
00880 break;
00881 }
00882
00883 }
00884
00885 void CMainDlg::OnDebuggerPathChanged()
00886 {
00887 bool b = !m_DbgToolsPath.empty();
00888 GetDlgItem(IDC_STARTDBG).EnableWindow(b);
00889 GetDlgItem(IDC_STOPDBG).EnableWindow(b);
00890 GetDlgItem(IDC_USEKD).EnableWindow(b);
00891 GetDlgItem(IDC_USEWINDBG).EnableWindow(b);
00892 GetDlgItem(IDC_RUNDBG).EnableWindow(b);
00893 GetDlgItem(IDC_USECUSTOM).EnableWindow(b);
00894 }
00895
00896 LRESULT CMainDlg::OnBnClickedDbgpath(WORD , WORD , HWND , BOOL& )
00897 {
00898 const TCHAR *pFileName = NULL;
00899 String fileName;
00900 if (!m_DbgToolsPath.empty())
00901 {
00902 fileName = m_DbgToolsPath + FilePath(_T("windbg.exe"));
00903 pFileName = fileName.c_str();
00904 }
00905 CFileDialog dlg(TRUE, _T("exe"), pFileName, OFN_HIDEREADONLY, _T("Debugging tools\0windbg.exe;kd.exe\0Executable files (*.exe)\0*.exe\0All files(*.*)\0*.*\0\0"));
00906 if (dlg.DoModal() == IDOK)
00907 {
00908 FilePath dbgPath = dlg.m_szFileName;
00909 dbgPath = dbgPath.GetParentPath();
00910 if (File::Exists(dbgPath + FilePath(_T("windbg.exe"))))
00911 {
00912 m_DbgToolsPath = dbgPath;
00913 m_Params.ToolsPath = m_DbgToolsPath;
00914 SaveParamsToRegistry();
00915 }
00916 OnDebuggerPathChanged();
00917 }
00918 return 0;
00919 }
00920
00921 void CMainDlg::DisplayStats(PatchedProcess &proc)
00922 {
00923 TCHAR tsz[512];
00924 if (!proc.pStatus)
00925 {
00926 m_StatsView.EnableWindow(FALSE);
00927 return;
00928 }
00929 int i = 0;
00930 m_StatsView.SetItem(i++, 1, LVIF_TEXT, Network::RateCalculator::FormatByteCount(proc.pStatus->BytesSent).c_str(), 0, 0, 0, 0);
00931 m_StatsView.SetItem(i++, 1, LVIF_TEXT, Network::RateCalculator::FormatByteCount(proc.pStatus->BytesReceived).c_str(), 0, 0, 0, 0);
00932 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%d"), proc.pStatus->PacketsSent);
00933 m_StatsView.SetItem(i++, 1, LVIF_TEXT, tsz, 0, 0, 0, 0);
00934 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%d"), proc.pStatus->PacketsReceived);
00935 m_StatsView.SetItem(i++, 1, LVIF_TEXT, tsz, 0, 0, 0, 0);
00936 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%s/s"), Network::RateCalculator::FormatByteCount(proc.PacketSendRate).c_str());
00937 m_StatsView.SetItem(i++, 1, LVIF_TEXT, tsz, 0, 0, 0, 0);
00938 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%s/s"), Network::RateCalculator::FormatByteCount(proc.PacketRecvRate).c_str());
00939 m_StatsView.SetItem(i++, 1, LVIF_TEXT, tsz, 0, 0, 0, 0);
00940
00941 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%d"), proc.pStatus->ResyncCount);
00942 m_StatsView.SetItem(i++, 1, LVIF_TEXT, tsz, 0, 0, 0, 0);
00943
00944 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%s/s"), Network::RateCalculator::FormatByteCount(proc.RecvRate).c_str());
00945 m_StatsView.SetItem(i++, 1, LVIF_TEXT, tsz, 0, 0, 0, 0);
00946 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%s/s"), Network::RateCalculator::FormatByteCount(proc.SendRate).c_str());
00947 m_StatsView.SetItem(i++, 1, LVIF_TEXT, tsz, 0, 0, 0, 0);
00948 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%s/s"), Network::RateCalculator::FormatByteCount(proc.MaxRecvRate).c_str());
00949 m_StatsView.SetItem(i++, 1, LVIF_TEXT, tsz, 0, 0, 0, 0);
00950 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%s/s"), Network::RateCalculator::FormatByteCount(proc.MaxSendRate).c_str());
00951 m_StatsView.SetItem(i++, 1, LVIF_TEXT, tsz, 0, 0, 0, 0);
00952
00953 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%d%%"), proc.CpuUsage / 10);
00954 m_StatsView.SetItem(i++, 1, LVIF_TEXT, tsz, 0, 0, 0, 0);
00955
00956 _sntprintf_s(tsz, __countof(tsz), _TRUNCATE, _T("%d%%"), proc.AvgCpuUsage / 10);
00957 m_StatsView.SetItem(i++, 1, LVIF_TEXT, tsz, 0, 0, 0, 0);
00958
00959 }
00960
00961 LRESULT CMainDlg::OnBnClickedTraceassist(WORD , WORD , HWND , BOOL& )
00962 {
00963 CTraceParamsDlg dlg;
00964 if (dlg.DoModal() == IDOK)
00965 {
00966 for (size_t i = 0; i < m_Processes.size(); i++)
00967 {
00968 PatchedProcess &proc = m_Processes[i];
00969 if (proc.pStatus)
00970 proc.pStatus->TraceAssistUpdatePending = true;
00971 }
00972 }
00973 return 0;
00974 }
00975
00976 LRESULT CMainDlg::OnLogPacketsChanged( WORD , WORD wID, HWND , BOOL& )
00977 {
00978 bool bLogPackets = ((SendDlgItemMessage(IDC_LOGPACKETS, BM_GETCHECK) & BST_CHECKED) != 0);
00979 int idx = m_ListView.GetSelectedIndex();
00980 if (idx != -1)
00981 {
00982 PatchedProcess &proc = m_Processes[idx];
00983 if ((proc.State == PatchSuccessful) && (proc.pStatus))
00984 proc.pStatus->LogAllPackets = bLogPackets;
00985 }
00986 return 0;
00987 }