Add script patcher and update protections (#588)
This commit is contained in:
parent
4d2667f140
commit
74c8e8d70c
15
CMakeSettings.json
Normal file
15
CMakeSettings.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x64-Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "RelWithDebInfo",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
}
|
||||
]
|
||||
}
|
@ -3,12 +3,16 @@
|
||||
#include "thread_pool.hpp"
|
||||
#include "looped/looped.hpp"
|
||||
#include "services/context_menu/context_menu_service.hpp"
|
||||
#include "script_patches.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
void backend::loop()
|
||||
{
|
||||
while (true) {
|
||||
register_script_patches();
|
||||
|
||||
while (true)
|
||||
{
|
||||
g->attempt_save();
|
||||
looped::system_self_globals();
|
||||
looped::system_update_pointers();
|
||||
|
18
src/backend/script_patches.hpp
Normal file
18
src/backend/script_patches.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "services/script_patcher/script_patcher_service.hpp"
|
||||
#include <script/scrProgramTable.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
void register_script_patches()
|
||||
{
|
||||
g_script_patcher_service.add_patch({ RAGE_JOAAT("freemode"), "2D 01 08 00 ? 38 00 5D ? ? ? 2A 06", 5, {0x6E, 0x2E, 0x01, 0x01}, &g->session.decloak_players });
|
||||
g_script_patcher_service.add_patch({ RAGE_JOAAT("freemode"), "2D 01 04 00 ? 2C ? ? ? 5D ? ? ? 6E 57 ? ? 2C", 5, { 0x2E, 0x01, 0x00 }, &g->protections.script_host_kick });
|
||||
g_script_patcher_service.add_patch({ RAGE_JOAAT("freemode"), "2D 01 09 00 00 5D ? ? ? 56 ? ? 2E", 5, { 0x2E, 0x01, 0x00 }, nullptr }); // disable death when undermap/spectating
|
||||
|
||||
for (auto& entry : *g_pointers->m_script_program_table)
|
||||
{
|
||||
if (entry.m_program)
|
||||
g_script_patcher_service.on_script_load(entry.m_program);
|
||||
}
|
||||
}
|
||||
}
|
@ -111,8 +111,10 @@ namespace big
|
||||
bool spectating = false;
|
||||
};
|
||||
|
||||
struct protections {
|
||||
struct script_events {
|
||||
struct protections
|
||||
{
|
||||
struct script_events
|
||||
{
|
||||
bool bounty = true;
|
||||
bool ceo_ban = true;
|
||||
bool ceo_kick = true;
|
||||
@ -140,9 +142,11 @@ namespace big
|
||||
};
|
||||
|
||||
script_events script_events{};
|
||||
bool script_host_kick = true;
|
||||
};
|
||||
|
||||
struct self {
|
||||
struct self
|
||||
{
|
||||
bool clean_player = false;
|
||||
bool force_wanted_level = false;
|
||||
bool free_cam = false;
|
||||
@ -188,6 +192,7 @@ namespace big
|
||||
bool disable_chat_filter = false;
|
||||
bool log_chat_messages = false;
|
||||
bool log_text_messages = false;
|
||||
bool decloak_players = false;
|
||||
};
|
||||
|
||||
struct settings {
|
||||
@ -233,7 +238,8 @@ namespace big
|
||||
|
||||
bool spoof_cheater = false;
|
||||
|
||||
bool spoof_hide_god = false;
|
||||
bool spoof_hide_god = true;
|
||||
bool spoof_hide_spectate = true;
|
||||
|
||||
bool spoof_rockstar_dev = false;
|
||||
bool spoof_rockstar_qa = false;
|
||||
@ -556,6 +562,8 @@ namespace big
|
||||
script_handler.start_activity = script_handler_j["start_activity"];
|
||||
}
|
||||
|
||||
this->protections.script_host_kick = j["protections"]["script_host_kick"];
|
||||
|
||||
this->tunables.disable_phone = j["tunables"]["disable_phone"];
|
||||
this->tunables.no_idle_kick = j["tunables"]["no_idle_kick"];
|
||||
|
||||
@ -589,6 +597,7 @@ namespace big
|
||||
this->session.log_chat_messages = j["session"]["log_chat_messages"];
|
||||
this->session.log_text_messages = j["session"]["log_text_messages"];
|
||||
this->session.disable_chat_filter = j["session"]["disable_chat_filter"];
|
||||
this->session.decloak_players = j["session"]["decloak_players"];
|
||||
|
||||
this->settings.dev_dlc = j["settings"]["dev_dlc"];
|
||||
this->settings.hotkeys.menu_toggle = j["settings"]["hotkeys"]["menu_toggle"];
|
||||
@ -623,6 +632,9 @@ namespace big
|
||||
this->spoofing.rockstar_id = j["spoofing"]["rockstar_id"];
|
||||
this->spoofing.username = j["spoofing"]["username"];
|
||||
|
||||
this->spoofing.spoof_hide_god = j["spoofing"]["spoof_hide_god"];
|
||||
this->spoofing.spoof_hide_spectate = j["spoofing"]["spoof_hide_spectate"];
|
||||
|
||||
this->vehicle.speed_unit = (SpeedUnit)j["vehicle"]["speed_unit"];
|
||||
this->vehicle.god_mode = j["vehicle"]["god_mode"];
|
||||
this->vehicle.proof_bullet = j["vehicle"]["proof_bullet"];
|
||||
@ -832,7 +844,9 @@ namespace big
|
||||
{ "teleport_to_warehouse", script_handler_protections.teleport_to_warehouse },
|
||||
{ "start_activity", script_handler_protections.start_activity },
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{ "script_host_kick", g->protections.script_host_kick }
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -897,7 +911,8 @@ namespace big
|
||||
"session", {
|
||||
{ "log_chat_messages", this->session.log_chat_messages },
|
||||
{ "log_text_messages", this->session.log_text_messages },
|
||||
{ "disable_chat_filter", this->session.disable_chat_filter }
|
||||
{ "disable_chat_filter", this->session.disable_chat_filter },
|
||||
{ "decloak_players", this->session.decloak_players },
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -951,7 +966,9 @@ namespace big
|
||||
{ "spoof_crew_data", this->spoofing.spoof_crew_data },
|
||||
{ "crew_tag", this->spoofing.crew_tag },
|
||||
{ "rockstar_crew", this->spoofing.rockstar_crew },
|
||||
{ "square_crew_tag", this->spoofing.square_crew_tag }
|
||||
{ "square_crew_tag", this->spoofing.square_crew_tag },
|
||||
{ "spoof_hide_god", this->spoofing.spoof_hide_god },
|
||||
{ "spoof_hide_spectate", this->spoofing.spoof_hide_spectate },
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -145,6 +145,17 @@ namespace rage
|
||||
bool ReadArray(PVOID array, int size) {
|
||||
return big::g_pointers->m_read_bitbuf_array(this, array, size, 0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T Read(int length)
|
||||
{
|
||||
static_assert(sizeof(T) <= 4, "maximum of 32 bit read");
|
||||
|
||||
uint32_t val = 0;
|
||||
ReadDword(&val, length);
|
||||
|
||||
return T(val);
|
||||
}
|
||||
public:
|
||||
uint8_t* m_data; //0x0000
|
||||
uint32_t m_bitOffset; //0x0008
|
||||
@ -155,119 +166,122 @@ namespace rage
|
||||
uint8_t m_flagBits; //0x001C
|
||||
};
|
||||
|
||||
enum class eNetMessage : uint32_t {
|
||||
CMsgInvalid = 0xFFFFF,
|
||||
CMsgSessionAcceptChat = 0x62,
|
||||
CMsgStartMatchCmd = 0x2D,
|
||||
CMsgSetInvitableCmd = 0x1F,
|
||||
CMsgSessionMemberIds = 0x23,
|
||||
CMsgRequestGamerInfo = 0x54,
|
||||
CMsgRemoveGamersFromSessionCmd = 0x53,
|
||||
CMsgNotMigrating = 0x35,
|
||||
CMsgMigrateHostResponse = 0x12,
|
||||
CMsgMigrateHostRequest = 0x66,
|
||||
CMsgJoinResponse = 0x2A,
|
||||
CMsgJoinRequest = 0x41,
|
||||
CMsgHostLeftWhilstJoiningCmd = 0x58,
|
||||
CMsgConfigResponse = 0x5F,
|
||||
CMsgConfigRequest = 0x48,
|
||||
CMsgChangeSessionAttributesCmd = 0x5A,
|
||||
CMsgAddGamerToSessionCmd = 0x64, // this is where send net info to lobby is called, among other things
|
||||
CMsgReassignResponse = 0x10,
|
||||
CMsgReassignNegotiate = 0x01,
|
||||
CMsgReassignConfirm = 0x26,
|
||||
CMsgPlayerData = 0x18,
|
||||
CMsgPackedReliables = 0x30,
|
||||
CMsgPackedCloneSyncACKs = 0x3B,
|
||||
CMsgNonPhysicalData = 0x16,
|
||||
CMsgNetArrayMgrUpdateAck = 0x5D,
|
||||
CMsgNetArrayMgrUpdate = 0x60,
|
||||
CMsgNetArrayMgrSplitUpdateAck = 0x25,
|
||||
CMsgScriptVerifyHostAck = 0x0B,
|
||||
CMsgScriptVerifyHost = 0x3E,
|
||||
CMsgScriptNewHost = 0x0E,
|
||||
CMsgScriptMigrateHostFailAck = 0x1A,
|
||||
CMsgScriptMigrateHost = 0x33,
|
||||
CMsgScriptLeaveAck = 0x40,
|
||||
CMsgScriptLeave = 0x17,
|
||||
CMsgScriptJoinHostAck = 0x4D,
|
||||
CMsgScriptJoinAck = 0x43,
|
||||
CMsgScriptJoin = 0x5C,
|
||||
CMsgScriptHostRequest = 0x67,
|
||||
CMsgScriptHandshakeAck = 0x5B,
|
||||
CMsgScriptHandshake = 0x57,
|
||||
CMsgScriptBotLeave = 0x2B, // unused?
|
||||
CMsgScriptBotJoinAck = 0x63, // unused?
|
||||
CMsgScriptBotJoin = 0x1C, // unused?
|
||||
CMsgScriptBotHandshakeAck = 0x31, // unused?
|
||||
CMsgScriptBotHandshake = 0x4B, // unused?
|
||||
CMsgPartyLeaveGame = 0x3D,
|
||||
CMsgPartyEnterGame = 0x1E,
|
||||
CMsgCloneSync = 0x4E, // aka clone_create, clone_sync etc.
|
||||
CMsgActivateNetworkBot = 0x65, // unused?
|
||||
CMsgRequestObjectIds = 0x29,
|
||||
CMsgInformObjectIds = 0x09,
|
||||
CMsgTextMessage = 0x24, // this one is for chat
|
||||
CMsgPlayerIsTyping = 0x61,
|
||||
CMsgPackedEvents = 0x4F, // aka received_event
|
||||
CMsgPackedEventReliablesCMsgs = 0x20,
|
||||
CMsgRequestKickFromHost = 0x0D,
|
||||
CMsgTransitionToGameStart = 0x50,
|
||||
CMsgTransitionToGameNotify = 0x02,
|
||||
CMsgTransitionToActivityStart = 0x06,
|
||||
CMsgTransitionToActivityFinish = 0x36,
|
||||
CMsgTransitionParameters = 0x3C,
|
||||
CMsgTransitionParameterString = 0x37,
|
||||
CMsgTransitionLaunchNotify = 0x1B,
|
||||
CMsgTransitionLaunch = 0x19,
|
||||
CMsgTransitionGamerInstruction = 0x14,
|
||||
CMsgTextMessage2 = 0x0A, // this one is for phone message
|
||||
CMsgSessionEstablishedRequest = 0x52,
|
||||
CMsgSessionEstablished = 0x07,
|
||||
CMsgRequestTransitionParameters = 0x42,
|
||||
CMsgRadioStationSyncRequest = 0x47,
|
||||
CMsgRadioStationSync = 0x46,
|
||||
CMsgPlayerCardSync = 0x3A,
|
||||
CMsgPlayerCardRequest = 0x6A,
|
||||
CMsgLostConnectionToHost = 0x81,
|
||||
CMsgKickPlayer = 0x34, // host kick
|
||||
CMsgDebugStall = 0x7E, // unused?
|
||||
CMsgCheckQueuedJoinRequestReply = 0x59,
|
||||
CMsgCheckQueuedJoinRequest = 0x51,
|
||||
CMsgBlacklist = 0x0C,
|
||||
CMsgRoamingRequestBubbleRequiredResponse = 0x83,
|
||||
CMsgRoamingRequestBubbleRequiredCheck = 0x82,
|
||||
CMsgRoamingRequestBubble = 0x2E,
|
||||
CMsgRoamingJoinBubble = 0x4C,
|
||||
CMsgRoamingJoinBubbleAck = 0x3F,
|
||||
CMsgRoamingInitialBubble = 0x32,
|
||||
CMsgVoiceStatus = 0x03,
|
||||
CMsgTextChatStatus = 0x00,
|
||||
CMsgJoinResponse2 = 0x08,
|
||||
CMsgJoinRequest2 = 0x68,
|
||||
CMsgNetTimeSync = 0x38, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 37
|
||||
CMsgNetComplaint = 0x55, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 54
|
||||
CMsgNetLagPing = 0x27, // unused? ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 26
|
||||
CMsgSearchResponse = 0x6B, // unused? ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 6A
|
||||
CMsgSearchRequest = 0x05, // unused?
|
||||
CMsgQosProbeResponse = 0x2C, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 2B
|
||||
CMsgQosProbeRequest = 0x1D, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 1C
|
||||
CMsgCxnRelayAddressChanged = 0x49, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 48
|
||||
CMsgCxnRequestRemoteTimeout = 0x2F, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 2E
|
||||
CMsgSessionDetailRequest = 0x22, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 21
|
||||
CMsgSessionDetailResponse = 0x13, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 12
|
||||
CMsgKeyExchangeOffer = 0x0F, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 0E (last result)
|
||||
CMsgKeyExchangeAnswer = 0x44, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 43
|
||||
CMsg_0x87 = 0x87,
|
||||
CMsg_0x88 = 0x88,
|
||||
CMsg_0x80 = 0x80,
|
||||
CMsg_0x28 = 0x28,
|
||||
CMsg_0x11 = 0x11,
|
||||
CMsg_0x45 = 0x45,
|
||||
CMsg_0x89 = 0x89,
|
||||
CMsg_0x86 = 0x86,
|
||||
enum class eNetMessage : uint32_t
|
||||
{
|
||||
MsgInvalid = 0xFFFFF,
|
||||
MsgSessionAcceptChat = 0x62,
|
||||
MsgStartMatchCmd = 0x2D,
|
||||
MsgSetInvitableCmd = 0x1F,
|
||||
MsgSessionMemberIds = 0x23,
|
||||
MsgRequestGamerInfo = 0x54,
|
||||
MsgRemoveGamersFromSessionCmd = 0x53,
|
||||
MsgNotMigrating = 0x35,
|
||||
MsgMigrateHostResponse = 0x12,
|
||||
MsgMigrateHostRequest = 0x66,
|
||||
MsgJoinResponse = 0x2A,
|
||||
MsgJoinRequest = 0x41,
|
||||
MsgHostLeftWhilstJoiningCmd = 0x58,
|
||||
MsgConfigResponse = 0x5F,
|
||||
MsgConfigRequest = 0x48,
|
||||
MsgChangeSessionAttributesCmd = 0x5A,
|
||||
MsgAddGamerToSessionCmd = 0x64, // this is where send net info to lobby is called, among other things
|
||||
MsgReassignResponse = 0x10,
|
||||
MsgReassignNegotiate = 0x01,
|
||||
MsgReassignConfirm = 0x26,
|
||||
MsgPlayerData = 0x18,
|
||||
MsgPackedReliables = 0x30,
|
||||
MsgPackedCloneSyncACKs = 0x3B,
|
||||
MsgNonPhysicalData = 0x16,
|
||||
MsgNetArrayMgrUpdateAck = 0x5D,
|
||||
MsgNetArrayMgrUpdate = 0x60,
|
||||
MsgNetArrayMgrSplitUpdateAck = 0x25,
|
||||
MsgScriptVerifyHostAck = 0x0B,
|
||||
MsgScriptVerifyHost = 0x3E,
|
||||
MsgScriptNewHost = 0x0E,
|
||||
MsgScriptMigrateHostFailAck = 0x1A,
|
||||
MsgScriptMigrateHost = 0x33,
|
||||
MsgScriptLeaveAck = 0x40,
|
||||
MsgScriptLeave = 0x17,
|
||||
MsgScriptJoinHostAck = 0x4D,
|
||||
MsgScriptJoinAck = 0x43,
|
||||
MsgScriptJoin = 0x5C,
|
||||
MsgScriptHostRequest = 0x67,
|
||||
MsgScriptHandshakeAck = 0x5B,
|
||||
MsgScriptHandshake = 0x57,
|
||||
MsgScriptBotLeave = 0x2B, // unused?
|
||||
MsgScriptBotJoinAck = 0x63, // unused?
|
||||
MsgScriptBotJoin = 0x1C, // unused?
|
||||
MsgScriptBotHandshakeAck = 0x31, // unused?
|
||||
MsgScriptBotHandshake = 0x4B, // unused?
|
||||
MsgPartyLeaveGame = 0x3D,
|
||||
MsgPartyEnterGame = 0x1E,
|
||||
MsgCloneSync = 0x4E, // aka clone_create, clone_sync etc.
|
||||
MsgActivateNetworkBot = 0x65, // unused?
|
||||
MsgRequestObjectIds = 0x29,
|
||||
MsgInformObjectIds = 0x09,
|
||||
MsgTextMessage = 0x24, // this one is for chat
|
||||
MsgPlayerIsTyping = 0x61,
|
||||
MsgPackedEvents = 0x4F, // aka received_event
|
||||
MsgPackedEventReliablesMsgs = 0x20,
|
||||
MsgRequestKickFromHost = 0x0D,
|
||||
MsgTransitionToGameStart = 0x50,
|
||||
MsgTransitionToGameNotify = 0x02,
|
||||
MsgTransitionToActivityStart = 0x06,
|
||||
MsgTransitionToActivityFinish = 0x36,
|
||||
MsgTransitionParameters = 0x3C,
|
||||
MsgTransitionParameterString = 0x37,
|
||||
MsgTransitionLaunchNotify = 0x1B,
|
||||
MsgTransitionLaunch = 0x19,
|
||||
MsgTransitionGamerInstruction = 0x14,
|
||||
MsgTextMessage2 = 0x0A, // this one is for phone message
|
||||
MsgSessionEstablishedRequest = 0x52,
|
||||
MsgSessionEstablished = 0x07,
|
||||
MsgRequestTransitionParameters = 0x42,
|
||||
MsgRadioStationSyncRequest = 0x47,
|
||||
MsgRadioStationSync = 0x46,
|
||||
MsgPlayerCardSync = 0x3A,
|
||||
MsgPlayerCardRequest = 0x6A,
|
||||
MsgLostConnectionToHost = 0x81,
|
||||
MsgKickPlayer = 0x34, // host kick
|
||||
MsgDebugStall = 0x7E, // unused?
|
||||
MsgCheckQueuedJoinRequestReply = 0x59,
|
||||
MsgCheckQueuedJoinRequest = 0x51,
|
||||
MsgBlacklist = 0x0C,
|
||||
MsgRoamingRequestBubbleRequiredResponse = 0x83,
|
||||
MsgRoamingRequestBubbleRequiredCheck = 0x82,
|
||||
MsgRoamingRequestBubble = 0x2E,
|
||||
MsgRoamingJoinBubble = 0x4C,
|
||||
MsgRoamingJoinBubbleAck = 0x3F,
|
||||
MsgRoamingInitialBubble = 0x32,
|
||||
MsgVoiceStatus = 0x03,
|
||||
MsgTextChatStatus = 0x00,
|
||||
MsgJoinResponse2 = 0x08,
|
||||
MsgJoinRequest2 = 0x68,
|
||||
MsgNetTimeSync = 0x38, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 37
|
||||
MsgNetComplaint = 0x55, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 54
|
||||
MsgNetLagPing = 0x27, // unused? ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 26
|
||||
MsgSearchResponse = 0x6B, // unused? ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 6A
|
||||
MsgSearchRequest = 0x05, // unused?
|
||||
MsgQosProbeResponse = 0x2C, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 2B
|
||||
MsgQosProbeRequest = 0x1D, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 1C
|
||||
MsgCxnRelayAddressChanged = 0x49, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 48
|
||||
MsgCxnRequestRemoteTimeout = 0x2F, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 2E
|
||||
MsgSessionDetailRequest = 0x22, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 21
|
||||
MsgSessionDetailResponse = 0x13, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 12
|
||||
MsgKeyExchangeOffer = 0x0F, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 0E (last result)
|
||||
MsgKeyExchangeAnswer = 0x44, // ctor 40 53 48 83 EC 20 BA ? ? ? ? 4C 8D 0D ? ? ? ? 48 8B D9 44 8D 42 43
|
||||
Msg_0x87 = 0x87,
|
||||
Msg_0x88 = 0x88,
|
||||
Msg_0x80 = 0x80,
|
||||
Msg_0x28 = 0x28,
|
||||
Msg_0x11 = 0x11,
|
||||
Msg_0x45 = 0x45,
|
||||
Msg_0x89 = 0x89,
|
||||
Msg_0x86 = 0x86,
|
||||
};
|
||||
namespace netConnection {
|
||||
|
||||
namespace netConnection
|
||||
{
|
||||
class InFrame
|
||||
{
|
||||
public:
|
||||
|
@ -25,5 +25,7 @@ namespace big
|
||||
static bool selectable(const std::string_view, bool, ImGuiSelectableFlags);
|
||||
static void selectable(const std::string_view, bool, std::function<void()>);
|
||||
static void selectable(const std::string_view, bool, ImGuiSelectableFlags, std::function<void()>);
|
||||
|
||||
static bool script_patch_checkbox(const std::string_view text, bool* option, const std::string_view tooltip = "");
|
||||
};
|
||||
}
|
||||
|
26
src/gui/components/script_patch_checkbox.cpp
Normal file
26
src/gui/components/script_patch_checkbox.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "components.hpp"
|
||||
#include "fiber_pool.hpp"
|
||||
#include "services/script_patcher/script_patcher_service.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
bool components::script_patch_checkbox(const std::string_view text, bool* option, const std::string_view tooltip)
|
||||
{
|
||||
bool ret = ImGui::Checkbox(text.data(), option);
|
||||
if (ret)
|
||||
{
|
||||
g_fiber_pool->queue_job([]
|
||||
{
|
||||
g_script_patcher_service.update();
|
||||
});
|
||||
}
|
||||
|
||||
if (!tooltip.empty())
|
||||
{
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip(tooltip.data());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -40,6 +40,8 @@ namespace big
|
||||
|
||||
detour_hook_helper::add<hooks::gta_thread_start>("GTS", g_pointers->m_gta_thread_start);
|
||||
detour_hook_helper::add<hooks::gta_thread_kill>("GTK", g_pointers->m_gta_thread_kill);
|
||||
detour_hook_helper::add<hooks::init_native_tables>("INT", g_pointers->m_init_native_tables);
|
||||
detour_hook_helper::add<hooks::script_vm>("SVM", g_pointers->m_script_vm);
|
||||
|
||||
detour_hook_helper::add<hooks::network_player_mgr_init>("NPMI", g_pointers->m_network_player_mgr_init);
|
||||
detour_hook_helper::add<hooks::network_player_mgr_shutdown>("NPMS", g_pointers->m_network_player_mgr_shutdown);
|
||||
|
@ -31,6 +31,8 @@ namespace big
|
||||
|
||||
static GtaThread* gta_thread_start(unsigned int** a1, unsigned int a2);
|
||||
static rage::eThreadState gta_thread_kill(GtaThread* thread);
|
||||
static bool init_native_tables(rage::scrProgram* program);
|
||||
static rage::eThreadState script_vm(uint64_t* start_stack, uint64_t** scr_globals, rage::scrProgram* program, rage::scrThreadContext* ctx);
|
||||
|
||||
static void network_player_mgr_init(CNetworkPlayerMgr* _this, std::uint64_t a2, std::uint32_t a3, std::uint32_t a4[4]);
|
||||
static void network_player_mgr_shutdown(CNetworkPlayerMgr* _this);
|
||||
|
@ -13,7 +13,7 @@ namespace big
|
||||
uint32_t extended{};
|
||||
if ((buffer.m_flagBits & 2) != 0 || (buffer.m_flagBits & 1) == 0 ? (pos = buffer.m_curBit) : (pos = buffer.m_maxBit),
|
||||
buffer.m_bitsRead + 15 > pos || !buffer.ReadDword(&magic, 14) || magic != 0x3246 || !buffer.ReadDword(&extended, 1)) {
|
||||
msgType = rage::eNetMessage::CMsgInvalid;
|
||||
msgType = rage::eNetMessage::MsgInvalid;
|
||||
return false;
|
||||
}
|
||||
length = extended ? 16 : 8;
|
||||
@ -23,6 +23,16 @@ namespace big
|
||||
return false;
|
||||
}
|
||||
|
||||
void gamer_handle_deserialize(rage::rlGamerHandle& hnd, rage::datBitBuffer& buf)
|
||||
{
|
||||
constexpr int PC_PLATFORM = 3;
|
||||
if ((hnd.m_platform = buf.Read<uint8_t>(8)) != PC_PLATFORM)
|
||||
return;
|
||||
|
||||
buf.ReadInt64((int64_t*)&hnd.m_rockstar_id, 64);
|
||||
hnd.unk_0009 = buf.Read<uint8_t>(8);
|
||||
}
|
||||
|
||||
bool hooks::receive_net_message(void* netConnectionManager, void* a2, rage::netConnection::InFrame* frame)
|
||||
{
|
||||
if (frame->get_event_type() == rage::netConnection::InFrame::EventType::FrameReceived)
|
||||
@ -43,7 +53,7 @@ namespace big
|
||||
{
|
||||
switch (msgType)
|
||||
{
|
||||
case rage::eNetMessage::CMsgTextMessage:
|
||||
case rage::eNetMessage::MsgTextMessage:
|
||||
{
|
||||
if (g->session.log_chat_messages)
|
||||
{
|
||||
@ -57,7 +67,7 @@ namespace big
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rage::eNetMessage::CMsgTextMessage2:
|
||||
case rage::eNetMessage::MsgTextMessage2:
|
||||
{
|
||||
if (g->session.log_text_messages)
|
||||
{
|
||||
@ -69,7 +79,7 @@ namespace big
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rage::eNetMessage::CMsgScriptMigrateHost:
|
||||
case rage::eNetMessage::MsgScriptMigrateHost:
|
||||
{
|
||||
if (std::chrono::system_clock::now() - player->m_last_transition_msg_sent < 200ms)
|
||||
{
|
||||
@ -86,7 +96,7 @@ namespace big
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rage::eNetMessage::CMsgRemoveGamersFromSessionCmd:
|
||||
case rage::eNetMessage::MsgRemoveGamersFromSessionCmd:
|
||||
{
|
||||
player_ptr pl;
|
||||
uint64_t session_id;
|
||||
@ -112,6 +122,31 @@ namespace big
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rage::eNetMessage::MsgLostConnectionToHost:
|
||||
{
|
||||
uint64_t session_id;
|
||||
buffer.ReadQWord(&session_id, 64);
|
||||
rage::rlGamerHandle handle;
|
||||
gamer_handle_deserialize(handle, buffer);
|
||||
|
||||
auto self = g_player_service->get_self();
|
||||
if (self->get_net_data() && self->get_net_data()->m_gamer_handle_2.m_rockstar_id == handle.m_rockstar_id)
|
||||
{
|
||||
g_notification_service->push_error("Protections", std::format("{} tried to lost connection kick you!", player->get_name()));
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto& [_, plyr] : g_player_service->players())
|
||||
{
|
||||
if (plyr->get_net_data() && plyr != player && player->get_net_data()->m_gamer_handle_2.m_rockstar_id == handle.m_rockstar_id)
|
||||
{
|
||||
g_notification_service->push_error("Protections", std::format("{} tried to lost connection kick {}!", player->get_name(), plyr->get_name()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,6 @@ namespace big
|
||||
if (g->notifications.gta_thread_kill.notify)
|
||||
g_notification_service->push("Script Thread Termination", std::format("Script Thread '{}' terminated.", thread->m_name));
|
||||
|
||||
g_native_hooks->do_cleanup_for_thread(thread);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -15,9 +15,6 @@ namespace big
|
||||
g_notification_service->push("Script Thread Startup", std::format("Script Thread '{}' started.", name));
|
||||
}
|
||||
|
||||
if (new_thread != nullptr)
|
||||
g_native_hooks->check_for_thread(new_thread);
|
||||
|
||||
return new_thread;
|
||||
}
|
||||
}
|
15
src/hooks/script/init_native_tables.cpp
Normal file
15
src/hooks/script/init_native_tables.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include "hooking.hpp"
|
||||
#include "services/script_patcher/script_patcher_service.hpp"
|
||||
#include "native_hooks/native_hooks.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
bool hooks::init_native_tables(rage::scrProgram* program)
|
||||
{
|
||||
bool ret = g_hooking->get_original<hooks::init_native_tables>()(program);
|
||||
g_script_patcher_service.on_script_load(program);
|
||||
g_native_hooks->hook_program(program);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
20
src/hooks/script/script_vm.cpp
Normal file
20
src/hooks/script/script_vm.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
#include "hooking.hpp"
|
||||
#include <script/scrProgram.hpp>
|
||||
|
||||
#include "services/script_patcher/script_patcher_service.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
rage::eThreadState hooks::script_vm(uint64_t* start_stack, uint64_t** scr_globals, rage::scrProgram* program, rage::scrThreadContext* ctx)
|
||||
{
|
||||
uint8_t** orig_bytecode = program->m_code_blocks;
|
||||
|
||||
if (auto bytecode = g_script_patcher_service.get_script_bytecode(program->m_name_hash))
|
||||
program->m_code_blocks = bytecode;
|
||||
|
||||
auto ret = g_hooking->get_original<hooks::script_vm>()(start_stack, scr_globals, program, ctx);
|
||||
|
||||
program->m_code_blocks = orig_bytecode;
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -7,7 +7,22 @@ namespace big
|
||||
auto ret = g_hooking->get_original<write_player_game_state_data_node>()(player, node);
|
||||
|
||||
if (g->spoofing.spoof_hide_god)
|
||||
{
|
||||
node->m_is_invincible = false;
|
||||
node->m_bullet_proof = false;
|
||||
node->m_collision_proof = false;
|
||||
node->m_explosion_proof = false;
|
||||
node->m_fire_proof = false;
|
||||
node->m_melee_proof = false;
|
||||
node->m_steam_proof = false;
|
||||
node->m_water_proof = false;
|
||||
}
|
||||
|
||||
if (g->spoofing.spoof_hide_spectate)
|
||||
{
|
||||
node->m_is_spectating = false;
|
||||
node->m_spectating_net_id = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ namespace memory
|
||||
inline pattern(const char* ida_sig) :
|
||||
pattern(std::string_view(ida_sig))
|
||||
{}
|
||||
private:
|
||||
|
||||
std::vector<std::optional<std::uint8_t>> m_bytes;
|
||||
};
|
||||
}
|
||||
|
@ -8,5 +8,14 @@ namespace big
|
||||
{
|
||||
LOG(INFO) << "NETWORK_BAIL prevented";
|
||||
}
|
||||
|
||||
inline void IS_PLAYER_PLAYING(rage::scrNativeCallContext* src)
|
||||
{
|
||||
// block undead OTR
|
||||
if (g->session.decloak_players && src->get_arg<Player>(0) != self::id)
|
||||
src->set_return_value<BOOL>(TRUE);
|
||||
else
|
||||
src->set_return_value<BOOL>(PLAYER::IS_PLAYER_PLAYING(src->get_arg<Player>(0)));
|
||||
};
|
||||
}
|
||||
}
|
@ -6,6 +6,9 @@
|
||||
#include "shop_controller.hpp"
|
||||
#include "network_session_host.hpp"
|
||||
|
||||
#include <script/scrProgram.hpp>
|
||||
#include <script/scrProgramTable.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
constexpr auto ALL_SCRIPT_HASH = RAGE_JOAAT("ALL_SCRIPTS");
|
||||
@ -18,12 +21,13 @@ namespace big
|
||||
add_native_detour(RAGE_JOAAT("carmod_shop"), 0x34E710FF01247C5A, carmod_shop::SET_VEHICLE_LIGHTS);
|
||||
add_native_detour(RAGE_JOAAT("carmod_shop"), 0x767FBC2AC802EF3D, carmod_shop::STAT_GET_INT);
|
||||
add_native_detour(RAGE_JOAAT("freemode"), 0x95914459A87EBA28, freemode::NETWORK_BAIL);
|
||||
add_native_detour(RAGE_JOAAT("freemode"), 0x5E9564D8246B909A, freemode::IS_PLAYER_PLAYING);
|
||||
add_native_detour(RAGE_JOAAT("shop_controller"), 0xDC38CC1E35B6A5D7, shop_controller::SET_WARNING_MESSAGE_WITH_HEADER);
|
||||
add_native_detour(RAGE_JOAAT("maintransition"), 0x6F3D4ED9BEE4E61D, network::NETWORK_SESSION_HOST);
|
||||
|
||||
for (const auto& native_detours_for_script : m_native_registrations)
|
||||
if (const auto thread = gta_util::find_script_thread(native_detours_for_script.first); thread != nullptr && thread->m_context.m_state == rage::eThreadState::running)
|
||||
this->check_for_thread(thread);
|
||||
for (auto& entry : *g_pointers->m_script_program_table)
|
||||
if (entry.m_program)
|
||||
hook_program(entry.m_program);
|
||||
|
||||
g_native_hooks = this;
|
||||
}
|
||||
@ -43,17 +47,16 @@ namespace big
|
||||
if (const auto& it = m_native_registrations.find(script_hash); it != m_native_registrations.end())
|
||||
{
|
||||
it->second.emplace_back(hash, detour);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_native_registrations.emplace(script_hash, std::vector<native_detour>({ { hash, detour } }));
|
||||
}
|
||||
|
||||
bool native_hooks::check_for_thread(const GtaThread* gta_thread)
|
||||
void native_hooks::hook_program(rage::scrProgram* program)
|
||||
{
|
||||
std::unordered_map<rage::scrNativeHash, rage::scrNativeHandler> native_replacements;
|
||||
const auto script_hash = gta_thread->m_script_hash;
|
||||
const auto script_hash = program->m_name_hash;
|
||||
|
||||
// Functions that need to be detoured for all scripts
|
||||
if (const auto& pair = m_native_registrations.find(ALL_SCRIPT_HASH); pair != m_native_registrations.end())
|
||||
@ -67,29 +70,15 @@ namespace big
|
||||
|
||||
if (!native_replacements.empty())
|
||||
{
|
||||
if (m_script_hooks.find(gta_thread->m_script_hash) != m_script_hooks.end())
|
||||
{
|
||||
// this should never happen but if it does we catch it
|
||||
LOG_IF(G3LOG_DEBUG, g->debug.logs.script_hook_logs) << "Dynamic native script hook still active for script, cleaning up...";
|
||||
|
||||
m_script_hooks.erase(gta_thread->m_script_hash);
|
||||
}
|
||||
|
||||
m_script_hooks.emplace(
|
||||
gta_thread->m_script_hash,
|
||||
std::make_unique<script_hook>(gta_thread->m_script_hash, native_replacements)
|
||||
program,
|
||||
std::make_unique<script_hook>(program, native_replacements)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void native_hooks::do_cleanup_for_thread(const GtaThread* gta_thread)
|
||||
void native_hooks::unhook_program(rage::scrProgram* program)
|
||||
{
|
||||
if (m_script_hooks.erase(gta_thread->m_script_hash))
|
||||
{
|
||||
LOG_IF(G3LOG_DEBUG, g->debug.logs.script_hook_logs) << gta_thread->m_name << " script terminated, cleaning up native hooks";
|
||||
}
|
||||
m_script_hooks.erase(program);
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ namespace big
|
||||
{
|
||||
using native_detour = std::pair<rage::scrNativeHash, rage::scrNativeHandler>;
|
||||
|
||||
std::map<rage::joaat_t, std::vector<native_detour>> m_native_registrations;
|
||||
std::map<rage::joaat_t, std::unique_ptr<script_hook>> m_script_hooks;
|
||||
std::unordered_map<rage::joaat_t, std::vector<native_detour>> m_native_registrations;
|
||||
std::unordered_map<rage::scrProgram*, std::unique_ptr<script_hook>> m_script_hooks;
|
||||
|
||||
public:
|
||||
native_hooks();
|
||||
@ -37,20 +37,9 @@ namespace big
|
||||
*/
|
||||
void add_native_detour(rage::joaat_t script_hash, rage::scrNativeHash hash, rage::scrNativeHandler detour);
|
||||
|
||||
/**
|
||||
* @brief Check if this thread requires us to hook anything
|
||||
*
|
||||
* @param gta_thread A GtaThread pointer to hook natives from
|
||||
* @return true If we detoured a function
|
||||
* @return false If no functions have been detoured
|
||||
*/
|
||||
bool check_for_thread(const GtaThread* gta_thread);
|
||||
/**
|
||||
* @brief If a GtaThread terminates call this function to remove the unused script_hook
|
||||
*
|
||||
* @param gta_thread
|
||||
*/
|
||||
void do_cleanup_for_thread(const GtaThread* gta_thread);
|
||||
void hook_program(rage::scrProgram* program);
|
||||
|
||||
void unhook_program(rage::scrProgram* program);
|
||||
};
|
||||
|
||||
inline native_hooks* g_native_hooks{};
|
||||
|
@ -434,6 +434,18 @@ namespace big
|
||||
m_join_session_by_info = ptr.add(1).rip().as<functions::join_session_by_info>();
|
||||
});
|
||||
|
||||
// Init Native Tables
|
||||
main_batch.add("INT", "8B CB E8 ? ? ? ? 8B 43 70 ? 03 C4 A9 00 C0 FF FF", [this](memory::handle ptr)
|
||||
{
|
||||
m_init_native_tables = ptr.add(3).rip().as<PVOID>();
|
||||
});
|
||||
|
||||
// Script VM
|
||||
main_batch.add("VM", "E8 ? ? ? ? 48 85 FF 48 89 1D", [this](memory::handle ptr)
|
||||
{
|
||||
m_script_vm = ptr.add(1).rip().as<PVOID>();
|
||||
});
|
||||
|
||||
auto mem_region = memory::module(nullptr);
|
||||
main_batch.run(mem_region);
|
||||
|
||||
|
@ -136,6 +136,9 @@ namespace big
|
||||
const char* m_online_version;
|
||||
|
||||
PVOID m_invalid_mods_crash_detour{};
|
||||
|
||||
PVOID m_init_native_tables{};
|
||||
PVOID m_script_vm{};
|
||||
};
|
||||
|
||||
inline pointers* g_pointers{};
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include "pointers.hpp"
|
||||
#include "script_hook.hpp"
|
||||
|
||||
#include "native_hooks/native_hooks.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
inline std::unordered_map<rage::scrProgram*, script_hook*> script_hook::s_map;
|
||||
@ -30,6 +32,12 @@ namespace big
|
||||
ensure();
|
||||
}
|
||||
|
||||
script_hook::script_hook(rage::scrProgram* program, std::unordered_map<rage::scrNativeHash, rage::scrNativeHandler> native_replacements) :
|
||||
m_native_replacements(std::move(native_replacements))
|
||||
{
|
||||
hook_instance(program);
|
||||
}
|
||||
|
||||
script_hook::~script_hook()
|
||||
{
|
||||
if (m_program)
|
||||
@ -101,6 +109,8 @@ namespace big
|
||||
hook->m_vmt_hook->disable();
|
||||
hook->m_vmt_hook.reset();
|
||||
|
||||
g_native_hooks->unhook_program(this_);
|
||||
|
||||
og_func(this_, free_memory);
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ namespace big
|
||||
{
|
||||
public:
|
||||
explicit script_hook(rage::joaat_t script_hash, std::unordered_map<rage::scrNativeHash, rage::scrNativeHandler> native_replacements);
|
||||
explicit script_hook(rage::scrProgram* program, std::unordered_map<rage::scrNativeHash, rage::scrNativeHandler> native_replacements);
|
||||
~script_hook();
|
||||
|
||||
void ensure();
|
||||
|
30
src/services/script_patcher/script_data.hpp
Normal file
30
src/services/script_patcher/script_data.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
namespace big
|
||||
{
|
||||
class script_data
|
||||
{
|
||||
std::uint32_t m_num_pages;
|
||||
|
||||
public:
|
||||
std::uint32_t m_code_size;
|
||||
std::uint8_t** m_bytecode;
|
||||
|
||||
script_data(std::uint32_t code_size, std::uint8_t** bytecode, std::uint32_t num_pages) :
|
||||
m_code_size(code_size),
|
||||
m_bytecode(bytecode),
|
||||
m_num_pages(num_pages)
|
||||
{
|
||||
}
|
||||
|
||||
~script_data()
|
||||
{
|
||||
for (auto i = 0u; i < m_num_pages; i++)
|
||||
{
|
||||
delete[] m_bytecode[i];
|
||||
}
|
||||
|
||||
delete[] m_bytecode;
|
||||
}
|
||||
};
|
||||
}
|
68
src/services/script_patcher/script_patch.cpp
Normal file
68
src/services/script_patcher/script_patch.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include "script_patch.hpp"
|
||||
#include "script_data.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
script_patch::script_patch(rage::joaat_t script, const memory::pattern pattern, int32_t offset, std::vector<std::uint8_t> patch, bool* enable_bool) :
|
||||
m_script(script),
|
||||
m_pattern(pattern),
|
||||
m_offset(offset),
|
||||
m_patch(std::move(patch)),
|
||||
m_bool(enable_bool),
|
||||
m_ip(0)
|
||||
{
|
||||
}
|
||||
|
||||
std::uint8_t* script_patch::get_code_address(script_data* data, std::uint32_t index)
|
||||
{
|
||||
return &data->m_bytecode[index >> 14][index & 0x3FFF];
|
||||
}
|
||||
|
||||
const std::optional<uint32_t> script_patch::get_code_location_by_pattern(script_data* data, const memory::pattern& pattern)
|
||||
{
|
||||
std::uint32_t code_size = data->m_code_size;
|
||||
for (std::uint32_t i = 0; i < (code_size - pattern.m_bytes.size()); i++)
|
||||
{
|
||||
for (std::uint32_t j = 0; j < pattern.m_bytes.size(); j++)
|
||||
if (pattern.m_bytes[j].has_value())
|
||||
if (pattern.m_bytes[j].value() != *get_code_address(data, i + j))
|
||||
goto incorrect;
|
||||
|
||||
return i;
|
||||
incorrect:
|
||||
continue;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void script_patch::enable(script_data* data)
|
||||
{
|
||||
std::memcpy(get_code_address(data, m_ip), m_patch.data(), m_patch.size());
|
||||
}
|
||||
|
||||
void script_patch::disable(script_data* data)
|
||||
{
|
||||
std::memcpy(get_code_address(data, m_ip), m_original.data(), m_original.size());
|
||||
}
|
||||
|
||||
void script_patch::update(script_data* data)
|
||||
{
|
||||
if (m_ip == 0)
|
||||
{
|
||||
auto result = get_code_location_by_pattern(data, m_pattern);
|
||||
if (!result.has_value())
|
||||
LOG(FATAL) << "Failed to find pattern";
|
||||
|
||||
m_ip = result.value() + m_offset;
|
||||
|
||||
for (int i = 0; i < m_patch.size(); i++)
|
||||
m_original.push_back(*get_code_address(data, m_ip + i));
|
||||
}
|
||||
|
||||
if (!m_bool || *m_bool)
|
||||
enable(data);
|
||||
else
|
||||
disable(data);
|
||||
}
|
||||
}
|
29
src/services/script_patcher/script_patch.hpp
Normal file
29
src/services/script_patcher/script_patch.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include "memory/pattern.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
struct script_data;
|
||||
|
||||
class script_patch
|
||||
{
|
||||
rage::joaat_t m_script;
|
||||
const memory::pattern m_pattern;
|
||||
int32_t m_offset;
|
||||
std::vector<uint8_t> m_patch;
|
||||
std::vector<uint8_t> m_original;
|
||||
bool* m_bool;
|
||||
int32_t m_ip;
|
||||
|
||||
static std::uint8_t* get_code_address(script_data* data, std::uint32_t index);
|
||||
static const std::optional<uint32_t> get_code_location_by_pattern(script_data* data, const memory::pattern& pattern);
|
||||
void enable(script_data* data);
|
||||
void disable(script_data* data);
|
||||
|
||||
public:
|
||||
inline rage::joaat_t get_script() { return m_script; }
|
||||
|
||||
script_patch(rage::joaat_t script, const memory::pattern pattern, int32_t offset, std::vector<std::uint8_t> patch, bool* enable_bool);
|
||||
void update(script_data* data);
|
||||
};
|
||||
}
|
87
src/services/script_patcher/script_patcher_service.cpp
Normal file
87
src/services/script_patcher/script_patcher_service.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include <script/scrProgram.hpp>
|
||||
#include "script_patcher_service.hpp"
|
||||
#include "script_patch.hpp"
|
||||
#include "script_data.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
script_data* script_patcher_service::get_data_for_script(rage::joaat_t script)
|
||||
{
|
||||
for (auto& p : m_script_data)
|
||||
{
|
||||
if (p.first == script)
|
||||
{
|
||||
return p.second.get();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool script_patcher_service::does_script_have_patches(rage::joaat_t script)
|
||||
{
|
||||
for (auto& p : m_script_patches)
|
||||
{
|
||||
if (p.get_script() == script)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void script_patcher_service::create_data_for_script(rage::scrProgram* program)
|
||||
{
|
||||
auto pages = new std::uint8_t * [program->get_num_code_pages()];
|
||||
|
||||
for (auto i = 0u; i < program->get_num_code_pages(); i++)
|
||||
{
|
||||
pages[i] = new std::uint8_t[program->get_code_page_size(i)];
|
||||
std::memcpy(pages[i], program->get_code_page(i), program->get_code_page_size(i));
|
||||
}
|
||||
|
||||
m_script_data.emplace(program->m_name_hash, std::make_unique<script_data>(program->m_code_size, pages, program->get_num_code_pages()));
|
||||
}
|
||||
|
||||
void script_patcher_service::update_all_patches_for_script(rage::joaat_t script)
|
||||
{
|
||||
auto data = get_data_for_script(script);
|
||||
|
||||
for (auto& p : m_script_patches)
|
||||
if (p.get_script() == script)
|
||||
p.update(data);
|
||||
}
|
||||
|
||||
void script_patcher_service::add_patch(script_patch&& patch)
|
||||
{
|
||||
m_script_patches.push_back(std::move(patch));
|
||||
}
|
||||
|
||||
void script_patcher_service::on_script_load(rage::scrProgram* program)
|
||||
{
|
||||
if (get_data_for_script(program->m_name_hash) == nullptr && does_script_have_patches(program->m_name_hash))
|
||||
{
|
||||
create_data_for_script(program);
|
||||
update_all_patches_for_script(program->m_name_hash);
|
||||
}
|
||||
}
|
||||
|
||||
std::uint8_t** script_patcher_service::get_script_bytecode(rage::joaat_t script)
|
||||
{
|
||||
if (auto data = get_data_for_script(script))
|
||||
return data->m_bytecode;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void script_patcher_service::update()
|
||||
{
|
||||
for (auto& p : m_script_patches)
|
||||
{
|
||||
auto data = get_data_for_script(p.get_script());
|
||||
if (data)
|
||||
{
|
||||
p.update(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
src/services/script_patcher/script_patcher_service.hpp
Normal file
26
src/services/script_patcher/script_patcher_service.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <script/scrProgram.hpp>
|
||||
#include "memory/pattern.hpp"
|
||||
#include "script_patch.hpp"
|
||||
#include "script_data.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
class script_patcher_service
|
||||
{
|
||||
std::vector<script_patch> m_script_patches;
|
||||
std::unordered_map<rage::joaat_t, std::unique_ptr<script_data>> m_script_data;
|
||||
script_data* get_data_for_script(rage::joaat_t script);
|
||||
bool does_script_have_patches(rage::joaat_t script);
|
||||
void create_data_for_script(rage::scrProgram* program);
|
||||
void update_all_patches_for_script(rage::joaat_t script);
|
||||
|
||||
public:
|
||||
void add_patch(script_patch&& patch);
|
||||
void on_script_load(rage::scrProgram* program);
|
||||
std::uint8_t** get_script_bytecode(rage::joaat_t script);
|
||||
void update();
|
||||
};
|
||||
|
||||
inline script_patcher_service g_script_patcher_service;
|
||||
}
|
@ -44,5 +44,8 @@ namespace big
|
||||
ImGui::Checkbox("Disable Filter", &g->session.disable_chat_filter);
|
||||
ImGui::Checkbox("Log Chat Messages", &g->session.log_chat_messages);
|
||||
ImGui::Checkbox("Log Text Messages", &g->session.log_text_messages);
|
||||
|
||||
components::sub_title("Decloak");
|
||||
components::script_patch_checkbox("Reveal OTR Players", &g->session.decloak_players);
|
||||
}
|
||||
}
|
||||
|
@ -52,8 +52,9 @@ namespace big
|
||||
ImGui::Text("Rockstar ID:");
|
||||
ImGui::InputScalar("##rockstar_id_input", ImGuiDataType_U64, &g->spoofing.rockstar_id);
|
||||
|
||||
components::sub_title("Proofs");
|
||||
components::sub_title("Hide Features");
|
||||
ImGui::Checkbox("Hide God Mode", &g->spoofing.spoof_hide_god);
|
||||
ImGui::Checkbox("Hide Spectate", &g->spoofing.spoof_hide_spectate);
|
||||
|
||||
components::sub_title("Crew");
|
||||
|
||||
|
@ -43,6 +43,7 @@ namespace big
|
||||
ImGui::BeginGroup();
|
||||
ImGui::Checkbox("Teleport To Warehouse", &g->protections.script_events.teleport_to_warehouse);
|
||||
ImGui::Checkbox("Start Activity", &g->protections.script_events.start_activity);
|
||||
components::script_patch_checkbox("Script Host Kick", &g->protections.script_host_kick);
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user