繁体   English   中英

确定是从EXE还是DLL调用调用者

[英]Determine whether caller is called from EXE or DLL

我需要确定调用者代码是来自EXE还是DLL。

DLL

#ifdef DLL_EXPORTS
    __declspec(dllexport) void say_hello();
    __declspec(dllexport) void getCurrentModuleName();
#else
    __declspec(dllimport) void say_hello();
    __declspec(dllexport) void getCurrentModuleName();
#endif

#include <cstdio>
#include <windows.h>
#include <Dbghelp.h>
#include <iostream>
#include <tchar.h>
#include "dll.h"
#include "Psapi.h"

__declspec(naked) void *GetStackPointer()
{
    __asm
    {
        mov eax, esp
        ret
    }
}

void getCurrentModuleName()
{
    BOOL result = SymInitialize(GetCurrentProcess(), NULL , TRUE);
    DWORD64 dwBaseAddress = SymGetModuleBase64(GetCurrentProcess(), (DWORD64)GetStackPointer());
    TCHAR szBuffer[50];
    GetModuleBaseName(GetCurrentProcess(), (HMODULE) dwBaseAddress, szBuffer, sizeof(szBuffer));
    std::wcout << _T("--->") << szBuffer << std::endl;
}

void say_hello() {
    getCurrentModuleName();
}

可执行程序

#include <windows.h>
#include <cstdio>
#include "dll.h"

int main() {
    printf ("ENTERING EXE CODE...\n");

    getCurrentModuleName();

    printf ("ENTERING DLL CODE...\n");

    say_hello();

    getchar();
}

这是输出。

ENTERING EXE CODE...
--->exe.exe
ENTERING DLL CODE...
--->exe.exe

我希望我能得到

ENTERING EXE CODE...
--->exe.exe
ENTERING DLL CODE...
--->dll.dll

由于最后一个调用者代码来自DLL本身(DLL中的say_hello)

有什么办法可以实现吗?

GetStackAddress返回ESP的值,它是对堆栈的引用。 堆栈按线程分配,与进程中加载​​的任何模块无关。 您需要做的是从堆栈中提取返回地址的值 - 这将是调用模块中的地址。

鉴于函数中通常的前缀代码是:

push ebp
mov  ebp,esp
sub  esp, bytes_of_local_variables

esp会有点随机,但[ebp]应指向前一个ebp,[ebp + 4]应该指向当前帧的返回地址。

所以,你可以试试这个:

__declspec(naked) void *GetReturnAddressAssumingStandardFramePointers()
{
    __asm
    {
        mov eax, [ebp+4]
        ret
    }
}

只需确保调用的函数不会使用/ Oy编译

在这种情况下,使用函数的返回地址,您可以通过直接查看堆栈来确定。 其余的答案仍然适用。

你在getCurrentModuleName()里面得到堆栈指针,但是你需要在getCurrentModuleName()的开头从堆栈中获取返回地址,它显示了调用getCurrentModuleName()

使用EnumProcessModules()。 对于每一个调用GetModuleInformation()。 将您正在执行的函数的地址(使用函数指针)与MODULEINFO结构的lpBaseOfDll和SizeOfImage成员进行比较。 如果它在范围内,你知道这是当前的模块。 如果是这样,请使用GetModuleBaseName检索模块的名称。

这是解决方案。 限制是,它只能跟踪多达62帧。

// Must have in order for us to turned address into module name.
SymInitialize(GetCurrentProcess(), NULL , TRUE);
// Limitation of RtlCaptureStackBackTrace.
const int kMaxCallers = 62; 
void* callers[kMaxCallers];
int count = RtlCaptureStackBackTrace(0, kMaxCallers, callers, NULL);
for (int i = 0; i < count; i++) {
    TCHAR szBuffer[50];
    DWORD64 dwBaseAddress = SymGetModuleBase64(GetCurrentProcess(), (DWORD64)callers[i]);
    GetModuleBaseName(GetCurrentProcess(), (HMODULE) dwBaseAddress, szBuffer, sizeof(szBuffer));
    std::wcout << _T("--->") << szBuffer << std::endl;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM