flat assembler
Message board for the users of flat assembler.

Index > Windows > SEH + RaiseException: Accessing register values

Author
Thread Post new topic Reply to topic
DimonSoft



Joined: 03 Mar 2010
Posts: 1228
Location: Belarus
DimonSoft 19 Aug 2015, 11:45
The question: Is there an easy (or any) way to access register values from my procedure within SEH handler?

I’m writing a program that uses HeapAlloc/HeapReAlloc/HeapFree stuff in many places, and I’d like to get rid of these test eax, eax / jz .ErrorHandler by using HEAP_GENERATE_EXCEPTIONS flag.

I have a lot of procedures (let’s call them constructors) which have the following form (error checks skipped for explanation purposes):

Code:
Flags = HEAP_ZERO_MEMORY or HEAP_GENERATE_EXCEPTIONS

proc SomeObject.Initialize uses esi edi,\
     Param1, Param2, ...

     invoke  HeapAlloc, [hHeap], Flags, SizeOfObjectInstance
     mov     esi, eax

     invoke  HeapAlloc, [hHeap], Flags, SizeOfField1
     mov     [esi + SomeObject.pField1], eax
     invoke  HeapAlloc, [hHeap], Flags, SizeOfField2
     mov     [esi + SomeObject.pField2], eax

     mov     eax, esi
     ret
endp    


If the 2nd or 3rd memory allocation fails, I’d like to undo previous allocations, i.e. the object construction succeeds only if all the allocations are successful. I know how to do it by checking return values, but, like I said, I’d like to use exceptions to make the normal program flow easier to read.

I’ve written a small test program, and saw that the CONTEXT structure contains values that the registers had inside somewhere inside RaiseException.

Code:
format PE GUI 4.0
entry WinMain

include 'win32w.inc'
include 'encoding\win1251.inc'

section '.code' code readable executable

proc WinMain
     xor        ebx, ebx

     push       .Finally
     push       dword [fs:ebx]
     mov        dword [fs:ebx], esp

     mov        esi, $DEADC0DE
     invoke     RaiseException, ebx, ebx, ebx, ebx

     pop        dword [fs:ebx]
     add        esp, 4
     invoke     ExitProcess, ebx

proc .Finally c,\
     pExcRec, pEstFrame, pCtx, pDispCtx
     mov        eax, [pEstFrame]
     mov        eax, [eax + CONTEXT.Esi]
     xor        eax, eax
     ret
endp
endp

section '.data' data readable writeable

szTest          du      "Test", 0

section '.idata' data import readable writeable

library kernel32, 'kernel32.dll',\
        gdi32,    'gdi32.dll',\
        user32,   'user32.dll'

include 'api\kernel32.inc'
include 'api\gdi32.inc'
include 'api\user32.inc'    


The behaviour is not surprising, but now I have the question: am I right that (in general) there’s no way to access the register values without saving them somewhere in memory (say, on the stack)?
Post 19 Aug 2015, 11:45
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20430
Location: In your JS exploiting you and your system
revolution 19 Aug 2015, 12:06
If you want to restore all the registers to some known state then you can do that in an exception handler. And the natural way to do that is to save the values somewhere in RAM for recovery later. There are no other places you could store such values.

Or maybe I misunderstand your problem?

However I think that a better approach than using exceptions is to make a small macro that wraps the allocate function with the 'test' and 'jz' instructions all in one. In the long term it will save you much hair pulling when you need to debug a problem. Exceptions after the fact can be tricky to diagnose when debugging.
Post 19 Aug 2015, 12:06
View user's profile Send private message Visit poster's website Reply with quote
DimonSoft



Joined: 03 Mar 2010
Posts: 1228
Location: Belarus
DimonSoft 19 Aug 2015, 14:37
revolution wrote:
If you want to restore all the registers to some known state then you can do that in an exception handler. And the natural way to do that is to save the values somewhere in RAM for recovery later. There are no other places you could store such values.

Or maybe I misunderstand your problem?

I guess, you understood it correctly. I just needed a confirmation Smile Thanks.

revolution wrote:
However I think that a better approach than using exceptions is to make a small macro that wraps the allocate function with the 'test' and 'jz' instructions all in one. In the long term it will save you much hair pulling when you need to debug a problem. Exceptions after the fact can be tricky to diagnose when debugging.

Yep, debugging them is quite tricky Sad
Post 19 Aug 2015, 14:37
View user's profile Send private message Visit poster's website Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 19 Aug 2015, 14:50
DimonSoft
Quote:
I’ve written a small test program, and saw that the CONTEXT structure

Your code is not referring to the CONTEXT structure. It incorrectly refers to the establisher frame structure.
Quote:
values that the registers had inside somewhere inside RaiseException

I'm not sure what particular guarantees does RaiseException give at the moment of exception generation, but when calling a function you should be ready that it corrupts eax, ecx and edx. If you want to generate an exception and preserve register values, then you should do int3 or ud2 or whatever other single instruction generating an exception. If you want to process exceptions generated by HeapAlloc, then you should store at least the return pointer (corresponding to the C __except block) in your establisher frame, so that you can put it into the CONTEXT structure before returning ExceptionContinueExecution. Whether you store ebp, ebx, esi and edi depends on the implementation of your function that calls HeapAlloc.

But I'd actually agree with the revolution's remark regarding a different approach.

Quote:
Code:
endp 
endp    

This is not how endp is meant to be used and may result in unwanted effects. There's no support for nested functions in fasm macros.

_________________
Faith is a superposition of knowledge and fallacy
Post 19 Aug 2015, 14:50
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1660
Location: Toronto, Canada
AsmGuru62 19 Aug 2015, 15:26
May I suggest something?.. it is slightly of topic, however...
I noticed that you have a few allocations in a row with a constant sizes passed.
You can improve your code by allocation one block of memory as a sum of sizes and then cutting the block into pieces later on.
This way you would need only one TEST EAX,EAX - something like that:
Code:
        invoke  HeapAlloc, [heap], 0, (sizeOfInstance + sizeOfFld1 + sizeOfFld2)
        test    eax, eax
        jz      .failed_object_allocation

        mov     [ptrObject], eax
        mov     edi, eax

        add     eax, sizeOfInstance
        mov     [edi + Fld1], eax

        add     eax, sizeOfFld1
        mov     [edi + Fld2], eax

        ... successful allocation ...

.failed_object_allocation:

        ... error handling here ...
    

Also, one HeapAlloc call is shorter than three with all parameters - a bonus!
Post 19 Aug 2015, 15:26
View user's profile Send private message Send e-mail Reply with quote
typedef



Joined: 25 Jul 2010
Posts: 2909
Location: 0x77760000
typedef 19 Aug 2015, 18:48
^I like that, but the trouble comes when you have to free any one of the higher bound pointers. You can't, since the headers aren't there. So, you'll have to keep the whole block until you are done with at least the lower bound pointer at mem_block+$00000000
Post 19 Aug 2015, 18:48
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.