1+ #include < stdio.h>
2+ #include < windows.h>
3+ #include < detours.h>
4+ #include < strsafe.h>
5+
6+ // #pragma warning(push)
7+ // #if _MSC_VER > 1400
8+ // #pragma warning(disable:6102 6103) // /analyze warnings
9+ // #endif
10+ // #pragma warning(pop)
11+
12+ // This code verifies that the named DLL has been configured correctly
13+ // to be imported into the target process. DLLs must export a function with
14+ // ordinal #1 so that the import table touch-up magic works.
15+ struct ExportContext
16+ {
17+ BOOL fHasOrdinal1 ;
18+ ULONG nExports;
19+ };
20+
21+ static BOOL CALLBACK ExportCallback (_In_opt_ PVOID pContext,
22+ _In_ ULONG nOrdinal,
23+ _In_opt_ LPCSTR pszSymbol,
24+ _In_opt_ PVOID pbTarget)
25+ {
26+ (void )pContext;
27+ (void )pbTarget;
28+ (void )pszSymbol;
29+
30+ ExportContext *pec = (ExportContext *)pContext;
31+
32+ if (nOrdinal == 1 ) {
33+ pec->fHasOrdinal1 = TRUE ;
34+ }
35+ pec->nExports ++;
36+
37+ return TRUE ;
38+ }
39+
40+ int CDECL main (int argc, char **argv)
41+ {
42+ // find the name of the ini file from the name of our executable
43+ char file_name[4096 ];
44+ GetModuleFileNameA (NULL , file_name, sizeof (file_name) - 4 );
45+
46+ // search for the point where we need to add the '.ini' to the string
47+ size_t pos = strlen (file_name);
48+
49+ if (pos == 0 ) {
50+ printf (" could not determine file name of executable\r\n " );
51+ return 1 ;
52+ } else {
53+ // search for the dot
54+ while (file_name[pos] != ' .' ) {
55+ if (--pos == 0 ) {
56+ // filename contains no dot, wtf fu
57+ printf (" name of executable contains no dot\r\n " );
58+ }
59+ }
60+ }
61+ file_name[pos + 1 ] = ' i' ;
62+ file_name[pos + 2 ] = ' n' ;
63+ file_name[pos + 3 ] = ' i' ;
64+ file_name[pos + 4 ] = ' \0 ' ;
65+
66+ // file_name now contains path to the .ini file
67+ printf (" ini file %s\r\n " , file_name);
68+
69+ // load the name of the exe file from the ini file
70+ char exe_name[4096 ];
71+ exe_name[0 ] = ' \0 ' ;
72+
73+ GetPrivateProfileStringA (
74+ " dll_inject" ,
75+ " exe_file" ,
76+ " " ,
77+ exe_name,
78+ sizeof (exe_name),
79+ file_name
80+ );
81+
82+ if (exe_name[0 ] == ' \0 ' ) {
83+ printf (" could not read %s section [dll_inject] key exe_file\r\n " , file_name);
84+ return 1 ;
85+ } else {
86+ printf (" exe file %s\r\n " , exe_name);
87+ }
88+
89+ // load the name of the dll file from the ini file
90+ char dll_file[4096 ];
91+ dll_file[0 ] = ' \0 ' ;
92+
93+ GetPrivateProfileStringA (
94+ " dll_inject" ,
95+ " dll_file" ,
96+ " " ,
97+ dll_file,
98+ sizeof (dll_file),
99+ file_name
100+ );
101+
102+ if (dll_file[0 ] == ' \0 ' ) {
103+ printf (" could not read %s section [dll_inject] key dll_file\r\n " , file_name);
104+ return 1 ;
105+ } else {
106+ printf (" dll file %s\r\n " , dll_file);
107+ }
108+
109+ STARTUPINFOA si;
110+ PROCESS_INFORMATION pi;
111+ CHAR command_string[4096 ];
112+
113+ ZeroMemory (&si, sizeof (si));
114+ ZeroMemory (&pi, sizeof (pi));
115+ si.cb = sizeof (si);
116+
117+ command_string[0 ] = L' \0 ' ;
118+
119+ argv[0 ] = exe_name;
120+
121+ for (int arg = 0 ; arg < argc; arg++) {
122+ if (strchr (argv[arg], ' ' ) != NULL || strchr (argv[arg], ' \t ' ) != NULL ) {
123+ StringCchCatA (command_string, sizeof (command_string), " \" " );
124+ StringCchCatA (command_string, sizeof (command_string), argv[arg]);
125+ StringCchCatA (command_string, sizeof (command_string), " \" " );
126+ }
127+ else {
128+ StringCchCatA (command_string, sizeof (command_string), argv[arg]);
129+ }
130+
131+ if (arg + 1 < argc) {
132+ StringCchCatA (command_string, sizeof (command_string), " " );
133+ }
134+ }
135+ printf (" start command %s\r\n " , command_string);
136+ DWORD dwFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED;
137+
138+ // save the current directory name
139+ char current_directory[4096 ];
140+ GetCurrentDirectoryA (sizeof (current_directory), current_directory);
141+ printf (" start cwd %s\r\n " , current_directory);
142+
143+ // remove the filename component from the path to our executable
144+ pos = strlen (file_name);
145+ if (pos == 0 ) {
146+ printf (" could not determine file name of executable\r\n " );
147+ return 1 ;
148+ }
149+
150+ // search for the backslash
151+ while (file_name[pos] != ' \\ ' ) {
152+ if (--pos == 0 ) {
153+ // filename contains no backslash
154+ printf (" path to executable contains no backslash\r\n " );
155+ return 1 ;
156+ }
157+ }
158+ // cut the string at the backslash
159+ file_name[pos] = ' \0 ' ;
160+
161+ // cd to the directory of our exe file
162+ if (!SetCurrentDirectoryA (file_name)) {
163+ printf (" could not cd to %s\r\n " , file_name);
164+ }
165+
166+ SetLastError (0 );
167+ char exe_name_full_path[4096 ];
168+ exe_name_full_path[0 ] = ' \0 ' ;
169+ char *file_part = NULL ;
170+ SearchPathA (
171+ NULL ,
172+ exe_name,
173+ " .exe" ,
174+ sizeof (exe_name_full_path),
175+ exe_name_full_path,
176+ &file_part
177+ );
178+
179+ // get the full path of the dll file
180+ char dll_file_full_path[4096 ];
181+
182+ if (!GetFullPathNameA (dll_file, sizeof (dll_file_full_path), dll_file_full_path, NULL )) {
183+ printf (" could not resolve full path of dll file\r\n " );
184+ return 1 ;
185+ } else {
186+ printf (" dll file [full path] %s\r\n " , dll_file_full_path);
187+ }
188+
189+ HMODULE hDll = LoadLibraryExA (dll_file_full_path, NULL , DONT_RESOLVE_DLL_REFERENCES);
190+ if (hDll == NULL ) {
191+ printf (" could not load dll file: %d\r\n " , GetLastError ());
192+ return 1 ;
193+ }
194+
195+ ExportContext ec;
196+ ec.fHasOrdinal1 = FALSE ;
197+ ec.nExports = 0 ;
198+ DetourEnumerateExports (hDll, &ec, ExportCallback);
199+ FreeLibrary (hDll);
200+
201+ if (!ec.fHasOrdinal1 ) {
202+ printf (" dll file does not export ordinal #1\r\n " );
203+ return 1 ;
204+ }
205+
206+ if (exe_name_full_path[0 ] == ' \0 ' ) {
207+ printf (" could not resolve full path of exe name %s\r\n " , exe_name);
208+ return 1 ;
209+ }
210+ printf (" exe file [full path] %s\r\n " , exe_name_full_path);
211+
212+ const char *dll_file_full_path_ptr = (const char *) dll_file_full_path;
213+
214+ if (!DetourCreateProcessWithDllsA (
215+ exe_name_full_path,
216+ command_string,
217+ NULL ,
218+ NULL ,
219+ TRUE ,
220+ dwFlags,
221+ NULL ,
222+ current_directory,
223+ &si,
224+ &pi,
225+ 1 , // one dll file
226+ &dll_file_full_path_ptr,
227+ NULL
228+ )) {
229+ DWORD dwError = GetLastError ();
230+ printf (" DetourCreateProcessWithDllEx failed: %d\r\n " , dwError);
231+ if (dwError == ERROR_INVALID_HANDLE) {
232+ #if DETOURS_64BIT
233+ printf (" withdll.exe: Can't detour a 32-bit target process from a 64-bit parent process.\r\n " );
234+ #else
235+ printf (" withdll.exe: Can't detour a 64-bit target process from a 32-bit parent process.\r\n " );
236+ #endif
237+ }
238+ return 1 ;
239+ }
240+
241+ ResumeThread (pi.hThread );
242+
243+ WaitForSingleObject (pi.hProcess , INFINITE);
244+
245+ DWORD child_process_result = 0 ;
246+ if (!GetExitCodeProcess (pi.hProcess , &child_process_result)) {
247+ printf (" GetExitCodeProcess failed: %d\r\n " , GetLastError ());
248+ return 1 ;
249+ }
250+
251+ return child_process_result;
252+ }
0 commit comments