Я лучше тебя
-
Автор темы
- #1
Привет форумчане.
Вряд ли кто-то здесь, использовал подобные методы для работы с обходом анти-читов игр, однако сегодня я решил поделится знатной штукой, как правило, большинство античитов не дают сделать снимок хуков сторонним приложениям, ибо те тулзы, которые для этого существуют, зачастую детектят. А хуки то палят при инжектах и прочих действиях, и не дают нормально читерить, по тому была предпринята вполне удачная попытка написать сканер.
По тому предоставляю самописный аналог:
cUtilit.h:Вряд ли кто-то здесь, использовал подобные методы для работы с обходом анти-читов игр, однако сегодня я решил поделится знатной штукой, как правило, большинство античитов не дают сделать снимок хуков сторонним приложениям, ибо те тулзы, которые для этого существуют, зачастую детектят. А хуки то палят при инжектах и прочих действиях, и не дают нормально читерить, по тому была предпринята вполне удачная попытка написать сканер.
По тому предоставляю самописный аналог:
Вариант еще очень сырой, однако будет дорабатываться. Тем, кто не знает зачем это нужно: просто пройдите мимо темы. Собрано из подручных средств вчера вечером, класс воялся на скорую руку.
Код:
#pragma once
typedef std::vector<unsigned char> vByte;
#define INRANGE(x,a,b) (x >= a && x <= b)
#define getBits( x ) (INRANGE(x,'0','9') ? (x - '0') : ((x&(~0x20)) - 'A' + 0xa))
#define getByte( x ) (getBits(x[0]) << 4 | getBits(x[1]))
#define LAST_STATUS_OFS (0x598 + 0x197 * (sizeof(void*)))
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
inline NTSTATUS LastNtStatus()
{
return *(NTSTATUS*)((unsigned char*)NtCurrentTeb() + LAST_STATUS_OFS);
}
class cUtilit
{
public:
static NTSTATUS Priviledge(const std::basic_string<TCHAR>& name = SE_DEBUG_NAME)
{
TOKEN_PRIVILEGES Priv, PrivOld;
DWORD cbPriv = sizeof(PrivOld);
HANDLE hToken;
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, FALSE, &hToken))
{
if (GetLastError() != ERROR_NO_TOKEN)
return LastNtStatus();
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
return LastNtStatus();
}
Priv.PrivilegeCount = 1;
Priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
LookupPrivilegeValue(NULL, name.c_str(), &Priv.Privileges[0].Luid);
if (!AdjustTokenPrivileges(hToken, FALSE, &Priv, sizeof(Priv), &PrivOld, &cbPriv))
{
CloseHandle(hToken);
return LastNtStatus();
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
CloseHandle(hToken);
return LastNtStatus();
}
return STATUS_SUCCESS;
}
};
cProcess.h:
cProcess.cpp:
Код:
#pragma once
#include <windows.h>
#include <vector>
#include <tlhelp32.h>
#include <dwmapi.h>
#include <psapi.h>
#pragma comment(lib, "dwmapi.lib")
#include "cModule.h"
#include "cUtilit.h"
class cProcess
{
public:
cProcess();
~cProcess();
bool Attach(HANDLE hProcess);
void Detach();
cModule* GetModule(const std::string&);
HANDLE GetHandle() const;
std::vector<cModule*> GetModuleList() const;
bool IsValidHandle() const;
bool valid();
DWORD GetProcessIdByName(const std::string&);
private:
bool DumpModList();
int SizeOfArray(char *);
private:
HANDLE m_hProcess = NULL;
std::vector<cModule*> m_pModList;
};
Код:
#include "cProcess.h"
cProcess::cProcess()
{
cUtilit::Priviledge();
}
bool cProcess::Attach(HANDLE hProcess)
{
Detach();
m_hProcess = hProcess;
if (!m_hProcess)
return false;
return DumpModList();
}
void cProcess::Detach()
{
if (m_hProcess)
CloseHandle(m_hProcess);
m_hProcess = NULL;
if (!m_pModList.empty())
{
for (auto& slot : m_pModList)
{
delete slot;
slot = nullptr;
}
}
}
bool cProcess::DumpModList()
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(this->m_hProcess));
if (hSnapshot == INVALID_HANDLE_VALUE)
return false;
MODULEENTRY32 Entry = { NULL };
Entry.dwSize = sizeof(MODULEENTRY32);
if (!Module32First(hSnapshot, &Entry))
{
CloseHandle(hSnapshot);
return false;
}
cModule* pMod = nullptr;
do {
char szPath[MAX_PATH] = { NULL };
GetModuleFileNameEx(m_hProcess, Entry.hModule, szPath, MAX_PATH);
pMod = new cModule((DWORD_PTR)Entry.hModule, (DWORD_PTR)Entry.modBaseSize, Entry.szModule, szPath);
m_pModList.push_back(pMod);
} while (Module32Next(hSnapshot, &Entry));
CloseHandle(hSnapshot);
return !m_pModList.empty();
}
DWORD cProcess::GetProcessIdByName(const std::string& szNameExe)
{
HANDLE hSnap;
DWORD pId = 0;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
try {
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (!hSnap) {
throw std::exception("Could not create process snapshot");
}
if (!Process32First(hSnap, &pe32)) {
throw std::exception("Enumerating processes failed");
}
do {
if (std::string(pe32.szExeFile) == szNameExe) {
pId = pe32.th32ProcessID;
break;
}
} while (Process32Next(hSnap, &pe32));
CloseHandle(hSnap);
return pId;
}
catch (std::exception e) {
CloseHandle(hSnap);
throw;
}
}
cModule* cProcess::GetModule(const std::string& ImageName)
{
if (m_pModList.empty())
return nullptr;
for (auto& pMod : m_pModList)
{
if (ImageName.compare(pMod->GetName()) == 0)
{
return pMod;
}
}
return nullptr;
}
HANDLE cProcess::GetHandle() const
{
return m_hProcess;
}
bool cProcess::IsValidHandle() const
{
return m_hProcess != INVALID_HANDLE_VALUE;
}
bool cProcess::valid()
{
DWORD dwExitCode = 0;
if (!m_hProcess || !GetExitCodeProcess(m_hProcess, &dwExitCode))
return false;
return (dwExitCode == STILL_ACTIVE);
}
std::vector<cModule*> cProcess::GetModuleList() const
{
return m_pModList;
}
int cProcess::SizeOfArray(char *chArray)
{
for (int iLength = 1; iLength < MAX_PATH; iLength++)
if (chArray[iLength] == '\0')
return iLength;
return 0;
}
cProcess::~cProcess()
{
}
cModule.h:
cModule.cpp:
Код:
#pragma once
#include <windows.h>
#include <string>
class cModule
{
public:
cModule(DWORD_PTR, DWORD_PTR, const std::string&, const std::string&);
~cModule();
DWORD_PTR GetImage() const;
DWORD_PTR GetSize() const;
const std::string& GetName() const;
const std::string& GetPath() const;
private:
DWORD_PTR m_ImageBase;
DWORD_PTR m_ImageSize;
std::string m_ImageName;
std::string m_ImagePath;
};
Код:
#include "cModule.h"
cModule::cModule(DWORD_PTR ImageBase, DWORD_PTR ImageSize, const std::string& ImageName, const std::string& ImagePath)
: m_ImageBase(ImageBase),
m_ImageSize(ImageSize),
m_ImageName(ImageName),
m_ImagePath(ImagePath)
{
}
DWORD_PTR cModule::GetImage() const
{
return m_ImageBase;
}
DWORD_PTR cModule::GetSize() const
{
return m_ImageSize;
}
const std::string& cModule::GetName() const
{
return m_ImageName;
}
const std::string& cModule::GetPath() const
{
return m_ImagePath;
}
cModule::~cModule()
{
}
Scaner.h:
Scanner.cpp:
Код:
#include <Windows.h>
#include <string>
#include <vector>
using namespace std;
#include "cProcess.h"
typedef struct hHookData
{
DWORD api_address;
DWORD api_size;
void* api_buffer_get;
void* api_buffer_set;
hHookData(DWORD _address, DWORD _size, void* _buffer_get, void* _buffer_set) : api_address(_address), api_size(_size), api_buffer_get(_buffer_get), api_buffer_set(_buffer_set)
{
}
};
typedef struct _export_data
{
FARPROC api_call;
char* api_name;
_export_data(FARPROC _call, char* _name) : api_call(_call), api_name(_name)
{
}
};
#define S_SUCCRESS(a) a != NULL
class Scanner
{
public:
Scanner();
Scanner(cProcess* g_pProcess);
~Scanner();
hHookData* GetExternalData(std::string NameOfModule, std::string NameOfFunction, DWORD size);
vector<hHookData*> ScanExternalModule(std::string NameOfModule, DWORD size);
private:
FARPROC find_function(HMODULE Mod, const char* fName);
vector<_export_data*> query_function_list(HMODULE Mod);
private:
cProcess* vProcess;
};
Код:
#include "Scanner.h"
Scanner::Scanner()
{
this->vProcess = nullptr;
}
Scanner::Scanner(cProcess* g_pProcess)
{
this->vProcess = g_pProcess;
}
Scanner::~Scanner()
{
}
FARPROC Scanner::find_function(HMODULE Mod, const char* fName)
{
ULONG uReturn = 0;
USHORT strTMP = 0;
USHORT tmpINDEX;
char * tmpName;
ULONG Adress;
if ((ULONG)fName <= 0xFFFF)
strTMP = (USHORT)fName;
if (Mod)
{
ULONG Portable_Executable = *(ULONG*)((ULONG)Mod + 0x3C) + (ULONG)Mod;
PIMAGE_EXPORT_DIRECTORY EXPORT_DIRECTORY = (PIMAGE_EXPORT_DIRECTORY)(*(ULONG*)((ULONG)Portable_Executable + 0x78) + (ULONG)Mod);
PULONG RVAPointer = (ULONG*)(EXPORT_DIRECTORY->AddressOfNames + (ULONG)Mod);
PUSHORT oTb_RVA = (USHORT*)(EXPORT_DIRECTORY->AddressOfNameOrdinals + (ULONG)Mod);
PULONG dwTbRVA = (ULONG*)(EXPORT_DIRECTORY->AddressOfFunctions + (ULONG)Mod);
ULONG size_CNT = (EXPORT_DIRECTORY->NumberOfNames > EXPORT_DIRECTORY->NumberOfFunctions) ? EXPORT_DIRECTORY->NumberOfNames : EXPORT_DIRECTORY->NumberOfFunctions;
for (USHORT i = 0; i < size_CNT; i++)
{
if (i < EXPORT_DIRECTORY->NumberOfFunctions)
{
tmpName = (char*)(RVAPointer[i] + (ULONG)Mod);
tmpINDEX = oTb_RVA[i];
}
else
{
tmpName = 0;
tmpINDEX = i;
}
Adress = dwTbRVA[tmpINDEX] + (ULONG)Mod;
if ((strTMP == tmpINDEX + EXPORT_DIRECTORY->Base) || (tmpName && !strcmp(tmpName, fName))) // wcscmp
{
uReturn = Adress;
break;
}
}
}
return reinterpret_cast<FARPROC>(uReturn);
}
vector<_export_data*> Scanner::query_function_list(HMODULE Mod)
{
vector<_export_data*> t3Vector;
ULONG uReturn = 0;
USHORT strTMP = 0;
USHORT tmpINDEX;
char * tmpName;
ULONG Adress;
if (Mod)
{
ULONG Portable_Executable = *(ULONG*)((ULONG)Mod + 0x3C) + (ULONG)Mod;
PIMAGE_EXPORT_DIRECTORY EXPORT_DIRECTORY = (PIMAGE_EXPORT_DIRECTORY)(*(ULONG*)((ULONG)Portable_Executable + 0x78) + (ULONG)Mod);
PULONG RVAPointer = (ULONG*)(EXPORT_DIRECTORY->AddressOfNames + (ULONG)Mod);
PUSHORT oTb_RVA = (USHORT*)(EXPORT_DIRECTORY->AddressOfNameOrdinals + (ULONG)Mod);
PULONG dwTbRVA = (ULONG*)(EXPORT_DIRECTORY->AddressOfFunctions + (ULONG)Mod);
ULONG size_CNT = (EXPORT_DIRECTORY->NumberOfNames > EXPORT_DIRECTORY->NumberOfFunctions) ? EXPORT_DIRECTORY->NumberOfNames : EXPORT_DIRECTORY->NumberOfFunctions;
for (USHORT i = 0; i < size_CNT; i++)
{
if (i < EXPORT_DIRECTORY->NumberOfFunctions)
{
tmpName = (char*)(RVAPointer[i] + (ULONG)Mod);
tmpINDEX = oTb_RVA[i];
}
else
{
tmpName = 0;
tmpINDEX = i;
}
Adress = dwTbRVA[tmpINDEX] + (ULONG)Mod;
t3Vector.push_back(new _export_data(reinterpret_cast<FARPROC>(Adress), tmpName));
}
}
return t3Vector;
}
hHookData* Scanner::GetExternalData(std::string NameOfModule, std::string NameOfFunction, DWORD size)
{
hHookData* Data = nullptr;
HMODULE m_pModule = GetModuleHandleA(NameOfModule.c_str());
cModule* g_pModule = this->vProcess->GetModule(NameOfModule);
if (S_SUCCRESS(m_pModule) && S_SUCCRESS(g_pModule))
{
FARPROC m_pFunction = this->find_function(m_pModule, NameOfFunction.c_str());
if (S_SUCCRESS(m_pFunction))
{
void* hLocalBuffer = malloc(size);
void* hExternalBuffer = malloc(size);
if (S_SUCCRESS(hLocalBuffer) && S_SUCCRESS(hExternalBuffer))
{
DWORD dwOldProtect = 0;
VirtualProtectEx(GetCurrentProcess(), m_pFunction, size, PAGE_EXECUTE_READ, &dwOldProtect);
ReadProcessMemory(GetCurrentProcess(), m_pFunction, hLocalBuffer, size, 0);
VirtualProtectEx(GetCurrentProcess(), m_pFunction, size, dwOldProtect, &dwOldProtect);
VirtualProtectEx(this->vProcess->GetHandle(), m_pFunction, size, PAGE_EXECUTE_READ, &dwOldProtect);
ReadProcessMemory(this->vProcess->GetHandle(), m_pFunction, hExternalBuffer, size, 0);
VirtualProtectEx(this->vProcess->GetHandle(), m_pFunction, size, dwOldProtect, &dwOldProtect);
if (memcmp(hLocalBuffer, hExternalBuffer, size) == 0)
{
free(hLocalBuffer);
free(hExternalBuffer);
}
else
{
Data = new hHookData(reinterpret_cast<DWORD>(m_pFunction), size, hLocalBuffer, hExternalBuffer);
}
}
}
}
return Data;
}
vector<hHookData*> Scanner::ScanExternalModule(std::string NameOfModule, DWORD size)
{
vector<hHookData*> Data;
HMODULE m_pModule = GetModuleHandleA(NameOfModule.c_str());
cModule* g_pModule = this->vProcess->GetModule(NameOfModule);
if (S_SUCCRESS(m_pModule) && S_SUCCRESS(g_pModule))
{
vector<_export_data*> m_pFunctionList = this->query_function_list(m_pModule);
if (S_SUCCRESS(m_pFunctionList.size()))
{
for (_export_data* data : m_pFunctionList)
{
if (S_SUCCRESS(data->api_call) && S_SUCCRESS(data->api_name))
{
void* hLocalBuffer = malloc(size);
void* hExternalBuffer = malloc(size);
if (S_SUCCRESS(hLocalBuffer) && S_SUCCRESS(hExternalBuffer))
{
DWORD dwOldProtect = 0;
VirtualProtectEx(GetCurrentProcess(), data->api_call, size, PAGE_EXECUTE_READ, &dwOldProtect);
ReadProcessMemory(GetCurrentProcess(), data->api_call, hLocalBuffer, size, 0);
VirtualProtectEx(GetCurrentProcess(), data->api_call, size, dwOldProtect, &dwOldProtect);
VirtualProtectEx(this->vProcess->GetHandle(), data->api_call, size, PAGE_EXECUTE_READ, &dwOldProtect);
ReadProcessMemory(this->vProcess->GetHandle(), data->api_call, hExternalBuffer, size, 0);
VirtualProtectEx(this->vProcess->GetHandle(), data->api_call, size, dwOldProtect, &dwOldProtect);
if (memcmp(hLocalBuffer, hExternalBuffer, size) == 0)
{
free(hLocalBuffer);
free(hExternalBuffer);
}
else
{
Data.push_back(new hHookData(reinterpret_cast<DWORD>(data->api_call), size, hLocalBuffer, hExternalBuffer));
}
}
}
}
}
}
return Data;
}
Код:
int main()
{
cProcess* g_pProcess = new cProcess;
DWORD PID = g_pProcess->GetProcessIdByName("process.exe");
if (PID > 0)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, PID);
if (hProcess)
{
g_pProcess->Attach(hProcess);
Scanner g_pScanner = Scanner(g_pProcess);
hHookData* getData = g_pScanner.GetExternalData("kernel32.dll", "LoadLibraryA", 5);
if (getData != nullptr)
{
//стоит хук
}
else
{
//Хука нет.
}
vector<hHookData*> Hooks = g_pScanner.ScanExternalModule("kernel32.dll", 5);
//выведет все хуки найденные в kernel32.dll если они есть.
//размеры естественно указывать руками, минимум 5 для тамполайна x32 и минимум 12 для x64
for (hHookData* Data : Hooks)
{
printf("find hook: 0x%X size: %d\n", Data->api_address, Data->api_size);
}
printf("Hooks Len: %d\n", Hooks.size());
system("pause");
}
}
g_pProcess->Detach();
delete g_pProcess;
return 0;
}