// Helpers public static RUNTIME_CHECK CheckAllTheThings(String Launch) { RUNTIME_CHECK rt = new RUNTIME_CHECK(); if (IntPtr.Size == 4) { rt.SwampIs32 = true; } else { rt.SwampIs32 = false; } if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("ProgramFiles(x86)"))) { rt.OSIs32 = false; } else { rt.OSIs32 = true; } bool bExists = File.Exists(Launch); rt.PePathIsValid = bExists; Int16 Arch = GetPeArch(Launch); rt.PeArch = Arch; return(rt); }
// Main logic public static void SpawnTheThing(String Launch, String RealCmdLine, String FakeCmdLine = "") { // Invoke all the checks RUNTIME_CHECK RunTime = CheckAllTheThings(Launch); if (RunTime.PePathIsValid == false) { Console.WriteLine("[!] Invalid PE path specified.."); return; } if (RunTime.PeArch == 0) { Console.WriteLine("[!] Invalid PE image.."); return; } if (RunTime.SwampIs32 && RunTime.PeArch == 0x020b || !RunTime.SwampIs32 && RunTime.PeArch == 0x010b) { Console.WriteLine("[!] SwampThing and target PE architectures do not match.."); return; } // Create the target process SecurityAttributes SecAttrib = new SecurityAttributes(); String CurrentDir = Directory.GetCurrentDirectory(); StartupInfo si = new StartupInfo(); ProcessInformation pi; bool bProc = CreateProcess(Launch, FakeCmdLine, SecAttrib, SecAttrib, false, CreateProcessFlags.CREATE_SUSPENDED, IntPtr.Zero, CurrentDir, si, out pi); if (!bProc) { Console.WriteLine("[!] Process execution failed.."); return; } else { Console.WriteLine("[>] CreateProcess -> Suspended"); } // Get PBI PROCESS_BASIC_INFORMATION CallResult = PBI(pi.hProcess); if (CallResult.PebBaseAddress == IntPtr.Zero) { Console.WriteLine("[!] Failed to aquire PBI"); return; } else { if (RunTime.PeArch == 0x010b) { Console.WriteLine("[+] PE Arch : 32-bit"); } else { Console.WriteLine("[+] PE Arch : 64-bit"); } Console.WriteLine("[+] Process Id : " + CallResult.UniqueProcessId); Console.WriteLine("[+] PEB Base : 0x" + string.Format("{0:X}", (CallResult.PebBaseAddress).ToInt64())); } // Get PEB->(IntPtr)_RTL_USER_PROCESS_PARAMETERS->(UNICODE_STRING)CommandLine Int32 RTL_USER_PROCESS_PARAMETERS; Int32 CommandLine; Int32 ReadSize; if (RunTime.PeArch == 0x010b) { RTL_USER_PROCESS_PARAMETERS = 0x10; CommandLine = 0x40; ReadSize = 0x4; } else { RTL_USER_PROCESS_PARAMETERS = 0x20; CommandLine = 0x70; ReadSize = 0x8; } // We can't acquire a remote PEB lock so we sleep briefly System.Threading.Thread.Sleep(500); // 500ms // Read remote PEB offsets UInt64 ProcParams; IntPtr pProcParams = ReadRemoteMem(pi.hProcess, ((CallResult.PebBaseAddress).ToInt64() + RTL_USER_PROCESS_PARAMETERS), ReadSize); if (ReadSize == 0x4) { ProcParams = (UInt64)Marshal.ReadInt32(pProcParams); } else { ProcParams = (UInt64)Marshal.ReadInt64(pProcParams); } Console.WriteLine("[+] RTL_USER_PROCESS_PARAMETERS : 0x" + string.Format("{0:X}", ProcParams)); UInt64 CmdLineUnicodeStruct = ProcParams + (UInt64)CommandLine; Console.WriteLine("[+] CommandLine : 0x" + string.Format("{0:X}", CmdLineUnicodeStruct)); // Get current CommandLine -> UNICODE_STRING UNICODE_STRING CurrentCmdLineStruct = new UNICODE_STRING(); Int32 UniStructSize = Marshal.SizeOf(CurrentCmdLineStruct); IntPtr pCmdLineStruct = ReadRemoteMem(pi.hProcess, (Int64)CmdLineUnicodeStruct, UniStructSize); CurrentCmdLineStruct = (UNICODE_STRING)Marshal.PtrToStructure(pCmdLineStruct, typeof(UNICODE_STRING)); Console.WriteLine("[+] UNICODE_STRING |-> Len : " + CurrentCmdLineStruct.Length); Console.WriteLine(" |-> MaxLen : " + CurrentCmdLineStruct.MaximumLength); Console.WriteLine(" |-> pBuff : 0x" + string.Format("{0:X}", (UInt64)CurrentCmdLineStruct.Buffer)); // Create replacement CommandLine Console.WriteLine("\n[>] Rewrite -> RTL_USER_PROCESS_PARAMETERS"); // RTL_USER_PROCESS_PARAMETERS unicode string params String WinDir = Environment.GetEnvironmentVariable("windir"); IntPtr uSystemDir = EmitUnicodeString((WinDir + "\\System32")); IntPtr uLaunchPath = EmitUnicodeString(Launch); IntPtr uWindowName = EmitUnicodeString("SwampThing"); IntPtr uRealCmdLine = EmitUnicodeString(" " + RealCmdLine); // Create local RTL_USER_PROCESS_PARAMETERS IntPtr pProcessParams = IntPtr.Zero; uint RtlCreateSuccess = RtlCreateProcessParametersEx(ref pProcessParams, uLaunchPath, uSystemDir, uSystemDir, uRealCmdLine, IntPtr.Zero, uWindowName, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 1); if (RtlCreateSuccess != 0) { Console.WriteLine("[!] Failed to create process parameters"); return; } else { Console.WriteLine("[+] RtlCreateProcessParametersEx : 0x" + string.Format("{0:X}", (UInt64)pProcessParams)); } // Remote map RTL_USER_PROCESS_PARAMETERS Int32 iProcessParamsSize = Marshal.ReadInt32((IntPtr)((Int64)pProcessParams + 4)); IntPtr pRemoteProcessParams = AllocRemoteMem(pi.hProcess, iProcessParamsSize, pProcessParams); Boolean bRemoteWriteSuccess = WriteRemoteMem(pi.hProcess, pProcessParams, pProcessParams, iProcessParamsSize, AllocationProtect.PAGE_READWRITE); if (bRemoteWriteSuccess) { Console.WriteLine("[+] RemoteAlloc : 0x" + string.Format("{0:X}", (UInt64)pRemoteProcessParams)); Console.WriteLine("[+] Size : " + iProcessParamsSize); } else { Console.WriteLine("[!] Failed to allocate custom RTL_USER_PROCESS_PARAMETERS"); return; } // Rewrite the process parameters pointer IntPtr pRewriteProcessParams = Marshal.AllocHGlobal(ReadSize); if (ReadSize == 0x4) { Marshal.WriteInt32(pRewriteProcessParams, (Int32)pProcessParams); } else { Marshal.WriteInt64(pRewriteProcessParams, (Int64)pProcessParams); } bRemoteWriteSuccess = WriteRemoteMem(pi.hProcess, pRewriteProcessParams, (IntPtr)((CallResult.PebBaseAddress).ToInt64() + RTL_USER_PROCESS_PARAMETERS), ReadSize, AllocationProtect.PAGE_READWRITE); if (bRemoteWriteSuccess) { Console.WriteLine("[?] Success, sleeping 500ms.."); } else { Console.WriteLine("[!] Failed to rewrite PEB->pProcessParameters"); return; } // Resume process UInt32 ResumeProc = ResumeThread(pi.hThread); System.Threading.Thread.Sleep(500); // Finally we rewrite the commandline to the fake value Console.WriteLine("\n[>] Reverting RTL_USER_PROCESS_PARAMETERS"); IntPtr uFakeCmdLine = EmitUnicodeString(" " + FakeCmdLine); Console.WriteLine("[+] Local UNICODE_STRING : 0x" + string.Format("{0:X}", (UInt64)uFakeCmdLine)); // Copy unicode buffer to remote process IntPtr pRemoteCmdLine = AllocRemoteMem(pi.hProcess, (Marshal.ReadInt16((IntPtr)((UInt64)uFakeCmdLine + 2)))); // MaxLength if (ReadSize == 0x4) { bRemoteWriteSuccess = WriteRemoteMem(pi.hProcess, (IntPtr)(Marshal.ReadInt32((IntPtr)((UInt64)uFakeCmdLine + 4))), pRemoteCmdLine, (Marshal.ReadInt16(uFakeCmdLine)), AllocationProtect.PAGE_READWRITE); } else { bRemoteWriteSuccess = WriteRemoteMem(pi.hProcess, (IntPtr)(Marshal.ReadInt64((IntPtr)((UInt64)uFakeCmdLine + 8))), pRemoteCmdLine, (Marshal.ReadInt16(uFakeCmdLine)), AllocationProtect.PAGE_READWRITE); } Console.WriteLine("[+] Remote UNICODE_STRING.Buffer : 0x" + string.Format("{0:X}", (UInt64)pRemoteCmdLine)); // Recalculate new RTL_USER_PROCESS_PARAMETERS pProcParams = ReadRemoteMem(pi.hProcess, ((CallResult.PebBaseAddress).ToInt64() + RTL_USER_PROCESS_PARAMETERS), ReadSize); if (ReadSize == 0x4) { ProcParams = (UInt64)Marshal.ReadInt32(pProcParams); } else { ProcParams = (UInt64)Marshal.ReadInt64(pProcParams); } Console.WriteLine("[+] pRTL_USER_PROCESS_PARAMETERS : 0x" + string.Format("{0:X}", ProcParams)); // Rewrite RTL_USER_PROCESS_PARAMETERS->CommandLine => Length, MaxLength, Buffer bRemoteWriteSuccess = WriteRemoteMem(pi.hProcess, uFakeCmdLine, (IntPtr)(ProcParams + (UInt32)CommandLine), 2, AllocationProtect.PAGE_READWRITE); bRemoteWriteSuccess = WriteRemoteMem(pi.hProcess, (IntPtr)((UInt64)uFakeCmdLine + 2), (IntPtr)(ProcParams + (UInt32)CommandLine + 2), 2, AllocationProtect.PAGE_READWRITE); IntPtr pRemoteBuff = Marshal.AllocHGlobal(8); if (ReadSize == 0x4) { Marshal.WriteInt32(pRemoteBuff, (Int32)pRemoteCmdLine); bRemoteWriteSuccess = WriteRemoteMem(pi.hProcess, pRemoteBuff, (IntPtr)(ProcParams + (UInt32)CommandLine + 4), 4, AllocationProtect.PAGE_READWRITE); } else { Marshal.WriteInt64(pRemoteBuff, (Int64)pRemoteCmdLine); bRemoteWriteSuccess = WriteRemoteMem(pi.hProcess, pRemoteBuff, (IntPtr)(ProcParams + (UInt32)CommandLine + 8), 8, AllocationProtect.PAGE_READWRITE); } Console.WriteLine("[?] Success rewrote Len, MaxLen, Buffer.."); }