mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Start processing of unknown commands print.
* UserMessages need to be properly read like in sub_14028E890 * Started building bf_read * Clean up will follow later.
This commit is contained in:
parent
1bf7b96641
commit
73dd49e8d1
@ -22,13 +22,35 @@ bool SVC_Print::Process()
|
||||
return true; // Original just return true also.
|
||||
}
|
||||
|
||||
bool SVC_UserMessage::Process()
|
||||
{
|
||||
bf_read buf = m_DataIn;
|
||||
UserMessages type = (UserMessages)buf.ReadByte();
|
||||
|
||||
if (type == UserMessages::TextMsg)
|
||||
{
|
||||
char text[256];
|
||||
buf.ReadString(text, sizeof(text));
|
||||
if (strnlen_s(text, 256) > 0)
|
||||
{
|
||||
DevMsg(eDLL_T::SERVER, text);
|
||||
}
|
||||
}
|
||||
|
||||
return SVC_UserMessage_Process(this); // Need to return original.
|
||||
}
|
||||
|
||||
void CNetMessages_Attach()
|
||||
{
|
||||
auto SVCPrint = &SVC_Print::Process;
|
||||
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_Print_VTable, (LPVOID&)SVCPrint, (LPVOID*)&SVC_Print_Process, 3);
|
||||
auto SVCUserMessage = &SVC_UserMessage::Process;
|
||||
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_Print_VTable, (LPVOID&)SVCPrint, (LPVOID*)&SVC_Print_Process, 3);
|
||||
//CMemory::HookVirtualMethod((uintptr_t)g_pSVC_UserMessage_VTable, (LPVOID&)SVCUserMessage, (LPVOID*)&SVC_UserMessage_Process, 3);
|
||||
}
|
||||
|
||||
void CNetMessages_Detach()
|
||||
{
|
||||
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_Print_VTable, (LPVOID)p_SVC_Print_Process, (LPVOID*)&SVC_Print_Process, 3);
|
||||
void* hkRestore = nullptr;
|
||||
CMemory::HookVirtualMethod((uintptr_t)g_pSVC_Print_VTable, (LPVOID)SVC_Print_Process, (LPVOID*)&hkRestore, 3);
|
||||
//CMemory::HookVirtualMethod((uintptr_t)g_pSVC_UserMessage_VTable, (LPVOID)SVC_UserMessage_Process, (LPVOID*)&hkRestore, 3);
|
||||
}
|
@ -1,4 +1,10 @@
|
||||
#pragma once
|
||||
#include "tier1/bitbuf.h"
|
||||
|
||||
enum class UserMessages : int
|
||||
{
|
||||
TextMsg = 0x2
|
||||
};
|
||||
|
||||
class CNetMessage
|
||||
{
|
||||
@ -10,17 +16,30 @@ public:
|
||||
void* m_NetChannel;
|
||||
};
|
||||
|
||||
class SVC_Print : CNetMessage
|
||||
class SVC_Print : public CNetMessage
|
||||
{
|
||||
public:
|
||||
bool Process();
|
||||
|
||||
void* m_pMessageHandler;
|
||||
char padding[8];
|
||||
const char* m_szText;
|
||||
private:
|
||||
char m_szTextBuffer[2048];
|
||||
};
|
||||
|
||||
class SVC_UserMessage : public CNetMessage
|
||||
{
|
||||
public:
|
||||
|
||||
bool Process();
|
||||
|
||||
private:
|
||||
char m_szTextBuffer[2048];
|
||||
void* m_pMessageHandler;
|
||||
char padding[8];
|
||||
int m_nMsgType;
|
||||
int m_nLength; // data length in bits
|
||||
bf_read m_DataIn;
|
||||
bf_write m_DataOut;
|
||||
};
|
||||
|
||||
struct VecNetMessages
|
||||
@ -49,11 +68,15 @@ inline CMemory MM_Heartbeat__ToString; // server HeartBeat? (baseserver.cpp).
|
||||
//-------------------------------------------------------------------------
|
||||
// SVC_Print
|
||||
//-------------------------------------------------------------------------
|
||||
inline CMemory p_SVC_Print_Process;
|
||||
inline auto SVC_Print_Process = p_SVC_Print_Process.RCast<bool(*)(SVC_Print* thisptr)>();
|
||||
|
||||
inline auto SVC_Print_Process = CMemory().RCast<bool(*)(SVC_Print* thisptr)>();
|
||||
inline void* g_pSVC_Print_VTable;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// SVC_UserMessage
|
||||
//-------------------------------------------------------------------------
|
||||
inline auto SVC_UserMessage_Process = CMemory().RCast<bool(*)(SVC_UserMessage* thisptr)>();
|
||||
inline void* g_pSVC_UserMessage_VTable;
|
||||
|
||||
void CNetMessages_Attach();
|
||||
void CNetMessages_Detach();
|
||||
|
||||
@ -63,23 +86,22 @@ class HMM_Heartbeat : public IDetour
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
std::cout << "| FUN: MM_Heartbeat::ToString : 0x" << std::hex << std::uppercase << MM_Heartbeat__ToString.GetPtr() << std::setw(nPad) << " |" << std::endl;
|
||||
std::cout << "| FUN: SVC_Print_Process : 0x" << std::hex << std::uppercase << p_SVC_Print_Process.GetPtr() << std::setw(nPad) << " |" << std::endl;
|
||||
std::cout << "| VAR: SVC_Print_VTable : 0x" << std::hex << std::uppercase << g_pSVC_Print_VTable << std::setw(nPad) << " |" << std::endl;
|
||||
std::cout << "| VAR: SVC_UserMessage_VTable : 0x" << std::hex << std::uppercase << g_pSVC_UserMessage_VTable << std::setw(nPad) << " |" << std::endl;
|
||||
std::cout << "+----------------------------------------------------------------+" << std::endl;
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
MM_Heartbeat__ToString = g_mGameDll.FindPatternSIMD(reinterpret_cast<rsig_t>("\x48\x83\xEC\x38\xE8\x00\x00\x00\x00\x3B\x05\x00\x00\x00\x00"), "xxxxx????xx????");
|
||||
// 0x1402312A0 // 48 83 EC 38 E8 ? ? ? ? 3B 05 ? ? ? ?
|
||||
p_SVC_Print_Process = g_mGameDll.FindPatternSIMD(reinterpret_cast<rsig_t>("\x48\x8B\xD1\x48\x8B\x49\x18\x48\x8B\x01\x48\xFF\x60\x28"), "xxxxxxxxxxxxxx");
|
||||
// 0x1402D0810 // 48 8B D1 48 8B 49 18 48 8B 01 48 FF 60 28
|
||||
|
||||
SVC_Print_Process = p_SVC_Print_Process.RCast<bool(*)(SVC_Print*)>();
|
||||
}
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
// We get the actual address of the vtable here, not the class instance.
|
||||
g_pSVC_Print_VTable = g_mGameDll.FindPatternSIMD(reinterpret_cast<rsig_t>("\x74\x1E\x48\x8D\x05\x00\x00\x00\x00\x89\x5F\x08"), "xxxxx????xxx").OffsetSelf(0x2).ResolveRelativeAddressSelf(0x3, 0x7);
|
||||
// 0x1402D21F6 74 1E 48 8D 05 ? ? ? ? 89 5F 08
|
||||
g_pSVC_UserMessage_VTable = g_mGameDll.FindPatternSIMD(reinterpret_cast<rsig_t>("\xE8\x00\x00\x00\x00\x48\x85\xFF\x74\x65"), "x????xxxxx").OffsetSelf(0xD).ResolveRelativeAddressSelf(0x3, 0x7);
|
||||
// 0x1402D295E E8 ? ? ? ? 48 85 FF 74 65
|
||||
}
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Attach(void) const { }
|
||||
|
@ -8,6 +8,261 @@
|
||||
#include "core/stdafx.h"
|
||||
#include "tier1/bitbuf.h"
|
||||
|
||||
const uint32 s_nMaskTable[33] = {
|
||||
0,
|
||||
(1 << 1) - 1,
|
||||
(1 << 2) - 1,
|
||||
(1 << 3) - 1,
|
||||
(1 << 4) - 1,
|
||||
(1 << 5) - 1,
|
||||
(1 << 6) - 1,
|
||||
(1 << 7) - 1,
|
||||
(1 << 8) - 1,
|
||||
(1 << 9) - 1,
|
||||
(1 << 10) - 1,
|
||||
(1 << 11) - 1,
|
||||
(1 << 12) - 1,
|
||||
(1 << 13) - 1,
|
||||
(1 << 14) - 1,
|
||||
(1 << 15) - 1,
|
||||
(1 << 16) - 1,
|
||||
(1 << 17) - 1,
|
||||
(1 << 18) - 1,
|
||||
(1 << 19) - 1,
|
||||
(1 << 20) - 1,
|
||||
(1 << 21) - 1,
|
||||
(1 << 22) - 1,
|
||||
(1 << 23) - 1,
|
||||
(1 << 24) - 1,
|
||||
(1 << 25) - 1,
|
||||
(1 << 26) - 1,
|
||||
(1 << 27) - 1,
|
||||
(1 << 28) - 1,
|
||||
(1 << 29) - 1,
|
||||
(1 << 30) - 1,
|
||||
0x7fffffff,
|
||||
0xffffffff,
|
||||
};
|
||||
|
||||
|
||||
CBitBuffer::CBitBuffer(void)
|
||||
{
|
||||
m_bOverflow = false;
|
||||
m_pDebugName = NULL;
|
||||
m_nDataBits = -1;
|
||||
m_nDataBytes = 0;
|
||||
}
|
||||
|
||||
void CBitBuffer::SetDebugName(const char* pName)
|
||||
{
|
||||
m_pDebugName = pName;
|
||||
}
|
||||
|
||||
const char* CBitBuffer::GetDebugName()
|
||||
{
|
||||
return m_pDebugName;
|
||||
}
|
||||
|
||||
bool CBitBuffer::IsOverflowed()
|
||||
{
|
||||
return m_bOverflow;
|
||||
}
|
||||
|
||||
void CBitBuffer::SetOverflowFlag()
|
||||
{
|
||||
m_bOverflow = true;
|
||||
}
|
||||
|
||||
void CBitRead::GrabNextDWord(bool bOverFlowImmediately)
|
||||
{
|
||||
if (m_pDataIn == m_pBufferEnd)
|
||||
{
|
||||
m_nBitsAvail = 1;
|
||||
m_nInBufWord = 0;
|
||||
|
||||
m_pDataIn++;
|
||||
|
||||
if (bOverFlowImmediately)
|
||||
SetOverflowFlag();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_pDataIn > m_pBufferEnd)
|
||||
{
|
||||
SetOverflowFlag();
|
||||
m_nInBufWord = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(reinterpret_cast<int>(m_pDataIn) + 3 < reinterpret_cast<int>(m_pBufferEnd));
|
||||
m_nInBufWord = LittleDWord(*(m_pDataIn++));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBitRead::FetchNext()
|
||||
{
|
||||
m_nBitsAvail = 32;
|
||||
GrabNextDWord(false);
|
||||
}
|
||||
|
||||
uint32 CBitRead::ReadUBitLong(int numbits)
|
||||
{
|
||||
if (m_nBitsAvail >= numbits)
|
||||
{
|
||||
unsigned int nRet = m_nInBufWord & s_nMaskTable[numbits];
|
||||
m_nBitsAvail -= numbits;
|
||||
if (m_nBitsAvail)
|
||||
{
|
||||
m_nInBufWord >>= numbits;
|
||||
}
|
||||
else
|
||||
{
|
||||
FetchNext();
|
||||
}
|
||||
return nRet;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 nRet = m_nInBufWord;
|
||||
numbits -= m_nBitsAvail;
|
||||
GrabNextDWord(true);
|
||||
|
||||
if (IsOverflowed())
|
||||
return 0;
|
||||
|
||||
nRet |= ((m_nInBufWord & s_nMaskTable[numbits]) << m_nBitsAvail);
|
||||
m_nBitsAvail = 32 - numbits;
|
||||
m_nInBufWord >>= numbits;
|
||||
|
||||
return nRet;
|
||||
}
|
||||
}
|
||||
|
||||
int CBitRead::ReadSBitLong(int numbits)
|
||||
{
|
||||
int nRet = ReadUBitLong(numbits);
|
||||
return (nRet << (32 - numbits)) >> (32 - numbits);
|
||||
}
|
||||
|
||||
int CBitRead::ReadByte()
|
||||
{
|
||||
return ReadSBitLong(sizeof(unsigned char) << 3);
|
||||
}
|
||||
|
||||
int CBitRead::ReadChar()
|
||||
{
|
||||
return ReadSBitLong(sizeof(char) << 3);
|
||||
}
|
||||
|
||||
bool CBitRead::ReadString(char* pStr, int maxLen, bool bLine, int* pOutNumChars)
|
||||
{
|
||||
assert(maxLen != 0);
|
||||
|
||||
bool bTooSmall = false;
|
||||
int iChar = 0;
|
||||
while (1)
|
||||
{
|
||||
char val = ReadChar();
|
||||
if (val == 0)
|
||||
break;
|
||||
else if (bLine && val == '\n')
|
||||
break;
|
||||
|
||||
if (iChar < (maxLen - 1))
|
||||
{
|
||||
pStr[iChar] = val;
|
||||
++iChar;
|
||||
}
|
||||
else
|
||||
{
|
||||
bTooSmall = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure it's null-terminated.
|
||||
pStr[iChar] = 0;
|
||||
|
||||
if (pOutNumChars)
|
||||
*pOutNumChars = iChar;
|
||||
|
||||
return !IsOverflowed() && !bTooSmall;
|
||||
}
|
||||
|
||||
bool CBitRead::Seek(int nPosition)
|
||||
{
|
||||
bool bSucc = true;
|
||||
if (nPosition < 0 || nPosition > m_nDataBits)
|
||||
{
|
||||
SetOverflowFlag();
|
||||
bSucc = false;
|
||||
nPosition = m_nDataBits;
|
||||
}
|
||||
int nHead = m_nDataBytes & 3; // non-multiple-of-4 bytes at head of buffer. We put the "round off"
|
||||
// at the head to make reading and detecting the end efficient.
|
||||
|
||||
int nByteOfs = nPosition / 8;
|
||||
if ((m_nDataBytes < 4) || (nHead && (nByteOfs < nHead)))
|
||||
{
|
||||
// partial first dword
|
||||
uint8 const* pPartial = (uint8 const*)m_pData;
|
||||
if (m_pData)
|
||||
{
|
||||
m_nInBufWord = *(pPartial++);
|
||||
if (nHead > 1)
|
||||
m_nInBufWord |= (*pPartial++) << 8;
|
||||
if (nHead > 2)
|
||||
m_nInBufWord |= (*pPartial++) << 16;
|
||||
}
|
||||
m_pDataIn = (uint32 const*)pPartial;
|
||||
m_nInBufWord >>= (nPosition & 31);
|
||||
m_nBitsAvail = (nHead << 3) - (nPosition & 31);
|
||||
}
|
||||
else
|
||||
{
|
||||
int nAdjPosition = nPosition - (nHead << 3);
|
||||
m_pDataIn = reinterpret_cast<uint32 const*> (
|
||||
reinterpret_cast<uint8 const*>(m_pData) + ((nAdjPosition / 32) << 2) + nHead);
|
||||
if (m_pData)
|
||||
{
|
||||
m_nBitsAvail = 32;
|
||||
GrabNextDWord();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nInBufWord = 0;
|
||||
m_nBitsAvail = 1;
|
||||
}
|
||||
m_nInBufWord >>= (nAdjPosition & 31);
|
||||
m_nBitsAvail = min(m_nBitsAvail, 32 - (nAdjPosition & 31)); // in case grabnextdword overflowed
|
||||
}
|
||||
return bSucc;
|
||||
}
|
||||
|
||||
void CBitRead::StartReading(const void* pData, int nBytes, int iStartBit, int nBits)
|
||||
{
|
||||
// Make sure it's dword aligned and padded.
|
||||
assert(((unsigned long)pData & 3) == 0);
|
||||
m_pData = (uint32*)pData;
|
||||
m_pDataIn = m_pData;
|
||||
m_nDataBytes = nBytes;
|
||||
|
||||
if (nBits == -1)
|
||||
{
|
||||
m_nDataBits = nBytes << 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(nBits <= nBytes * 8);
|
||||
m_nDataBits = nBits;
|
||||
}
|
||||
m_bOverflow = false;
|
||||
m_pBufferEnd = reinterpret_cast<uint32 const*> (reinterpret_cast<uint8 const*> (m_pData) + nBytes);
|
||||
if (m_pData)
|
||||
Seek(iStartBit);
|
||||
|
||||
}
|
||||
|
||||
inline int BitByte(int bits)
|
||||
{
|
||||
// return PAD_NUMBER( bits, 8 ) >> 3;
|
||||
|
@ -9,9 +9,61 @@ typedef enum
|
||||
BITBUFERROR_NUM_ERRORS
|
||||
} BitBufErrorType;
|
||||
|
||||
#define LittleDWord(val) (val)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Used for serialization
|
||||
//-----------------------------------------------------------------------------
|
||||
#pragma pack(push,1)
|
||||
class CBitBuffer
|
||||
{
|
||||
public:
|
||||
CBitBuffer(void);
|
||||
void SetDebugName(const char* pName);
|
||||
const char* GetDebugName();
|
||||
bool IsOverflowed();
|
||||
void SetOverflowFlag();
|
||||
|
||||
////////////////////////////////////
|
||||
const char* m_pDebugName;
|
||||
uint8_t m_bOverflow;
|
||||
char gap_0x11[7];
|
||||
size_t m_nDataBits;
|
||||
size_t m_nDataBytes;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class CBitRead : public CBitBuffer
|
||||
{
|
||||
public:
|
||||
void GrabNextDWord(bool bOverFlowImmediately = false);
|
||||
void FetchNext();
|
||||
|
||||
int ReadSBitLong(int numbits);
|
||||
uint32 ReadUBitLong(int numbits);
|
||||
|
||||
int ReadByte();
|
||||
int ReadChar();
|
||||
bool ReadString(char* pStr, int bufLen, bool bLine = false, int* pOutNumChars = nullptr);
|
||||
|
||||
void StartReading(const void* pData, int nBytes, int iStartBit = 0, int nBits = -1);
|
||||
|
||||
bool Seek(int nPosition);
|
||||
|
||||
////////////////////////////////////
|
||||
uint32_t m_nInBufWord;
|
||||
uint32_t m_nBitsAvail;
|
||||
const uint32* m_pDataIn;
|
||||
const uint32* m_pBufferEnd;
|
||||
const uint32* m_pData;
|
||||
};
|
||||
|
||||
class bf_read : public CBitRead
|
||||
{
|
||||
public:
|
||||
|
||||
};
|
||||
|
||||
struct bf_write
|
||||
{
|
||||
public:
|
||||
|
Loading…
x
Reference in New Issue
Block a user