Hello! I'm trying to make a menu for a toy, but I can't figure out the function that crashes the program after an injection. I will describe everything in detail with comments, if I'm wrong, please correct: I create a stream in the process (the injection works fine) with the following contents:

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); 

Here is table = 6ace76d3. Here is a piece of memory:

 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 

Next comes the function call that crashes the program:

 // vtbl[42] указывает на функцию endScene размером 5 байт? pEndScene = (oEndScene)Mem->Create_Hook((PBYTE)vtbl[42], (PBYTE)myEndScene, 5); 

I will give the function code, which I did not understand in general:

 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); } 
  • @Arhad SO has no relation to the RF. questions about reverse engineering are completely resolved here - meta.ru.stackoverflow.com/questions/1070 - PashaPash
  • cc @Duracell - meta.ru.stackoverflow.com/questions/1070 - PashaPash
  • @PashaPash, I recommend that you familiarize yourself with the Criminal Code of the Russian Federation (Art. 1201) and similar laws of your country if you do not live in the territory of the Russian Federation! By establishing the "game", the author accepted the license agreement - the law - above the forum rules! (not to mention the moral principles and norms (if this is an online game, then I have nothing to talk about at all)). - Duracell
  • @PashaPash, if a game with open source and "licensee" is allowed to make any changes to the source code - that is another matter! Here I do not argue. - Duracell
  • I want to insert a menu in C & C: Generals, they definitely don’t support it, but this is about the source code, it’s not. I am guided by the fact that for C & C: Tiberium Wars they laid out the algorithms by which it was encrypted and now it can be reengineered to create all sorts of mods, and it came out much later than the generals - helldrg

1 answer 1

Your mistakes:

  • The game is written on directX8, not version 9, you are trying to hook version 9, LoadLibraryA("d3d9.dll") , you need LoadLibraryA("d3d8.dll") and in the table virtual methods there, as far as I remember, have a slightly different sequence (to check which version of dx applications only need to open the debugger and view the list of loaded modules or view info on wikipedia).

  • You are trying (most likely, these are my guesses) to inject code into the generals.exe process, but this is just a child window and it does not perform the functions of rendering the game world \ menu, etc., you need a game.dat process.

In the evening, when I come home, I will try to redo your code in working condition and supplement the answer. If you are interested, you can read an interesting article on your topic .

UPD:

 #include <Windows.h> #include <d3d8.h> #include <d3dx8.h> #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; } 

How to fix problems with lack of libci:

  1. Download the lib itself and upload it to the project;
  2. Overload additional dependencies, as stated here.

Result: enter image description here

  • Comments are not intended for extended discussion; conversation moved to chat . - PashaPash