aboutsummaryrefslogtreecommitdiffhomepage
path: root/samples/withdll/withdll.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'samples/withdll/withdll.cpp')
-rw-r--r--samples/withdll/withdll.cpp540
1 files changed, 540 insertions, 0 deletions
diff --git a/samples/withdll/withdll.cpp b/samples/withdll/withdll.cpp
new file mode 100644
index 0000000..4704573
--- /dev/null
+++ b/samples/withdll/withdll.cpp
@@ -0,0 +1,540 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// Test DetourCreateProcessWithDll function (withdll.cpp).
+//
+// Microsoft Research Detours Package
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+#include <stdio.h>
+#include <windows.h>
+#include <detours.h>
+#pragma warning(push)
+#if _MSC_VER > 1400
+#pragma warning(disable:6102 6103) // /analyze warnings
+#endif
+#include <strsafe.h>
+#pragma warning(pop)
+
+//////////////////////////////////////////////////////////////////////////////
+//
+void PrintUsage(void)
+{
+ printf("Usage:\n"
+ " withdll.exe [options] [command line]\n"
+ "Options:\n"
+ " /d:file.dll : Start the process with file.dll.\n"
+ " /v : Verbose, display memory at start.\n"
+ " /? : This help screen.\n");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// This code verifies that the named DLL has been configured correctly
+// to be imported into the target process. DLLs must export a function with
+// ordinal #1 so that the import table touch-up magic works.
+//
+struct ExportContext
+{
+ BOOL fHasOrdinal1;
+ ULONG nExports;
+};
+
+static BOOL CALLBACK ExportCallback(_In_opt_ PVOID pContext,
+ _In_ ULONG nOrdinal,
+ _In_opt_ LPCSTR pszSymbol,
+ _In_opt_ PVOID pbTarget)
+{
+ (void)pContext;
+ (void)pbTarget;
+ (void)pszSymbol;
+
+ ExportContext *pec = (ExportContext *)pContext;
+
+ if (nOrdinal == 1) {
+ pec->fHasOrdinal1 = TRUE;
+ }
+ pec->nExports++;
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+
+//////////////////////////////////////////////////////////////////////////////
+//
+
+void TypeToString(DWORD Type, char *pszBuffer, size_t cBuffer)
+{
+ if (Type == MEM_IMAGE) {
+ StringCchPrintfA(pszBuffer, cBuffer, "img");
+ }
+ else if (Type == MEM_MAPPED) {
+ StringCchPrintfA(pszBuffer, cBuffer, "map");
+ }
+ else if (Type == MEM_PRIVATE) {
+ StringCchPrintfA(pszBuffer, cBuffer, "pri");
+ }
+ else {
+ StringCchPrintfA(pszBuffer, cBuffer, "%x", Type);
+ }
+}
+
+void StateToString(DWORD State, char *pszBuffer, size_t cBuffer)
+{
+ if (State == MEM_COMMIT) {
+ StringCchPrintfA(pszBuffer, cBuffer, "com");
+ }
+ else if (State == MEM_FREE) {
+ StringCchPrintfA(pszBuffer, cBuffer, "fre");
+ }
+ else if (State == MEM_RESERVE) {
+ StringCchPrintfA(pszBuffer, cBuffer, "res");
+ }
+ else {
+ StringCchPrintfA(pszBuffer, cBuffer, "%x", State);
+ }
+}
+
+void ProtectToString(DWORD Protect, char *pszBuffer, size_t cBuffer)
+{
+ if (Protect == 0) {
+ StringCchPrintfA(pszBuffer, cBuffer, "");
+ }
+ else if (Protect == PAGE_EXECUTE) {
+ StringCchPrintfA(pszBuffer, cBuffer, "--x");
+ }
+ else if (Protect == PAGE_EXECUTE_READ) {
+ StringCchPrintfA(pszBuffer, cBuffer, "r-x");
+ }
+ else if (Protect == PAGE_EXECUTE_READWRITE) {
+ StringCchPrintfA(pszBuffer, cBuffer, "rwx");
+ }
+ else if (Protect == PAGE_EXECUTE_WRITECOPY) {
+ StringCchPrintfA(pszBuffer, cBuffer, "rcx");
+ }
+ else if (Protect == PAGE_NOACCESS) {
+ StringCchPrintfA(pszBuffer, cBuffer, "---");
+ }
+ else if (Protect == PAGE_READONLY) {
+ StringCchPrintfA(pszBuffer, cBuffer, "r--");
+ }
+ else if (Protect == PAGE_READWRITE) {
+ StringCchPrintfA(pszBuffer, cBuffer, "rw-");
+ }
+ else if (Protect == PAGE_WRITECOPY) {
+ StringCchPrintfA(pszBuffer, cBuffer, "rc-");
+ }
+ else if (Protect == (PAGE_GUARD | PAGE_EXECUTE)) {
+ StringCchPrintfA(pszBuffer, cBuffer, "g--x");
+ }
+ else if (Protect == (PAGE_GUARD | PAGE_EXECUTE_READ)) {
+ StringCchPrintfA(pszBuffer, cBuffer, "gr-x");
+ }
+ else if (Protect == (PAGE_GUARD | PAGE_EXECUTE_READWRITE)) {
+ StringCchPrintfA(pszBuffer, cBuffer, "grwx");
+ }
+ else if (Protect == (PAGE_GUARD | PAGE_EXECUTE_WRITECOPY)) {
+ StringCchPrintfA(pszBuffer, cBuffer, "grcx");
+ }
+ else if (Protect == (PAGE_GUARD | PAGE_NOACCESS)) {
+ StringCchPrintfA(pszBuffer, cBuffer, "g---");
+ }
+ else if (Protect == (PAGE_GUARD | PAGE_READONLY)) {
+ StringCchPrintfA(pszBuffer, cBuffer, "gr--");
+ }
+ else if (Protect == (PAGE_GUARD | PAGE_READWRITE)) {
+ StringCchPrintfA(pszBuffer, cBuffer, "grw-");
+ }
+ else if (Protect == (PAGE_GUARD | PAGE_WRITECOPY)) {
+ StringCchPrintfA(pszBuffer, cBuffer, "grc-");
+ }
+ else {
+ StringCchPrintfA(pszBuffer, cBuffer, "%x", Protect);
+ }
+}
+
+typedef union
+{
+ struct
+ {
+ DWORD Signature;
+ IMAGE_FILE_HEADER FileHeader;
+ } ih;
+
+ IMAGE_NT_HEADERS32 ih32;
+ IMAGE_NT_HEADERS64 ih64;
+} IMAGE_NT_HEADER;
+
+struct SECTIONS
+{
+ PBYTE pbBeg;
+ PBYTE pbEnd;
+ CHAR szName[16];
+} Sections[256];
+DWORD SectionCount = 0;
+DWORD Bitness = 0;
+
+PCHAR FindSectionName(PBYTE pbBase, PBYTE& pbEnd)
+{
+ for (DWORD n = 0; n < SectionCount; n++) {
+ if (Sections[n].pbBeg == pbBase) {
+ pbEnd = Sections[n].pbEnd;
+ return Sections[n].szName;
+ }
+ }
+ pbEnd = NULL;
+ return NULL;
+}
+
+ULONG PadToPage(ULONG Size)
+{
+ return (Size & 0xfff)
+ ? Size + 0x1000 - (Size & 0xfff)
+ : Size;
+}
+
+BOOL GetSections(HANDLE hp, PBYTE pbBase)
+{
+ DWORD beg = 0;
+ DWORD cnt = 0;
+ SIZE_T done;
+ IMAGE_DOS_HEADER idh;
+
+ if (!ReadProcessMemory(hp, pbBase, &idh, sizeof(idh), &done) || done != sizeof(idh)) {
+ return FALSE;
+ }
+
+ if (idh.e_magic != IMAGE_DOS_SIGNATURE) {
+ return FALSE;
+ }
+
+ IMAGE_NT_HEADER inh;
+ if (!ReadProcessMemory(hp, pbBase + idh.e_lfanew, &inh, sizeof(inh), &done) || done != sizeof(inh)) {
+ printf("No Read\n");
+ return FALSE;
+ }
+
+ if (inh.ih.Signature != IMAGE_NT_SIGNATURE) {
+ printf("No NT\n");
+ return FALSE;
+ }
+
+ beg = idh.e_lfanew
+ + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader )
+ + inh.ih.FileHeader.SizeOfOptionalHeader;
+ cnt = inh.ih.FileHeader.NumberOfSections;
+ Bitness = (inh.ih32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) ? 32 : 64;
+#if 0
+ printf("%d %d count=%d\n", beg, Bitness, cnt);
+#endif
+
+ IMAGE_SECTION_HEADER ish;
+ for (DWORD n = 0; n < cnt; n++) {
+ if (!ReadProcessMemory(hp, pbBase + beg + n * sizeof(ish), &ish, sizeof(ish), &done) || done != sizeof(ish)) {
+ printf("No Read\n");
+ return FALSE;
+ }
+ Sections[n].pbBeg = pbBase + ish.VirtualAddress;
+ Sections[n].pbEnd = pbBase + ish.VirtualAddress + PadToPage(ish.Misc.VirtualSize);
+ memcpy(Sections[n].szName, ish.Name, sizeof(ish.Name));
+ Sections[n].szName[sizeof(ish.Name)] = '\0';
+#if 0
+ printf("--- %p %s\n", Sections[n].pbBeg, Sections[n].szName);
+#endif
+ }
+ SectionCount = cnt;
+
+ return TRUE;
+}
+
+BOOL DumpProcess(HANDLE hp)
+{
+ ULONG64 base;
+ ULONG64 next;
+
+ MEMORY_BASIC_INFORMATION mbi;
+
+ printf(" %12s %8s %8s: %3s %3s %4s %3s : %8s\n", "Address", "Offset", "Size", "Typ", "Sta", "Prot", "Ini", "Contents");
+ printf(" %12s %8s %8s: %3s %3s %4s %3s : %8s\n", "------------", "--------", "--------", "---", "---", "----", "---", "-----------------");
+
+ for (next = 0;;) {
+ base = next;
+ ZeroMemory(&mbi, sizeof(mbi));
+ if (VirtualQueryEx(hp, (PVOID)base, &mbi, sizeof(mbi)) == 0) {
+ break;
+ }
+ if ((mbi.RegionSize & 0xfff) == 0xfff) {
+ break;
+ }
+
+ next = (ULONG64)mbi.BaseAddress + mbi.RegionSize;
+
+ if (mbi.State == MEM_FREE) {
+ continue;
+ }
+
+ CHAR szType[16];
+ TypeToString(mbi.Type, szType, ARRAYSIZE(szType));
+ CHAR szState[16];
+ StateToString(mbi.State, szState, ARRAYSIZE(szState));
+ CHAR szProtect[16];
+ ProtectToString(mbi.Protect, szProtect, ARRAYSIZE(szProtect));
+ CHAR szAllocProtect[16];
+ ProtectToString(mbi.AllocationProtect, szAllocProtect, ARRAYSIZE(szAllocProtect));
+
+ CHAR szFile[MAX_PATH];
+ szFile[0] = '\0';
+ DWORD cb = 0;
+ PCHAR pszFile = szFile;
+
+ if (base == (ULONG64)mbi.AllocationBase) {
+#if 0
+ cb = pfGetMappedFileName(hp, (PVOID)mbi.AllocationBase, szFile, ARRAYSIZE(szFile));
+#endif
+ if (GetSections(hp, (PBYTE)mbi.AllocationBase)) {
+ next = base + 0x1000;
+ StringCchPrintfA(szFile, ARRAYSIZE(szFile), "%d-bit PE", Bitness);
+ }
+ }
+ if (cb > 0) {
+ for (DWORD c = 0; c < cb; c++) {
+ szFile[c] = (szFile[c] >= 'a' && szFile[c] <= 'z')
+ ? szFile[c] - 'a' + 'A' : szFile[c];
+ }
+ szFile[cb] = '\0';
+ }
+
+ if ((pszFile = strrchr(szFile, '\\')) == NULL) {
+ pszFile = szFile;
+ }
+ else {
+ pszFile++;
+ }
+
+ PBYTE pbEnd;
+ PCHAR pszSect = FindSectionName((PBYTE)base, pbEnd);
+ if (pszSect != NULL) {
+ pszFile = pszSect;
+ if (next > (ULONG64)pbEnd) {
+ next = (ULONG64)pbEnd;
+ }
+ }
+
+ CHAR szDesc[128];
+ ZeroMemory(&szDesc, ARRAYSIZE(szDesc));
+ if (base == (ULONG64)mbi.AllocationBase) {
+ StringCchPrintfA(szDesc, ARRAYSIZE(szDesc), " %12I64x %8I64x %8I64x: %3s %3s %4s %3s : %s",
+ (ULONG64)base,
+ (ULONG64)base - (ULONG64)mbi.AllocationBase,
+ (ULONG64)next - (ULONG64)base,
+ szType,
+ szState,
+ szProtect,
+ szAllocProtect,
+ pszFile);
+
+
+ }
+ else {
+ StringCchPrintfA(szDesc, ARRAYSIZE(szDesc), " %12s %8I64x %8I64x: %3s %3s %4s %3s : %s",
+ "-",
+ (ULONG64)base - (ULONG64)mbi.AllocationBase,
+ (ULONG64)next - (ULONG64)base,
+ szType,
+ szState,
+ szProtect,
+ szAllocProtect,
+ pszFile);
+ }
+ printf("%s\n", szDesc);
+ }
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////// main.
+//
+int CDECL main(int argc, char **argv)
+{
+ BOOLEAN fNeedHelp = FALSE;
+ BOOLEAN fVerbose = FALSE;
+ LPCSTR rpszDllsRaw[256];
+ LPCSTR rpszDllsOut[256];
+ DWORD nDlls = 0;
+
+ for (DWORD n = 0; n < ARRAYSIZE(rpszDllsRaw); n++) {
+ rpszDllsRaw[n] = NULL;
+ rpszDllsOut[n] = NULL;
+ }
+
+ int arg = 1;
+ for (; arg < argc && (argv[arg][0] == '-' || argv[arg][0] == '/'); arg++) {
+
+ CHAR *argn = argv[arg] + 1;
+ CHAR *argp = argn;
+ while (*argp && *argp != ':' && *argp != '=')
+ argp++;
+ if (*argp == ':' || *argp == '=')
+ *argp++ = '\0';
+
+ switch (argn[0]) {
+ case 'd': // Set DLL Name
+ case 'D':
+ if (nDlls < ARRAYSIZE(rpszDllsRaw)) {
+ rpszDllsRaw[nDlls++] = argp;
+ }
+ else {
+ printf("withdll.exe: Too many DLLs.\n");
+ fNeedHelp = TRUE;
+ break;
+ }
+ break;
+
+ case 'v': // Verbose
+ case 'V':
+ fVerbose = TRUE;
+ break;
+
+ case '?': // Help
+ fNeedHelp = TRUE;
+ break;
+
+ default:
+ fNeedHelp = TRUE;
+ printf("withdll.exe: Bad argument: %s\n", argv[arg]);
+ break;
+ }
+ }
+
+ if (arg >= argc) {
+ fNeedHelp = TRUE;
+ }
+
+ if (nDlls == 0) {
+ fNeedHelp = TRUE;
+ }
+
+ if (fNeedHelp) {
+ PrintUsage();
+ return 9001;
+ }
+
+ /////////////////////////////////////////////////////////// Validate DLLs.
+ //
+ for (DWORD n = 0; n < nDlls; n++) {
+ CHAR szDllPath[1024];
+ PCHAR pszFilePart = NULL;
+
+ if (!GetFullPathNameA(rpszDllsRaw[n], ARRAYSIZE(szDllPath), szDllPath, &pszFilePart)) {
+ printf("withdll.exe: Error: %s is not a valid path name..\n",
+ rpszDllsRaw[n]);
+ return 9002;
+ }
+
+ DWORD c = (DWORD)strlen(szDllPath) + 1;
+ PCHAR psz = new CHAR [c];
+ StringCchCopyA(psz, c, szDllPath);
+ rpszDllsOut[n] = psz;
+
+ HMODULE hDll = LoadLibraryExA(rpszDllsOut[n], NULL, DONT_RESOLVE_DLL_REFERENCES);
+ if (hDll == NULL) {
+ printf("withdll.exe: Error: %s failed to load (error %ld).\n",
+ rpszDllsOut[n],
+ GetLastError());
+ return 9003;
+ }
+
+ ExportContext ec;
+ ec.fHasOrdinal1 = FALSE;
+ ec.nExports = 0;
+ DetourEnumerateExports(hDll, &ec, ExportCallback);
+ FreeLibrary(hDll);
+
+ if (!ec.fHasOrdinal1) {
+ printf("withdll.exe: Error: %s does not export ordinal #1.\n",
+ rpszDllsOut[n]);
+ printf(" See help entry DetourCreateProcessWithDllEx in Detours.chm.\n");
+ return 9004;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ STARTUPINFOA si;
+ PROCESS_INFORMATION pi;
+ CHAR szCommand[2048];
+ CHAR szExe[1024];
+ CHAR szFullExe[1024] = "\0";
+ PCHAR pszFileExe = NULL;
+
+ ZeroMemory(&si, sizeof(si));
+ ZeroMemory(&pi, sizeof(pi));
+ si.cb = sizeof(si);
+
+ szCommand[0] = L'\0';
+
+ StringCchCopyA(szExe, sizeof(szExe), argv[arg]);
+ for (; arg < argc; arg++) {
+ if (strchr(argv[arg], ' ') != NULL || strchr(argv[arg], '\t') != NULL) {
+ StringCchCatA(szCommand, sizeof(szCommand), "\"");
+ StringCchCatA(szCommand, sizeof(szCommand), argv[arg]);
+ StringCchCatA(szCommand, sizeof(szCommand), "\"");
+ }
+ else {
+ StringCchCatA(szCommand, sizeof(szCommand), argv[arg]);
+ }
+
+ if (arg + 1 < argc) {
+ StringCchCatA(szCommand, sizeof(szCommand), " ");
+ }
+ }
+ printf("withdll.exe: Starting: `%s'\n", szCommand);
+ for (DWORD n = 0; n < nDlls; n++) {
+ printf("withdll.exe: with `%s'\n", rpszDllsOut[n]);
+ }
+ fflush(stdout);
+
+ DWORD dwFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED;
+
+ SetLastError(0);
+ SearchPathA(NULL, szExe, ".exe", ARRAYSIZE(szFullExe), szFullExe, &pszFileExe);
+ if (!DetourCreateProcessWithDllsA(szFullExe[0] ? szFullExe : NULL, szCommand,
+ NULL, NULL, TRUE, dwFlags, NULL, NULL,
+ &si, &pi, nDlls, rpszDllsOut, NULL)) {
+ DWORD dwError = GetLastError();
+ printf("withdll.exe: DetourCreateProcessWithDllEx failed: %ld\n", dwError);
+ if (dwError == ERROR_INVALID_HANDLE) {
+#if DETOURS_64BIT
+ printf("withdll.exe: Can't detour a 32-bit target process from a 64-bit parent process.\n");
+#else
+ printf("withdll.exe: Can't detour a 64-bit target process from a 32-bit parent process.\n");
+#endif
+ }
+ ExitProcess(9009);
+ }
+
+ if (fVerbose) {
+ DumpProcess(pi.hProcess);
+ }
+
+ ResumeThread(pi.hThread);
+
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ DWORD dwResult = 0;
+ if (!GetExitCodeProcess(pi.hProcess, &dwResult)) {
+ printf("withdll.exe: GetExitCodeProcess failed: %ld\n", GetLastError());
+ return 9010;
+ }
+
+ for (DWORD n = 0; n < nDlls; n++) {
+ if (rpszDllsOut[n] != NULL) {
+ delete[] rpszDllsOut[n];
+ rpszDllsOut[n] = NULL;
+ }
+ }
+
+ return dwResult;
+}
+//
+///////////////////////////////////////////////////////////////// End of File.