From e60add32d6f5466fe2f1c057c1183d2536d44c6d Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Mon, 14 Oct 2024 20:07:51 +0800 Subject: [PATCH] Fix layout for CZDS worldmap. --- Plugins/VGUI2Extension/ClientVGUI.cpp | 191 +++++++++++++++++++++++++- Plugins/VGUI2Extension/privatefuncs.h | 8 ++ src/metahook.cpp | 68 ++++++--- 3 files changed, 243 insertions(+), 24 deletions(-) diff --git a/Plugins/VGUI2Extension/ClientVGUI.cpp b/Plugins/VGUI2Extension/ClientVGUI.cpp index ebaf205b..9bcf15e6 100644 --- a/Plugins/VGUI2Extension/ClientVGUI.cpp +++ b/Plugins/VGUI2Extension/ClientVGUI.cpp @@ -38,6 +38,8 @@ IClientVGUI* g_pClientVGUI = NULL; CounterStrikeViewport* g_pCounterStrikeViewport = NULL; static vgui::Panel* g_pCSBackGroundPanel = NULL; +static vgui::Panel* g_pWorldMapPanel = NULL; +static vgui::Panel* g_pWorldMapMissionSelectPanel = NULL; static hook_t* g_phook_ClientVGUI_Panel_Init = NULL; static hook_t* g_phook_ClientVGUI_KeyValues_LoadFromFile = NULL; @@ -290,6 +292,65 @@ bool VGUI2_IsCSBackGroundPanelActivate(PVOID Candidate, int *pOffsetBase) return false; } +typedef struct +{ + bool bFoundCall80h; + int iFoundPush255Count; + void* SurfaceGetScreenSize; +}VGUI2_IsCWorldMapPaintBackground_SearchContext; + +bool VGUI2_IsCWorldMapPaintBackground(PVOID Candidate, void ** pSurfaceGetScreenSize) +{ + VGUI2_IsCWorldMapPaintBackground_SearchContext ctx = { 0 }; + + g_pMetaHookAPI->DisasmRanges(Candidate, 0x500, [](void* inst, PUCHAR address, size_t instLen, int instCount, int depth, PVOID context) { + auto pinst = (cs_insn*)inst; + auto ctx = (VGUI2_IsCWorldMapPaintBackground_SearchContext*)context; + + if (!ctx->bFoundCall80h && + pinst->id == X86_INS_CALL && + pinst->detail->x86.op_count == 1 && + pinst->detail->x86.operands[0].type == X86_OP_MEM && + pinst->detail->x86.operands[0].mem.base != 0 && + pinst->detail->x86.operands[0].mem.disp == 0x80) + { + ctx->bFoundCall80h = true; + ctx->SurfaceGetScreenSize = address; + } + + if (ctx->iFoundPush255Count < 4 && + pinst->id == X86_INS_PUSH && + pinst->detail->x86.op_count == 1 && + pinst->detail->x86.operands[0].type == X86_OP_IMM && + pinst->detail->x86.operands[0].imm == 0xFF) + { + ctx->iFoundPush255Count ++; + } + + if (ctx->bFoundCall80h && ctx->iFoundPush255Count >= 4) + return TRUE; + + if (address[0] == 0xCC) + return TRUE; + + if (pinst->id == X86_INS_RET) + return TRUE; + + return FALSE; + + }, 0, &ctx); + + if (ctx.bFoundCall80h && ctx.iFoundPush255Count >= 4) + { + if (pSurfaceGetScreenSize) + (*pSurfaceGetScreenSize) = ctx.SurfaceGetScreenSize; + + return true; + } + + return false; +} + typedef struct { PVOID CallCandidates[4]; @@ -535,6 +596,26 @@ void ClientVGUI_KeyValues_LoadFromFile_CounterStrike(KeyValues* pthis, const cha } } +void ClientVGUI_KeyValues_LoadFromFile_CZDS(KeyValues* pthis, const char* resourceName, const char* pathId) +{ + if (!strcmp(resourceName, "resource/UI/WorldMap.res")) + { + auto pWorldMap = pthis->FindKey("WorldMap"); + + if (pWorldMap) + { + ClientVGUI_KeyValues_FitToFullScreen(pWorldMap); + } + + auto pMissionSelect = pthis->FindKey("MissionSelect"); + + if (pMissionSelect) + { + ClientVGUI_KeyValues_FitToFullScreen(pMissionSelect); + } + } +} + void __fastcall CCSBackGroundPanel_Activate(vgui::Panel* pthis, int dummy) { gPrivateFuncs.CCSBackGroundPanel_Activate(pthis, dummy); @@ -546,6 +627,38 @@ void __fastcall CCSBackGroundPanel_Activate(vgui::Panel* pthis, int dummy) } } +void __fastcall CWorldMap_PaintBackground_SurfaceGetScreenSize(vgui::ISurface *pthis, int dummy, int& screenWide, int& screenTall) +{ + //xScale = swide / 640.0; + //yScale = stall / 480.0; + + //Let xScale = yScale + vgui::surface()->GetScreenSize(screenWide, screenTall); + + screenWide = (double)screenTall * 640.0 / 480.0; +} + +void __fastcall CWorldMap_PaintBackground(vgui::Panel* pthis, int dummy) +{ + gPrivateFuncs.CWorldMap_PaintBackground(pthis, dummy); +} + +void __fastcall CWorldMapMissionSelect_PaintBackground_SurfaceGetScreenSize(vgui::ISurface *pthis, int dummy, int& screenWide, int& screenTall) +{ + //xScale = swide / 640.0; + //yScale = stall / 480.0; + + //Let xScale = yScale + vgui::surface()->GetScreenSize(screenWide, screenTall); + + screenWide = (double)screenTall * 640.0 / 480.0; +} + +void __fastcall CWorldMapMissionSelect_PaintBackground(vgui::Panel* pthis, int dummy) +{ + gPrivateFuncs.CWorldMapMissionSelect_PaintBackground(pthis, dummy); +} + #if 0 void ResizeWindowControls(vgui::Panel* pWindow, int offsetX, int offsetY) { @@ -704,9 +817,13 @@ bool __fastcall ClientVGUI_KeyValues_LoadFromFile(void* pthis, int dummy, IFileS } } - if (ret && g_bIsCounterStrike) + if (ret) { - ClientVGUI_KeyValues_LoadFromFile_CounterStrike((KeyValues *)pthis, resourceName, pathId); + if (g_bIsCounterStrike) + ClientVGUI_KeyValues_LoadFromFile_CounterStrike((KeyValues *)pthis, resourceName, pathId); + + if (g_bIsCZDS) + ClientVGUI_KeyValues_LoadFromFile_CZDS((KeyValues*)pthis, resourceName, pathId); } return ret; @@ -788,9 +905,79 @@ void CClientVGUIProxy::Start(void) break; } } + Sig_FuncNotFound(CCSBackGroundPanel_Activate); } + if (g_bIsCZDS) + { + int offset_WorldMapPanel = 0x7A8; + + g_pWorldMapPanel = *(vgui::Panel**)((PUCHAR)this + offset_WorldMapPanel); + + gPrivateFuncs.CWorldMap_vftable = *(PVOID**)g_pWorldMapPanel; + + if ( + !((ULONG_PTR)gPrivateFuncs.CWorldMap_vftable > (ULONG_PTR)g_dwClientBase && + (ULONG_PTR)gPrivateFuncs.CWorldMap_vftable < (ULONG_PTR)g_dwClientBase + g_dwClientSize)) + { + Sig_NotFound("CWorldMap"); + } + + for (int index = 105; index <= 106; ++index) + { + PVOID SurfaceGetScreenSize = NULL; + if (VGUI2_IsCWorldMapPaintBackground(gPrivateFuncs.CWorldMap_vftable[index], &SurfaceGetScreenSize)) + { + if (!SurfaceGetScreenSize) + { + Sig_NotFound("CWorldMap_PaintBackground_SurfaceGetScreenSize"); + } + g_pMetaHookAPI->InlinePatchRedirectBranch(SurfaceGetScreenSize, CWorldMap_PaintBackground_SurfaceGetScreenSize, NULL); + + gPrivateFuncs.CWorldMap_PaintBackground_vftable_index = index; + //g_pMetaHookAPI->VFTHook(g_pWorldMapPanel, 0, index, CWorldMap_PaintBackground, (void**)&gPrivateFuncs.CWorldMap_PaintBackground); + break; + } + } + } + + if (g_bIsCZDS) + { + g_pWorldMapMissionSelectPanel = g_pWorldMapPanel->FindChildByName("MissionSelect"); + + if (!g_pWorldMapMissionSelectPanel) + { + Sig_NotFound("WorldMapMissionSelectPanel"); + } + + gPrivateFuncs.CWorldMapMissionSelect_vftable = *(PVOID**)g_pWorldMapMissionSelectPanel; + + if ( + !((ULONG_PTR)gPrivateFuncs.CWorldMapMissionSelect_vftable > (ULONG_PTR)g_dwClientBase && + (ULONG_PTR)gPrivateFuncs.CWorldMapMissionSelect_vftable < (ULONG_PTR)g_dwClientBase + g_dwClientSize)) + { + Sig_NotFound("CWorldMapMissionSelect_vftable"); + } + + for (int index = 105; index <= 106; ++index) + { + PVOID SurfaceGetScreenSize = NULL; + if (VGUI2_IsCWorldMapPaintBackground(gPrivateFuncs.CWorldMapMissionSelect_vftable[index], &SurfaceGetScreenSize)) + { + if (!SurfaceGetScreenSize) + { + Sig_NotFound("CWorldMapMissionSelect_PaintBackground_SurfaceGetScreenSize"); + } + g_pMetaHookAPI->InlinePatchRedirectBranch(SurfaceGetScreenSize, CWorldMapMissionSelect_PaintBackground_SurfaceGetScreenSize, NULL); + + gPrivateFuncs.CWorldMapMissionSelect_PaintBackground_vftable_index = index; + //g_pMetaHookAPI->VFTHook(g_pWorldMapMissionSelectPanel, 0, index, CWorldMapMissionSelect_PaintBackground, (void**)&gPrivateFuncs.CWorldMapMissionSelect_PaintBackground); + break; + } + } + } + VGUI2ExtensionInternal()->ClientVGUI_Start(); g_NativeClientHasVGUI1 = UseVGUI1(); diff --git a/Plugins/VGUI2Extension/privatefuncs.h b/Plugins/VGUI2Extension/privatefuncs.h index a9ef02a6..cbfe92ab 100644 --- a/Plugins/VGUI2Extension/privatefuncs.h +++ b/Plugins/VGUI2Extension/privatefuncs.h @@ -64,6 +64,14 @@ typedef struct void** CCSBackGroundPanel_vftable; int CCSBackGroundPanel_XOffsetBase; + int CWorldMap_PaintBackground_vftable_index; + void(__fastcall* CWorldMap_PaintBackground)(void* pthis, int dummy); + void** CWorldMap_vftable; + + int CWorldMapMissionSelect_PaintBackground_vftable_index; + void(__fastcall* CWorldMapMissionSelect_PaintBackground)(void* pthis, int dummy); + void** CWorldMapMissionSelect_vftable; + //void* (__fastcall* CClientMOTD_ctor)(void* pthis, int, void* parent); //void (__fastcall* CClientMOTD_PerformLayout)(void* pthis, int dummy); //void (__fastcall* CClientMOTD_ApplySettings)(void* pthis, int dummy, void* inResourceData); diff --git a/src/metahook.cpp b/src/metahook.cpp index 1bcbd46c..5697b159 100644 --- a/src/metahook.cpp +++ b/src/metahook.cpp @@ -2495,38 +2495,62 @@ bool MH_IsBogusVFTableEntry(PVOID pVirtualFuncAddr, PVOID pOldFuncAddr) hook_t* MH_InlinePatchRedirectBranch(void* pInstructionAddress, void* pNewFuncAddr, void** pOrginalCall) { - auto pSourceCode = (PUCHAR)pInstructionAddress; + typedef struct + { + PUCHAR pSourceCode; + PUCHAR pNewFuncAddr; + ULONG PatchLength; + UCHAR NewCodeBytes[8]; + }MH_InlinePatchRedirectBranch_PatchContext; - ULONG PatchLength = 0; - UCHAR NewCodeBytes[8]; + MH_InlinePatchRedirectBranch_PatchContext ctx = { 0 }; + + ctx.pSourceCode = (PUCHAR)pInstructionAddress; + ctx.pNewFuncAddr = (PUCHAR)pNewFuncAddr; + memset(ctx.NewCodeBytes, 0x90, sizeof(ctx.NewCodeBytes)); - if (pSourceCode[0] == 0xE9 || pSourceCode[0] == 0xE8) + if (ctx.pSourceCode[0] == 0xE9 || ctx.pSourceCode[0] == 0xE8) { - PatchLength = 5; - NewCodeBytes[0] = pSourceCode[0]; - *(int*)(NewCodeBytes + 1) = (PUCHAR)pNewFuncAddr - ((PUCHAR)pInstructionAddress + 5); + ctx.PatchLength = 5; + ctx.NewCodeBytes[0] = ctx.pSourceCode[0]; + *(int*)(ctx.NewCodeBytes + 1) = ctx.pNewFuncAddr - (ctx.pSourceCode + 5); } - else if (pSourceCode[0] == 0xFF && pSourceCode[1] == 0x15) + else if (ctx.pSourceCode[0] == 0xFF && ctx.pSourceCode[1] == 0x15) { //indirect call - PatchLength = 6; - NewCodeBytes[0] = 0xE8; - NewCodeBytes[5] = 0x90; - *(int*)(NewCodeBytes + 1) = (PUCHAR)pNewFuncAddr - ((PUCHAR)pInstructionAddress + 5); + ctx.PatchLength = 6; + ctx.NewCodeBytes[0] = 0xE8; + *(int*)(ctx.NewCodeBytes + 1) = ctx.pNewFuncAddr - (ctx.pSourceCode + 5); } - else if (pSourceCode[0] == 0xFF && pSourceCode[1] == 0x25) + else if (ctx.pSourceCode[0] == 0xFF && ctx.pSourceCode[1] == 0x25) { //indirect jmp - PatchLength = 6; - NewCodeBytes[0] = 0xE9; - NewCodeBytes[5] = 0x90; - *(int*)(NewCodeBytes + 1) = (PUCHAR)pNewFuncAddr - ((PUCHAR)pInstructionAddress + 5); + ctx.PatchLength = 6; + ctx.NewCodeBytes[0] = 0xE9; + *(int*)(ctx.NewCodeBytes + 1) = ctx.pNewFuncAddr - (ctx.pSourceCode + 5); } else { - return NULL; + MH_DisasmSingleInstruction(pInstructionAddress, [](void* inst, PUCHAR address, size_t instLen, PVOID context) { + + auto pinst = (cs_insn*)inst; + auto ctx = (MH_InlinePatchRedirectBranch_PatchContext*)context; + + if (pinst->id == X86_INS_CALL && + pinst->detail->x86.op_count == 1 && + pinst->detail->x86.operands[0].type == X86_OP_MEM && instLen >= 5) + { + ctx->PatchLength = instLen; + ctx->NewCodeBytes[0] = 0xE8; + *(int*)(ctx->NewCodeBytes + 1) = ctx->pNewFuncAddr - (ctx->pSourceCode + 5); + } + + }, &ctx); } + if (!ctx.PatchLength) + return NULL; + hook_t* h = MH_NewHook(MH_HOOK_INLINEPATCH); if (!h) @@ -2538,9 +2562,9 @@ hook_t* MH_InlinePatchRedirectBranch(void* pInstructionAddress, void* pNewFuncAd h->pNewFuncAddr = pNewFuncAddr; h->pOrginalCall = pOrginalCall; h->hookData.inlinepatch.pInstructionAddress = pInstructionAddress; - h->hookData.inlinepatch.PatchLength = PatchLength; - memcpy(h->hookData.inlinepatch.NewCodeBytes, NewCodeBytes, PatchLength); - memcpy(h->hookData.inlinepatch.OriginalBytes, (PUCHAR)pInstructionAddress, PatchLength); + h->hookData.inlinepatch.PatchLength = ctx.PatchLength; + memcpy(h->hookData.inlinepatch.NewCodeBytes, ctx.NewCodeBytes, ctx.PatchLength); + memcpy(h->hookData.inlinepatch.OriginalBytes, (PUCHAR)pInstructionAddress, ctx.PatchLength); if (g_bTransactionHook) { @@ -2548,7 +2572,7 @@ hook_t* MH_InlinePatchRedirectBranch(void* pInstructionAddress, void* pNewFuncAd } else { - MH_WriteMemory(pInstructionAddress, NewCodeBytes, PatchLength); + MH_WriteMemory(pInstructionAddress, ctx.NewCodeBytes, ctx.PatchLength); if (h->pOrginalCall) (*h->pOrginalCall) = h->pOldFuncAddr;