brunph / gta-antisig

21 stars 2 forks source link

Bypass is detected? #1

Closed maybegreat48 closed 1 year ago

maybegreat48 commented 2 years ago

The game runs a routine every minute that hashes the bonus tunable data and count and compares that with another hash presumably generated when the tunables are downloaded

See https://github.com/Yimura/YimMenu/issues/274

(PS maybe we can just zero qword_7FF7DB5B3C50 every tick)

yubie-re commented 2 years ago

the hash is calculated during tunables processing. this bypass SHOULD still work fine if injected before tunables are downloaded (at least basing off the psuedo you posted), but you're right that by changing the signature count after is detectable. By changing the "bonus" string the game sees it as just not having any sigs in the tunables json in the first place, so the signature hash would still be the same before and after. would just need to find a way to remove them after they're loaded in (maybe trigger a tunable download so it's overwritten?). either way, it's more efficient to just stop more parts of the system as a whole rather than attacking each part at once.

yubie-re commented 2 years ago

download seems to be able to be triggered by calling ctunables+8, but probably has to be done within a game thread, so a hook of some sorts will have to be added

maybegreat48 commented 2 years ago

if ( v0 && is_network_session && qword_7FF7DB5B3C50 ) The function only runs if the hash is initialized already, if we replace the hash ptr with nullptr the check will not run NETWORK::NETWORK_REQUEST_CLOUD_TUNABLES looks like it reloads the tunables

yubie-re commented 2 years ago

some relevant details: it's a standard sha1 hash. general structure/psuedo below:

sha1_init(ctx);
sha1_update(ctx, game_version);
int sig_count = 0;
for(auto sig : tunable_array)
{
    if(sig.m_game_version == currrent)
    {
        sha1_update(ctx, sig.data[0]); // non arxan encrypted data, still xor'd
        sha1_update(ctx, sig.data[1]);
        sha1_update(ctx, sig.data[2]);
        sha1_update(ctx, sig.data[3]);
        sha1_update(ctx, (sig.data[4] ^ xor_const) & 0xFFFFFF);
        sig_count++;
    }
}
sha1_update(ctx, sig_count);
char out[20];
sha1_final(ctx, out);
// jumps to some obfuscated routine which most likely sets the mentioned qword.
yubie-re commented 2 years ago

qword_7FF7DB5B3C50 (gta+26A3C50) is going to be hard to get a reliable sig for. would basically have to hardcode it and change each update which isn't great.

yubie-re commented 2 years ago

alternate idea: call gta5.exe + 107B904, aka parse_tunables: parse_tunables(__int64 ctunables, __int64 tunables_json, unsigned int json_size, char unk_false, char unk_true, unsigned int *unk); call it as so:

auto str = R"({"version":1,"format":1,"poolSize":2200,"bonus":[]})";
parse_tunables(tunables, str, sizeof(str), false, true, nullptr);

and patch out GTA5.exe + 107C6E4 with a ret temporarily so actual tunables don't get overwritten/parsed, only the bonus section, giving us an immediate effect. still requires a proper tlscontext, but could be worth looking into since I don't want to add an invoker to this project.