Определить, вызывается ли вызывающий из EXE или DLL - PullRequest
4 голосов
/ 03 декабря 2010

Мне нужно определить код вызывающего абонента, будь то 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();
}

EXE

#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 (скажем, hello в DLL)

Есть ли способ, которым я могу этого достичь?

Ответы [ 5 ]

3 голосов
/ 03 декабря 2010

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

1 голос
/ 03 декабря 2010

В этом случае используйте адрес возврата функции, который вы можете выяснить, посмотрев прямо в стек.Остальная часть ответа все еще применяется.

0 голосов
/ 08 декабря 2010

Вот решение.Ограничение состоит в том, что он может отслеживать только до 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;
}
0 голосов
/ 03 декабря 2010

Использовать EnumProcessModules (). Для каждого вызова GetModuleInformation (). Сравните адрес выполняемой функции (используя указатель функции) с членами lpBaseOfDll и SizeOfImage структуры MODULEINFO. Если он попадает в диапазон, вы знаете, что это текущий модуль. Если это так, используйте GetModuleBaseName для получения имени модуля.

0 голосов
/ 03 декабря 2010

Вы получаете указатель стека внутри getCurrentModuleName(), который находится в DLL, но вам нужно получить адрес возврата из стека в начале getCurrentModuleName(), который показывает, откуда был вызван getCurrentModuleName().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...