Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Load an EXE file and run it from memory

Tags:

c#

.net

I'm trying to run an executable from memory such as outlined in this article. I can run any .net/managed exes quite easily. But I cannot run executables such as notepad.exe or calc.exe. How can I get it so I can also run unmanaged exes?

like image 755
Lienau Avatar asked Aug 24 '10 06:08

Lienau


People also ask

Can you run an exe file from command prompt?

Type "start [filename.exe]" into Command Prompt, replacing "filename" with the name of your selected file. Replace "[filename.exe]" with your program's name. This allows you to run your program from the file path.

How do I run a .exe file?

Running EXE Files (Windows) Double-click an EXE file to run it. EXE files are Windows executable files, and are designed to be run as programs. Double-clicking any EXE file will start it.

Can an exe file run on its own?

On Windows e.g. if you store the file in a startup folder or its name in a certain registry key, the OS will execute it. No, an exe cannot be run until it has been clicked or has given admin rights to do that on startup so you're safe until you do anything.


2 Answers

In the case of running .NET executables from memory, the libraries and CLR itself are doing a lot of heavy lifting for you. For native executables like notepad.exe and calc.exe, you'll have to do a lot of manual work to get it to happen. Basically, you have to act like the Windows loader.

There's probably pages of caveats here, but this in-depth article has the steps you need to load a PE wiki, msdn into memory and do the correct rebasing and fixups. Then, you should be able to find the entry point (like in the article) and run it.

If you're really just wanting to run notepad.exe and calc.exe, the easiest way, of course, would be to use Process.Start and run them off disk. Otherwise, if you have an executable embedded as a resource in your process, then the next easiest way would be to just write the contents out to disk in a temporary location (see Path.GetTempFileName) and then execute it from there.

like image 117
Chris Schmich Avatar answered Oct 13 '22 23:10

Chris Schmich


I am not sure but the following code from this thread might be helpful:

using System; using System.Runtime.InteropServices;  /*   * Title: CMemoryExecute.cs  * Description: Runs an EXE in memory using native WinAPI. Very optimized and tiny.  *   * Developed by: affixiate   * Release date: December 10, 2010  * Released on: http://opensc.ws  * Credits:  *          MSDN (http://msdn.microsoft.com)  *          NtInternals (http://undocumented.ntinternals.net)  *          Pinvoke (http://pinvoke.net)  *            * Comments: If you use this code, I require you to give me credits. Don't be a ripper! ;]  */  // ReSharper disable InconsistentNaming public static unsafe class CMemoryExecute {     public struct STARTUPINFO     {         public uint cb;         public string lpReserved;         public string lpDesktop;         public string lpTitle;         public uint dwX;         public uint dwY;         public uint dwXSize;         public uint dwYSize;         public uint dwXCountChars;         public uint dwYCountChars;         public uint dwFillAttribute;         public uint dwFlags;         public short wShowWindow;         public short cbReserved2;         public IntPtr lpReserved2;         public IntPtr hStdInput;         public IntPtr hStdOutput;         public IntPtr hStdError;     }      /// <summary>     /// Runs an EXE (which is loaded in a byte array) in memory.     /// </summary>     /// <param name="exeBuffer">The EXE buffer.</param>     /// <param name="hostProcess">Full path of the host process to run the buffer in.</param>     /// <param name="optionalArguments">Optional command line arguments.</param>     /// <returns></returns>     public static bool Run(byte[] exeBuffer, string hostProcess, string optionalArguments = "")     {         // STARTUPINFO         STARTUPINFO StartupInfo = new STARTUPINFO();         StartupInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;         StartupInfo.wShowWindow = SW_HIDE;          var IMAGE_SECTION_HEADER = new byte[0x28]; // pish         var IMAGE_NT_HEADERS = new byte[0xf8]; // pinh         var IMAGE_DOS_HEADER = new byte[0x40]; // pidh         var PROCESS_INFO = new int[0x4]; // pi         var CONTEXT = new byte[0x2cc]; // ctx          byte* pish;         fixed (byte* p = &IMAGE_SECTION_HEADER[0])             pish = p;          byte* pinh;         fixed (byte* p = &IMAGE_NT_HEADERS[0])             pinh = p;          byte* pidh;         fixed (byte* p = &IMAGE_DOS_HEADER[0])             pidh = p;          byte* ctx;         fixed (byte* p = &CONTEXT[0])             ctx = p;          // Set the flag.         *(uint*)(ctx + 0x0 /* ContextFlags */) = CONTEXT_FULL;          // Get the DOS header of the EXE.         Buffer.BlockCopy(exeBuffer, 0, IMAGE_DOS_HEADER, 0, IMAGE_DOS_HEADER.Length);          /* Sanity check:  See if we have MZ header. */         if (*(ushort*)(pidh + 0x0 /* e_magic */) != IMAGE_DOS_SIGNATURE)             return false;          var e_lfanew = *(int*)(pidh + 0x3c);          // Get the NT header of the EXE.         Buffer.BlockCopy(exeBuffer, e_lfanew, IMAGE_NT_HEADERS, 0, IMAGE_NT_HEADERS.Length);          /* Sanity check: See if we have PE00 header. */         if (*(uint*)(pinh + 0x0 /* Signature */) != IMAGE_NT_SIGNATURE)             return false;          // Run with parameters if necessary.         if (!string.IsNullOrEmpty(optionalArguments))             hostProcess += " " + optionalArguments;          if (!CreateProcess(null, hostProcess, IntPtr.Zero, IntPtr.Zero, false, CREATE_SUSPENDED, IntPtr.Zero, null, ref StartupInfo, PROCESS_INFO))             return false;          var ImageBase = new IntPtr(*(int*)(pinh + 0x34));         NtUnmapViewOfSection((IntPtr)PROCESS_INFO[0] /* pi.hProcess */, ImageBase);         if (VirtualAllocEx((IntPtr)PROCESS_INFO[0] /* pi.hProcess */, ImageBase, *(uint*)(pinh + 0x50 /* SizeOfImage */), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE) == IntPtr.Zero)             Run(exeBuffer, hostProcess, optionalArguments); // Memory allocation failed; try again (this can happen in low memory situations)          fixed (byte* p = &exeBuffer[0])             NtWriteVirtualMemory((IntPtr)PROCESS_INFO[0] /* pi.hProcess */, ImageBase, (IntPtr)p, *(uint*)(pinh + 84 /* SizeOfHeaders */), IntPtr.Zero);          for (ushort i = 0; i < *(ushort*)(pinh + 0x6 /* NumberOfSections */); i++)         {             Buffer.BlockCopy(exeBuffer, e_lfanew + IMAGE_NT_HEADERS.Length + (IMAGE_SECTION_HEADER.Length * i), IMAGE_SECTION_HEADER, 0, IMAGE_SECTION_HEADER.Length);             fixed (byte* p = &exeBuffer[*(uint*)(pish + 0x14 /* PointerToRawData */)])                 NtWriteVirtualMemory((IntPtr)PROCESS_INFO[0] /* pi.hProcess */, (IntPtr)((int)ImageBase + *(uint*)(pish + 0xc /* VirtualAddress */)), (IntPtr)p, *(uint*)(pish + 0x10 /* SizeOfRawData */), IntPtr.Zero);         }          NtGetContextThread((IntPtr)PROCESS_INFO[1] /* pi.hThread */, (IntPtr)ctx);         NtWriteVirtualMemory((IntPtr)PROCESS_INFO[0] /* pi.hProcess */, (IntPtr)(*(uint*)(ctx + 0xAC /* ecx */)), ImageBase, 0x4, IntPtr.Zero);         *(uint*)(ctx + 0xB0 /* eax */) = (uint)ImageBase + *(uint*)(pinh + 0x28 /* AddressOfEntryPoint */);         NtSetContextThread((IntPtr)PROCESS_INFO[1] /* pi.hThread */, (IntPtr)ctx);         NtResumeThread((IntPtr)PROCESS_INFO[1] /* pi.hThread */, IntPtr.Zero);           return true;     }      #region WinNT Definitions      private const uint CONTEXT_FULL = 0x10007;     private const int CREATE_SUSPENDED = 0x4;     private const int MEM_COMMIT = 0x1000;     private const int MEM_RESERVE = 0x2000;     private const int PAGE_EXECUTE_READWRITE = 0x40;     private const ushort IMAGE_DOS_SIGNATURE = 0x5A4D; // MZ     private const uint IMAGE_NT_SIGNATURE = 0x00004550; // PE00      private static short SW_SHOW = 5;     private static short SW_HIDE = 0;     private const uint STARTF_USESTDHANDLES = 0x00000100;     private const uint STARTF_USESHOWWINDOW = 0x00000001;       #region WinAPI     [DllImport("kernel32.dll", SetLastError = true)]     private static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, int[] lpProcessInfo);      [DllImport("kernel32.dll", SetLastError = true)]     private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);      [DllImport("ntdll.dll", SetLastError = true)]     private static extern uint NtUnmapViewOfSection(IntPtr hProcess, IntPtr lpBaseAddress);      [DllImport("ntdll.dll", SetLastError = true)]     private static extern int NtWriteVirtualMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, uint nSize, IntPtr lpNumberOfBytesWritten);      [DllImport("ntdll.dll", SetLastError = true)]     private static extern int NtGetContextThread(IntPtr hThread, IntPtr lpContext);      [DllImport("ntdll.dll", SetLastError = true)]     private static extern int NtSetContextThread(IntPtr hThread, IntPtr lpContext);      [DllImport("ntdll.dll", SetLastError = true)]     private static extern uint NtResumeThread(IntPtr hThread, IntPtr SuspendCount);     #endregion      #endregion } 
like image 25
Sajib Mahmood Avatar answered Oct 13 '22 22:10

Sajib Mahmood