Jump to content
Tuts 4 You

change PE header in suspended process


Recommended Posts

It's possible to create suspended process, change for example entrypoint and  when resumed it would start from changed EP?


I have a non-working executable(wrong EP) idea is to modify PE header but only when it's loaded in memory. I used WriteProcessMemory api to write correct EP to header but when resumed, process crashes. 

WriteProcessMemory returns success, so problem must be somewhere else. Is it too late to modify header when the process is suspended?


thanx in andvance

Edited by JustAGuy
Link to comment

I had to google process hollowing to find out what it is, but no, I do not try to replace one process with another, but to create loader which modifies a few PE header values in memory in order for process to work

Link to comment

it works, you did something wrong


It means you created suspended process changed EP in memory , resumed process and it started form new EP?

Link to comment

yes it works, sorry I got something wrong, you must set entrypoint with SetThreadContext

Edited by Aguila
Link to comment

You can debug any process right after its first APC delivery, using: windbg.exe -xe ld:ntdll.dll YourExeName
Text below is result of debugging notepad on XP SP3 x86, 5 years ago :medieval: :When process A creates a normal process B:
After A called CreateProcess() and kernel did all the magic, kernel uses APC to call B's ntdll!LdrInitializeThunk and to transfer the execution to B.Windows uses ntdll!KiUserApcDispatcher (of process B) as the reciever of the APC. Kernel sets the KiUAD()'s stack contents.KiUserApcDispatcher(
  IN PVOID                Unused1,
  IN PVOID                Unused2,
  IN PVOID                Unused3,
  IN PVOID                ContextStart,
  IN PVOID                ContextBody);Unused1 = 7C901166 -> ntdll!LdrInitializeThunk -> it's "Used" here ;)
Unused2 = 00000000
Unused3 = 7c900000
ContextStart = 00000000
ContextBody = 17 00 01 00 -> Beginning of a context structure which is on the stack.ntdll!KiUserApcDispatcher() loads ContextBody's stack pointer into edi for using it after popping the ntdll!LdrInitializeThunk() address (Unused1) into eax and calling it for initialization.ntdll!KiUserApcDispatcher:
lea     edi,[esp+10h -> ContextBody]
pop     eax -> ntdll!LdrInitializeThunk() address = Unused1
call    eax -> Stepping over this will generate the debugger's first break-exception (int3). ntdll!LdrInitializeThunk() does not change the eip and eax of ContextBody structure.
push    1
push    edi
call    ntdll!ZwContinueThen KiUAD() calls ntdll!ZwContinue(edi -> ContextBody, TRUE)NtContinue(
  IN PCONTEXT             ThreadContext,
  IN BOOLEAN              RaiseAlert );Inside the ContextBody structure:
   +0x000 ContextFlags     : 0x10017
   +0x09c Edi              : 0xa4f6ee
   +0x0a0 Esi              : 0xa4f718
   +0x0a4 Ebx              : 0x7ffdd000
   +0x0a8 Edx              : 0x30
   +0x0ac Ecx              : 0x20fa685
   +0x0b0 Eax              : 0x100739d -> the real entrypoint of the process
   +0x0b4 Ebp              : 0
   +0x0b8 Eip              : 0x7c810735 -> This is where the execution resumes and is address of kernel32!BaseProcessStartThunk:
   +0x0bc SegCs            : 0x1b
   +0x0c0 EFlags           : 0x300
   +0x0c4 Esp              : 0x7fffc -> sets esp to top of the stack
xor     ebp,ebp
push    eax -> pushes the real entrypoint of the process
push    0
jmp     kernel32!BaseProcessStart
push    0Ch
push    offset kernel32!`string'+0x98
call    kernel32!_SEH_prolog
and     dword ptr [ebp-4],0
push    4
lea     eax,[ebp+8]
push    eax
push    9 -> _THREAD_INFORMATION_CLASS->ThreadQuerySetWin32StartAddress
push    0FFFFFFFEh
call    dword ptr [kernel32!_imp__NtSetInformationThread -> Sets the thread strart address (_ETHREAD->Win32StartAddress) to it's real one
call    dword ptr [ebp+8] -> Calls the real entrypoint.
push    eax -> Real entrypoint returned..
call    kernel32!ExitThread -> .. exit this thread.Real entrypoint is inside the ContextBody->Eax and kernel fills the ContextBody before the APC call.For a suspended process B, kernel does not automatically call ntdll!LdrInitializeThunk() via APC.

I guess you can remotely install a hook (without dll) on ntdll!ZwContinue to change the real EP (ContextBody->Eax) into any address you want.



@ Aguila:

On XP SP3 x86, Set/GetThreadContext doesn't work with a new suspended processes. (attachment)


When I break on KiUAD() with Windbg, before ZwContinue, trying to set a hardware breakpoint shows this error:


on ntdll!KiUserApcDispatcher+0x4 (pop     eax):

-ba ntdll!KiUserApcDispatcher
        ^ Unable to set breakpoint error
The system resets thread contexts after the process breakpoint so hardware breakpoints cannot be set. Go to the executable's entry point and set it then.



Please correct me if i'm wrong.


Link to comment

works on all operating systems


GetThreadContext(PI.hThread, &ctx);
ctx->Eax = pImageBase + AddressOfEntryPoint;
SetThreadContext(PI.hThread, &ctx);

  • Like 2
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Create New...