465 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			465 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | //  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
 |