Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safely hooking C functions into assembly

I'm trying to put some C hooks into some code that someone else wrote in asm. I don't know much about x86 asm and I want to make sure I'm doing this safely.

So far I've got this much:

EXTERN _C_func

CALL _C_func

And that seems to work, but I'm sure that's dangerous as-is. At the very least it could be destroying EAX, and possibly more.

So I think all I need to know is: Which registers does C destroy and how do I ensure the registers are being saved properly? Is there anything else I can do to make sure I can safely insert hooks into arbitrary locations?

I'm using Visual Studio for the C functions, if that helps. Thank you.

UPDATE:

I looked up the "paranoid" method several people suggested and it looks like this:

pushfd
pushad
call _C_func
popad
popfd

AD = (A)ll general registers

FD = (F)lags

(I'm not sure what the 'd' stands for, but it means 32-bit registers instead of 16-bit.)

But the most efficient method is illustrated in Kragen's answer below. (Assuming you don't need the preserve the flags. If you do, add the FD instructions.)

Also, be careful about allocating lots of stack variables in your C function as it could overrun the asm subroutine's stack space.

I think that about does it, thanks for you help everyone!

like image 706
Jason Avatar asked Apr 24 '26 06:04

Jason


2 Answers

If the calling convention is cdecl and the signature of C_funct is simply:

void C_func(void);

Then that is perfectly "safe", however the registers EAX, ECX and EDX are "available for use inside the function", and so may be overwritten.

To protect against this you can save the registers that you care about and restore them afterwards:

push eax
push ecx
push edx

call _C_func

pop edx
pop ecx
pop eax

By convention the registers EBX, ESI, EDI, and EBP shouldn't be modified by the callee.

I believe that the flags may be modified by the callee - again if you care about preserving the value of flags then you should save them.

See the Wikipedia page on x86 calling conventions.

like image 123
Justin Avatar answered Apr 26 '26 21:04

Justin


You need to be aware of calling conventions. See this article for a discussion on calling conventions.

If you are paranoid about registers, you can always push all registers onto the stack before calling the function (functions shouldn't return without cleaning up, except for those registers that carry return information).

like image 35
Jörgen Sigvardsson Avatar answered Apr 26 '26 19:04

Jörgen Sigvardsson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!