RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Just starting out? Need help? Post your questions and find answers here.
boyoss
User
User
Posts: 81
Joined: Fri Feb 05, 2016 10:11 am

RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by boyoss »

Hi everyone! :D

I’ve been using a custom RunPE (memory injection) routine in my PureBasic project for years without any issues. It’s basically a method that “wraps” my main executable, asks for a password, and then launches it—just an extra layer of protection. I originally found the code here:
viewtopic.php?p=311116&sid=71318ad4a9f4 ... 91#p311116

Everything was fine on older Windows versions, but ever since upgrading to Windows 24H2, I’m now getting the 0xc0000141 error at launch, and the process never starts. I tried a few tweaks (changing context flags, checking 32/64-bit settings, etc.), but I still get the same error. Has anyone else encountered this problem or found a workaround?

Here’s the code I’m using, which worked great on previous versions:

Code: Select all

Procedure RunPE(lBuff, parameters.s) 
	; http://forums.purebasic.com/english/viewtopic.php?p=311116&sid=71318ad4a9f408ffe97d5eb450eef191#p311116
	Protected *idh.IMAGE_DOS_HEADER  = lBuff 
	Protected *ish.IMAGE_SECTION_HEADERS 
	Protected pi.PROCESS_INFORMATION 
	Protected *inh.IMAGE_NT_HEADERS 
	Protected si.STARTUPINFO 
	Protected lpBaseAddres.l 
	Protected Ctx.CONTEXT 
	Protected Addr.l, RET.l, i.l 
		
	CreateProcess_(#NUL, ProgramFilename() + " " + parameters, #NUL, #NUL, #False, #CREATE_SUSPENDED, #NUL, #NUL, @si, @pi) 
	Ctx\ContextFlags = #CONTEXT_INTEGER 
	If GetThreadContext_(pi\hThread, Ctx) = 0      : Goto EndThread : EndIf 
	
	ReadProcessMemory_(pi\hProcess, Ctx\Ebx + 8, @Addr, 4, #NUL) 
	If ZwUnmapViewOfSection_(Pi\hProcess, Addr)    : Goto EndThread : EndIf 
	If lBuff = 0                                   : Goto EndThread : EndIf 
	
	*inh = lBuff + *idh\e_lfanew 
	
	lpBaseAddres = VirtualAllocEx_(pi\hProcess, *inh\OptionalHeader\ImageBase, *inh\OptionalHeader\SizeOfImage, #MEM_COMMIT | #MEM_RESERVE, #PAGE_EXECUTE_READWRITE) 
	WriteProcessMemory_(pi\hProcess, lpBaseAddres, lBuff, *inh\OptionalHeader\SizeOfHeaders, @ret) 
	*ish = *inh\OptionalHeader + *inh\FileHeader\SizeOfOptionalHeader 
	
	For i = 0 To *inh\FileHeader\NumberOfSections - 1 
		WriteProcessMemory_(pi\hProcess, lpBaseAddres + *ish\ish[i]\VirtualAddress, lBuff + *ish\ish[i]\PointerToRawData, *ish\ish[i]\SizeOfRawData, @ret) 
	Next 
	
	WriteProcessMemory_(pi\hProcess, Ctx\Ebx + 8, @lpBaseAddres, 4, #NUL) 
	Ctx\Eax = lpBaseAddres + *inh\OptionalHeader\AddressOfEntryPoint 
	SetThreadContext_(pi\hThread, Ctx) 
	ResumeThread_(pi\hThread) 
	ProcedureReturn 
	
	EndThread: 
	TerminateProcess_(pi\hProcess, #NUL) 
	CloseHandle_(pi\hThread) 
	CloseHandle_(pi\hProcess) 
EndProcedure


RunPE(?filea, "") 

 
DataSection 
	filea:
	IncludeBinary "C:\Windows\SysWOW64\calc.exe" : end_filea:
EndDataSection

Any suggestions or updated methods to get this running on Windows 24H2? I’d really appreciate any insight. Thank you so much in advance! :)

Cheers,
Joseph
Last edited by boyoss on Thu Jan 23, 2025 10:30 pm, edited 1 time in total.
miso
Enthusiast
Enthusiast
Posts: 409
Joined: Sat Oct 21, 2023 4:06 pm
Location: Hungary

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by miso »

Hello,

try replacing the long variables to integer. Not sure if that's the problem though, but the chances are good.

(the ones that refers to addresses like lpBaseAddres.l )
boyoss
User
User
Posts: 81
Joined: Fri Feb 05, 2016 10:11 am

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by boyoss »

you mean like this? same problem... :( :?

Code: Select all

Procedure RunPE(lBuff.i, parameters.s)

    ; http://forums.purebasic.com/english/viewtopic.php?p=311116&sid=71318ad4a9f408ffe97d5eb450eef191#p311116

    Protected *idh.IMAGE_DOS_HEADER  = lBuff

    Protected *ish.IMAGE_SECTION_HEADERS

    Protected pi.PROCESS_INFORMATION

    Protected *inh.IMAGE_NT_HEADERS

    Protected si.STARTUPINFO

    Protected lpBaseAddres.i

    Protected Ctx.CONTEXT

    Protected Addr.i, RET.i, i.i

        

    CreateProcess_(#NUL, ProgramFilename() + " " + parameters, #NUL, #NUL, #False, #CREATE_SUSPENDED, #NUL, #NUL, @si, @pi)

    Ctx\ContextFlags = #CONTEXT_INTEGER

    If GetThreadContext_(pi\hThread, Ctx) = 0      : Goto EndThread : EndIf

    

    ReadProcessMemory_(pi\hProcess, Ctx\Ebx + 8, @Addr, 4, #NUL)

    If ZwUnmapViewOfSection_(Pi\hProcess, Addr)    : Goto EndThread : EndIf

    If lBuff = 0                                   : Goto EndThread : EndIf

    

    *inh = lBuff + *idh\e_lfanew

    

    lpBaseAddres = VirtualAllocEx_(pi\hProcess, *inh\OptionalHeader\ImageBase, *inh\OptionalHeader\SizeOfImage, #MEM_COMMIT | #MEM_RESERVE, #PAGE_EXECUTE_READWRITE)

    WriteProcessMemory_(pi\hProcess, lpBaseAddres, lBuff, *inh\OptionalHeader\SizeOfHeaders, @ret)

    *ish = *inh\OptionalHeader + *inh\FileHeader\SizeOfOptionalHeader

    

    For i = 0 To *inh\FileHeader\NumberOfSections - 1

        WriteProcessMemory_(pi\hProcess, lpBaseAddres + *ish\ish[i]\VirtualAddress, lBuff + *ish\ish[i]\PointerToRawData, *ish\ish[i]\SizeOfRawData, @ret)

    Next

    

    WriteProcessMemory_(pi\hProcess, Ctx\Ebx + 8, @lpBaseAddres, 4, #NUL)

    Ctx\Eax = lpBaseAddres + *inh\OptionalHeader\AddressOfEntryPoint

    SetThreadContext_(pi\hThread, Ctx)

    ResumeThread_(pi\hThread)

    ProcedureReturn

    

    EndThread:

    TerminateProcess_(pi\hProcess, #NUL)

    CloseHandle_(pi\hThread)

    CloseHandle_(pi\hProcess)

EndProcedure
miso
Enthusiast
Enthusiast
Posts: 409
Joined: Sat Oct 21, 2023 4:06 pm
Location: Hungary

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by miso »

Yes, I meant that. Unfortunately, that was my only guess.
ricardo_sdl
Enthusiast
Enthusiast
Posts: 141
Joined: Sat Sep 21, 2019 4:24 pm

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by ricardo_sdl »

Where exactly you get the eror? When calling CreateProcess_? Your program starts okay without CreateProcess_? Did you try to zero the memory for sti and pi structs (like in this example?
You can check my games at:
https://ricardo-sdl.itch.io/
User avatar
Piero
Addict
Addict
Posts: 863
Joined: Sat Apr 29, 2023 6:04 pm
Location: Italy

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by Piero »

It may also seem a black hat thing, but the most irritating thing is that the term "injection" probably reminds to most of us of far worse stuff…
8)
boyoss
User
User
Posts: 81
Joined: Fri Feb 05, 2016 10:11 am

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by boyoss »

I just want to clarify that my software is a serious, fully legitimate application—it's even certified by Microsoft.
The “injection” reference in my post simply describes how I’m protecting the program in memory, rather than distributing the original, unprotected file.

This is purely a security layer and not related to any malicious behavior or virus development.

Hope that clears things up!
tj1010
Enthusiast
Enthusiast
Posts: 716
Joined: Mon Feb 25, 2013 5:51 pm

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by tj1010 »

Piero wrote: Thu Jan 23, 2025 9:19 pm It may also seem a black hat thing, but the most irritating thing is that the term "injection" probably reminds to most of us of far worse stuff…
8)
99% of malware doesn't manually map pe/elf/mach. Most just do crypter or packer to get past static-sigature AV and the fake HIDS/HIPS; which is most AV regardless of marketing..

If I wanted license protection on something I'd just put TheMida or VMProtect on it and hide the check in VM code. Oreans products explicitly support PB binaries and it's not expensive. Someone talented at cracking would still have to spend hours devirtualizing and fixing hashes and pointers on new code, and since it's not an AAA game they likely won't bother..

I didn't test this, but it's likely breaking relocation, or there is some process-hollowing protection. ASLR and DEP are transparently handled by VirtualAllocEx and the kernel->EPROCESS. Windows 10 and 11 have the same process security and UAC hasn't changed..
User avatar
Piero
Addict
Addict
Posts: 863
Joined: Sat Apr 29, 2023 6:04 pm
Location: Italy

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by Piero »

tj1010 wrote: Thu Jan 23, 2025 10:16 pmASLR and DEP are transparently handled by VirtualAllocEx and the kernel->EPROCESS.
My ignorance about your Egyptian simply makes me hope you will employ your skills for the benefit of us all :wink:
boyoss
User
User
Posts: 81
Joined: Fri Feb 05, 2016 10:11 am

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by boyoss »

Hi everyone,
I got help from DeepSeek AI to prepare an updated version of the RunPE code, but now I'm getting a 0xc00004ac error.

Does anyone know if there's a way to fix this, or should we assume this method simply won't work anymore with recent Windows versions?

Here's the new code I'm trying:

Code: Select all

Procedure RunPE(lBuff, parameters.s)
    ; Define structures
    Protected *idh.IMAGE_DOS_HEADER = lBuff
    Protected *inh.IMAGE_NT_HEADERS
    Protected *ish.IMAGE_SECTION_HEADER
    Protected pi.PROCESS_INFORMATION
    Protected si.STARTUPINFO
    Protected lpBaseAddress.l
    Protected Ctx.CONTEXT
    Protected Addr.l, RET.l, i.l

    ; Initialize STARTUPINFO structure
    ZeroMemory_(@si, SizeOf(STARTUPINFO))
    si\cb = SizeOf(STARTUPINFO)

    ; Create a suspended process
    If CreateProcess_(#NUL, ProgramFilename(), #NUL, #NUL, #False, #CREATE_SUSPENDED, #NUL, #NUL, @si, @pi) = 0
        Debug "CreateProcess failed: " + Str(GetLastError_())
        ProcedureReturn #False
    EndIf

    ; Set context flags and get thread context
    Ctx\ContextFlags = #CONTEXT_FULL
    If GetThreadContext_(pi\hThread, @Ctx) = 0
        Debug "GetThreadContext failed: " + Str(GetLastError_())
        TerminateProcess_(pi\hProcess, 0)
        CloseHandle_(pi\hThread)
        CloseHandle_(pi\hProcess)
        ProcedureReturn #False
    EndIf

    ; Read the base address of the target process
    If ReadProcessMemory_(pi\hProcess, Ctx\Ebx + 8, @Addr, 4, #NUL) = 0
        Debug "ReadProcessMemory failed: " + Str(GetLastError_())
        TerminateProcess_(pi\hProcess, 0)
        CloseHandle_(pi\hThread)
        CloseHandle_(pi\hProcess)
        ProcedureReturn #False
    EndIf

    ; Get the NT headers
    *inh = lBuff + *idh\e_lfanew

    ; Allocate memory in the target process (let Windows choose the base address)
    lpBaseAddress = VirtualAllocEx_(pi\hProcess, #Null, *inh\OptionalHeader\SizeOfImage, #MEM_COMMIT | #MEM_RESERVE, #PAGE_EXECUTE_READWRITE)
    If lpBaseAddress = 0
        Debug "VirtualAllocEx failed: " + Str(GetLastError_())
        TerminateProcess_(pi\hProcess, 0)
        CloseHandle_(pi\hThread)
        CloseHandle_(pi\hProcess)
        ProcedureReturn #False
    EndIf

    ; Write the headers to the target process
    If WriteProcessMemory_(pi\hProcess, lpBaseAddress, lBuff, *inh\OptionalHeader\SizeOfHeaders, @RET) = 0
        Debug "WriteProcessMemory (headers) failed: " + Str(GetLastError_())
        TerminateProcess_(pi\hProcess, 0)
        CloseHandle_(pi\hThread)
        CloseHandle_(pi\hProcess)
        ProcedureReturn #False
    EndIf

    ; Write each section to the target process
    *ish = lBuff + *idh\e_lfanew + SizeOf(IMAGE_NT_HEADERS)
    For i = 0 To *inh\FileHeader\NumberOfSections - 1
        If WriteProcessMemory_(pi\hProcess, lpBaseAddress + *ish\VirtualAddress, lBuff + *ish\PointerToRawData, *ish\SizeOfRawData, @RET) = 0
            Debug "WriteProcessMemory (section " + Str(i) + ") failed: " + Str(GetLastError_())
            TerminateProcess_(pi\hProcess, 0)
            CloseHandle_(pi\hThread)
            CloseHandle_(pi\hProcess)
            ProcedureReturn #False
        EndIf
        *ish + SizeOf(IMAGE_SECTION_HEADER)
    Next

    ; Update the base address in the target process
    If WriteProcessMemory_(pi\hProcess, Ctx\Ebx + 8, @lpBaseAddress, 4, #NUL) = 0
        Debug "WriteProcessMemory (base address) failed: " + Str(GetLastError_())
        TerminateProcess_(pi\hProcess, 0)
        CloseHandle_(pi\hThread)
        CloseHandle_(pi\hProcess)
        ProcedureReturn #False
    EndIf

    ; Set the entry point
    Ctx\Eax = lpBaseAddress + *inh\OptionalHeader\AddressOfEntryPoint

    ; Set the thread context
    If SetThreadContext_(pi\hThread, @Ctx) = 0
        Debug "SetThreadContext failed: " + Str(GetLastError_())
        TerminateProcess_(pi\hProcess, 0)
        CloseHandle_(pi\hThread)
        CloseHandle_(pi\hProcess)
        ProcedureReturn #False
    EndIf

    ; Load required dependencies manually (example: kernel32.dll)
    Protected hKernel32 = LoadLibrary_("kernel32.dll")
    If hKernel32 = 0
        Debug "Failed to load kernel32.dll"
        TerminateProcess_(pi\hProcess, 0)
        CloseHandle_(pi\hThread)
        CloseHandle_(pi\hProcess)
        ProcedureReturn #False
    EndIf

    ; Resume the thread
    If ResumeThread_(pi\hThread) = -1
        Debug "ResumeThread failed: " + Str(GetLastError_())
        TerminateProcess_(pi\hProcess, 0)
        CloseHandle_(pi\hThread)
        CloseHandle_(pi\hProcess)
        ProcedureReturn #False
    EndIf

    ; Close handles
    CloseHandle_(pi\hThread)
    CloseHandle_(pi\hProcess)

    Debug "Process executed successfully"
    ProcedureReturn #True
EndProcedure

; Example usage
RunPE(?filea, "")

DataSection
    filea:
    IncludeBinary "C:\Windows\SysWOW64\calc.exe"
    end_filea:
EndDataSection
tj1010
Enthusiast
Enthusiast
Posts: 716
Joined: Mon Feb 25, 2013 5:51 pm

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by tj1010 »

This worked on 11 24H2 64bit with all security disabled. I'm not sure what feature breaks it I didn't want to reboot and test a lot..

Code: Select all

Procedure RunPE(lBuff, parameters.s)
  Protected *idh.IMAGE_DOS_HEADER  = lBuff 
  Protected *ish.IMAGE_SECTION_HEADERS 
  Protected pi.PROCESS_INFORMATION 
  Protected *inh.IMAGE_NT_HEADERS 
  Protected si.STARTUPINFO 
  Protected lpBaseAddres.l 
  Protected Ctx.CONTEXT 
  Protected Addr.l, RET.l, i.l
  If CreateProcess_(#NUL,ProgramFilename()+" "+parameters,#NUL,#NUL,#False,#CREATE_SUSPENDED,#NUL,#NUL, @si, @pi)
    Ctx\ContextFlags = #CONTEXT_INTEGER 
    If GetThreadContext_(pi\hThread, Ctx)
      If ReadProcessMemory_(pi\hProcess, Ctx\Rcx+8, @Addr, 4, #NUL)
        If ZwUnmapViewOfSection_(Pi\hProcess, Addr)
          If lBuff > 0
            *inh = lBuff+*idh\e_lfanew
            lpBaseAddres = VirtualAllocEx_(pi\hProcess, *inh\OptionalHeader\ImageBase, *inh\OptionalHeader\SizeOfImage, #MEM_COMMIT | #MEM_RESERVE, #PAGE_EXECUTE_READWRITE) 
            WriteProcessMemory_(pi\hProcess, lpBaseAddres, lBuff, *inh\OptionalHeader\SizeOfHeaders, @ret) 
            *ish = *inh\OptionalHeader + *inh\FileHeader\SizeOfOptionalHeader 
            For i = 0 To *inh\FileHeader\NumberOfSections - 1 
              WriteProcessMemory_(pi\hProcess, lpBaseAddres + *ish\ish[i]\VirtualAddress, lBuff + *ish\ish[i]\PointerToRawData, *ish\ish[i]\SizeOfRawData, @ret) 
            Next 
            WriteProcessMemory_(pi\hProcess, Ctx\Rcx+8, @lpBaseAddres, 4, #NUL) 
            Ctx\Rdx = lpBaseAddres + *inh\OptionalHeader\AddressOfEntryPoint 
            SetThreadContext_(pi\hThread, Ctx) 
            ResumeThread_(pi\hThread) 
            ProcedureReturn
          Else
            TerminateProcess_(pi\hProcess, #NUL)
            CloseHandle_(pi\hThread) 
            CloseHandle_(pi\hProcess)
            MessageRequester("Error","lBuff Empty")
          EndIf
        Else
          TerminateProcess_(pi\hProcess, #NUL)
          CloseHandle_(pi\hThread) 
          CloseHandle_(pi\hProcess)
          MessageRequester("Error","ZwUnmapViewOfSection Failed")
        EndIf
      Else
        TerminateProcess_(pi\hProcess, #NUL)
        CloseHandle_(pi\hThread) 
        CloseHandle_(pi\hProcess)
        MessageRequester("Error","ReadProcessMemory Failed")
      EndIf
    Else
      TerminateProcess_(pi\hProcess, #NUL)
      CloseHandle_(pi\hThread) 
      CloseHandle_(pi\hProcess)
      MessageRequester("Error","GetThreadContext Failed")
    EndIf
  Else
    MessageRequester("Error","Process Failed To Launch")
  EndIf
EndProcedure
boyoss
User
User
Posts: 81
Joined: Fri Feb 05, 2016 10:11 am

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by boyoss »

ok i'm checking thank you
tj1010
Enthusiast
Enthusiast
Posts: 716
Joined: Mon Feb 25, 2013 5:51 pm

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by tj1010 »

I found out the MEM_PRIVATE to MEM_IMAGE change in the windows loader broke RunPE in 24H2. There are around four other methods to run memory resident code via CreateProcess->VirtualAllocEX, though. You can also hook a call in ntdll to disable to check for MEM_IMAGE.

I use to have code to map a exe without CreateProcess using host process PID but I lost it on a SSD that went bad. These other methods are just based around process hollowing.

There is also a way with PowerShell that I never looked in to that doesn't need a new PID, and of course with a driver by manipulating EPROCESS or memory injection.
boyoss
User
User
Posts: 81
Joined: Fri Feb 05, 2016 10:11 am

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by boyoss »

Thank you.
If you provide me a working code i'll pay you 100 dollars..
breeze4me
Enthusiast
Enthusiast
Posts: 633
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: RunPE No Longer Works on Windows 24H2 (0xc0000141 Error) – Need Help :)

Post by breeze4me »

I haven't seen that code yet, but here's an interesting link.
https://github.com/hasherezade/libpeconv/issues/59
https://github.com/hasherezade/libpeconv
Locked