-
May 20th, 2010, 05:07 PM
#1
Inline Assembly
Hi guys. I'm trying to call MessageBoxA from inline assembly using the following code:
Code:
int main(int argc,char* argv[]){
HWND hwnd=0;
char* text="text";
char* cap="caption";
UINT ty=MB_OK;
__asm{
push ty
push cap
push text
push hwnd
call MessageBoxA
};
return 0;
}
This code doesn't work, however. Can you guys offer some assistance?
Thanks.
-
May 20th, 2010, 11:38 PM
#2
Re: Inline Assembly
Code:
__asm
{
push ty
push cap
push text
push hwnd
call dword ptr MessageBoxA
}
Last edited by GeoRanger; May 20th, 2010 at 11:39 PM.
Reason: forgot code tags
-
May 21st, 2010, 12:06 AM
#3
Re: Inline Assembly
If you are interested, or if you find it helpful, I'll show you how to figure that out, as follows:
You and I don't know how to write the assembly code for the call, but the compiler does, so all we need to do is look at what the compiler generates if left to its own devices. To do that start by writing
Code:
int main(int argc,char* argv[])
{
HWND hwnd=0;
char* text="text";
char* cap="caption";
UINT ty=MB_OK;
MessageBoxA(hwnd, text, cap, ty);
return 0;
}
and put a breakpoint on the call to MessageBoxA. When you hit the break, open your dissassembly window to see:
Code:
008613BE mov dword ptr [hwnd],0
char* text="text";
008613C5 mov dword ptr [text],offset string "text" (865810h)
char* cap="caption";
008613CC mov dword ptr [cap],offset string "caption" (865804h)
UINT ty=MB_OK;
008613D3 mov dword ptr [ty],0
MessageBoxA(hwnd, text, cap, ty);
008613DA mov esi,esp
008613DC mov eax,dword ptr [ty]
008613DF push eax
008613E0 mov ecx,dword ptr [cap]
008613E3 push ecx
008613E4 mov edx,dword ptr [text]
008613E7 push edx
008613E8 mov eax,dword ptr [hwnd]
008613EB push eax
008613EC call dword ptr [__imp__MessageBoxA@16 (868338h)]
The extra instructions are because it is a debug build. We need to see what it looks like in a release build. Unfortunately, that's not necessarily as straightforward because no debugging information is available, so the object code will be more difficult to navigate. A slick trick which can be very useful when you need to debug a release build is to insert a manual interrupt. Interrupt 3 is the same interrupt used by DebugBreak. With that, you can both land-on and bracket the code you want to see by doing the following:
Code:
int main(int argc,char* argv[])
{
HWND hwnd=0;
char* text="text";
char* cap="caption";
UINT ty=MB_OK;
__asm int 3
MessageBoxA(hwnd, text, cap, ty);
__asm int 3
return 0;
}
Now just simply run it (as a release build, but either run it out of the debugger, or else attach the debugger to the process after it crashes). When you open the dissassembly window, now you'll see what you need:
Code:
__asm int 3
010C1000 int 3
MessageBoxA(hwnd, text, cap, ty);
010C1001 push 0
010C1003 push offset string "caption" (10C210Ch)
010C1008 push offset string "text" (10C2104h)
010C100D push 0
010C100F call dword ptr [__imp__MessageBoxA@16 (10C20A4h)]
__asm int 3
010C1015 int 3
Now to get the result in my first post, simply substitute your variables back for the (optimized) stack pushes, replace the MessageBoxA symbol, and you've got it.
Last edited by GeoRanger; May 21st, 2010 at 12:15 AM.
Reason: Forgot to mention that all four stack pushes need to be restored to the original variables.
-
May 21st, 2010, 08:12 AM
#4
Re: Inline Assembly
Ahhh, that helps A LOT. And your short dissertation on how to figure it out is much appreciated. I couldn't find any other documentation on how to do it, either on Google or MSDN.
On a side note, would you happen to know why it's a dword ptr call?
Thank you for your time :-D.
-
May 21st, 2010, 08:23 AM
#5
Re: Inline Assembly
Because it's an indirect jump.
A direct jump would require the code segment to affectively change at load time to fixup the jump-to address to the actual API call.
This has as disadvantage:
- The code memorypage needs to change from Readonly to ReadWrite.
- lots and lots of address fixups at load time slowing loading.
The First is the biggest issue, it would mean that a large part of each programs code would end up being private copies, and thus require a lot more memory. Codepages in dlls etc are now all readonly & shared.
So what happens is that there is a single DWORD variable for each API function being called (the import table) holding the address of where the function actually is.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|