initial
This commit is contained in:
1626
common/detour/detourfunc.cpp
Normal file
1626
common/detour/detourfunc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
277
common/detour/detourfunc.h
Normal file
277
common/detour/detourfunc.h
Normal file
@@ -0,0 +1,277 @@
|
||||
//========= Copyright <20> 1996-2002, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose: Function Detouring code used by the overlay
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
#ifndef DETOURFUNC_H
|
||||
#define DETOURFUNC_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
void * HookFunc( BYTE *pRealFunctionAddr, const BYTE *pHookFunctionAddr, int nJumpsToFollowBeforeHooking = 0 );
|
||||
|
||||
bool HookFuncSafe( BYTE *pRealFunctionAddr, const BYTE *pHookFunctionAddr, void ** ppRelocFunctionAddr, int nJumpsToFollowBeforeHooking = 0 );
|
||||
bool bIsFuncHooked( BYTE *pRealFunctionAddr, void *pHookFunc = NULL );
|
||||
void UnhookFunc( BYTE *pRealFunctionAddr, BYTE *pOriginalFunctionAddr_DEPRECATED );
|
||||
void UnhookFunc( BYTE *pRealFunctionAddr, bool bLogFailures = true );
|
||||
void UnhookFuncByRelocAddr( BYTE *pRelocFunctionAddr, bool bLogFailures = true );
|
||||
|
||||
void RegregisterTrampolines();
|
||||
|
||||
void DetectUnloadedHooks();
|
||||
|
||||
#if defined( _WIN32 ) && DEBUG_ENABLE_DETOUR_RECORDING
|
||||
template <typename T, int k_nCountElements >
|
||||
class CCallRecordSet
|
||||
{
|
||||
public:
|
||||
typedef T ElemType_t;
|
||||
|
||||
CCallRecordSet()
|
||||
{
|
||||
m_cElements = 0;
|
||||
m_cElementPostWrite = 0;
|
||||
m_cElementMax = k_nCountElements;
|
||||
m_cubElements = sizeof(m_rgElements);
|
||||
memset( m_rgElements, 0, sizeof(m_rgElements) );
|
||||
}
|
||||
|
||||
// if return value is >= 0, then we matched an existing record
|
||||
int AddFunctionCallRecord( const ElemType_t &fcr )
|
||||
{
|
||||
// if we are full, dont bother searching any more
|
||||
// this reduces our perf impact to near zero if these functions are
|
||||
// called a lot more than we expect
|
||||
int cElements = m_cElements;
|
||||
if ( cElements >= k_nCountElements )
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
// search backwards through the log
|
||||
for( int i = cElements-1; i >= 0; i-- )
|
||||
{
|
||||
if ( m_rgElements[i] == fcr )
|
||||
return i;
|
||||
}
|
||||
|
||||
cElements = ++m_cElements;
|
||||
if ( cElements <= k_nCountElements )
|
||||
{
|
||||
m_rgElements[cElements-1] = fcr;
|
||||
}
|
||||
// if an external reader sees m_cElements != m_cElementPostWrite
|
||||
// they know the last item(s) may not be complete
|
||||
m_cElementPostWrite++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
CInterlockedIntT< int > m_cElements;
|
||||
CInterlockedIntT< int > m_cElementPostWrite;
|
||||
int m_cElementMax;
|
||||
int m_cubElements;
|
||||
ElemType_t m_rgElements[k_nCountElements];
|
||||
};
|
||||
|
||||
|
||||
class CRecordDetouredCalls
|
||||
{
|
||||
public:
|
||||
CRecordDetouredCalls();
|
||||
|
||||
void SetMasterSwitchOn() { m_bMasterSwitch = true; }
|
||||
bool BIsMasterSwitchOn() { return m_bMasterSwitch; }
|
||||
|
||||
bool BShouldRecordProtectFlags( DWORD flProtect );
|
||||
|
||||
void RecordGetAsyncKeyState( DWORD vKey,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
void RecordVirtualAlloc( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect,
|
||||
LPVOID lpvResult, DWORD dwGetLastError,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
void RecordVirtualProtect( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD flOldProtect,
|
||||
BOOL bResult, DWORD dwGetLastError,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
void RecordVirtualAllocEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect,
|
||||
LPVOID lpvResult, DWORD dwGetLastError,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
void RecordVirtualProtectEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD flOldProtect,
|
||||
BOOL bResult, DWORD dwGetLastError,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
void RecordLoadLibraryW(
|
||||
LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags,
|
||||
HMODULE hModule, DWORD dwGetLastError,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
void RecordLoadLibraryA(
|
||||
LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags,
|
||||
HMODULE hModule, DWORD dwGetLastError,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
struct FunctionCallRecordBase_t
|
||||
{
|
||||
void SharedInit(
|
||||
DWORD dwResult, DWORD dwGetLastError,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
DWORD m_dwResult;
|
||||
DWORD m_dwGetLastError;
|
||||
LPVOID m_lpFirstCallersAddress;
|
||||
LPVOID m_lpLastCallerAddress;
|
||||
};
|
||||
|
||||
// for GetAsyncKeyState the only thing we care about is the call site
|
||||
// dont care about results or params
|
||||
struct GetAsyncKeyStateCallRecord_t : public FunctionCallRecordBase_t
|
||||
{
|
||||
GetAsyncKeyStateCallRecord_t()
|
||||
{}
|
||||
|
||||
void InitGetAsyncKeyState( DWORD vKey,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
bool operator==( const FunctionCallRecordBase_t &rhs ) const
|
||||
{
|
||||
// compare callers only, dont care about results or params
|
||||
return
|
||||
m_lpFirstCallersAddress == rhs.m_lpFirstCallersAddress &&
|
||||
m_lpLastCallerAddress == rhs.m_lpLastCallerAddress;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct VirtualAllocCallRecord_t : public FunctionCallRecordBase_t
|
||||
{
|
||||
VirtualAllocCallRecord_t()
|
||||
{}
|
||||
|
||||
// VirtualAlloc
|
||||
void InitVirtualAlloc( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect,
|
||||
LPVOID lpvResult, DWORD dwGetLastError,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
// VirtualAllocEx
|
||||
void InitVirtualAllocEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect,
|
||||
LPVOID lpvResult, DWORD dwGetLastError,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
// VirtualProtect
|
||||
void InitVirtualProtect( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD flOldProtect,
|
||||
BOOL bResult, DWORD dwGetLastError,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
// VirtualProtectEx
|
||||
void InitVirtualProtectEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD flOldProtect,
|
||||
BOOL bResult, DWORD dwGetLastError,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
bool operator==( const VirtualAllocCallRecord_t &rhs ) const
|
||||
{
|
||||
// compare everything
|
||||
return
|
||||
m_dwResult == rhs.m_dwResult &&
|
||||
m_dwGetLastError == rhs.m_dwGetLastError &&
|
||||
m_dwProcessId == rhs.m_dwProcessId &&
|
||||
m_lpAddress == rhs.m_lpAddress &&
|
||||
m_dwSize == rhs.m_dwSize &&
|
||||
m_flProtect == rhs.m_flProtect &&
|
||||
m_dw2 == rhs.m_dw2 &&
|
||||
m_lpFirstCallersAddress == rhs.m_lpFirstCallersAddress &&
|
||||
m_lpLastCallerAddress == rhs.m_lpLastCallerAddress;
|
||||
}
|
||||
|
||||
DWORD m_dwProcessId;
|
||||
LPVOID m_lpAddress;
|
||||
SIZE_T m_dwSize;
|
||||
DWORD m_flProtect;
|
||||
DWORD m_dw2;
|
||||
};
|
||||
|
||||
// for LoadLibrary just log everything, params and call sites
|
||||
struct LoadLibraryCallRecord_t : public FunctionCallRecordBase_t
|
||||
{
|
||||
LoadLibraryCallRecord_t() {}
|
||||
|
||||
// LoadLibraryExW or LoadLibraryW
|
||||
void InitLoadLibraryW(
|
||||
LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags,
|
||||
HMODULE hModule, DWORD dwGetLastError,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
void InitLoadLibraryA(
|
||||
LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags,
|
||||
HMODULE hModule, DWORD dwGetLastError,
|
||||
PVOID lpCallersAddress, PVOID lpCallersCallerAddress
|
||||
);
|
||||
|
||||
bool operator==( const LoadLibraryCallRecord_t &rhs ) const
|
||||
{
|
||||
// compare the result ( hModule ) but not the callers
|
||||
// we arent going to have a perfect history of every caller
|
||||
if ( m_dwResult != rhs.m_dwResult )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// and then what we have of the actual filename
|
||||
return ( memcmp( m_rgubFileName, &rhs.m_rgubFileName, sizeof(m_rgubFileName) ) == 0 );
|
||||
}
|
||||
|
||||
uint8 m_rgubFileName[128];
|
||||
HANDLE m_hFile;
|
||||
DWORD m_dwFlags;
|
||||
};
|
||||
|
||||
// These GUIDs are constants, and it is how we find this structure when looking through the data section
|
||||
// when we are trying to read this data with an external process
|
||||
GUID m_guidMarkerBegin;
|
||||
|
||||
// some helpers for parsing the structure externally
|
||||
int m_nVersionNumber;
|
||||
int m_cubRecordDetouredCalls;
|
||||
int m_cubGetAsyncKeyStateCallRecord;
|
||||
int m_cubVirtualAllocCallRecord;
|
||||
int m_cubVirtualProtectCallRecord;
|
||||
int m_cubLoadLibraryCallRecord;
|
||||
|
||||
// these numbers were chosen by profiling CS:GO a bunch
|
||||
CCallRecordSet< GetAsyncKeyStateCallRecord_t, 50 > m_GetAsyncKeyStateCallRecord;
|
||||
CCallRecordSet< VirtualAllocCallRecord_t, 300 > m_VirtualAllocCallRecord;
|
||||
CCallRecordSet< VirtualAllocCallRecord_t, 500 > m_VirtualProtectCallRecord;
|
||||
CCallRecordSet< LoadLibraryCallRecord_t, 200 > m_LoadLibraryCallRecord;
|
||||
|
||||
bool m_bMasterSwitch;
|
||||
// These GUIDs are constants, and it is how we find this structure when looking through the data section
|
||||
GUID m_guidMarkerEnd;
|
||||
|
||||
};
|
||||
|
||||
extern CRecordDetouredCalls g_RecordDetouredCalls;
|
||||
|
||||
typedef PVOID (WINAPI *RtlGetCallersAddress_t)( PVOID *CallersAddress, PVOID *CallersCaller );
|
||||
extern RtlGetCallersAddress_t g_pRtlGetCallersAddress;
|
||||
#endif // _WIN32
|
||||
|
||||
#endif // DETOURFUNC_H
|
||||
1281
common/detour/disassembler.cpp
Normal file
1281
common/detour/disassembler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
48
common/detour/disassembler.h
Normal file
48
common/detour/disassembler.h
Normal file
@@ -0,0 +1,48 @@
|
||||
//========= Copyright <20> 1996-2006, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: couple of helper functions for win32 PE modules
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#pragma once
|
||||
|
||||
enum EOpCodeOffsetType
|
||||
{
|
||||
k_ENoRelativeOffsets,
|
||||
k_EDWORDOffsetAtByteTwo,
|
||||
k_EDWORDOffsetAtByteThree,
|
||||
k_EDWORDOffsetAtByteFour,
|
||||
k_EBYTEOffsetAtByteTwo,
|
||||
};
|
||||
|
||||
bool ParseOpcode( unsigned char *pOpcode, int &nLength, EOpCodeOffsetType &eOffsetType );
|
||||
|
||||
#define CALCULATE_ADDRESS(base, offset) (((DWORD)(base)) + (offset))
|
||||
#define GET_HEADER_DICTIONARY(module, idx) &(module)->pNtHeaders->OptionalHeader.DataDirectory[idx]
|
||||
|
||||
|
||||
// This structure describes an opcode parsed by our disassembler
|
||||
typedef unsigned __int32 uint32;
|
||||
typedef unsigned char uint8;
|
||||
typedef struct
|
||||
{
|
||||
int bOpcode;
|
||||
int cubOpcode;
|
||||
int cubImmed;
|
||||
uint32 uJump;
|
||||
uint32 uImmed; // not filled in
|
||||
bool bModRM;
|
||||
bool bRelative;
|
||||
bool bCantContinue;
|
||||
bool bJumpOrCall;
|
||||
bool bURJ;
|
||||
} OPCODE_t;
|
||||
|
||||
bool ParseCode( uint8 *pubCode, OPCODE_t *pOpcode, int cubLeft );
|
||||
uint32 ComputeJumpAddress( OPCODE_t *pOpcode, uint32 uVACurrent );
|
||||
bool OpcodeText( OPCODE_t *pOpcode, char *rgchText );
|
||||
bool LikelyValid( OPCODE_t *pOpcode );
|
||||
bool LikelyNewValid( OPCODE_t *pOpcode );
|
||||
int DisassembleSingleFunction( unsigned char *pubStart, int cub );
|
||||
|
||||
|
||||
Reference in New Issue
Block a user