Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I raise an exception in an asm block?

I want to raise an exception in a X64 asm block.

Lets assume I have a function like so:

function Example(Values: array of integer): integer;
asm
  or rcx,rcx
  jz @error
  ....

I know I can just read the pointer and get a AV, however I want to raise a more descriptive error.

I could make an additional function and call that one:

asm
  or rcx,rcx
  jz @error
  ....
@error:
  mov ecx, 1
  mov rdx, ErrorString
  jmp RaiseError
  ....

function RaiseError(code: integer; const Msg: string);
begin
  case code of
    1: raise EEmptyArrayError.Create(Msg);

However the error will then occur outside the function in which is was caused. How do I get the exception to (seem to) originate from inside the Example function.

Note that this is X64, so all the SEH answers that apply to X86 are no good because X64 uses VEH.

like image 784
Johan Avatar asked Sep 28 '22 06:09

Johan


1 Answers

The full syntax of raise is:

raise Exception at address  

All you need to do is to pass the current IP as a parameter and the error proc can pass that on to the exception.

You can get the RIP using lea rax, [rip].

Thus the code becomes:

asm
  or rcx,rcx
  jz @error
  ....
@error:
  mov ecx, 1
  mov rdx, ErrorString
  lea r8,[rip]
  jmp RaiseError 
  ....

function RaiseError(code: integer; const Msg: string; address: pointer);
begin
  case code of
    1: raise EEmptyArrayError.Create(Msg) at address;

Of course in this case it's easier to use

function RaiseError(code: integer; const Msg: string);
begin
  case code of
    1: raise EEmptyArrayError.Create(Msg) at ReturnAddress;

Note
In this case if you keep the jmp the error will seem to originate from the calling routine, in this case that's actually correct. If you want the exception to point the guilty finger at your asm code then use a call.

like image 105
Johan Avatar answered Dec 08 '22 19:12

Johan