【问题标题】:Access violation when calling function of a game from dll从dll调用游戏函数时访问冲突
【发布时间】:2018-11-11 13:30:09
【问题描述】:

我尝试调用一个名为“以撒的结合:重生”的游戏函数来设置您当前拥有的密钥数量。这是我目前注入的 dll 代码:

main.cpp

#include <iostream>

typedef void(__cdecl *funcB)(byte namePtr);
funcB originalFunction;

BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
{
    uintptr_t modBase = (uintptr_t)GetModuleHandle(NULL);
    originalFunction = (funcB)(modBase + 0x150860);
    switch (dwReason)
    {
    case DLL_PROCESS_ATTACH:
        originalFunction(17); //set keys to 17
        break;
    default:
        break;
    }
    return TRUE;
}

这是来自 x64dbg 的函数汇编:

010E0860 | 55                       | push ebp                                |
010E0861 | 8B EC                    | mov ebp,esp                             |
010E0863 | 83 EC 08                 | sub esp,8                               |
010E0866 | 8B 81 D8 24 00 00        | mov eax,dword ptr ds:[ecx+24D8]         | ;line that calls the EXCEPTION_ACCESS_VIOLATION
010E086C | 8D 55 08                 | lea edx,dword ptr ss:[ebp+8]            |
010E086F | 03 45 08                 | add eax,dword ptr ss:[ebp+8]            |
010E0872 | 83 F8 63                 | cmp eax,63                              | 63:'c'
010E0875 | 89 45 08                 | mov dword ptr ss:[ebp+8],eax            |
010E0878 | 56                       | push esi                                |
010E0879 | 8D 75 FC                 | lea esi,dword ptr ss:[ebp-4]            |
010E087C | C7 45 FC 63 00 00 00     | mov dword ptr ss:[ebp-4],63             | 63:'c'
010E0883 | 0F 4D D6                 | cmovge edx,esi                          |
010E0886 | C7 45 F8 00 00 00 00     | mov dword ptr ss:[ebp-8],0              |
010E088D | 8D 45 F8                 | lea eax,dword ptr ss:[ebp-8]            |
010E0890 | 5E                       | pop esi                                 |
010E0891 | 83 3A 00                 | cmp dword ptr ds:[edx],0                |
010E0894 | 0F 4F C2                 | cmovg eax,edx                           |
010E0897 | 8B 00                    | mov eax,dword ptr ds:[eax]              |
010E0899 | 89 81 D8 24 00 00        | mov dword ptr ds:[ecx+24D8],eax         |
010E089F | A1 D0 A0 4C 01           | mov eax,dword ptr ds:[14CA0D0]          |
010E08A4 | 83 B8 6C F5 10 00 02     | cmp dword ptr ds:[eax+10F56C],2         |
010E08AB | 74 14                    | je isaac-ng.10E08C1                     |
010E08AD | C7 80 6C F5 10 00 01 00  | mov dword ptr ds:[eax+10F56C],1         |
010E08B7 | C7 80 74 F5 10 00 02 00  | mov dword ptr ds:[eax+10F574],2         |
010E08C1 | 8B E5                    | mov esp,ebp                             |
010E08C3 | 5D                       | pop ebp                                 |
010E08C4 | C2 04 00                 | ret 4                                   |

我假设该函数采用的唯一参数是设置键的数字,但由于我对 RE 还很陌生,所以我不太确定。另外,如果我没记错的话,调用约定应该是__cdecl

我认为这可能与 ecx 设置错误有关,因为它在程序集中的函数调用之前设置为不同的东西。

x64dbg 日志:

EXCEPTION_DEBUG_INFO:
           dwFirstChance: 1
           ExceptionCode: C0000005 (EXCEPTION_ACCESS_VIOLATION)
          ExceptionFlags: 00000000
        ExceptionAddress: 010E0866 isaac-ng.010E0866
        NumberParameters: 2
ExceptionInformation[00]: 00000000 Read
ExceptionInformation[01]: 01661ED8 Inaccessible Address
First chance exception on 010E0866 (C0000005, EXCEPTION_ACCESS_VIOLATION)!

【问题讨论】:

  • ecx 用于在 C++ 代码中传递 this 指针。因此,这看起来像是某个类的方法,因此您需要将指针传递给实例。
  • 看起来像 MSVC++ thiscall: "在 Microsoft Visual C++ 编译器上,this 指针在 ECX 中传递,它是清理堆栈的被调用者,镜像使用的 stdcall 约定在 C 中用于此编译器和 Windows API 函数。当函数使用可变数量的参数时,清理堆栈的是调用者(参见 cdecl)。"
  • 我如何将实例传递给 c++ 代码?我只是将调用约定设置为thiscall
  • 您还需要一个指向该方法所属类的实例的指针。

标签: c++ assembly reverse-engineering


【解决方案1】:

好的,所以我对thiscall 的工作原理进行了一些研究,现在已经解决了。我把我的 dll 代码改成了这个,

#include <windows.h>
#include <iostream>

struct _Isaac { //Make a class for the function
    typedef void(__thiscall *funcB)(void *pThis, int keyAmount);
    funcB originalFunction;

    void *pThis = (void*)0x12ED56E8; //Address for the instance
};

_Isaac Isaac;

BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
{
    uintptr_t modBase = (uintptr_t)GetModuleHandle(NULL);
    Isaac.originalFunction = (_Isaac::funcB)(modBase + 0x150860);
    switch (dwReason)
    {
    case DLL_PROCESS_ATTACH:
        Isaac.originalFunction((void*)Isaac.pThis, 17);
        break;
    default:
        break;
    }
    return TRUE;
}

现在它可以正常工作了。无论如何,感谢您的快速响应和建议,我是一个忘记 OOP 的新手 :)

【讨论】:

    猜你喜欢
    • 2014-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多