Здравствуйте! Пытаюсь сделать меню для игрушки, но не могу разобраться в функции,
которая крашит программу после инъекции. Опишу все подробно с комментариями, если я
не прав, пожалуйста поправьте:
Создаю поток в процессе (инжект работает нормально) с таким содержимым:
DWORD*vtbl = 0;
//Здесь я записываю начальный адрес модуля
DWORD hD3D9 = (DWORD)LoadLibraryA("d3d9.dll");
//ищу функцию Direct3DCreate или что то другое?
DWORD table = MemHack->FindPattern(hD3D9, 0x128000, (PBYTE)"\xC7\x06\x00\x00\x00\x00\x89\x86\x00\x00\x00\x00\x89\x86",
"xx????xx????xx");//
// со смещением в 2 байта копируем указатель
memcpy(&vtbl, (void*)(table + 2), 4);
Здесь table = 6ace76d3. Вот кусок памяти:
d3d9.Direct3DCreate9Ex+54AC - E8 71000000 - call d3d9.Direct3DCreate9Ex+5522
d3d9.Direct3DCreate9Ex+54B1 - 33 C0 - xor eax,eax
d3d9.Direct3DCreate9Ex+54B3 - C7 06 9C86CD6A - mov [esi],d3d9.dll+869C { [6ACD9D30] }
d3d9.Direct3DCreate9Ex+54B9 - 89 86 08310000 - mov [esi+00003108],eax
d3d9.Direct3DCreate9Ex+54BF - 89 86 00310000 - mov [esi+00003100],eax
Далее идет вызов функции, который крашит программу:
// vtbl[42] указывает на функцию endScene размером 5 байт?
pEndScene = (oEndScene)Mem->Create_Hook((PBYTE)vtbl[42], (PBYTE)myEndScene, 5);
Приведу код функции, который в общем представлении я не понял:
void * cMemory::Create_Hook(BYTE *src, const BYTE *dst, const int len)
{
BYTE *jmp;
DWORD dwback;
DWORD jumpto, newjump;
VirtualProtect(src,len,PAGE_EXECUTE_READWRITE,&dwback);
// вот отсюда я не понял зачем эта проверка вообще нужна
if(src[0] == 0xE9)
{
jmp = (BYTE*)malloc(10);
jumpto = (*(DWORD*)(src+1))+((DWORD)src)+5;
newjump = (jumpto-(DWORD)(jmp+5));
jmp[0] = 0xE9;
*(DWORD*)(jmp+1) = newjump;
jmp += 5;
jmp[0] = 0xE9;
*(DWORD*)(jmp+1) = (DWORD)(src-jmp);
}
else
{
jmp = (BYTE*)malloc(5+len);
memcpy(jmp,src,len);
jmp += len;
jmp[0] = 0xE9;
*(DWORD*)(jmp+1) = (DWORD)(src+len-jmp)-5;
}
src[0] = 0xE9;
*(DWORD*)(src+1) = (DWORD)(dst - src) - 5;
for(int i = 5; i < len; i++)
src[i] = 0x90;
VirtualProtect(src,len,dwback,&dwback);
// здесь указатель на функцию?
return (jmp-len);
}
Ответы
Ответ 1
Ваши ошибки:
Игра написана на directX8, а не 9 версии, Вы пытаетесь хукнуть 9 версию, собственно
LoadLibraryA("d3d9.dll"), нужно LoadLibraryA("d3d8.dll") и в таблице виртуальные методы
там, на сколько я помню, имеют немного другую последовательность (для проверки того,
какую версию dx использует приложения нужно всего лишь открыть отладчик и просмотреть
список загруженных модулей или посмотреть инфо в википедии).
Вы пытаетесь(скорее всего, это мои догадки) сделать иньекцию кода в процесс generals.exe,
но это просто дочернее окно и оно не выполняет функции отрисовки игрового мира\меню
и т.д., Вам нужен процесс game.dat.
Вечером, когда приду домой, постараюсь переделать Ваш код в рабочее состояние и дополню
ответ. Если Вам интересно, можете почитать интересную статью по Вашей теме.
UPD:
#include
#include
#include
#pragma comment (lib, "d3d8.lib")
#pragma comment (lib, "d3dx8.lib")
#pragma comment( lib, "LIBCI.lib" )
#include "MessageControll.h"
#include "ConsoleControll.h"
//"Game.dat"+0056C9A4
// Hook Function
HRESULT WINAPI HookedPresent(LPDIRECT3DDEVICE8 pDevice, CONST RECT* pSourceRect,
CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion);
HRESULT WINAPI HookedReset(LPDIRECT3DDEVICE8 pDevice, D3DPRESENT_PARAMETERS *params);
// Orig Function
typedef HRESULT(WINAPI* tPresent)(LPDIRECT3DDEVICE8 pDevice, CONST RECT* pSourceRect,
CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion);
typedef HRESULT(WINAPI *tReset)(LPDIRECT3DDEVICE8 pDevice, D3DPRESENT_PARAMETERS *pp);
DWORD origReset = 0, origPresent = 0;
tPresent _tPresent = nullptr;
tReset _tReset = nullptr;
ID3DXFont* pFont = nullptr;
void createFont(IDirect3DDevice8* pDevice)
{
LOGFONT log_font = {
50, //height
0, //width;
0, // lfEscapement;
0, //lfOrientation;
FW_BOLD, // lfWeight;
FALSE, // lfItalic;
FALSE, // lfUnderline;
FALSE, // lfStrikeOut;
DEFAULT_CHARSET, // lfCharSet;
OUT_DEFAULT_PRECIS, //lfOutPrecision;
CLIP_DEFAULT_PRECIS, // lfClipPrecision;
ANTIALIASED_QUALITY,// lfQuality;
DEFAULT_PITCH,// lfPitchAndFamily;
"Tahoma"// lfFaceName[LF_FACESIZE];
};
HFONT font = CreateFont(10, 10, 0, 0, FW_NORMAL, false, false, false, DEFAULT_CHARSET,
OUT_OUTLINE_PRECIS, 0, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial");
if (D3DXCreateFontIndirect(pDevice, &log_font, &pFont) != D3D_OK)
{
console("D3DXCreateFontIndirect error!");
}
}
VOID D3DX_Font(LPDIRECT3DDEVICE8 Device_Interface)
{
RECT Rect = { 0,0,1000,1000 };
//if (Device_Interface != NULL)
//{
// HFONT Logical_Font_Characteristics = CreateFont(16, 0, 0, 0, 400, 0, 0, 0,
0, 0, 0, 2, 0, "Arial");
// if (Logical_Font_Characteristics != NULL)
// {
// D3DXCreateFont(Device_Interface, Logical_Font_Characteristics, &pFont);
// DeleteObject(Logical_Font_Characteristics);
// }
//}
if (pFont != NULL)
{
pFont->Begin();
pFont->DrawText("StackOverflow.ru!", -1, &Rect, 0, 0xFFFF0000);
pFont->End();
}
}
//=========================================================
//if (bDrawText && m_pFont)
//{
// PrintTextB(m_pFont,
// 250, 20, //x, y
// 255, 255, 255, 255, //color values (and then alpha)
// "Testing 1234567890!!!");
//}
//My custom PrintText Function:
//void drawText(const D3DXVECTOR4& area, const DWORD& color, TCHAR *text, ...)
//{
// TCHAR buf[1024]{};
//
// RECT FontRect = {
//
// (long)area.x,
// (long)area.y,
// (long)area.x + (long)area.z,
// (long)area.y + (long)area.w
// };
//
// va_list vaList;
// va_start(vaList, text);
//
//#ifdef UNICODE
// vswprintf_s(buf, text, vaList);
//#else
// vsprintf_s(buf, text, vaList);
//#endif
//
// va_end(vaList);
//
// pFont->Begin();
// pFont->DrawText(buf, -1, &FontRect, 0, color);
// pFont->End();
//}
void* DetourCreate(BYTE *src, const BYTE *dst, const int len)
{
BYTE *jmp;
DWORD dwback, dwold;
DWORD jumpto, newjump;
VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &dwback);
if (src[0] == 0xE9)
{
jmp = (PBYTE)malloc(10);
VirtualProtect(jmp, 10, PAGE_EXECUTE_READWRITE, &dwold);
jumpto = (*(DWORD*)(src + 1)) + ((DWORD)src) + 5;
newjump = (jumpto - (DWORD)(jmp + 5));
jmp[0] = 0xE9;
*(DWORD*)(jmp + 1) = newjump;
jmp += 5;
jmp[0] = 0xE9;
*(DWORD*)(jmp + 1) = (DWORD)(src - jmp);
}
else
{
jmp = (PBYTE)malloc(5 + len);
VirtualProtect(jmp, 5 + len, PAGE_EXECUTE_READWRITE, &dwold);
memcpy(jmp, src, len);
jmp += len;
jmp[0] = 0xE9;
*(DWORD*)(jmp + 1) = (DWORD)(src + len - jmp) - 5;
}
src[0] = 0xE9;
*(DWORD*)(src + 1) = (DWORD)(dst - src) - 5;
for (int i = 5; i < len; i++)
{
src[i] = 0x90;
}
VirtualProtect(src, len, dwback, &dwback);
return (jmp - len);
}
void GetDevice9Methods()
{
D3DDISPLAYMODE ds{};
D3DPRESENT_PARAMETERS pp{};
IDirect3DDevice8* dev{};
HMODULE hD3D8Dll = GetModuleHandle("d3d8.dll");
//console("address \"d3d8.dll\" [%#x]", hD3D8Dll);
//Инициализируем свой девайс, чтобы узнать адреса функций ресета и презента в
виртуальной таблице методов
if (hD3D8Dll)
{
IDirect3D8* d3d8 = Direct3DCreate8(D3D_SDK_VERSION);
//console("address \"IDirect3D8\" [%#x]", d3d8);
if (d3d8->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &ds) != D3D_OK)
{
d3d8->Release();
return;
}
pp.Windowed = 1;
pp.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC;
pp.BackBufferFormat = ds.Format;
if (d3d8->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetForegroundWindow(),
D3DCREATE_HARDWARE_VERTEXPROCESSING, &pp, &dev) == D3D_OK)
{
if (dev)
{
//Копируем адреса виртуальных методов
origReset = *((DWORD*)(*(DWORD*)dev) + 14);
origPresent = *((DWORD*)(*(DWORD*)dev) + 15);
//console("address \"Reset method\" [%#x]", origReset);
//console("address \"Present method\" [%#x]", origPresent);
dev->Release();
d3d8->Release();
}
}
else
{
d3d8->Release();
return;
}
}
}
DWORD WINAPI InitThread(HINSTANCE hinstDLL)
{
//t_con.create();
GetDevice9Methods();
if (origReset && origPresent)
{
_tPresent = (tPresent)DetourCreate((PBYTE)origPresent, (PBYTE)HookedPresent, 5);
_tReset = (tReset)DetourCreate((PBYTE)origReset, (PBYTE)HookedReset, 5);
}
while (!GetAsyncKeyState(VK_END))
{
Sleep(1);
}
//t_con.del();
FreeLibraryAndExitThread(hinstDLL, 0);
return 1;
}
HRESULT WINAPI HookedPresent(LPDIRECT3DDEVICE8 pDevice, CONST RECT* pSourceRect,
CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion)
{
if (!pFont)
{
createFont(pDevice);
}
else
{
D3DX_Font(pDevice);
}
D3DRECT rec = { 10, 10, 30, 30 };
//pDevice->Clear(1, &rec, D3DCLEAR_TARGET, 0xFFFF0000, 1.0f, 0);
return _tPresent(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
}
HRESULT WINAPI HookedReset(LPDIRECT3DDEVICE8 pDevice, D3DPRESENT_PARAMETERS *params)
{
return _tReset(pDevice, params);
}
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH://Вызывается первым
CreateThread(0, 0, LPTHREAD_START_ROUTINE(InitThread), hinstDLL, 0, 0);
return 1;
case DLL_PROCESS_DETACH://вызывается после освобождения библиотеки
break;
case DLL_THREAD_ATTACH://вызывается при создании потока
break;
case DLL_THREAD_DETACH://вызывается после разрушения потока
break;
}
return TRUE;
}
Как пофиксить проблемы с нехваткой libci:
Скачать саму либу и заинклудить в проект;
Заинклудить дополнительные зависимости, как сказано тут.
Результат: