465 lines
13 KiB
C++
Vendored

//////////////////////////////////////////////////////////////////////////////
//
// Detours Test Program (impmunge.cpp of impmunge.exe)
//
// Microsoft Research Detours Package
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#pragma warning(push)
#if _MSC_VER > 1400
#pragma warning(disable:6102 6103) // /analyze warnings
#endif
#include <strsafe.h>
#include <detours.h>
#pragma warning(disable:4091) // empty typedef
#include <imagehlp.h>
#pragma warning(pop)
////////////////////////////////////////////////////////////// Error Messages.
//
VOID AssertMessage(PCSTR szMsg, PCSTR szFile, DWORD nLine)
{
printf("ASSERT(%s) failed in %s, line %ld.", szMsg, szFile, nLine);
}
#define ASSERT(x) \
do { if (!(x)) { AssertMessage(#x, __FILE__, __LINE__); DebugBreak(); }} while (0)
;
//////////////////////////////////////////////////////////////////////////////
//
static BOOLEAN s_fRestore = FALSE;
static BOOLEAN s_fList = TRUE;
static BOOLEAN s_fMunge = FALSE;
static BOOLEAN s_fToSymbols = FALSE;
//////////////////////////////////////////////////////////////////////////////
//
static BOOL CALLBACK ListByway(_In_opt_ PVOID pContext,
_In_opt_ LPCSTR pszFile,
_Outptr_result_maybenull_ LPCSTR *ppszOutFile)
{
(void)pContext;
(void)ppszOutFile;
printf(" byway -------------------------------- %s\n", pszFile ? pszFile : "");
return TRUE;
}
static BOOL CALLBACK ListFile(_In_opt_ PVOID pContext,
_In_ LPCSTR pszOrigFile,
_In_ LPCSTR pszFile,
_Outptr_result_maybenull_ LPCSTR *ppszOutFile)
{
(void)pContext;
(void)ppszOutFile;
printf(" file %-32.32s %-32.32s\n",
pszOrigFile ? pszOrigFile : "",
pszFile ? pszFile : "");
return TRUE;
}
static BOOL CALLBACK ListSymbol(_In_opt_ PVOID pContext,
_In_ ULONG nOrigOrdinal,
_In_ ULONG nOrdinal,
_Out_ ULONG *pnOutOrdinal,
_In_opt_ LPCSTR pszOrigSymbol,
_In_opt_ LPCSTR pszSymbol,
_Outptr_result_maybenull_ LPCSTR *ppszOutSymbol)
{
(void)pContext;
(void)pnOutOrdinal;
(void)ppszOutSymbol;
char szOrig[80];
char szLast[80];
if (pszOrigSymbol == NULL) {
StringCchPrintfA(szOrig, sizeof(szOrig), "#%d", nOrigOrdinal);
pszOrigSymbol = szOrig;
}
if (pszSymbol == NULL) {
StringCchPrintfA(szLast, sizeof(szLast), "#%d", nOrdinal);
pszSymbol = szLast;
}
printf(" symbol %-32.32s %-32.32s\n", pszOrigSymbol, pszSymbol);
return TRUE;
}
static BOOL CALLBACK ListCommit(PVOID pContext)
{
(void)pContext;
printf(" commit\n");
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//
struct MUNGE_STATE
{
BOOL fLastWasByway;
LONG nBywayCount;
CHAR szBuffer[512];
};
static BOOL CALLBACK MungeByway(_In_opt_ PVOID pContext,
_In_opt_ LPCSTR pszFile,
_Outptr_result_maybenull_ LPCSTR *ppszOutFile)
{
MUNGE_STATE *pState = (MUNGE_STATE *)pContext;
printf("|");
if (pState->fLastWasByway) {
return TRUE;
}
pState->fLastWasByway = TRUE;
if (pszFile == NULL) {
StringCchPrintfA(pState->szBuffer, sizeof(pState->szBuffer), "mb_munge_%d.dll", pState->nBywayCount++);
*ppszOutFile = pState->szBuffer;
}
return TRUE;
}
static BOOL CALLBACK MungeFile(_In_opt_ PVOID pContext,
_In_ LPCSTR pszOrigFile,
_In_ LPCSTR pszFile,
_Outptr_result_maybenull_ LPCSTR *ppszOutFile)
{
(void)pszOrigFile;
MUNGE_STATE *pState = (MUNGE_STATE *)pContext;
pState->fLastWasByway = FALSE;
printf("*");
StringCchPrintfA(pState->szBuffer, sizeof(pState->szBuffer), "mf_%s", pszFile);
*ppszOutFile = pState->szBuffer;
return TRUE;
}
static BOOL CALLBACK MungeSymbol(_In_opt_ PVOID pContext,
_In_ ULONG nOrigOrdinal,
_In_ ULONG nOrdinal,
_Out_ ULONG *pnOutOrdinal,
_In_opt_ LPCSTR pszOrigSymbol,
_In_opt_ LPCSTR pszSymbol,
_Outptr_result_maybenull_ LPCSTR *ppszOutSymbol)
{
(void)nOrigOrdinal;
(void)pszOrigSymbol;
MUNGE_STATE *pState = (MUNGE_STATE *)pContext;
pState->fLastWasByway = FALSE;
printf(".");
if (nOrdinal != 0) {
if (s_fToSymbols) {
StringCchPrintfA(pState->szBuffer, sizeof(pState->szBuffer), "mo_%d", (int)nOrdinal);
*pnOutOrdinal = 0;
*ppszOutSymbol = pState->szBuffer;
}
else {
*pnOutOrdinal = 10000 + nOrdinal;
*ppszOutSymbol = NULL;
}
}
else {
StringCchPrintfA(pState->szBuffer, sizeof(pState->szBuffer), "ms_%s", pszSymbol);
*pnOutOrdinal = 0;
*ppszOutSymbol = pState->szBuffer;
}
return TRUE;
}
static BOOL CALLBACK MungeCommit(PVOID pContext)
{
MUNGE_STATE *pState = (MUNGE_STATE *)pContext;
pState->fLastWasByway = FALSE;
printf("\n");
(void)pContext;
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//
static BOOL CALLBACK RestoreByway(_In_opt_ PVOID pContext,
_In_opt_ LPCSTR pszFile,
_Outptr_result_maybenull_ LPCSTR *ppszOutFile)
{
(void)pContext;
(void)pszFile;
*ppszOutFile = NULL;
return TRUE;
}
static BOOL CALLBACK RestoreFile(_In_opt_ PVOID pContext,
_In_ LPCSTR pszOrigFile,
_In_ LPCSTR pszFile,
_Outptr_result_maybenull_ LPCSTR *ppszOutFile)
{
(void)pContext;
(void)pszFile;
*ppszOutFile = pszOrigFile;
return TRUE;
}
static BOOL CALLBACK RestoreSymbol(_In_opt_ PVOID pContext,
_In_ ULONG nOrigOrdinal,
_In_ ULONG nOrdinal,
_Out_ ULONG *pnOutOrdinal,
_In_opt_ LPCSTR pszOrigSymbol,
_In_opt_ LPCSTR pszSymbol,
_Outptr_result_maybenull_ LPCSTR *ppszOutSymbol)
{
(void)pContext;
(void)nOrdinal;
(void)pszSymbol;
*pnOutOrdinal = nOrigOrdinal;
*ppszOutSymbol = pszOrigSymbol;
return TRUE;
}
static BOOL CALLBACK RestoreCommit(PVOID pContext)
{
(void)pContext;
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//
BOOL EditFile(PCHAR pszInput, PCHAR pszOutput)
{
BOOL fGood = TRUE;
HANDLE hOld = INVALID_HANDLE_VALUE;
HANDLE hNew = INVALID_HANDLE_VALUE;
PDETOUR_BINARY pBinary = NULL;
if (pszOutput != NULL) {
printf("%s -> %s:\n", pszInput, pszOutput);
}
else {
printf("%s:\n", pszInput);
}
hOld = CreateFileA(pszInput,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hOld == INVALID_HANDLE_VALUE) {
printf("Couldn't open input file: %s, error: %ld\n",
pszInput, GetLastError());
fGood = FALSE;
goto end;
}
if ((pBinary = DetourBinaryOpen(hOld)) == NULL) {
printf("DetourBinaryOpen failed: %ld\n", GetLastError());
goto end;
}
if (hOld != INVALID_HANDLE_VALUE) {
CloseHandle(hOld);
hOld = INVALID_HANDLE_VALUE;
}
if (s_fRestore) {
if (!DetourBinaryEditImports(pBinary,
NULL,
RestoreByway,
RestoreFile,
RestoreSymbol,
RestoreCommit)) {
printf("DetourBinaryEditImports for munge failed: %ld\n", GetLastError());
}
}
if (s_fMunge) {
MUNGE_STATE state;
state.fLastWasByway = FALSE;
state.nBywayCount = 1;
if (!DetourBinaryEditImports(pBinary,
&state,
MungeByway,
MungeFile,
MungeSymbol,
MungeCommit)) {
printf("DetourBinaryEditImports for munge failed: %ld\n", GetLastError());
}
}
if (s_fList) {
if (!DetourBinaryEditImports(pBinary,
NULL,
ListByway,
ListFile,
ListSymbol,
ListCommit)) {
printf("DetourBinaryEditImports for list failed: %ld\n", GetLastError());
}
}
if (pszOutput != NULL) {
hNew = CreateFileA(pszOutput,
GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hNew == INVALID_HANDLE_VALUE) {
printf("Couldn't open output file: %s, error: %ld\n",
pszOutput, GetLastError());
fGood = FALSE;
goto end;
}
if (!DetourBinaryWrite(pBinary, hNew)) {
printf("DetourBinaryWrite failed: %ld\n", GetLastError());
fGood = FALSE;
}
CloseHandle(hNew);
hNew = INVALID_HANDLE_VALUE;
}
DetourBinaryClose(pBinary);
pBinary = NULL;
if (fGood && pszOutput != NULL) {
if (!BindImageEx(BIND_NO_BOUND_IMPORTS, pszOutput, ".", ".", NULL)) {
printf("Warning: Couldn't bind binary %s: %ld\n", pszOutput, GetLastError());
}
}
end:
if (pBinary) {
DetourBinaryClose(pBinary);
pBinary = NULL;
}
if (hNew != INVALID_HANDLE_VALUE) {
CloseHandle(hNew);
hNew = INVALID_HANDLE_VALUE;
}
if (hOld != INVALID_HANDLE_VALUE) {
CloseHandle(hOld);
hOld = INVALID_HANDLE_VALUE;
}
return fGood;
}
//////////////////////////////////////////////////////////////////////////////
//
void PrintUsage(void)
{
printf("Usage:\n"
" impmunge [options] binary_files\n"
"Options:\n"
" /l : List imports.\n"
" /l- : Don't list imports.\n"
" /m : Munge imports.\n"
" /r : Remove import munges.\n"
" /o:file : Set name of output file; must be include with /m or /r.\n"
" /? : This help screen.\n");
}
//////////////////////////////////////////////////////////////////////// main.
//
int CDECL main(int argc, char **argv)
{
BOOL fNeedHelp = FALSE;
PCHAR pszOutput = NULL;
int arg = 1;
for (; arg < argc && !fNeedHelp; arg++) {
if (argv[arg][0] == '-' || argv[arg][0] == '/') {
CHAR *argn = argv[arg] + 1;
CHAR *argp = argn;
while (*argp && *argp != ':')
argp++;
if (*argp == ':')
*argp++ = '\0';
switch (argn[0]) {
case 'l': // List contents of import table.
case 'L':
s_fList = (argn[1] != '-');
break;
case 'm': // Munge import table.
case 'M':
s_fMunge = (argn[1] != '-');
break;
case 'o': // Set output file name.
case 'O':
pszOutput = argp;
break;
case 'r': // Restore file to unmunged state.
case 'R':
s_fRestore = (argn[1] != '-');
break;
case 's': // Munge ordinals to symbols
case 'S':
s_fToSymbols = true;
break;
case '?': // Help
fNeedHelp = TRUE;
break;
default:
fNeedHelp = TRUE;
printf("Bad argument: %s:%s\n", argn, argp);
break;
}
}
else {
if (!s_fList && !s_fMunge && !s_fRestore) {
fNeedHelp = TRUE;
break;
}
if (pszOutput == NULL && (s_fMunge || s_fRestore)) {
fNeedHelp = TRUE;
break;
}
EditFile(argv[arg], pszOutput);
pszOutput = NULL;
}
}
if (argc == 1) {
fNeedHelp = TRUE;
}
if (fNeedHelp) {
PrintUsage();
return 1;
}
return 0;
}
// End of File