【问题标题】:Using WinAPI to retrieve a class pointer?使用 WinAPI 检索类指针?
【发布时间】:2013-02-16 12:13:44
【问题描述】:

在任何人问之前,这里没有恶意。该项目仅用于教育和个人使用,最多被设计为“作弊引擎”或未来可能的反作弊机制。无意以任何恶意方式使用它。

我有以下 3 个项目的解决方案:

  • 32 位 MFC 应用程序,允许用户选择要注入的进程
  • 32 位 Win32 DLL 通过 VirtualAlloc + WriteProcessMemory + CreateRemoteThread + LoadLibrary 技术注入目标进程
  • 32 位 Win32 控制台应用程序用于测试何时发生本地注入

在 DLL 中,我创建了以下一组函数:

////////////////
// Deceiver.h //
////////////////
#ifdef DECEIVED_EXPORTS
#   define DECEIVED_API __declspec(dllexport)
#else
#   define DECEIVED_API __declspec(dllimport)
#endif

volatile class DECEIVED_API CDeceived
{
public:
    CDeceived(void);
    virtual HANDLE WINAPI GetRunningProcess();
    virtual DWORD WINAPI GetRunningProcessId();
    virtual HANDLE WINAPI GetRunningThread();
    virtual DWORD WINAPI GetRunningThreadId();
    virtual LPVOID WINAPI Allocate(DWORD size);
    virtual BOOL WINAPI Deallocate(LPVOID address, DWORD size);
    virtual BOOL WINAPI Read(LPVOID address, LPVOID buffer, DWORD size);
    virtual BOOL WINAPI Write(LPVOID address, LPVOID buffer, DWORD size);
    virtual BOOL WINAPI ReadEx(HANDLE hProcess, LPVOID address, LPVOID buffer, DWORD size);
    virtual BOOL WINAPI WriteEx(HANDLE hProcess, LPVOID address, LPVOID buffer, DWORD size);

    WCHAR m_signature[10];
};

extern DECEIVED_API CDeceived* deceiver;
LPVOID DECEIVED_API WINAPI RemoteInitialize();


//////////////////
// Deceiver.cpp //
//////////////////
#include "stdafx.h"
#include "Deceived.h"

DECEIVED_API CDeceived* deceiver = NULL;

CDeceived::CDeceived()
{
    memcpy(&m_signature[0], L"Deceived?\0", 10);
}

HANDLE WINAPI CDeceived::GetRunningProcess()
{
    return GetCurrentProcess();
}

DWORD WINAPI CDeceived::GetRunningProcessId()
{
    return GetCurrentProcessId();
}

HANDLE WINAPI CDeceived::GetRunningThread()
{
    return GetCurrentThread();
}

DWORD WINAPI CDeceived::GetRunningThreadId()
{
    return GetCurrentThreadId();
}

LPVOID WINAPI CDeceived::Allocate(DWORD size)
{
    return VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
}

BOOL WINAPI CDeceived::Deallocate(LPVOID address, DWORD size)
{
    return VirtualFree(address, size, MEM_RELEASE);
}

BOOL WINAPI CDeceived::Read(LPVOID address, LPVOID buffer, DWORD size)
{
    DWORD dwBytesRead = 0;
    BOOL bRet = ReadProcessMemory(GetCurrentProcess(), address, buffer, size, &dwBytesRead);
    return bRet && (dwBytesRead > 0);
}

BOOL WINAPI CDeceived::Write(LPVOID address, LPVOID buffer, DWORD size)
{
    DWORD dwBytesWritten = 0;
    BOOL bRet = WriteProcessMemory(GetCurrentProcess(), address, buffer, size, &dwBytesWritten);
    return bRet && (dwBytesWritten > 0);
}

BOOL WINAPI CDeceived::ReadEx(HANDLE hProcess, LPVOID address, LPVOID buffer, DWORD size)
{
    DWORD dwBytesRead = 0;
    BOOL bRet = ReadProcessMemory(hProcess, address, buffer, size, &dwBytesRead);
    return bRet && (dwBytesRead > 0);
}

BOOL WINAPI CDeceived::WriteEx(HANDLE hProcess, LPVOID address, LPVOID buffer, DWORD size)
{
    DWORD dwBytesWritten = 0;
    BOOL bRet = WriteProcessMemory(hProcess, address, buffer, size, &dwBytesWritten);
    return bRet && (dwBytesWritten > 0);
}

LPVOID DECEIVED_API WINAPI RemoteInitialize()
{
    #ifdef _DEBUG
        MessageBoxA(NULL, "Please attach a debugger", "Deceived::RemoteInitialize", MB_ICONINFORMATION);
    #endif

    if(deceiver != NULL) delete deceiver;
    deceiver = new CDeceived();
    LPVOID lpReturn = deceiver->Allocate(sizeof(deceiver));

    if(lpReturn) {
        deceiver->Write(lpReturn, &deceiver, sizeof(deceiver));
        return lpReturn;
    }

    return NULL;
}


MFC应用程序将DLL注入到Console测试项目后...

它调用 RemoteInitialize() 来初始化远程类并将虚拟内存空间中的地址返回给调用者,然后将其本地化为 CDeceived 的共享实例 em>类。以下是我的处理方式:

BOOL CDeceiverHook::Validate(LPVOID lpDeceivedAddress)
{
    CDeceived *deceiver = new CDeceived();
    BOOL bRet = deceiver->ReadEx(hProcess, lpDeceivedAddress, &m_deceived, sizeof(m_deceived));
    int cmp = _wcsicmp(m_deceived->m_signature, L"Deceived?");
    return bRet && (cmp == 0);
}


...但是本地化类指针似乎没有指向远程类指针,而是在它的虚拟表中保存了几个 NULL 指针,如果您尝试执行其中任何一个,则会导致访问冲突。

我可能应该注意到,我已经通过 OpenThreadToken、ImpersonateSelf 和 SetPrivilege 成功地为 MFC 应用程序提供了适当的调试权限。我是否还必须以某种方式将班级的地址锁定在内存中,也许?是 volatile 关键字不够用,还是在这里用错了?我需要做什么来检索由 DLL 分配的完全相同的指针?

提前致谢!任何有效的建议都会给予支持。

【问题讨论】:

    标签: c++ class winapi volatile readprocessmemory


    【解决方案1】:

    每个进程在地址空间中都有不同的 DLL 实例,并且可能在不同的地址上,您不能简单地强制进程加载 DLL 并期望从另一个进程使用它的地址空间。

    有几种方法可以使您注入的 DLL 与注入器进程相互通信:

    • 共享内存:您可以使用 MapViewOfFile 在两个或多个进程之间共享内存,请注意您应该注意哪些指针存储在类实例中,并且虚拟成员不工作,因为 vtable 属于另一个地址空间。

    • RPC:可以使用Win32 RPC进行进程间调用,共享数据,个人觉得太复杂了。

    • Named Pipes/Winsock:我的首选,既易于使用,又可以(几乎)做任何你想做的事情。

    • Microsoft Message Queue(MSMQ):不太了解,我觉得也可以用。

    • Win32 消息:您可以使用 RegisterWindowMessage 处理跨系统的 Windows 消息并共享数据,仅对共享小值(两个 DWORD)有用

    您可以在 MSDN 上看到执行 IPC 的其他方法:http://msdn.microsoft.com/en-us/library/windows/desktop/aa365574(v=vs.85).aspx

    我明确推荐你使用 Named Pipes/Winsock,如果是这样,你可以使用 Google Protobuf 在进程之间轻松共享数据结构。

    【讨论】:

    • 我过去使用过一些 IPC 技术。我的一个理想偏好是能够以与本地类相同的方式使用远程类,而无需联网……即:remoteclass->myvar = remoteclass->myfunc() 例如,没有 otherclass->send(myclass->myvar)otherclass->recv(remoteclass->myvar) 或其他一些交易的开销.如果它可以在纯 Winapi 中完成,那肯定是一个奖励。我现在会考虑使用 MapViewOfFile,但我真的很想避免像瘟疫这样的网络技术。
    • 最接近的方法是使用 Win32 RPC,我觉得它非常烦人和复杂,但这只是个人问题。对于使用命名管道/Winsock 的快速 RPC 而不必直接弄乱它们,您可以在这里查看:code.google.com/p/protobuf/wiki/…
    • 谢谢!迫不得已,我还可以(可能)制作一个 COM 对象并从 MFC 应用程序中挂钩。过去,我通过注入一个挂钩 Direct3D 虚拟表的 DLL 来实现这种效果……但挂钩在 DLL 本身中,所以可能会出现同样的问题。
    • 刚刚也发现了这个,而且是相当新的:codeproject.com/Articles/4837/Introduction-to-RPC-Part-1
    • 使用 ATL COM/RPC。我真的记得在 Windows 98 和 VC6 中弄乱这些东西,是的,这就像强迫垃圾进入你的喉咙。但从那以后我已经走了很长一段路,现在对我来说实际上更有意义了。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2018-08-10
    • 1970-01-01
    • 2021-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    • 2018-02-18
    相关资源
    最近更新 更多