├── .gitignore ├── Makefile ├── README.md └── inject.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: inject.exe 2 | 3 | inject.exe: inject.c 4 | cl /nologo /Fe$@ $< 5 | @rm inject.obj 6 | 7 | clean: 8 | rm -f inject.exe 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Inject 2 | 3 | Inject is a tool which injects an ordered list of shared libraries into the address space of a binary executable. The created process is initially suspended, and resumes execution once the ordered list of shared libraries have been loaded into its address space, and their respective DllMain functions have finished executing. 4 | 5 | ## Usage 6 | 7 | ``` 8 | $ inject EXE [DLL...] 9 | ``` 10 | 11 | ## Examples 12 | 13 | ``` 14 | $ inject a.exe b.dll c.dll 15 | ``` 16 | 17 | Order of execution: 18 | 19 | 1. Create a suspended process of `a.exe`. 20 | 2. Load `b.dll` into the address space of `a.exe`. 21 | 3. Execute the `DllMain` function of `b.dll`. 22 | 4. Load `c.dll` into the address space of `a.exe`. 23 | 5. Execute the `DllMain` function of `d.dll`. 24 | 6. Resume execution of `a.exe`. 25 | 26 | ## Credits 27 | 28 | Inject was greatly inspired by Risc's use of DLL-injection in [diablo-improvements](https://github.com/r1sc/diablo-improvements). 29 | 30 | ## Public domain 31 | 32 | The source code and any original content of this repository is hereby released into the [public domain]. 33 | 34 | [public domain]: https://creativecommons.org/publicdomain/zero/1.0/ 35 | -------------------------------------------------------------------------------- /inject.c: -------------------------------------------------------------------------------- 1 | // Inject is a tool which injects an ordered list of shared libraries into the 2 | // address space of a binary executable. The created process is initially 3 | // suspended, and resumes execution once the ordered list of shared libraries 4 | // have been loaded into its address space, and their respective DllMain 5 | // functions have finished executing. 6 | // 7 | // Usage 8 | // 9 | // $ inject EXE [DLL...] 10 | // 11 | // Examples 12 | // 13 | // $ inject a.exe b.dll c.dll 14 | // 15 | // Order of execution: 16 | // 17 | // 1. Creates a suspended process of "a.exe". 18 | // 2. Loads "b.dll" into the address space of "a.exe". 19 | // 3. Executes the "DllMain" function of "b.dll". 20 | // 4. Loads "c.dll" into the address space of "a.exe". 21 | // 5. Executes the "DllMain" function of "d.dll". 22 | // 6. Resumes execution of "a.exe". 23 | #include 24 | #include 25 | 26 | int main(int argc, char **argv) { 27 | int i, len; 28 | char *exe_path, *lib_path; 29 | void *page; 30 | STARTUPINFO si = {0}; 31 | PROCESS_INFORMATION pi = {0}; 32 | HANDLE hThread; 33 | 34 | // Print usage. 35 | if (argc < 2) { 36 | fprintf(stderr, "Usage: inject EXE [DLL...]\n"); 37 | fprintf(stderr, "Inject an ordered list of shared libraries into the address space of a binary executable.\n"); 38 | return 1; 39 | } 40 | 41 | // Execute the process in suspended mode. 42 | exe_path = argv[1]; 43 | si.cb = sizeof(STARTUPINFO); 44 | if (!CreateProcess(NULL, exe_path, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { 45 | fprintf(stderr, "CreateProcess(\"%s\") failed; error code = 0x%08X\n", exe_path, GetLastError()); 46 | return 1; 47 | } 48 | 49 | // Allocate a page in memory for the arguments of LoadLibrary. 50 | page = VirtualAllocEx(pi.hProcess, NULL, MAX_PATH, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); 51 | if (page == NULL) { 52 | fprintf(stderr, "VirtualAllocEx failed; error code = 0x%08X\n", GetLastError()); 53 | return 1; 54 | } 55 | 56 | // Inject the ordered list of shared libraries into the address space of the 57 | // process. 58 | for (i = 2; i < argc; i++) { 59 | // Verify path length. 60 | lib_path = argv[i]; 61 | len = strlen(lib_path) + 1; 62 | if (len > MAX_PATH) { 63 | fprintf(stderr, "path length (%d) exceeds MAX_PATH (%d).\n", len, MAX_PATH); 64 | return 1; 65 | } 66 | if (GetFileAttributes(lib_path) == INVALID_FILE_ATTRIBUTES) { 67 | fprintf(stderr, "unable to locate library (%s).\n", lib_path); 68 | return 1; 69 | } 70 | 71 | // Write library path to the page used for LoadLibrary arguments. 72 | if (WriteProcessMemory(pi.hProcess, page, lib_path, len, NULL) == 0) { 73 | fprintf(stderr, "WriteProcessMemory failed; error code = 0x%08X\n", GetLastError()); 74 | return 1; 75 | } 76 | 77 | // Inject the shared library into the address space of the process, 78 | // through a call to LoadLibrary. 79 | hThread = CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) LoadLibraryA, page, 0, NULL); 80 | if (hThread == NULL) { 81 | fprintf(stderr, "CreateRemoteThread failed; error code = 0x%08X\n", GetLastError()); 82 | return 1; 83 | } 84 | 85 | // Wait for DllMain to return. 86 | if (WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) { 87 | fprintf(stderr, "WaitForSingleObject failed; error code = 0x%08X\n", GetLastError()); 88 | return 1; 89 | } 90 | 91 | // Cleanup. 92 | CloseHandle(hThread); 93 | } 94 | 95 | // Resume the execution of the process, once all libraries have been injected 96 | // into its address space. 97 | if (ResumeThread(pi.hThread) == -1) { 98 | fprintf(stderr, "ResumeThread failed; error code = 0x%08X\n", GetLastError()); 99 | return 1; 100 | } 101 | 102 | // Cleanup. 103 | CloseHandle(pi.hProcess); 104 | VirtualFreeEx(pi.hProcess, page, MAX_PATH, MEM_RELEASE); 105 | return 0; 106 | } 107 | --------------------------------------------------------------------------------