1

誰かが尋ねる前に、ここに悪意はありません。このプロジェクトは単に教育的および個人的な使用を目的としており、せいぜい「チートエンジン」または将来のチート防止メカニズムとして設計されています。これを悪意のある方法で使用する意図はありません。

私は次の3つのプロジェクトで解決策を持っています:

  • ユーザーが注入するプロセスを選択できる32ビットMFCアプリケーション
  • VirtualAlloc + WriteProcessMemory + CreateRemoteThread+LoadLibrary技術を介してターゲットプロセスに挿入する32ビットWin32DLL
  • ローカルインジェクションが発生したときにテストする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をコンソールテストプロジェクトに挿入した後...

RemoteInitialize()を呼び出してリモートクラスを初期化し、仮想メモリ空​​間のアドレスを呼び出し元に返します。呼び出し元では、CDeceivedクラスの共有インスタンスにローカライズする必要があります。これが私がこれをどのように扱っているかです:

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によって割り当てられたまったく同じポインタを取得するにはどうすればよいですか?

前もって感謝します!有効なアドバイスには賛成票が投じられます。

4

1 に答える 1

2

各プロセスは、アドレス空間にDLLの異なるインスタンスを持ち、おそらく異なるアドレスにあります。プロセスにDLLを強制的にロードさせ、別のプロセスからのアドレス空間を使用することを期待することはできません。

インジェクションされたDLLをインジェクタープロセスと相互通信する方法はいくつかあります。

  • 共有メモリ:MapViewOfFileを使用して、2つ以上のプロセス間でメモリを共有できます。クラスインスタンスに格納されるポインタに注意する必要があり、vtableは別のアドレス空間に属しているため仮想メンバーは機能しないことに注意してください。

  • RPC:Win32 RPCを使用して、プロセス間で呼び出しを行ったり、データを共有したりできます。個人的には、複雑すぎると思います。

  • 名前付きパイプ/Winsock:私の好みのもので、使いやすく、(ほぼ)好きなことを何でもできます。

  • Microsoft Message Queue(MSMQ):よくわかりませんが、それも使用できると思います。

  • Win32メッセージ:RegisterWindowMessageを使用して、システム全体でWindowsメッセージを処理し、データを共有できます。これは、小さな値(2つのDWORD)を共有する場合にのみ役立ちます。

MSDNで確認できるように、IPCを実行する他の方法があります:http://msdn.microsoft.com/en-us/library/windows/desktop/aa365574 (v = vs.85).aspx

名前付きパイプ/Winsockを使用することを強くお勧めします。使用する場合は、Google Protobufを使用して、プロセス間でデータ構造体を簡単に共有できます。

于 2013-02-16T04:13:44.947 に答える