roflmuffin / CounterStrikeSharp

CounterStrikeSharp allows you to write server plugins in C# for Counter-Strike 2/Source2/CS2
https://docs.cssharp.dev
Other
743 stars 111 forks source link

Copy bytes of a module to prevent signature scanning failures and some minor changes #414

Closed Nukoooo closed 3 months ago

Nukoooo commented 4 months ago

Why

With the current implementation of FindSignature, we scan bytes in memory, which can get patched or modified during runtime, and if we try to scan bytes that are patched then it results in a failure. Here is the minimum code to reproduce:

private MemoryFunctionWithReturn<CPlayer_ObserverServices, IntPtr, bool> CPlayerObserverService_OnClientCommand;

public override void OnAllPluginsLoaded(bool hotReload)
{
    var signature = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
        ? @"\x48\x89\x5C\x24\x2A\x48\x89\x6C\x24\x2A\x48\x89\x74\x24\x2A\x57\x48\x83\xEC\x2A\x83\xBA\x2A\x2A\x2A\x2A\x2A\x48\x8D\x2D\x2A\x2A\x2A\x2A\x48\x8B\xF2\x48\x8B\xF9"
        : @"\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x4C\x8D\x2D\x2A\x2A\x2A\x2A\x41\x54\x49\x89\xFC\x53\x48\x89\xF3";

    var address = NativeAPI.FindSignature(Addresses.ServerPath, signature);

    // Returns the address
    Logger.LogInformation($"[Prehook] CPlayerObserverService_OnClientCommand: 0x{address:X}");

    CPlayerObserverService_OnClientCommand = new(signature, Addresses.ServerPath);
    CPlayerObserverService_OnClientCommand.Hook(Handler, HookMode.Pre);

    address = NativeAPI.FindSignature(Addresses.ServerPath, signature);

    // If we find the signature after it is hooked, it returns 0.
    // Because the first 5 bytes (assuming it is within 2GB range) are replaced with "0xE8 0xDE 0xAD 0xBE 0xEF"
    // and the bytes we are looking for, take Linux signature as an example, are "0x55 0x48 0x89 0xE5 0x41"
    // hence FindSignature fails to find the bytes we need
    Logger.LogInformation($"[PostHook] CPlayerObserverService_OnClientCommand: 0x{address:X}");
}

private HookResult Handler(DynamicHook arg)
{
    return HookResult.Continue;
}

What's changed in this PR

NaiJii commented 4 months ago

This is good, I did something similar (but didn't cache from files) and it improves sigscans speed quite a bit.

roflmuffin commented 4 months ago

I'm assuming this means then if you call a virtual function that has been hooked, you will find the newly trampolined address and that works as expected?

Nukoooo commented 4 months ago

the newly trampolined address

I'm not sure what this means, if it means the address of a hooked function then yes, this PR addresses this issue.

roflmuffin commented 4 months ago

Testing this on Linux, the TestPlugin SwitchTeam hook no longer works, because it doesn't appear to be able to find the module:

[01:09:54.385] CSSharp: Cannot find module /home/container/game/csgo/bin/linuxsteamrt64/libserver.so.

The file obviously very much exists, but doesn't appear to be loaded into the map

roflmuffin commented 3 months ago

@Nukoooo Ready to merge?

Nukoooo commented 3 months ago

I can't really think of anything to add/improve right now, so yeah please merge :)