core/CrazyDebugger.cpp
author Asher Baker <asherkin@gmail.com>
Thu May 16 14:58:14 2013 +0100 (2013-05-16)
changeset 3920 e4fa6b583893
parent 2289 44045ead61cd
permissions -rw-r--r--
Fixed copy-paste error in 116256b519b5.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "sm_globals.h"
    33 #include "sourcemm_api.h"
    34 #include "Tlhelp32.h"
    35 #include "LibrarySys.h"
    36 #include "minidump.h"
    37 #include "sm_stringutil.h"
    38 
    39 bool HookImportAddrTable(BYTE *base, const char *func, DWORD hookfunc, char *err, size_t maxlength)
    40 {
    41 	IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)base;
    42 	if (dos->e_magic != IMAGE_DOS_SIGNATURE)
    43 	{
    44 		UTIL_Format(err, maxlength, "%s", "Could not detect valid DOS signature");
    45 		return false;
    46 	}
    47 
    48 	IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)(base + dos->e_lfanew);
    49 	if (nt->Signature != IMAGE_NT_SIGNATURE)
    50 	{
    51 		UTIL_Format(err, maxlength, "%s", "Could not detect valid NT signature");
    52 		return false;
    53 	}
    54 
    55 	IMAGE_IMPORT_DESCRIPTOR *desc = 
    56 		(IMAGE_IMPORT_DESCRIPTOR *)
    57 		(base + nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
    58 	if (base == (BYTE *)desc)
    59 	{
    60 		UTIL_Format(err, maxlength, "%s", "Could not find IAT");
    61 		return false;
    62 	}
    63 
    64 	bool entryFound = false;
    65 	while (desc->Name)
    66 	{
    67 		if (desc->FirstThunk != 0)
    68 		{
    69 			IMAGE_THUNK_DATA *data = (IMAGE_THUNK_DATA *)(base + desc->OriginalFirstThunk);
    70 			DWORD *iat = (DWORD *)(base + desc->FirstThunk);
    71 			while (data->u1.Function)
    72 			{
    73 				if ((data->u1.Ordinal & IMAGE_ORDINAL_FLAG32) != IMAGE_ORDINAL_FLAG32)
    74 				{
    75 					IMAGE_IMPORT_BY_NAME *import = (IMAGE_IMPORT_BY_NAME *)(base + data->u1.AddressOfData);
    76 					if (strcmp((char *)import->Name, func) == 0)
    77 					{
    78 						DWORD oldprot, oldprot2;
    79 						VirtualProtect(iat, 4, PAGE_READWRITE, &oldprot);
    80 						*iat = hookfunc;
    81 						VirtualProtect(iat, 4, oldprot, &oldprot2);
    82 						entryFound = true;
    83 					}
    84 				}
    85 				data++;
    86 				iat++;
    87 			}
    88 		}
    89 		desc++;
    90 	}
    91 
    92 	if (!entryFound)
    93 	{
    94 		UTIL_Format(err, maxlength, "Could not find IAT entry for %s", func);
    95 		return false;
    96 	}
    97 
    98 	return true;
    99 }
   100 
   101 BOOL
   102 WINAPI
   103 MiniDumpWriteDump2(
   104 				  IN HANDLE hProcess,
   105 				  IN DWORD ProcessId,
   106 				  IN HANDLE hFile,
   107 				  IN MINIDUMP_TYPE DumpType,
   108 				  IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
   109 				  IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
   110 				  IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
   111 				  )
   112 {
   113 	DumpType = (MINIDUMP_TYPE)((int)DumpType|MiniDumpWithFullMemory|MiniDumpWithHandleData);
   114 	return MiniDumpWriteDump(hProcess, ProcessId, hFile, DumpType, ExceptionParam, UserStreamParam, CallbackParam);
   115 }
   116 
   117 FARPROC WINAPI GetProcAddress2(HMODULE hModule, LPCSTR lpProcName)
   118 {
   119 	if (strcmp(lpProcName, "MiniDumpWriteDump") == 0)
   120 	{
   121 		return (FARPROC)MiniDumpWriteDump2;
   122 	}
   123 
   124 	return GetProcAddress(hModule, lpProcName);
   125 }
   126 
   127 HMODULE WINAPI LoadLibraryEx2(LPCTSTR lpFileName, HANDLE hFile, DWORD dwFlags)
   128 {
   129 	HMODULE lib = LoadLibraryEx(lpFileName, hFile, dwFlags);
   130 
   131 	/* Steam.dll seems to get loaded using an abs path, thus the use of stristr() */
   132 	if (stristr(lpFileName, "steam.dll"))
   133 	{
   134 		char err[64];
   135 		if (!HookImportAddrTable((BYTE *)lib, "GetProcAddress", (DWORD)GetProcAddress2, err, sizeof(err)))
   136 		{
   137 			Error("[SM] %s in steam.dll\n", err);
   138 			return NULL;
   139 		}
   140 	}
   141 
   142 	return lib;
   143 }
   144 
   145 class CrazyWindowsDebugger : public SMGlobalClass
   146 {
   147 public:
   148 	void OnSourceModAllInitialized()
   149 	{
   150 		HANDLE hModuleList = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
   151 		MODULEENTRY32 me32;
   152 		BYTE *engine = NULL;
   153 		BYTE *steam = NULL;
   154 		char err[64];
   155 
   156 		me32.dwSize = sizeof(MODULEENTRY32);
   157 
   158 		if (!Module32First(hModuleList, &me32))
   159 		{
   160 			Error("Could not initialize crazy debugger!");
   161 		}
   162 
   163 		do
   164 		{
   165 			if (strcasecmp(me32.szModule, "engine.dll") == 0)
   166 			{
   167 				engine = me32.modBaseAddr;
   168 			}
   169 			else if (strcasecmp(me32.szModule, "steam.dll") == 0)
   170 			{
   171 				steam = me32.modBaseAddr;
   172 			}
   173 		} while  (Module32Next(hModuleList, &me32));
   174 
   175 		CloseHandle(hModuleList);
   176 
   177 		/* This really should not happen, but ... */
   178 		if (!engine)
   179 		{
   180 			Error("[SM] Could not find engine.dll\n");
   181 		}
   182 
   183 		/* Steam.dll isn't loaded yet */
   184 		if (!steam)
   185 		{
   186 			if (!HookImportAddrTable(engine, "LoadLibraryExA", (DWORD)LoadLibraryEx2, err, sizeof(err)))
   187 			{
   188 				Error("[SM] %s in engine.dll)\n", err);
   189 			}
   190 		}
   191 		else
   192 		{
   193 			if (!HookImportAddrTable(steam, "GetProcAddress", (DWORD)GetProcAddress2, err, sizeof(err)))
   194 			{
   195 				Error("[SM] %s in steam.dll)\n", err);
   196 			}
   197 		}
   198 	}
   199 } s_CrazyDebugger;