Suspending an application on startup in a sandbox

soup_not

New member
Recently I needed to debug an exe started within a sandbox from the entry point, but it was difficult since Sandboxie restarts it after running. So after googling and not finding any easy solutions, I wrote a Python script to start the application in a suspended state, which allowed me to attach the debugger to the real process and debug it from the start. Maybe someone else will find it useful despite how trivial it seems:

Python:
import ctypes
import os

# Define necessary structures for Windows API
class STARTUPINFO(ctypes.Structure):
    _fields_ = [
        ("cb", ctypes.c_ulong),
        ("lpReserved", ctypes.c_char_p),
        ("lpDesktop", ctypes.c_char_p),
        ("lpTitle", ctypes.c_char_p),
        ("dwX", ctypes.c_ulong),
        ("dwY", ctypes.c_ulong),
        ("dwXSize", ctypes.c_ulong),
        ("dwYSize", ctypes.c_ulong),
        ("dwXCountChars", ctypes.c_ulong),
        ("dwYCountChars", ctypes.c_ulong),
        ("dwFillAttribute", ctypes.c_ulong),
        ("dwFlags", ctypes.c_ulong),
        ("wShowWindow", ctypes.c_ushort),
        ("cbReserved2", ctypes.c_ushort),
        ("lpReserved2", ctypes.POINTER(ctypes.c_ubyte)),
        ("hStdInput", ctypes.c_void_p),
        ("hStdOutput", ctypes.c_void_p),
        ("hStdError", ctypes.c_void_p),
    ]

class PROCESS_INFORMATION(ctypes.Structure):
    _fields_ = [
        ("hProcess", ctypes.c_void_p),
        ("hThread", ctypes.c_void_p),
        ("dwProcessId", ctypes.c_ulong),
        ("dwThreadId", ctypes.c_ulong),
    ]

# Load the Windows API library
kernel32 = ctypes.windll.kernel32

# Constants
CREATE_SUSPENDED = 0x00000004

def run_suspended(path_to_executable):
    si = STARTUPINFO()
    si.cb = ctypes.sizeof(STARTUPINFO)
    pi = PROCESS_INFORMATION()

    # Prepare the command line
    cmd = path_to_executable.encode('ascii')

    # Create the process in a suspended state
    if kernel32.CreateProcessA(
        None,           # lpApplicationName
        cmd,            # lpCommandLine
        None,           # lpProcessAttributes
        None,           # lpThreadAttributes
        False,          # bInheritHandles
        CREATE_SUSPENDED, # dwCreationFlags
        None,           # lpEnvironment
        None,           # lpCurrentDirectory
        ctypes.byref(si),  # lpStartupInfo
        ctypes.byref(pi)   # lpProcessInformation
    ):
        print(f"Process created with PID: {pi.dwProcessId}")
        # Here you can resume the process when you're ready with: kernel32.ResumeThread(pi.hThread)
        # Or use Sandboxie process menu -> Resume
        kernel32.CloseHandle(pi.hProcess)
        kernel32.CloseHandle(pi.hThread)
    else:
        print("Failed to create process.")
        print(ctypes.GetLastError())

# Usage
run_suspended("Calc.exe")
 
Thank you for the code. You can also use the "WaitForDebugger" setting in Sandboxie. It can be helpful for debugging purposes as it allows you to pause the execution of a program until a debugger is attached.
INI:
WaitForDebugger=program.exe
 
Back
Top