I'm currently reversing file that is packed with PECompact packer. I'm interested in actual algorithm how it unpacks itself rather than having unpacked file.

It uses SEH for modifying program flow. So I would like to ask about SEH.

So what I have: Step 1

So I add breakpoint at 0x4517E4 after I pass exception into app I go here

enter image description here

It does some code modifications and returns 0 (ExceptionContinueExecution from EXCEPTION_DISPOSITION enum). It returns to kernel function, but where should execution be continued from, after it goes back into app? I have tried putting breakpoint at 0x401016 because it is a point where exception occurred and it stopped there, I would like to ask if this is just a coincidence, or it should work this way?

I believe it is related to EXCEPTION_RECORD structure ExceptionAddress value. Am I right?

So that I really want to know how exception handling determines point, from which program execution should be continued according to different return values from handler function.

Also file I'm working on can be downloaded here

  • and the reason for doing this according to the author - to prevent anti-malware software from seeing the unpacking code and reporting false positives. The problem is that we can emulate right through the SEH and still see the unpacker code. Nov 3, 2015 at 16:15
  • @peterferrie didn't knew that, and it sound like "anti anti-malware". But ye it is very simple to reach unpacking stub.
    – ST3
    Nov 4, 2015 at 7:18

2 Answers 2


I think this is a great moment to introduce you to this great article written back in 1997, but which still holds up. I really recommend that you read it because it will explain to you everything about SEH. To answer your question about continuing execution, I will quote one paragraph from the article:

When the operating system sees that ExceptionContinueExecution was returned, it interprets this to mean that you've fixed the problem and the faulting instruction should be restarted. Since my _except_handler function tweaked the EAX register to point to valid memory, the MOV EAX,1 instruction works the second time and function main continues normally. See, that wasn't so complicated, was it?

MOV     EAX, F0450569
LEA     ECX, DWORD PTR DS:[EAX+1000129E]   ;  ecx will be 00451807
MOV     DWORD PTR DS:[ECX+1], EAX          ;  451808 will hold f0450569
MOV     EDX, DWORD PTR SS:[ESP+4]          ;  ExceptionRecord
MOV     EDX, DWORD PTR DS:[EDX+C]          ;  ExceptionRecord->ExceptionAddress == 401016
MOV     BYTE PTR DS:[EDX], 0E9             ;  byte@exceptionAddress to e9 five byte jump
ADD     EDX, 5                             ;  ExceptionAddress+5 ==40101b
SUB     ECX, EDX                           ;  451807-edx = 507ec
MOV     DWORD PTR DS:[EDX-4], ECX          ;  assembles jmp 507ec @exception address
XOR     EAX, EAX                           ;  retn 0 == exception has been handled
RETN                                       ; 401016 == jmp 507ec instead of mov [eax],ecx

since the exception handler does not modify the eip but changes the opcodes of old eip you will end up executing the same old eip
pure coincidence
normally you should check ContextRecord->Eip before exiting from seh handler this contains the eip that will be executed upon retun from kernel check [[ESP+C]+0XB8] on the retn to see the Context->Eip in seh handler

you can also set a breakpoint in ntdll.NtContinue this is the function that crosses the um->km boundary on seh exit
when hit you can set a bp on CONTEXT->Eip ( xxx* + 0xb8 on x86 32 bit)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.