Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

834 lines
22 KiB

//////////////////////////////////////////////////////////////////////////////
//
// Module: detours.lib
// File: detours.cpp
// Author: Galen Hunt
//
// Detours for binary functions. Version 1.2. (Build 35)
//
// Copyright 1995-1999, Microsoft Corporation
//
// http://research.microsoft.com/sn/detours
//
//#include <ole2.h>
#include "stdafx.h"
#include <imagehlp.h>
//////////////////////////////////////////////////////////////////////////////
//
enum {
OP_JMP_DS = 0x25,
OP_JA = 0x77,
OP_NOP = 0x90,
OP_CALL = 0xe8,
OP_JMP = 0xe9,
OP_PREFIX = 0xff,
OP_MOV_EAX = 0xa1,
OP_SET_EAX = 0xb8,
OP_JMP_EAX = 0xe0,
OP_RET_POP = 0xc2,
OP_RET = 0xc3,
OP_BRK = 0xcc,
SIZE_OF_JMP = 5,
SIZE_OF_NOP = 1,
SIZE_OF_BRK = 1,
SIZE_OF_TRP_OPS = SIZE_OF_JMP /* + SIZE_OF_BRK */,
};
class CEnableWriteOnCodePage
{
public:
CEnableWriteOnCodePage(PBYTE pbCode, LONG cbCode = DETOUR_TRAMPOLINE_SIZE)
{
m_pbCode = pbCode;
m_cbCode = cbCode;
m_dwOldPerm = 0;
m_hProcess = GetCurrentProcess();
if (m_pbCode && m_cbCode) {
if (!FlushInstructionCache(m_hProcess, pbCode, cbCode)) {
return;
}
if (!VirtualProtect(pbCode,
cbCode,
PAGE_EXECUTE_READWRITE,
&m_dwOldPerm)) {
return;
}
}
}
~CEnableWriteOnCodePage()
{
if (m_dwOldPerm && m_pbCode && m_cbCode) {
DWORD dwTemp = 0;
if (!FlushInstructionCache(m_hProcess, m_pbCode, m_cbCode)) {
return;
}
if (!VirtualProtect(m_pbCode, m_cbCode, m_dwOldPerm, &dwTemp)) {
return;
}
}
}
BOOL SetPermission(DWORD dwPerms)
{
if (m_dwOldPerm && m_pbCode && m_cbCode) {
m_dwOldPerm = dwPerms;
return TRUE;
}
return FALSE;
}
BOOL IsValid(VOID)
{
return m_pbCode && m_cbCode && m_dwOldPerm;
}
private:
HANDLE m_hProcess;
PBYTE m_pbCode;
LONG m_cbCode;
DWORD m_dwOldPerm;
};
//////////////////////////////////////////////////////////////////////////////
//
static BOOL detour_insert_jump(PBYTE pbCode, PBYTE pbDest, LONG cbCode)
{
if (cbCode < SIZE_OF_JMP)
return FALSE;
*pbCode++ = OP_JMP;
LONG offset = (LONG)pbDest - (LONG)(pbCode + 4);
*((PDWORD&)pbCode)++ = offset;
for (cbCode -= SIZE_OF_JMP; cbCode > 0; cbCode--)
*pbCode++ = OP_BRK;
return TRUE;
}
static BOOL detour_insert_detour(PBYTE pbTarget,
PBYTE pbTrampoline,
PBYTE pbDetour)
{
if (pbTarget[0] == OP_NOP)
return FALSE;
if (pbTarget[0] == OP_JMP) // Already has a detour.
return FALSE;
PBYTE pbCont = pbTarget;
for (LONG cbTarget = 0; cbTarget < SIZE_OF_TRP_OPS;) {
BYTE bOp = *pbCont;
pbCont = DetourCopyInstruction(NULL, pbCont, NULL);
cbTarget = pbCont - pbTarget;
if (bOp == OP_JMP ||
bOp == OP_JMP_DS ||
bOp == OP_JMP_EAX ||
bOp == OP_RET_POP ||
bOp == OP_RET) {
break;
}
}
if (cbTarget < SIZE_OF_TRP_OPS) {
// Too few instructions.
return FALSE;
}
if (cbTarget > (DETOUR_TRAMPOLINE_SIZE - SIZE_OF_JMP - SIZE_OF_NOP - 1)) {
// Too many instructions.
return FALSE;
}
//////////////////////////////////////////////////////// Finalize Reroute.
//
CEnableWriteOnCodePage ewTrampoline(pbTrampoline, DETOUR_TRAMPOLINE_SIZE);
CEnableWriteOnCodePage ewTarget(pbTarget, cbTarget);
if (!ewTrampoline.SetPermission(PAGE_EXECUTE_READWRITE))
return FALSE;
if (!ewTarget.IsValid())
return FALSE;
pbTrampoline[0] = OP_NOP;
PBYTE pbSrc = pbTarget;
PBYTE pbDst = pbTrampoline + SIZE_OF_NOP;
for (LONG cbCopy = 0; cbCopy < cbTarget;) {
pbSrc = DetourCopyInstruction(pbDst, pbSrc, NULL);
cbCopy = pbSrc - pbTarget;
pbDst = pbTrampoline + SIZE_OF_NOP + cbCopy;
}
if (cbCopy != cbTarget) // Count came out different!
return FALSE;
pbCont = pbTarget + cbTarget;
if (!detour_insert_jump(pbTrampoline + 1 + cbTarget, pbCont, SIZE_OF_JMP))
return FALSE;
pbTrampoline[DETOUR_TRAMPOLINE_SIZE-1] = (BYTE)cbTarget;
if (!detour_insert_jump(pbTarget, pbDetour, cbTarget))
return FALSE;
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//
BOOL WINAPI DetourRemoveWithTrampoline(PBYTE pbTrampoline,
PBYTE pbDetour)
{
pbTrampoline = DetourFindFinalCode(pbTrampoline);
pbDetour = DetourFindFinalCode(pbDetour);
////////////////////////////////////// Verify that Trampoline is in place.
//
if (pbTrampoline[0] != OP_NOP) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
LONG cbTarget = pbTrampoline[DETOUR_TRAMPOLINE_SIZE-1];
if (cbTarget == 0 || cbTarget >= DETOUR_TRAMPOLINE_SIZE - 1) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (pbTrampoline[cbTarget + SIZE_OF_NOP] != OP_JMP) {
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
LONG offset = *((PDWORD)&pbTrampoline[cbTarget + SIZE_OF_NOP + 1]);
PBYTE pbTarget = pbTrampoline +
SIZE_OF_NOP + cbTarget + SIZE_OF_JMP + offset - cbTarget;
if (pbTarget[0] != OP_JMP) { // Missing detour.
SetLastError(ERROR_INVALID_BLOCK);
return FALSE;
}
offset = *((PDWORD)&pbTarget[1]);
PBYTE pbTargetDetour = pbTarget + SIZE_OF_JMP + offset;
if (pbTargetDetour != pbDetour) {
SetLastError(ERROR_INVALID_ACCESS);
return FALSE;
}
/////////////////////////////////////////////////////// Remove the Detour.
CEnableWriteOnCodePage ewTarget(pbTarget, cbTarget);
PBYTE pbSrc = pbTrampoline + SIZE_OF_NOP;
PBYTE pbDst = pbTarget;
for (LONG cbCopy = 0; cbCopy < cbTarget; pbDst = pbTarget + cbCopy) {
pbSrc = DetourCopyInstruction(pbDst, pbSrc, NULL);
cbCopy = pbSrc - (pbTrampoline + SIZE_OF_NOP);
}
if (cbCopy != cbTarget) { // Count came out different!
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
return TRUE;
}
PBYTE WINAPI DetourFunction(PBYTE pbTarget,
PBYTE pbDetour)
{
PBYTE pbTrampoline = new BYTE [DETOUR_TRAMPOLINE_SIZE];
if (pbTrampoline == NULL)
return NULL;
pbTarget = DetourFindFinalCode(pbTarget);
pbDetour = DetourFindFinalCode(pbDetour);
if (detour_insert_detour(pbTarget, pbTrampoline, pbDetour))
return pbTrampoline;
delete[] pbTrampoline;
return NULL;
}
BOOL WINAPI DetourFunctionWithEmptyTrampoline(PBYTE pbTrampoline,
PBYTE pbTarget,
PBYTE pbDetour)
{
return DetourFunctionWithEmptyTrampolineEx(pbTrampoline, pbTarget, pbDetour,
NULL, NULL, NULL);
}
BOOL WINAPI DetourFunctionWithEmptyTrampolineEx(PBYTE pbTrampoline,
PBYTE pbTarget,
PBYTE pbDetour,
PBYTE *ppbRealTrampoline,
PBYTE *ppbRealTarget,
PBYTE *ppbRealDetour)
{
pbTrampoline = DetourFindFinalCode(pbTrampoline);
pbTarget = DetourFindFinalCode(pbTarget);
pbDetour = DetourFindFinalCode(pbDetour);
if (ppbRealTrampoline)
*ppbRealTrampoline = pbTrampoline;
if (ppbRealTarget)
*ppbRealTarget = pbTarget;
if (ppbRealDetour)
*ppbRealDetour = pbDetour;
if (pbTrampoline == NULL || pbDetour == NULL || pbTarget == NULL)
return FALSE;
if (pbTrampoline[0] == OP_NOP && pbTrampoline[1] != OP_NOP) {
// Already Patched.
return 2;
}
if (pbTrampoline[0] != OP_NOP ||
pbTrampoline[1] != OP_NOP) {
return FALSE;
}
return detour_insert_detour(pbTarget, pbTrampoline, pbDetour);
}
BOOL WINAPI DetourFunctionWithTrampoline(PBYTE pbTrampoline,
PBYTE pbDetour)
{
return DetourFunctionWithTrampolineEx(pbTrampoline, pbDetour, NULL, NULL);
}
BOOL WINAPI DetourFunctionWithTrampolineEx(PBYTE pbTrampoline,
PBYTE pbDetour,
PBYTE *ppbRealTrampoline,
PBYTE *ppbRealTarget)
{
PBYTE pbTarget = NULL;
pbTrampoline = DetourFindFinalCode(pbTrampoline);
pbDetour = DetourFindFinalCode(pbDetour);
if (ppbRealTrampoline)
*ppbRealTrampoline = pbTrampoline;
if (ppbRealTarget)
*ppbRealTarget = NULL;
if (pbTrampoline == NULL || pbDetour == NULL)
return FALSE;
if (pbTrampoline[0] == OP_NOP && pbTrampoline[1] != OP_NOP) {
// Already Patched.
return 2;
}
if (pbTrampoline[0] != OP_NOP ||
pbTrampoline[1] != OP_NOP ||
pbTrampoline[2] != OP_CALL ||
pbTrampoline[7] != OP_PREFIX ||
pbTrampoline[8] != OP_JMP_EAX) {
return FALSE;
}
PVOID (__fastcall * pfAddr)(VOID);
pfAddr = (PVOID (__fastcall *)(VOID))(pbTrampoline +
SIZE_OF_NOP + SIZE_OF_NOP + SIZE_OF_JMP +
*(LONG *)&pbTrampoline[3]);
pbTarget = DetourFindFinalCode((PBYTE)(*pfAddr)());
if (ppbRealTarget)
*ppbRealTarget = pbTarget;
return detour_insert_detour(pbTarget, pbTrampoline, pbDetour);
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////
//
typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(LPAPI_VERSION AppVersion);
typedef BOOL (NTAPI *PF_SymInitialize)(IN HANDLE hProcess,
IN LPSTR UserSearchPath,
IN BOOL fInvadeProcess);
typedef DWORD (NTAPI *PF_SymSetOptions)(IN DWORD SymOptions);
typedef DWORD (NTAPI *PF_SymGetOptions)(VOID);
typedef BOOL (NTAPI *PF_SymLoadModule)(IN HANDLE hProcess,
IN HANDLE hFile,
IN PSTR ImageName,
IN PSTR ModuleName,
IN DWORD BaseOfDll,
IN DWORD SizeOfDll);
typedef BOOL (NTAPI *PF_SymGetModuleInfo)(IN HANDLE hProcess,
IN DWORD dwAddr,
OUT PIMAGEHLP_MODULE ModuleInfo);
typedef BOOL (NTAPI *PF_SymGetSymFromName)(IN HANDLE hProcess,
IN LPSTR Name,
OUT PIMAGEHLP_SYMBOL Symbol);
typedef BOOL (NTAPI *PF_BindImage)(IN LPSTR pszImageName,
IN LPSTR pszDllPath,
IN LPSTR pszSymbolPath);
static HANDLE s_hProcess = NULL;
static HINSTANCE s_hImageHlp = NULL;
static PF_ImagehlpApiVersionEx s_pfImagehlpApiVersionEx = NULL;
static PF_SymInitialize s_pfSymInitialize = NULL;
static PF_SymSetOptions s_pfSymSetOptions = NULL;
static PF_SymGetOptions s_pfSymGetOptions = NULL;
static PF_SymLoadModule s_pfSymLoadModule = NULL;
static PF_SymGetModuleInfo s_pfSymGetModuleInfo = NULL;
static PF_SymGetSymFromName s_pfSymGetSymFromName = NULL;
static PF_BindImage s_pfBindImage = NULL;
static BOOL LoadImageHlp(VOID)
{
if (s_hImageHlp)
return TRUE;
if (s_hProcess == NULL) {
s_hProcess = GetCurrentProcess();
s_hImageHlp = LoadLibraryA("imagehlp.dll");
if (s_hImageHlp == NULL)
return FALSE;
s_pfImagehlpApiVersionEx
= (PF_ImagehlpApiVersionEx)GetProcAddress(s_hImageHlp,
"ImagehlpApiVersionEx");
s_pfSymInitialize
= (PF_SymInitialize)GetProcAddress(s_hImageHlp, "SymInitialize");
s_pfSymSetOptions
= (PF_SymSetOptions)GetProcAddress(s_hImageHlp, "SymSetOptions");
s_pfSymGetOptions
= (PF_SymGetOptions)GetProcAddress(s_hImageHlp, "SymGetOptions");
s_pfSymLoadModule
= (PF_SymLoadModule)GetProcAddress(s_hImageHlp, "SymLoadModule");
s_pfSymGetModuleInfo
= (PF_SymGetModuleInfo)GetProcAddress(s_hImageHlp, "SymGetModuleInfo");
s_pfSymGetSymFromName
= (PF_SymGetSymFromName)GetProcAddress(s_hImageHlp, "SymGetSymFromName");
s_pfBindImage
= (PF_BindImage)GetProcAddress(s_hImageHlp, "BindImage");
API_VERSION av;
ZeroMemory(&av, sizeof(av));
av.MajorVersion = API_VERSION_NUMBER;
if (s_pfImagehlpApiVersionEx) {
(*s_pfImagehlpApiVersionEx)(&av);
}
if (s_pfImagehlpApiVersionEx == NULL || av.MajorVersion < API_VERSION_NUMBER) {
FreeLibrary(s_hImageHlp);
s_hImageHlp = NULL;
return FALSE;
}
if (s_pfSymInitialize) {
(*s_pfSymInitialize)(s_hProcess, NULL, FALSE);
}
if (s_pfSymGetOptions && s_pfSymSetOptions) {
DWORD dw = (*s_pfSymGetOptions)();
dw &= (SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
(*s_pfSymSetOptions)(dw);
}
return TRUE;
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
//
PBYTE WINAPI DetourFindFinalCode(PBYTE pbCode)
{
if (pbCode == NULL)
return NULL;
//BUGBUG PBYTE pbTemp = pbCode;
if (pbCode[0] == OP_JMP) { // Reference passed.
pbCode = pbCode + SIZE_OF_JMP + *(LONG *)&pbCode[1];
}
else if (pbCode[0] == OP_PREFIX && pbCode[1] == OP_JMP_DS) {
pbCode = *(PBYTE *)&pbCode[2];
pbCode = *(PBYTE *)pbCode;
}
return pbCode;
}
PBYTE WINAPI DetourFindFunction(PCHAR pszModule, PCHAR pszFunction)
{
/////////////////////////////////////////////// First, Try GetProcAddress.
//
HINSTANCE hInst = LoadLibraryA(pszModule);
if (hInst == NULL) {
return NULL;
}
PBYTE pbCode = (PBYTE)GetProcAddress(hInst, pszFunction);
if (pbCode) {
return pbCode;
}
////////////////////////////////////////////////////// Then Try ImageHelp.
//
if (!LoadImageHlp() ||
s_pfSymLoadModule == NULL ||
s_pfSymGetModuleInfo == NULL ||
s_pfSymGetSymFromName == NULL) {
return NULL;
}
(*s_pfSymLoadModule)(s_hProcess, NULL, pszModule, NULL, (DWORD)hInst, 0);
IMAGEHLP_MODULE modinfo;
ZeroMemory(&modinfo, sizeof(modinfo));
if (!(*s_pfSymGetModuleInfo)(s_hProcess, (DWORD)hInst, &modinfo)) {
return NULL;
}
CHAR szFullName[512];
strcpy(szFullName, modinfo.ModuleName);
strcat(szFullName, "!");
strcat(szFullName, pszFunction);
//BUGBUG DWORD nDisplacement = 0;
struct CFullSymbol : IMAGEHLP_SYMBOL {
CHAR szRestOfName[512];
} symbol;
ZeroMemory(&symbol, sizeof(symbol));
symbol.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
symbol.MaxNameLength = sizeof(symbol.szRestOfName)/sizeof(0);
if (!(*s_pfSymGetSymFromName)(s_hProcess, szFullName, &symbol)) {
return NULL;
}
return (PBYTE)symbol.Address;
}
//////////////////////////////////////////////////// Instance Image Functions.
//
HINSTANCE WINAPI DetourEnumerateInstances(HINSTANCE hinstLast)
{
PBYTE pbLast;
if (hinstLast == NULL) {
pbLast = (PBYTE)0x10000;
}
else {
pbLast = (PBYTE)hinstLast + 0x10000;
}
MEMORY_BASIC_INFORMATION mbi;
ZeroMemory(&mbi, sizeof(mbi));
for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
if (VirtualQuery((PVOID)pbLast, &mbi, sizeof(mbi)) <= 0) {
return NULL;
}
if (mbi.State != MEM_COMMIT)
continue;
__try {
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pbLast;
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
continue;
}
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
pDosHeader->e_lfanew);
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
continue;
}
return (HINSTANCE)pDosHeader;
} __except(EXCEPTION_EXECUTE_HANDLER) {
/* nothing. */
}
}
return NULL;
}
PBYTE WINAPI DetourFindEntryPointForInstance(HINSTANCE hInst)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hInst;
if (hInst == NULL) {
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
}
__try {
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
SetLastError(ERROR_BAD_EXE_FORMAT);
return NULL;
}
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
pDosHeader->e_lfanew);
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
SetLastError(ERROR_INVALID_EXE_SIGNATURE);
return NULL;
}
if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
SetLastError(ERROR_EXE_MARKED_INVALID);
return NULL;
}
return (PBYTE)pNtHeader->OptionalHeader.AddressOfEntryPoint +
pNtHeader->OptionalHeader.ImageBase;
} __except(EXCEPTION_EXECUTE_HANDLER) {
}
SetLastError(ERROR_EXE_MARKED_INVALID);
return NULL;
}
static inline PBYTE RvaAdjust(HINSTANCE hInst, DWORD raddr)
{
if (raddr != NULL) {
return (PBYTE)hInst + raddr;
}
return NULL;
}
BOOL WINAPI DetourEnumerateExportsForInstance(HINSTANCE hInst,
PVOID pContext,
PF_DETOUR_BINARY_EXPORT_CALLBACK pfExport)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hInst;
if (hInst == NULL) {
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
}
__try {
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
SetLastError(ERROR_BAD_EXE_FORMAT);
return NULL;
}
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
pDosHeader->e_lfanew);
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
SetLastError(ERROR_INVALID_EXE_SIGNATURE);
return FALSE;
}
if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
SetLastError(ERROR_EXE_MARKED_INVALID);
return FALSE;
}
PIMAGE_EXPORT_DIRECTORY pExportDir
= (PIMAGE_EXPORT_DIRECTORY)
RvaAdjust(hInst,
pNtHeader->OptionalHeader
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
//BUGBUG ULONG cbExportDir = pNtHeader->OptionalHeader
//BUGBUG .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
if (pExportDir == NULL) {
SetLastError(ERROR_EXE_MARKED_INVALID);
return FALSE;
}
//BUGBUG PCHAR pszName = (PCHAR)RvaAdjust(hInst, pExportDir->Name);
PDWORD pdwFunctions = (PDWORD)RvaAdjust(hInst, pExportDir->AddressOfFunctions);
PDWORD pdwNames = (PDWORD)RvaAdjust(hInst, pExportDir->AddressOfNames);
PWORD pwOrdinals = (PWORD)RvaAdjust(hInst, pExportDir->AddressOfNameOrdinals);
for (DWORD nFunc = 0; nFunc < pExportDir->NumberOfFunctions; nFunc++) {
PBYTE pbCode = (PBYTE)RvaAdjust(hInst, pdwFunctions[nFunc]);
PCHAR pszName = (nFunc < pExportDir->NumberOfNames) ?
(PCHAR)RvaAdjust(hInst, pdwNames[nFunc]) : NULL;
ULONG nOrdinal = pExportDir->Base + pwOrdinals[nFunc];
if (!(*pfExport)(pContext, nOrdinal, pszName, pbCode)) {
break;
}
}
SetLastError(NO_ERROR);
return TRUE;
} __except(EXCEPTION_EXECUTE_HANDLER) {
}
SetLastError(ERROR_EXE_MARKED_INVALID);
return FALSE;
}
PDETOUR_LOADED_BINARY WINAPI DetourBinaryFromInstance(HINSTANCE hInst)
{
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hInst;
if (hInst == NULL) {
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
}
__try {
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
SetLastError(ERROR_BAD_EXE_FORMAT);
return NULL;
}
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
pDosHeader->e_lfanew);
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
SetLastError(ERROR_INVALID_EXE_SIGNATURE);
return NULL;
}
if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
SetLastError(ERROR_EXE_MARKED_INVALID);
return NULL;
}
PIMAGE_SECTION_HEADER pSectionHeaders
= (PIMAGE_SECTION_HEADER)((PBYTE)pNtHeader
+ sizeof(pNtHeader->Signature)
+ sizeof(pNtHeader->FileHeader)
+ pNtHeader->FileHeader.SizeOfOptionalHeader);
for (DWORD n = 0; n < pNtHeader->FileHeader.NumberOfSections; n++) {
if (strcmp((PCHAR)pSectionHeaders[n].Name, ".detour") == 0) {
if (pSectionHeaders[n].VirtualAddress == 0 ||
pSectionHeaders[n].SizeOfRawData == 0) {
break;
}
PBYTE pbData = (PBYTE)pDosHeader + pSectionHeaders[n].VirtualAddress;
DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pbData;
if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
break;
}
if (pHeader->nDataOffset == 0) {
pHeader->nDataOffset = pHeader->cbHeaderSize;
}
return (PBYTE)pHeader;
}
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
}
SetLastError(ERROR_EXE_MARKED_INVALID);
return NULL;
}
DWORD WINAPI DetourGetSizeOfBinary(PDETOUR_LOADED_BINARY pBinary)
{
__try {
DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pBinary;
if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
SetLastError(ERROR_INVALID_HANDLE);
return 0;
}
return pHeader->cbDataSize;
} __except(EXCEPTION_EXECUTE_HANDLER) {
SetLastError(ERROR_INVALID_HANDLE);
return 0;
}
SetLastError(ERROR_INVALID_HANDLE);
return 0;
}
PBYTE WINAPI DetourFindPayloadInBinary(PDETOUR_LOADED_BINARY pBinary,
REFGUID rguid,
DWORD * pcbData)
{
PBYTE pbData = NULL;
//BUGBUG DWORD cbData = 0;
if (pcbData) {
*pcbData = 0;
}
if (pBinary == NULL) {
pBinary = DetourBinaryFromInstance(NULL);
}
__try {
DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pBinary;
if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
SetLastError(ERROR_INVALID_EXE_SIGNATURE);
return NULL;
}
PBYTE pbBeg = ((PBYTE)pHeader) + pHeader->nDataOffset;
PBYTE pbEnd = ((PBYTE)pHeader) + pHeader->cbDataSize;
for (pbData = pbBeg; pbData < pbEnd;) {
DETOUR_SECTION_RECORD *pSection = (DETOUR_SECTION_RECORD *)pbData;
if (pSection->guid == rguid) {
if (pcbData) {
*pcbData = pSection->cbBytes - sizeof(*pSection);
return (PBYTE)(pSection + 1);
}
}
pbData = (PBYTE)pSection + pSection->cbBytes;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
//////////////////////////////////////////////////////////////////////////////
//
BOOL WINAPI DetourBinaryBindA(PCHAR pszFile, PCHAR pszDll, PCHAR pszPath)
{
if (!LoadImageHlp()) {
SetLastError(ERROR_MOD_NOT_FOUND);
return FALSE;
}
if (s_pfBindImage) {
return (*s_pfBindImage)(pszFile, pszDll ? pszDll : ".", pszPath ? pszPath : ".");
}
SetLastError(ERROR_INVALID_FUNCTION);
return FALSE;
}
static void UnicodeToOem(PWCHAR pwzIn, PCHAR pszOut, INT cbOut)
{
cbOut = WideCharToMultiByte(CP_OEMCP, 0,
pwzIn, lstrlenW(pwzIn),
pszOut, cbOut-1,
NULL, NULL);
pszOut[cbOut] = '\0';
}
BOOL WINAPI DetourBinaryBindW(PWCHAR pwzFile, PWCHAR pwzDll, PWCHAR pwzPath)
{
if (!LoadImageHlp()) {
SetLastError(ERROR_MOD_NOT_FOUND);
return FALSE;
}
CHAR szFile[MAX_PATH];
CHAR szDll[MAX_PATH];
CHAR szPath[MAX_PATH];
UnicodeToOem(pwzFile, szFile, sizeof(szFile));
UnicodeToOem(pwzDll, szDll, sizeof(szDll));
UnicodeToOem(pwzPath, szPath, sizeof(szPath));
if (s_pfBindImage) {
return (s_pfBindImage)(szFile, szDll, szPath);
}
SetLastError(ERROR_INVALID_FUNCTION);
return FALSE;
}
// End of File