home..

Bypassing the Forgelight Engine’s Anti-Data Tampering Code

Planetside 2 and H1Z1 generate hashes for specific intervals of data within some data structures. In H1Z1, a lot more areas have this type of data tampering protection enabled. If the stored hash is not equal to a recently generated hash, the game will force an exception and crash.

In this example, it’s going to be used to bypass the data tampering protection contained within weapon firemode data for Planetside 2.

uintptr_t calculateXorHash(const Address& begin, const Address& end)
{
	uintptr_t hash = 0;
 
	for (Address i = begin; i.as<uintptr_t>() < end.as<uintptr_t>(); i = i.get(8))
		hash ^= i.to<uintptr_t>();
 
	return hash;
}
// mess with all the fire mode data...
fireMode.zeroTheSpread();
fireMode.zeroTheRecoil();
fireMode.setNumBullets(50);
fireMode.setProjectileSpeed(999999.0f);
 
// and then update the firemode data hash
// or we will crash next frame due to data tampering detection :)
fireMode.updateHash();
void FireMode::updateHash()
{
	*get(hashStore).as<uintptr_t*>() = calculateXorHash(get(hashBegin), get(hashEnd));
}

Pretty silly stuff.

The offsets are not shown, but the hashing for the firemode starts at firemode + 0x10, and ends at firemode + 0x178. The resulting hash always seems to be stored at the end of the hashing interval.

Now, this can be applied to any interval of data that uses this protection. All that’s needed is the address/offset of the beginning of the protected data, and the end (or the size) of the protected data. This is assuming that everywhere this protection is found, the resulting hash is stored at the end of the interval.

A little side note: The game also sets a bool to true when it finds that the hashes do not match eachother. I believe this bool is stored right after the hash.

Pseudo struct layout of the firemode, showing how the anti-data tampering works:

struct FireModeExample
{
	char arbitrary[0x10]; // 0x0
	
	// data to be hashed/"protected"
	char dataToBeHashed[0x168]; // 0x10
	// hash to be compared to next frame's data hash
	unsigned long long hash; // 0x178
 
	// I believe that when this is set to true, the game, or the anticheat
	// forces an exception and causes a crash.
	// I don't just set this to false, because it probably checks this value before the end of the frame
	// which is where my hooks are.
	bool dataTampered;
}
© 2023 praydog   •  Theme  Moonwalk