Ok, found it. Need to hook NtCreateUserProcess in ntdll.dll as well, since
cmd.exe apparently uses this instead of the normal CreateProcess family for
creating processes.
Attached is a diff with this hook implemented, have tested it and it works
well, even with command chaining.
--
Robert
On Monday, November 3, 2014 3:59:37 PM UTC+1, Robert Pettersen wrote:
>
> Small followup, seems it doesnt matter if I chain commands or not, using
> cmd.exe to invoke commands will fail to detect output, even tho they
> execute correctly.
>
> * 1) cmd /C gcc -c -o test.o test.c
>
> *** tup errors ***
>
> tup error: Expected to write to file 'test.o' from cmd 20 but didn't
>
>
> Perhaps cmd.exe starts sub-processes in a way we haven't hooked for...
>
>
> And just noticed that one of the debug hooks provide erronous information
> in tup_inject_dll:
>
> DEBUG_HOOK("%s is WOW64: %i\n", GetCommandLineA(), bWow64);
>>
>
> gives you the calling process, witch in most cases is tup.exe, to get the
> name of the process that tup starts up we need
>
> TCHAR buffer[1024];
>
> if (GetModuleFileNameEx(lpProcessInformation->hProcess,0,buffer,1024)){
>
> DEBUG_HOOK("Executable: %s\n", buffer);
>
> }
>
>
>
>
> On Monday, November 3, 2014 2:51:21 PM UTC+1, Robert Pettersen wrote:
>>
>> Hi Mike,
>>
>> 1) See 2)
>>
>> 2) 32bit processes can not inject into 64bit processes. cmd.exe on 64bit
>> windows is a bit of magic, haven't really figured it out. But that was the
>> reason I put have_shell=1 yes. We have a special case where we chain a
>> 32bit compiler with a 64bit compiler, and tup fails to detect output
>> written. But the expected behaviour is achieved.
>>
>> 3) You are right, compiling with the 64bit compiler with the -m32 flag
>> seem to produce the expected output.
>>
>> 4) Think we have to ifdef the entire function, or atleast pepper it
>> somewhat. Wow64 is loading 32bit binaries from 64bit host (yeah, naming is
>> a bit confusing), and the other case is 64bit from 64bit, but as you have
>> seen, the function does not contain a proper loading of 32bit from 32bit.
>> See the attached patch-diff for a suggestion. Have tested it and it seems
>> to work, with the exception of the cmd chaining. Maybe you have better luck
>> now that you know more about it.
>>
>> --
>> Robert
>>
>> On Saturday, November 1, 2014 4:25:22 PM UTC+1, [email protected] wrote:
>>>
>>> Hi Robert, thanks so much for working on this! I think we are fairly
>>> close.
>>>
>>> I've tried to incorporate this patch and produce both the
>>> tup-dllinject.dll (64-bit) and tup-dllinject32.dll from the same tree. To
>>> build binaries from Linux, you'll need both a CONFIG_TUP_MINGW and
>>> CONFIG_TUP_MINGW32 in tup.config:
>>>
>>> CONFIG_TUP_MINGW=x86_64-w64-mingw32
>>> CONFIG_TUP_MINGW32=i686-w64-mingw32
>>>
>>> I have a few questions so far, all pretty inter-related:
>>>
>>> 1) Why did you want to force have_shell=1 in windepfile.c? That causes
>>> many of the tests to fail, so if it is truly necessary I'll have to find a
>>> way to fix those tests (there are many). Or if there is some particular
>>> case that doesn't work without it, I'll want to add a test to check for it
>>> (and possibly fix it a different way)
>>>
>>> 2) Should it be possible to inject the 64-bit DLL into a 64-bit process
>>> from a 32-bit process? For example, if I run "sh -c './64-test.exe'", then
>>> sh (a 32-bit process) gets injected with a 32-bit dll, but 64-test.exe (a
>>> 64-bit process) doesn't get injected. (Whereas if I just run 64-test.exe
>>> directly, it gets injected fine since tup.exe is 64-bit). Is this why you
>>> added have_shell=1 above?
>>>
>>> 3) Am I compiling the dllinjection code correctly? I left in the
>>> @(TUP_32_BIT) code that you had commented out. (To be honest I'm not sure
>>> what it's used for - I can't find the email thread or issue that talks
>>> about it). Specifically, do I need to use both x86_64-w64-mingw32 and
>>> i686-w64-mingw32? Or is there some way with -m64 / -m32 / -somethingelse
>>> that we can just use x86_64-w64-mingw32?
>>>
>>> 4) The 64-bit DLL injection code won't compile with the 32-bit compiler,
>>> since the CONTEXT structure no longer has the .Rip field. I put an #ifdef
>>> around it, but I hit the "Error: Shouldn't be hooking here for the 32-bit
>>> dll" message (something I added to your patch) when using sh -c
>>> './64-test.exe' from question 2). Is there a better way to handle that?
>>>
>>> Hopefully we can get these sorted out & in the master branch soon.
>>>
>>> Thanks again,
>>> -Mike
>>>
>>> On Wed, Aug 6, 2014 at 5:40 AM, Robert Pettersen <[email protected]>
>>> wrote:
>>>
>>>> Hi,
>>>>
>>>> Really sorry about not posting any updates, been swamped with work and
>>>> just got back from vacation. I don't have time to setup a git repo and
>>>> commit the code, means I'll actually have to clean-up and comment the
>>>> code.
>>>> But I have attached a diff between the current origin/HEAD and the changes
>>>> I made to get it working on 64bit host windows. Haven't made any changes
>>>> since the initial work, since it has been stable for our use. Be warned
>>>> tho, I have not tested this on a 32bit host system, it will however
>>>> execute
>>>> 32bit binaries on a 64bit host system.
>>>>
>>>> ~/tup64$ cat tup.config
>>>>
>>>> CONFIG_TUP_MINGW=x86_64-w64-mingw32
>>>>
>>>>
>>>> I can probably answer some questions about the code and help out some
>>>> here on the forum, but I can't guarantee their timelyness. Really swamped
>>>> with work.
>>>>
>>>> Again, really sorry for not posting responses here sooner!
>>>>
>>>> On Monday, March 17, 2014 8:46:22 PM UTC+1, [email protected] wrote:
>>>>
>>>>> On Mon, Mar 17, 2014 at 8:51 AM, Tristan Rybak <[email protected]>
>>>>> wrote:
>>>>>
>>>>>> Hi Mike, Robert,
>>>>>> Any news on a patch for 64bit windows?
>>>>>> I am using the executable attached to first post and it's working
>>>>>> great (very big thanks for that Robert!)
>>>>>> but I'd like to have new features and bugfixes introduced later too
>>>>>> please.
>>>>>> Maybe I could help with integrating the fix into repository somehow?
>>>>>> Regards,
>>>>>> Tristan
>>>>>>
>>>>>
>>>>> Hi Tristan,
>>>>>
>>>>> I don't think I've seen the patch from Robert yet, though maybe I've
>>>>> missed it. I'd be happy to get it included if he's interested in getting
>>>>> it
>>>>> upstream.
>>>>>
>>>>> Thanks,
>>>>> -Mike
>>>>>
>>>> --
>>>> --
>>>> tup-users mailing list
>>>> email: [email protected]
>>>> unsubscribe: [email protected]
>>>> options: http://groups.google.com/group/tup-users?hl=en
>>>> ---
>>>> You received this message because you are subscribed to the Google
>>>> Groups "tup-users" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send
>>>> an email to [email protected].
>>>> For more options, visit https://groups.google.com/d/optout.
>>>>
>>>
>>>
--
--
tup-users mailing list
email: [email protected]
unsubscribe: [email protected]
options: http://groups.google.com/group/tup-users?hl=en
---
You received this message because you are subscribed to the Google Groups
"tup-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
diff --git a/Tuprules.tup b/Tuprules.tup
index 668222d..665457e 100644
--- a/Tuprules.tup
+++ b/Tuprules.tup
@@ -63,7 +63,7 @@ ifeq (@(TUP_MINGW),)
!mingwar = |> |>
else
!mingwcc = |> ^ MINGWCC %f^ @(TUP_MINGW)-gcc -c %f -o %o $(CFLAGS) $(CFLAGS_%f) $(MINGWCFLAGS) |> %B.omingw
-!mingwcc32 = |> ^ MINGW32CC %f^ @(TUP_MINGW32)-gcc -c %f -o %o $(CFLAGS) $(CFLAGS_%f) $(MINGWCFLAGS) |> %B.omingw32
+!mingwcc32 = |> ^ MINGW32CC %f^ @(TUP_MINGW)-gcc -m32 -c %f -o %o $(CFLAGS) $(CFLAGS_%f) $(MINGWCFLAGS) |> %B.omingw32
!mingwar = |> ^ MINGWAR %o^ @(TUP_MINGW)-ar crs %o %f |>
endif
diff --git a/src/compat/win32/wow64.h b/src/compat/win32/wow64.h
index 6ee276c..b213ba0 100644
--- a/src/compat/win32/wow64.h
+++ b/src/compat/win32/wow64.h
@@ -3,7 +3,54 @@
#define WOW64_CONTEXT_i386 0x00010000
#define WOW64_CONTEXT_CONTROL (WOW64_CONTEXT_i386 | __MSABI_LONG(0x00000001))
+#define WOW64_MAXIMUM_SUPPORTED_EXTENSION 512
+#define WOW64_SIZE_OF_80387_REGISTERS 80
+
+#ifdef _WIN64
+typedef struct _WOW64_FLOATING_SAVE_AREA {
+ DWORD ControlWord;
+ DWORD StatusWord;
+ DWORD TagWord;
+ DWORD ErrorOffset;
+ DWORD ErrorSelector;
+ DWORD DataOffset;
+ DWORD DataSelector;
+ BYTE RegisterArea[WOW64_SIZE_OF_80387_REGISTERS];
+ DWORD Cr0NpxState;
+} WOW64_FLOATING_SAVE_AREA, *PWOW64_FLOATING_SAVE_AREA;
+
+typedef struct _WOW64_CONTEXT {
+ DWORD ContextFlags;
+ DWORD Dr0;
+ DWORD Dr1;
+ DWORD Dr2;
+ DWORD Dr3;
+ DWORD Dr6;
+ DWORD Dr7;
+ WOW64_FLOATING_SAVE_AREA FloatSave;
+ DWORD SegGs;
+ DWORD SegFs;
+ DWORD SegEs;
+ DWORD SegDs;
+ DWORD Edi;
+ DWORD Esi;
+ DWORD Ebx;
+ DWORD Edx;
+ DWORD Ecx;
+ DWORD Eax;
+ DWORD Ebp;
+ DWORD Eip;
+ DWORD SegCs;
+ DWORD EFlags;
+ DWORD Esp;
+ DWORD SegSs;
+ BYTE ExtendedRegisters[WOW64_MAXIMUM_SUPPORTED_EXTENSION];
+} WOW64_CONTEXT, *PWOW64_CONTEXT;
+
BOOL WINAPI Wow64GetThreadContext(HANDLE hThread, PWOW64_CONTEXT lpContext);
BOOL WINAPI Wow64SetThreadContext(HANDLE hThread, const WOW64_CONTEXT *lpContext);
#endif
+
+
+#endif
diff --git a/src/dllinject/dllinject.c b/src/dllinject/dllinject.c
index 3b7be54..98a1ec4 100644
--- a/src/dllinject/dllinject.c
+++ b/src/dllinject/dllinject.c
@@ -33,6 +33,7 @@
#ifndef STATUS_SUCCESS
#include <ntstatus.h>
#endif
+#include <winternl.h>
#include <psapi.h>
#include <stdio.h>
#include <string.h>
@@ -329,7 +330,6 @@ typedef BOOL (WINAPI *CreateProcessWithTokenW_t)(
__in LPSTARTUPINFOW lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation);
-typedef void *PIO_STATUS_BLOCK;
typedef NTSTATUS (WINAPI *NtOpenFile_t)(
__out PHANDLE FileHandle,
__in ACCESS_MASK DesiredAccess,
@@ -351,6 +351,21 @@ typedef NTSTATUS (WINAPI *NtCreateFile_t)(
__in PVOID EaBuffer,
__in ULONG EaLength);
+typedef NTSTATUS (WINAPI *NtCreateUserProcess_t)(
+PHANDLE ProcessHandle,
+PHANDLE ThreadHandle,
+ACCESS_MASK ProcessDesiredAccess,
+ACCESS_MASK ThreadDesiredAccess,
+POBJECT_ATTRIBUTES ProcessObjectAttributes,
+POBJECT_ATTRIBUTES ThreadObjectAttributes,
+ULONG ProcessFlags,
+ULONG ThreadFlags,
+PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
+ULONG_PTR CreateInfo,
+ULONG_PTR AttributeList
+);
+
+
typedef int (*access_t)(const char *pathname, int mode);
typedef FILE *(*fopen_t)(const char *path, const char *mode);
typedef int (*rename_t)(const char *oldpath, const char *newpath);
@@ -397,6 +412,7 @@ static CreateProcessWithLogonW_t CreateProcessWithLogonW_orig;
static CreateProcessWithTokenW_t CreateProcessWithTokenW_orig;
static NtCreateFile_t NtCreateFile_orig;
static NtOpenFile_t NtOpenFile_orig;
+static NtCreateUserProcess_t NtCreateUserProcess_orig;
static access_t _access_orig;
static fopen_t fopen_orig;
static rename_t rename_orig;
@@ -725,6 +741,53 @@ out_free:
return rc;
}
+NTSTATUS WINAPI NtCreateUserProcess_hook(PHANDLE ProcessHandle,
+PHANDLE ThreadHandle,
+ACCESS_MASK ProcessDesiredAccess,
+ACCESS_MASK ThreadDesiredAccess,
+POBJECT_ATTRIBUTES ProcessObjectAttributes,
+POBJECT_ATTRIBUTES ThreadObjectAttributes,
+ULONG ProcessFlags,
+ULONG ThreadFlags,
+PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
+ULONG_PTR CreateInfo,
+ULONG_PTR AttributeList)
+{
+
+ NTSTATUS rc = NtCreateUserProcess_orig(ProcessHandle,
+ ThreadHandle, ProcessDesiredAccess,
+ ThreadDesiredAccess,
+ ProcessObjectAttributes,
+ ThreadObjectAttributes,
+ ProcessFlags, ThreadFlags,
+ ProcessParameters,CreateInfo, AttributeList);
+
+ if (rc != STATUS_SUCCESS) {
+ return rc;
+ }
+
+ TCHAR buffer[1024];
+ if (GetModuleFileNameEx(*ProcessHandle,0,buffer,1024)){
+ char *exec = strrchr(buffer, '\\');
+ if (exec == NULL) return rc;
+
+ exec++;
+ if (strncasecmp(exec, "tup32detect.exe", 15) == 0 ||
+ strncasecmp(exec, "mspdbsrv.exe", 12) == 0)
+ return rc;
+
+ DEBUG_HOOK("NtCreateUser: %s\n", buffer);
+
+ PROCESS_INFORMATION processInformation;
+ processInformation.hProcess = *ProcessHandle;
+ processInformation.hThread = *ThreadHandle;
+
+ tup_inject_dll(&processInformation, s_depfilename, s_vardict_file);
+ }
+
+ return rc;
+}
+
BOOL WINAPI DeleteFileA_hook(
__in LPCSTR lpFileName)
{
@@ -1481,6 +1544,7 @@ static struct patch_entry patch_table[] = {
#define MODULE_NAME "ntdll.dll"
HOOK(NtCreateFile),
HOOK(NtOpenFile),
+ HOOK(NtCreateUserProcess),
#undef MODULE_NAME
#define MODULE_NAME "msvcrt.dll"
HOOK(_access),
@@ -2126,12 +2190,18 @@ int tup_inject_dll(
size_t code_size;
DWORD old_protect;
HANDLE process;
- BOOL bWow64 = 0;
+#ifdef _WIN64
+ BOOL bWow64 = 0;
IsWow64Process(lpProcessInformation->hProcess, &bWow64);
+
+ TCHAR buffer[1024];
+ if (GetModuleFileNameEx(lpProcessInformation->hProcess,0,buffer,1024)){
+ DEBUG_HOOK("%s is WOW64: %i\n", buffer, bWow64);
+ }
+
// WOW64
- DEBUG_HOOK("%s is WOW64: %i\n", GetCommandLineA(), bWow64);
if (bWow64) {
remote_thread32_t remote;
@@ -2211,7 +2281,7 @@ int tup_inject_dll(
if( !Wow64SetThreadContext( lpProcessInformation->hThread, &ctx ) )
return -1;
} else {
-#ifdef _WIN64
+#endif
HMODULE kernel32;
remote_thread_t remote;
@@ -2224,7 +2294,11 @@ int tup_inject_dll(
strcat(remote.execdir, execdir);
strcat(remote.dll_name, execdir);
strcat(remote.dll_name, "\\");
+#ifdef _WIN64
strcat(remote.dll_name, "tup-dllinject.dll");
+#else
+ strcat(remote.dll_name, "tup-dllinject32.dll");
+#endif
strcat(remote.func_name, "tup_inject_init");
CONTEXT ctx;
@@ -2233,9 +2307,13 @@ int tup_inject_dll(
return -1;
/* Align code_size to a 16 byte boundary */
+#ifdef _WIN64
code_size = ( (uintptr_t) &remote_end
- (uintptr_t) &remote_stub + 0x0F)
& ~0x0F;
+#else
+ code_size = (sizeof(remote_stub32) + 0x0F) & ~0x0F;
+#endif
DEBUG_HOOK("Injecting dll '%s' '%s' %s' '%s'\n",
@@ -2265,11 +2343,19 @@ int tup_inject_dll(
unsigned char code[code_size];
+#ifdef _WIN64
memcpy( code, &remote_stub, code_size );
*(DWORD*)(code + 0x7) = low32(ctx.Rip);
*(DWORD*)(code + 0xf) = high32(ctx.Rip);
*(DWORD64*)(code + 0x30) = (long long unsigned int)(remote_data + code_size);
*(DWORD64*)(code + 0x3d) = (long long unsigned int)(DWORD_PTR)remote_data + ((DWORD_PTR)&remote_init - (DWORD_PTR)&remote_stub);
+#else
+ memcpy( code, &remote_stub32, code_size );
+ *(DWORD*)(code + 0x1) = ctx.Eip; // Return addr
+ *(DWORD*)(code + 0x8) = (DWORD)((DWORD_PTR)remote_data + code_size); // Arg (ptr to remote (TCB))
+ *(DWORD*)(code + 0xd) = (DWORD)((DWORD_PTR)remote_data + ((DWORD_PTR)&remote_stub32.remote_init - (DWORD_PTR)&remote_stub32)); // Func (ptr to remote_init)
+#endif
+
if (!WriteProcessMemory(process, remote_data, code, code_size, NULL))
return -1;
@@ -2283,15 +2369,18 @@ int tup_inject_dll(
if (!FlushInstructionCache(process, remote_data, code_size + sizeof(remote)))
return -1;
+#ifdef _WIN64
ctx.Rip = (DWORD_PTR)remote_data;
+#else
+ ctx.Eip = (DWORD_PTR)remote_data;
+#endif
+
ctx.ContextFlags = CONTEXT_CONTROL;
if( !SetThreadContext( lpProcessInformation->hThread, &ctx ) )
return -1;
-#else
- DEBUG_HOOK("Error: Shouldn't be hooking here for the 32-bit dll.\n");
- return -1;
-#endif
+#ifdef _WIN64
}
+#endif
return 0;
}