////////////////////////////////////////////////////////////////////////////// // // Detours Test Program (impmunge.cpp of impmunge.exe) // // Microsoft Research Detours Package // // Copyright (c) Microsoft Corporation. All rights reserved. // #include #include #include #pragma warning(push) #if _MSC_VER > 1400 #pragma warning(disable:6102 6103) // /analyze warnings #endif #include #include #pragma warning(disable:4091) // empty typedef #include #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