Add script patcher and update protections (#588)

This commit is contained in:
maybegreat48 2022-11-12 18:35:28 +00:00 committed by GitHub
parent 4244ff8093
commit e6ce363963
31 changed files with 610 additions and 172 deletions

15
CMakeSettings.json Normal file
View 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": ""
}
]
}

View File

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

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

View File

@ -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 },
}
},
{

View File

@ -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:

View File

@ -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 = "");
};
}

View 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;
}
}

View File

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

View File

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

View File

@ -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;
}
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View 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;
}
}

View 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;
}
}

View File

@ -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;
}

View File

@ -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;
};
}

View File

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

View File

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

View File

@ -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{};

View File

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

View File

@ -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{};

View File

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

View File

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

View 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;
}
};
}

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

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

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

View 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;
}

View File

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

View File

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

View File

@ -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();
}