对Win32 API调用在组装中的工作方式感到困惑 [英] Confusion with how Win32 API calls work in assembly

查看:70
本文介绍了对Win32 API调用在组装中的工作方式感到困惑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不知道如何更好地提出这个问题,但是为什么这样做:

call ExitProcess

与此相同吗?:

mov eax, ExitProcess
mov eax, [eax]
call eax

我认为这些是等效的:

call ExitProcess


mov eax, ExitProcess
call eax

解决方案

从DLL导入代码时,符号ExitProcess实际上不是退出进程的代码地址(它是地址地址).因此,在这种情况下,必须取消引用它才能获取实际的代码地址.

这意味着您必须使用:

call [ExitProcess]

调用它.

例如,在


但是,直接在用户代码中导入DLL并不是获得该功能的唯一方法.我将在下面解释为什么您同时看到两种方式.

调用DLL函数的正常"方法是先将其标记为extern,然后从DLL中将其标记为import:

extern ExitProcess
import ExitProcess kernel32.dll
:
call [ExitProcess]

由于将符号设置为对代码的间接引用,因此需要间接调用它.

经过一番搜索后,似乎出现了 is 代码,它们使用裸露的形式:

call ExitProcess

据我所知,这似乎都使用了alink链接程序,该链接程序与win32.lib库文件链接.该库可能提供了用于调用 actual DLL代码的存根,例如:

import ExitProcessActual kernel32.dll ExitProcess
global ExitProcess

ExitProcess:
    jmp [ExitProcessActual]

nasm中,这将从DLL导入ExitProcess的地址并称为ExitProcessActual,请记住,该地址是对代码的间接引用,而不是代码本身的地址. /p>

然后它将导出ExitProcess入口点(此LIB文件中的一个,而不是DLL中的一个),以便其他人可以使用它.

然后有人可以简单地写:

extern ExitProcess
:
call ExitProcess

退出该过程-库将跳转到实际的DLL代码.


事实上,经过更多的研究,这确实是确切的.从alink下载随附的alink.txt文件中:

用于Win32的示例导入库包含在win32.lib中.包括Kernel32User32GDI32Shell32ADVAPI32versionwinmmlz32commdlgcommctl的所有命名导出.

使用:

alink -oPE file[.obj] win32.lib

包含或指定

INCLUDELIB "win32"

在您的源文件中.

这由一系列用于导入重定向的条目-call MessageBoxA组成,它跳转到导入表中的[__imp_MessageBoxA].

如果使用call [__imp_importName]而不是call importName,则对导入的调用将运行得更快.

请参阅我的示例程序test.asm,该示例程序以两种方式调用消息框:

includelib "win32.lib"
extrn MessageBoxA:near
extrn __imp_MessageBoxA:dword

codeseg

start:
push 0 ; OK button
push offset title1
push offset string1
push 0
call MessageBoxA

push 0 ; OK button
push offset title1
push offset string2
push 0
call large [large __imp_MessageBoxA]

(__imp_MessageBoxA是从DLL导入的符号,等效于我上面的ExitProcessActual).

I don't know how to ask this better but why does this:

call ExitProcess

do the same as this?:

mov eax, ExitProcess
mov eax, [eax]
call eax

I would think that these would be equivalent:

call ExitProcess


mov eax, ExitProcess
call eax

解决方案

When importing the code from a DLL, the symbol ExitProcess isn't actually the address of the code that exits your process (it's the address of the address). So, in that case, you have to dereference it to get the actual code address.

That means that you must use:

call [ExitProcess]

to call it.

For example, there's some code at this location containing the following:

;; Note how we use 'AllocConsole' as if it was a variable. 'AllocConsole', to 
;; NASM, means the address of the AllocConsole "variable" ; but since the 
;; pointer to the AllocConsole() Win32 API function is stored in that 
;; variable, we need to call the address from that variable. 
;; So it's "call the code at the address: whatever's at the address
;; AllocConsole" . 
call [AllocConsole] 


However, importing the DLL directly in user code is not the only way to get at the function. I'll explain why you're seeing both ways below.

The "normal" means of calling a DLL function is to mark it extern then import it from the DLL:

extern ExitProcess
import ExitProcess kernel32.dll
:
call [ExitProcess]

Because that sets up the symbol to be an indirect reference to the code, you need to call it indirectly.

After some searching, it appears there is code in the wild that uses the naked form:

call ExitProcess

From what I can tell, this all seems to use the alink linker, which links with the win32.lib library file. It's possible that this library provides the stub for calling the actual DLL code, something like:

import ExitProcessActual kernel32.dll ExitProcess
global ExitProcess

ExitProcess:
    jmp [ExitProcessActual]

In nasm, this would import the address of ExitProcess from the DLL and call it ExitProcessActual, keeping in mind that this address is an indirect reference to the code, not the address of the code itself.

It would then export the ExitProcess entry point (the one in this LIB file, not the one in the DLL) so that others could use it.

Then someone could simply write:

extern ExitProcess
:
call ExitProcess

to exit the process - the library would jump to the actual DLL code.


In fact, with a little more research, this is exactly what's happening. From the alink.txt file which comes with the alink download:

A sample import library for Win32 is included as win32.lib. All named exports in Kernel32, User32, GDI32, Shell32, ADVAPI32, version, winmm, lz32, commdlg and commctl are included.

Use:

alink -oPE file[.obj] win32.lib

to include it or specify

INCLUDELIB "win32"

in your source file.

This consists of a series of entries for import redirection - call MessageBoxA, and it jumps to [__imp_MessageBoxA], which is in the import table.

Thus calls to imports will run faster if call [__imp_importName] is used instead of call importName.

See test.asm, my sample program, which calls up a message box both ways:

includelib "win32.lib"
extrn MessageBoxA:near
extrn __imp_MessageBoxA:dword

codeseg

start:
push 0 ; OK button
push offset title1
push offset string1
push 0
call MessageBoxA

push 0 ; OK button
push offset title1
push offset string2
push 0
call large [large __imp_MessageBoxA]

(__imp_MessageBoxA is the symbol imported from the DLL, equivalent to my ExitProcessActual above).

这篇关于对Win32 API调用在组装中的工作方式感到困惑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆