Прежде чем кто-либо спросит, здесь нет злого умысла. Этот проект предназначен исключительно для образовательных и личных целей и, в лучшем случае, предназначен для того, чтобы стать «чит-движком» или возможным будущим античит-механизмом. Нет никакого намерения использовать это каким-либо злонамеренным образом.
////////////////
// 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;
}
Это вызывает 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 в своей виртуальной таблице, которые вызывают нарушения доступа, если вы пытаетесь выполнить любой из них.
Вероятно, я должен отметить, что я успешно предоставил приложению MFC надлежащие права на отладку через OpenThreadToken, ImpersonateSelf и SetPrivilege. Должен ли я также каким-то образом заблокировать адрес класса в памяти? Это летучий Ключевое слово недостаточно или неправильно используется здесь? Что мне нужно сделать, чтобы получить тот же указатель, выделенный DLL?
Заранее спасибо! Голосование будет дано за любой действительный совет.
Каждый процесс имеет свой экземпляр библиотеки DLL в адресном пространстве и, возможно, по другому адресу, вы не можете просто заставить процесс загрузить библиотеку DLL и ожидать использования ее адресного пространства от другого процесса.
Есть несколько способов связать вашу внедренную DLL с процессом инжектора:
Общая память: вы можете разделить память между двумя или более процессами, используя MapViewOfFile, обратите внимание, что вы должны позаботиться о том, какие указатели хранятся в экземпляре класса, и что виртуальные члены не работают, поскольку виртуальная таблица принадлежит другому адресному пространству.
RPC: Вы можете использовать Win32 RPC для выполнения вызовов между процессом и совместного использования данных, лично я считаю, что это слишком сложно.
Named Pipes / Winsock: Мои любимые, простые в использовании, и вы можете делать (почти) все, что захотите.
Microsoft Message Queue (MSMQ): Не знаю много об этом, я думаю, что это тоже можно использовать.
Сообщения Win32: RegisterWindowMessage можно использовать для обработки сообщений Windows по всей системе и обмена данными, что полезно только для обмена небольшими значениями (два DWORD)
Есть и другие способы выполнения IPC, как вы можете видеть на MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365574(v=vs.85).aspx
Я настоятельно рекомендую вам использовать Named Pipes / Winsock, если это так, вы можете использовать Google Protobuf для простого обмена структурами данных между процессами.
Других решений пока нет …