blob: a941f3e35761f391e5ba978f15676e54c07b4235 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2012-2014 Google, Inc. All rights reserved.
* Copyright (c) 2007-2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2002-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2002 Hewlett-Packard Company */
// DynamoRIO.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "DynamoRIO.h"
#include "MainFrm.h"
#include "DynamoRIODoc.h"
#include "DynamoRIOView.h"
#include "OptionsDlg.h"
#include "IgnoreDlg.h"
#include "SyswideDlg.h"
#include <assert.h>
#include <process.h> // for system()
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define HELP_PATH _T("\\docs\\html\\index.html")
// FIXME: these are duplicated with the installation wizard, so
// that the GUI can set env vars for new users (installer can only
// set for user installing)
#define INITIAL_OPTIONS _T("-stats -loglevel 1")
#define INITIAL_SYSTEMWIDE _T("\\lib\\debug\\dynamorio.dll")
#define INITIAL_IGNORE _T("drinject.exe;DynamoRIO.exe")
//#define INITIAL_IGNORE _T("drinject.exe;DynamoRIO.exe;CSRSS.EXE;WINLOGON.EXE;SERVICES.EXE;LSASS.EXE;svchost.exe;SPOOLSV.EXE;taskmgr.exe;jconfigdnt.exe;explorer.exe")
/////////////////////////////////////////////////////////////////////////////
// CDynamoRIOApp
BEGIN_MESSAGE_MAP(CDynamoRIOApp, CWinApp)
//{{AFX_MSG_MAP(CDynamoRIOApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
ON_COMMAND(ID_APP_EXIT, OnAppExit)
#ifndef DRSTATS_DEMO
ON_COMMAND(ID_EDIT_OPTIONS, OnEditOptions)
ON_COMMAND(ID_LIBRARY_RELEASE, OnLibraryRelease)
ON_COMMAND(ID_LIBRARY_PROFILE, OnLibraryProfile)
ON_COMMAND(ID_LIBRARY_DEBUG, OnLibraryDebug)
ON_COMMAND(ID_FILE_RUN, OnFileRun)
ON_COMMAND(ID_FILE_SYSTEMWIDE, OnFileSystemwide)
ON_COMMAND(ID_HELP_HELP, OnHelpHelp)
ON_COMMAND(ID_EDIT_IGNORELIST, OnEditIgnorelist)
#endif
//}}AFX_MSG_MAP
#ifndef DRSTATS_DEMO
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
// Standard print setup command
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
#endif
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDynamoRIOApp construction
CDynamoRIOApp::CDynamoRIOApp()
{
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CDynamoRIOApp object
CDynamoRIOApp theApp;
// FIXME: find better way to have other classes access this one
/* static */ CDynamoRIOView * CDynamoRIOApp::GetActiveView()
{
return (CDynamoRIOView *) theApp.m_pMainFrame->GetActiveView();
}
#ifndef DRSTATS_DEMO
/* static */ BOOL CDynamoRIOApp::SystemwideSet()
{
return theApp.m_bInjectAll;
}
/*static */TCHAR * CDynamoRIOApp::GetDllPath()
{
return theApp.m_dll_path;
}
/*static */DLL_TYPE CDynamoRIOApp::GetDllType()
{
return theApp.m_dll_type;
}
/*static */void CDynamoRIOApp::SetSystemwideSetting(int val)
{
theApp.WriteProfileInt(_T("Settings"), _T("Confirm Systemwide"), val);
}
/*static */void CDynamoRIOApp::AboutToExit()
{
theApp.PreExit();
}
#endif /* !DRSTATS_DEMO */
/*static */void CDynamoRIOApp::SetStatusbarText(TCHAR *txt)
{
theApp.m_pMainFrame->SetStatusBarText(0, txt);
}
/////////////////////////////////////////////////////////////////////////////
// CDynamoRIOApp initialization
BOOL CDynamoRIOApp::InitInstance()
{
#ifndef DRSTATS_DEMO
TCHAR msg[MAX_PATH*2];
#endif
BOOL windows_NT;
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
if (!CheckWindowsVersion(windows_NT)) {
// abort
return FALSE;
}
#if 0 // warning C4996: 'CWinApp::Enable3dControlsStatic': CWinApp::Enable3dControlsStatic is no longer needed. You should remove this call.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
#endif
#ifndef DRSTATS_DEMO
// Change the registry key under which our settings are stored,
// including MRU
SetRegistryKey(L_DYNAMORIO_REGISTRY_KEY);
LoadStdProfileSettings(12); // Load standard INI file options (including MRU)
#endif
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
#ifdef DRSTATS_DEMO
IDR_MAINFRAME_DEMO,
#else
IDR_MAINFRAME,
#endif
RUNTIME_CLASS(CDynamoRIODoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CDynamoRIOView));
AddDocTemplate(pDocTemplate);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// enable file manager drag/drop and DDE Execute open
m_pMainWnd->DragAcceptFiles();
// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
// I can't find any other way to access the main frame
m_pMainFrame = (CMainFrame *) m_pMainWnd;
// I can't figure out how to disable a menu item that has a command
// handler when this var is set, so I disable it:
m_pMainFrame->m_bAutoMenuEnable = FALSE;
#ifndef DRSTATS_DEMO
m_bSystemwideAllowed = TRUE;
// set the string we'll put into the registry key to inject system-wide
TCHAR data[1024];
int len = GetEnvironmentVariable(_T("DYNAMORIO_HOME"), m_dynamorio_home, _MAX_DIR);
#if 1 //NOCHECKIN
if (len == 0)
m_dynamorio_home[0] = _T('\0');
#else
if (len == 0) {
int res = MessageBox(NULL,
_T("DYNAMORIO_HOME environment variable not found.\n")
_T("Set all the DynamoRIO environment variables to their default values?\n")
_T("(Otherwise this GUI cannot operate and must exit.)"),
_T("DynamoRIO Not Configured for Current User"), MB_YESNO | MYMBFLAGS);
if (res == IDYES) {
if (!ConfigureForNewUser())
return FALSE;
} else {
// abort
return FALSE;
}
}
#endif
if (windows_NT) {
// we don't support systemwide on NT
// hack: use "confirm systemwide" setting to decide whether to notify user
if (GetProfileInt(_T("Settings"), _T("Confirm Systemwide"), 1) == 1) {
MessageBox(NULL, _T("Run All is not supported on Windows NT, it will be disabled"),
_T("Notice"), MB_OK | MYMBFLAGS);
// but then how does user turn off, if can't do Run All?
// just turn it off now:
SetSystemwideSetting(0);
}
m_bSystemwideAllowed = FALSE; // so key won't be cleared
DisableSystemwideInject();
} else {
//NOCHECKIN assert(len > 0 && len < _MAX_DIR && len + _tcslen(L_INJECT_ALL_DLL_SUBPATH) < MAX_PATH);
_stprintf(data, _T("%s%s"), m_dynamorio_home, L_INJECT_ALL_DLL_SUBPATH);
// make sure it exists
CFile check;
if (!check.Open(data, CFile::modeRead|CFile::shareDenyNone)) {
#if 0 // I'm disabling this dialog until we decide to support running apps
_stprintf(msg, _T("Library %s does not exist"), data);
MessageBox(NULL, msg, _T("Error"), MB_OK | MYMBFLAGS);
#endif
m_bSystemwideAllowed = FALSE; // so key won't be cleared
DisableSystemwideInject();
} else {
if (_tcschr(data, _T(' ')) != NULL) {
// registry key cannot handle spaces in names!
// must get 8.3 alias -- and some volumes do not support such an alias!
len = GetShortPathName(data, m_inject_all_value, MAX_PATH);
if (len == 0) {
_stprintf(msg, _T("Cannot find 8.3 alias for space-containing path \"%s\"!\nDisabling Run All"),
data);
MessageBox(NULL, msg, _T("Error"), MB_OK | MYMBFLAGS);
m_bSystemwideAllowed = FALSE; // so key won't be cleared
DisableSystemwideInject();
}
} else {
_tcscpy(m_inject_all_value, data);
}
check.Close();
}
}
// find current status of system-wide injection
if (m_bSystemwideAllowed) {
HKEY hk;
unsigned long size = 1024;
int res = RegOpenKeyEx(INJECT_ALL_HIVE, INJECT_ALL_KEY_L, 0, KEY_READ, &hk);
assert(res == ERROR_SUCCESS);
res = RegQueryValueEx(hk, INJECT_ALL_SUBKEY_L, 0, NULL, (LPBYTE) data, &size);
assert(res == ERROR_SUCCESS);
RegCloseKey(hk);
// WARNING: do not use Unicode build!
// if ever get size==2, it's b/c of Unicode build!
// Plus, stats viewing doesn't work w/ Unicode build
if (size > sizeof(TCHAR)) {
// make sure we're the ones who set this value
if (_tcscmp(m_inject_all_value, data) != 0) {
// FIXME: have user notify us of conflict?
int res = MessageBox(NULL,
_T("DynamoRIO's RunAll system-wide injection method is ")
_T("being used by some other program.\n")
_T("DynamoRIO can attempt to override the other program.\n")
_T("Otherwise, system-wide injection will be disabled.\n")
_T("Override?"),
_T("DynamoRIO Conflict"),
MB_YESNO | MYMBFLAGS);
if (res == IDYES) {
// now clear the registry key
SetSystemwideInject(_T(""));
// if the call fails, callee calls Disable for us
} else {
m_bSystemwideAllowed = FALSE; // so key won't be cleared
DisableSystemwideInject();
}
} else {
m_bInjectAll = TRUE;
}
} else {
// empty value: no injection
m_bInjectAll = FALSE;
}
}
if (m_bSystemwideAllowed) {
m_pMainWnd->GetMenu()->CheckMenuItem(ID_FILE_SYSTEMWIDE,
MF_BYCOMMAND | ((m_bInjectAll) ? MF_CHECKED : MF_UNCHECKED));
}
// make sure preinject dll exists
if (m_bSystemwideAllowed) {
CFile check;
if (!check.Open(m_inject_all_value, CFile::modeRead|CFile::shareDenyNone)) {
#if 0 // I'm disabling this dialog until we decide to support running apps
_stprintf(msg, _T("Library %s does not exist!\nDisabling Run All"), m_inject_all_value);
MessageBox(NULL, msg, _T("DynamoRIO Configuration Error"), MB_OK | MYMBFLAGS);
#endif
DisableSystemwideInject();
} else
check.Close();
}
m_dll_path[0] = _T('\0');
DisableMissingLibraries(TRUE);
// now select the previously checked library
int lib = GetProfileInt(_T("Settings"), _T("Library"), 1);
int tried = 0;
while (tried < 3) {
if (lib == 0 && SwitchLibraries(L_DLLPATH_RELEASE, FALSE)) {
OnLibraryRelease();
break;
} else if (lib == 1 && SwitchLibraries(L_DLLPATH_DEBUG, FALSE)) {
OnLibraryDebug();
break;
} else if (lib == 2 && SwitchLibraries(L_DLLPATH_PROFILE, FALSE)) {
OnLibraryProfile();
break;
}
lib = (lib + 1) % 3;
tried++;
}
if (tried == 3) {
#if 0 // Disabling
MessageBox(NULL, _T("Cannot find any DynamoRIO libraries!\n")
_T("Running of applications will be disabled."), _T("Error"), MB_OK | MYMBFLAGS);
#endif
// disable Run and libraries
m_pMainWnd->GetMenu()->EnableMenuItem(ID_FILE_RUN, MF_BYCOMMAND|MF_GRAYED);
DisableSystemwideInject();
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_RELEASE, MF_BYCOMMAND|MF_GRAYED);
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_DEBUG, MF_BYCOMMAND|MF_GRAYED);
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_PROFILE, MF_BYCOMMAND|MF_GRAYED);
m_pMainWnd->GetMenu()->CheckMenuItem(ID_LIBRARY_RELEASE, MF_BYCOMMAND|MF_UNCHECKED);
m_pMainWnd->GetMenu()->CheckMenuItem(ID_LIBRARY_DEBUG, MF_BYCOMMAND|MF_UNCHECKED);
m_pMainWnd->GetMenu()->CheckMenuItem(ID_LIBRARY_PROFILE, MF_BYCOMMAND|MF_UNCHECKED);
}
if (m_bInjectAll) {
MessageBox(NULL, _T("Run All is already set!"),
_T("Warning"), MB_OK | MYMBFLAGS);
// FIXME: share this code with OnFileSystemwide
SetEnvVarPermanently(_T("DYNAMORIO_SYSTEMWIDE"), m_dll_path);
// disable changing the library
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_RELEASE, MF_BYCOMMAND|MF_GRAYED);
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_DEBUG, MF_BYCOMMAND|MF_GRAYED);
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_PROFILE, MF_BYCOMMAND|MF_GRAYED);
}
#endif /*! DRSTATS_DEMO */
return TRUE;
}
/*static*/ BOOL CDynamoRIOApp::GetWindowsVersion(OSVERSIONINFOW *version)
{
/* i#1418: GetVersionEx is just plain broken on win8.1+ so we use the Rtl version */
typedef DWORD NTSTATUS;
typedef NTSTATUS (NTAPI *RtlGetVersion_t)(OSVERSIONINFOW *info);
# define NT_SUCCESS(res) ((res) >= 0)
RtlGetVersion_t RtlGetVersion;
NTSTATUS res;
HANDLE ntdll_handle = GetModuleHandle(_T("ntdll.dll"));
if (ntdll_handle == NULL)
return FALSE;
RtlGetVersion = (RtlGetVersion_t)
GetProcAddress((HMODULE)ntdll_handle, "RtlGetVersion");
if (RtlGetVersion == NULL)
return FALSE;
version->dwOSVersionInfoSize = sizeof(*version);
res = RtlGetVersion(version);
return NT_SUCCESS(res);
}
BOOL CDynamoRIOApp::CheckWindowsVersion(BOOL &windows_NT)
{
// make sure we're on an NT-based system
windows_NT = FALSE;
TCHAR bad_os[64];
OSVERSIONINFOW version;
BOOL res = GetWindowsVersion(&version);
assert(res);
if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
// WinNT or descendents: rather than continually update
// the list of known versions here we assume they're all ok.
// XXX i#1419: if we ever check for win8 or higher we'll want to switch
// to RtlGetVersion().
if (version.dwMajorVersion == 4) {
// Windows NT
windows_NT = TRUE;
} else {
// 2K or later
}
return TRUE;
} else if (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
/* Win95 or Win98 */
unsigned ver_high = (version.dwBuildNumber >> 24) & 0xff;
unsigned ver_low = (version.dwBuildNumber >> 16) & 0xff;
if (ver_low >= 90 || ver_high >= 5)
_stprintf(bad_os, _T("Windows ME"));
else if (ver_low >= 10 && ver_low < 90)
_stprintf(bad_os, _T("Windows 98"));
else if (ver_low < 5)
_stprintf(bad_os, _T("Windows 31 / WfWg"));
else if (ver_low < 10)
_stprintf(bad_os, _T("Windows 98"));
else
assert(false);
} else {
/* Win32S on Windows 3.1 */
_stprintf(bad_os, _T("Win32s"));
}
TCHAR msg[128];
_stprintf(msg, _T("DynamoRIO does not support %s"), bad_os);
MessageBox(m_pMainFrame->m_hWnd, msg, _T("Fatal Error"), MB_OK | MYMBFLAGS);
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// App command to run the dialog
void CDynamoRIOApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
/////////////////////////////////////////////////////////////////////////////
// CDynamoRIOApp message handlers
CDocument * CDynamoRIOApp::OpenDocumentFile(LPCTSTR
#ifndef DRSTATS_DEMO /* avoid warning */
lpszFileName
#endif
)
{
#ifndef DRSTATS_DEMO
RunNewApp(lpszFileName);
#endif
return m_pMainFrame->GetActiveView()->GetDocument();
}
#ifndef DRSTATS_DEMO
static TCHAR szFilter[] = _T("Executable Files (*.exe)|*.exe|All Files (*.*)|*.*||");
void CDynamoRIOApp::OnFileRun()
{
CFileDialog fileDlg(TRUE, _T(".exe"), NULL,
// hide the "open as read-only" checkbox
OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
szFilter);
int res = fileDlg.DoModal();
if (res == IDCANCEL)
return;
CString file = fileDlg.GetPathName();
RunNewApp(file);
}
BOOL CDynamoRIOApp::RunNewApp(LPCTSTR lpszFileName)
{
m_pMainFrame->SetStatusBarText(0, lpszFileName);
AddToRecentFileList(lpszFileName);
CDynamoRIODoc *doc = (CDynamoRIODoc *) m_pMainFrame->GetActiveView()->GetDocument();
doc->RunApplication(lpszFileName);
return TRUE;
}
void CDynamoRIOApp::OnFileSystemwide()
{
assert(m_bSystemwideAllowed);
if (!m_bInjectAll && GetProfileInt(_T("Settings"), _T("Confirm Systemwide"), 1) == 1) {
// confirm with user the gravity of this setting
CSyswideDlg dlg;
int res = dlg.DoModal();
if (res == IDCANCEL)
return;
}
TCHAR * val;
if (m_bInjectAll) {
m_bInjectAll = FALSE;
val = _T("");
// enable changing existing libraries
DisableMissingLibraries(FALSE);
} else {
m_bInjectAll = TRUE;
val = m_inject_all_value;
// point DYNAMORIO_SYSTEMWIDE to the currently selected library
SetEnvVarPermanently(_T("DYNAMORIO_SYSTEMWIDE"), m_dll_path);
// disable changing the library
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_RELEASE, MF_BYCOMMAND|MF_GRAYED);
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_DEBUG, MF_BYCOMMAND|MF_GRAYED);
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_PROFILE, MF_BYCOMMAND|MF_GRAYED);
}
if (!SetSystemwideInject(val))
return;
m_pMainWnd->GetMenu()->CheckMenuItem(ID_FILE_SYSTEMWIDE,
MF_BYCOMMAND | ((m_bInjectAll) ? MF_CHECKED : MF_UNCHECKED));
}
BOOL CDynamoRIOApp::SetSystemwideInject(TCHAR *val)
{
assert(m_bSystemwideAllowed);
HKEY hk;
// must have administrative privilegs to write this key!
int res = RegOpenKeyEx(INJECT_ALL_HIVE, INJECT_ALL_KEY_L, 0, KEY_WRITE, &hk);
if (res != ERROR_SUCCESS) {
MessageBox(NULL,
_T("DynamoRIO's system-wide injection method requires administrative privileges.\n")
_T("You must restart this program with such privileges to use this feature."),
_T("Lack of Privileges"), MB_OK | MYMBFLAGS);
// now disable systemwide injection
m_bSystemwideAllowed = FALSE; // prevent infinite loop
DisableSystemwideInject();
return FALSE;
}
res = RegSetValueEx(hk, INJECT_ALL_SUBKEY_L, 0, REG_SZ, (LPBYTE) val, _tcslen(val)+1);
assert(res == ERROR_SUCCESS);
RegCloseKey(hk);
return TRUE;
}
void CDynamoRIOApp::DisableSystemwideInject()
{
if (m_bSystemwideAllowed) {
// clear key
SetSystemwideInject(_T(""));
}
// disable systemwide altogether
m_bSystemwideAllowed = FALSE;
m_bInjectAll = FALSE;
// disable checkbox, but allow editing ignore list
m_pMainWnd->GetMenu()->EnableMenuItem(ID_FILE_SYSTEMWIDE,
MF_BYCOMMAND|MF_GRAYED);
m_pMainFrame->SetStatusBarText(0, _T("Disabled system-wide injection"));
}
void CDynamoRIOApp::OnEditOptions()
{
COptionsDlg ops;
ops.DoModal();
}
void CDynamoRIOApp::OnEditIgnorelist()
{
CIgnoreDlg dlg;
dlg.DoModal();
}
void CDynamoRIOApp::DisableMissingLibraries(BOOL notify)
{
BOOL release_ok, debug_ok, profile_ok;
if (SwitchLibraries(L_DLLPATH_RELEASE, notify)) {
release_ok = TRUE;
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_RELEASE, MF_BYCOMMAND);
} else {
release_ok = FALSE;
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_RELEASE, MF_BYCOMMAND|MF_GRAYED);
}
if (SwitchLibraries(L_DLLPATH_DEBUG, notify)) {
debug_ok = TRUE;
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_DEBUG, MF_BYCOMMAND);
} else {
debug_ok = FALSE;
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_DEBUG, MF_BYCOMMAND|MF_GRAYED);
}
if (SwitchLibraries(L_DLLPATH_PROFILE, notify)) {
profile_ok = TRUE;
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_PROFILE, MF_BYCOMMAND);
} else {
profile_ok = FALSE;
m_pMainWnd->GetMenu()->EnableMenuItem(ID_LIBRARY_PROFILE, MF_BYCOMMAND|MF_GRAYED);
}
}
BOOL CDynamoRIOApp::SwitchLibraries(TCHAR *newdllpath, BOOL notify)
{
// first see if new dll exists
CFile check;
TCHAR msg[MAX_PATH*2];
TCHAR file[MAX_PATH];
assert(_tcslen(m_dynamorio_home) + _tcslen(newdllpath) < MAX_PATH);
_stprintf(file, _T("%s%s"), m_dynamorio_home, newdllpath);
if (!check.Open(file, CFile::modeRead|CFile::shareDenyNone)) {
if (notify) {
_stprintf(msg, _T("Library %s does not exist"), file);
#if 0 // I'm disabling this dialog until we decide to support running apps
MessageBox(NULL, msg, _T("DynamoRIO Configuration Error"), MB_OK | MYMBFLAGS);
#endif
}
return FALSE;
}
check.Close();
// set dll pointer for single-app injection
_tcscpy(m_dll_path, file);
return TRUE;
}
void CDynamoRIOApp::OnLibraryRelease()
{
if (!SwitchLibraries(L_DLLPATH_RELEASE, TRUE))
return;
m_dll_type = DLL_RELEASE;
COptionsDlg::CheckOptionsVersusDllType(m_dll_type);
m_pMainWnd->GetMenu()->CheckMenuItem(ID_LIBRARY_RELEASE, MF_BYCOMMAND | MF_CHECKED);
m_pMainWnd->GetMenu()->CheckMenuItem(ID_LIBRARY_DEBUG, MF_BYCOMMAND | MF_UNCHECKED);
m_pMainWnd->GetMenu()->CheckMenuItem(ID_LIBRARY_PROFILE, MF_BYCOMMAND | MF_UNCHECKED);
}
void CDynamoRIOApp::OnLibraryDebug()
{
if (!SwitchLibraries(L_DLLPATH_DEBUG, TRUE))
return;
m_dll_type = DLL_DEBUG;
COptionsDlg::CheckOptionsVersusDllType(m_dll_type);
m_pMainWnd->GetMenu()->CheckMenuItem(ID_LIBRARY_RELEASE, MF_BYCOMMAND | MF_UNCHECKED);
m_pMainWnd->GetMenu()->CheckMenuItem(ID_LIBRARY_DEBUG, MF_BYCOMMAND | MF_CHECKED);
m_pMainWnd->GetMenu()->CheckMenuItem(ID_LIBRARY_PROFILE, MF_BYCOMMAND | MF_UNCHECKED);
}
void CDynamoRIOApp::OnLibraryProfile()
{
if (!SwitchLibraries(L_DLLPATH_PROFILE, TRUE))
return;
m_dll_type = DLL_PROFILE;
COptionsDlg::CheckOptionsVersusDllType(m_dll_type);
m_pMainWnd->GetMenu()->CheckMenuItem(ID_LIBRARY_RELEASE, MF_BYCOMMAND | MF_UNCHECKED);
m_pMainWnd->GetMenu()->CheckMenuItem(ID_LIBRARY_DEBUG, MF_BYCOMMAND | MF_UNCHECKED);
m_pMainWnd->GetMenu()->CheckMenuItem(ID_LIBRARY_PROFILE, MF_BYCOMMAND | MF_CHECKED);
}
void CDynamoRIOApp::OnHelpHelp()
{
TCHAR helppath[MAX_PATH];
_stprintf(helppath, _T("%s%s"), m_dynamorio_home, HELP_PATH);
TCHAR cwd[MAX_PATH];
int cwd_res = GetCurrentDirectory(MAX_PATH, cwd);
assert(cwd_res > 0);
// launch browser on documentation file!
HINSTANCE res = ShellExecute(m_pMainWnd->m_hWnd, _T("open"),
helppath, NULL, cwd, SW_SHOWNORMAL);
// FIXME: I get back 2 == SE_ERR_FNF == file not found, but netscape finds and
// displays it fine...
if ((int)res <= 32) {
TCHAR msg[MAX_PATH*2];
_stprintf(msg, _T("Error browsing help document %s"), helppath);
MessageBox(m_pMainWnd->m_hWnd, msg, _T("Error"), MB_OK | MYMBFLAGS);
}
}
// MessageBox crashes in ExitInstance so I added this PreExit routine, called
// using the framework's notion of "save unsaved data?" for CDocument
void CDynamoRIOApp::PreExit()
{
BOOL ok = TRUE; // libraries may have been disabled
if (_tcsstr(m_dll_path, L_DLLPATH_RELEASE) != NULL)
ok = WriteProfileInt(_T("Settings"), _T("Library"), 0);
else if (_tcsstr(m_dll_path, L_DLLPATH_DEBUG) != NULL)
ok = WriteProfileInt(_T("Settings"), _T("Library"), 1);
else if (_tcsstr(m_dll_path, L_DLLPATH_PROFILE) != NULL)
ok = WriteProfileInt(_T("Settings"), _T("Library"), 2);
assert(ok);
if (m_bSystemwideAllowed && m_bInjectAll) {
// FIXME: MessageBox crashes...try to get this code into
// MFC's auto-framework for saving unsaved documents!
int res = MessageBox(NULL, // m_pMainWnd is NULL now!
_T("Run All is currently set. Turn it off?"),
_T("Confirmation"), MB_YESNO | MYMBFLAGS);
if (res == IDYES) {
// clear key
SetSystemwideInject(_T(""));
}
}
}
void CDynamoRIOApp::SetEnvVarPermanently(TCHAR *var, TCHAR *val)
{
// it takes a while to broadcast the "we've changed env vars" message,
// so set a wait cursor
HCURSOR prev_cursor = SetCursor(LoadCursor(IDC_WAIT));
TCHAR msg[MAX_PATH];
HKEY hk;
int res;
// current user only
res = RegOpenKeyEx(HKEY_CURRENT_USER, _T("Environment"), 0, KEY_WRITE, &hk);
if (res != ERROR_SUCCESS) {
_stprintf(msg, _T("Error writing to HKEY_CURRENT_USER\\Environment"));
MessageBox(NULL, msg, _T("Error"), MB_OK | MYMBFLAGS);
}
res = RegSetValueEx(hk, var, 0, REG_SZ, (LPBYTE) val, _tcslen(val)+1);
assert(res == ERROR_SUCCESS);
RegCloseKey(hk);
// tell system that we've changed environment (else won't take effect until
// user logs out and back in)
DWORD dwReturnValue;
// Code I copied this from used an ANSI string...I'm leaving
// it like that FIXME
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
(LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
// set local var too
BOOL ok = SetEnvironmentVariable(var, val);
assert(ok);
SetCursor(prev_cursor);
}
BOOL CDynamoRIOApp::ConfigureForNewUser()
{
// Need to find location of dynamorio install
BOOL ok = FALSE;
TCHAR msg[MAX_PATH*2];
int res;
// First attempt: look at gui's executable path
GetModuleFileName(NULL, m_dynamorio_home, MAX_PATH);
TCHAR *sub = _tcsstr(m_dynamorio_home, _T("\\bin\\DynamoRIO.exe"));
if (sub != NULL) {
*sub = _T('\0');
_stprintf(msg, _T("Is this the location of the DynamoRIO installation?\n%s\n"),
m_dynamorio_home);
res = MessageBox(NULL, msg, _T("Confirmation"), MB_YESNO | MYMBFLAGS);
if (res == IDNO)
ok = FALSE;
else
ok = TRUE;
}
if (!ok) {
// Second attempt: read Start Menu's link files
// FIXME: code that up
// Last resort: ask user to locate directory
BROWSEINFO bi;
bi.hwndOwner = m_pMainFrame->m_hWnd;
bi.pidlRoot = NULL;
bi.pszDisplayName = m_dynamorio_home;
bi.lpszTitle = _T("Locate Root of DynamoRIO Installation");
bi.ulFlags = 0;
bi.lpfn = NULL;
bi.lParam = NULL;
bi.iImage = 0;
ITEMIDLIST *id = SHBrowseForFolder(&bi);
if (id == NULL) // cancelled
return FALSE;
SHGetPathFromIDList(id, m_dynamorio_home);
}
// it takes a while to broadcast the "we've changed env vars" message,
// so set a wait cursor
HCURSOR prev_cursor = SetCursor(LoadCursor(IDC_WAIT));
HKEY hk;
// current user only
res = RegOpenKeyEx(HKEY_CURRENT_USER, _T("Environment"), 0, KEY_WRITE, &hk);
if (res != ERROR_SUCCESS) {
_stprintf(msg, _T("Error writing to HKEY_CURRENT_USER\\Environment"));
MessageBox(NULL, msg, _T("Error"), MB_OK | MYMBFLAGS);
}
// DYNAMORIO_HOME
TCHAR *val = m_dynamorio_home;
res = RegSetValueEx(hk, _T("DYNAMORIO_HOME"), 0, REG_SZ, (LPBYTE) val, _tcslen(val)+1);
assert(res == ERROR_SUCCESS);
// set local var too
ok = SetEnvironmentVariable(_T("DYNAMORIO_HOME"), val);
assert(ok);
// DYNAMORIO_OPTIONS
val = INITIAL_OPTIONS;
res = RegSetValueEx(hk, _T("DYNAMORIO_OPTIONS"), 0, REG_SZ, (LPBYTE) val, _tcslen(val)+1);
assert(res == ERROR_SUCCESS);
// set local var too
ok = SetEnvironmentVariable(_T("DYNAMORIO_OPTIONS"), val);
assert(ok);
// DYNAMORIO_SYSTEMWIDE
TCHAR buf[MAX_PATH];
_stprintf(buf, _T("%s%s"), m_dynamorio_home, INITIAL_SYSTEMWIDE);
val = buf;
res = RegSetValueEx(hk, _T("DYNAMORIO_SYSTEMWIDE"), 0, REG_SZ, (LPBYTE) val, _tcslen(val)+1);
assert(res == ERROR_SUCCESS);
// set local var too
ok = SetEnvironmentVariable(_T("DYNAMORIO_SYSTEMWIDE"), val);
assert(ok);
// DYNAMORIO_IGNORE
val = INITIAL_IGNORE;
res = RegSetValueEx(hk, _T("DYNAMORIO_IGNORE"), 0, REG_SZ, (LPBYTE) val, _tcslen(val)+1);
assert(res == ERROR_SUCCESS);
// set local var too
ok = SetEnvironmentVariable(_T("DYNAMORIO_IGNORE"), val);
assert(ok);
RegCloseKey(hk);
// tell system that we've changed environment (else won't take effect until
// user logs out and back in)
DWORD dwReturnValue;
// Code I copied this from used an ANSI string...I'm leaving
// it like that FIXME
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
(LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
// FIXME: Doc keeps its own internal var w/ home, must update here,
// better to have Doc grab ours!
CDynamoRIODoc *doc = (CDynamoRIODoc *) m_pMainFrame->GetActiveView()->GetDocument();
doc->InitPaths();
SetCursor(prev_cursor);
return TRUE;
}
#endif /* !DRSTATS_DEMO */
void CDynamoRIOApp::OnAppExit()
{
// Same as double-clicking on main window close box.
ASSERT(AfxGetMainWnd() != NULL);
AfxGetMainWnd()->SendMessage(WM_CLOSE);
}
int CDynamoRIOApp::ExitInstance()
{
// no longer need to do anything special -- PreExit does it now
return CWinApp::ExitInstance();
}