誰かが尋ねる前に、ここに悪意はありません。このプロジェクトは単に教育的および個人的な使用を目的としており、せいぜい「チートエンジン」または将来のチート防止メカニズムとして設計されています。これを悪意のある方法で使用する意図はありません。
私は次の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によって割り当てられたまったく同じポインタを取得するにはどうすればよいですか?
前もって感謝します!有効なアドバイスには賛成票が投じられます。