Jump to content
Moopler
Sign in to follow this  
NewSprux2.0?

Snippet [Warframe] Hacking necessities

Recommended Posts

For anyone interested in ever hacking Warframe, most of their in-game structures are based on this encoding:

EncodedType.hpp

#pragma once

class EncodedType
{
	unsigned int flags;			// + 0x00 - 1st bit = init flag, rest = pointer

public:
	bool initialized();

protected:
	void set_flags();
};

class EncodedShort : public EncodedType
{
	static const unsigned short data_key = 0x1A9E;
	static const unsigned short checksum_key = 0xD7F1;

	unsigned short data;		// + 0x04
	unsigned short checksum;	// + 0x06

public:
	unsigned short get();
	void set(unsigned short* value);
};

class EncodedInt : public EncodedType
{
	static const unsigned int data_key = 0x3D821A9E;
	static const unsigned int checksum_key = 0x2D30D7F1;

	unsigned int data;			// + 0x04
	unsigned int checksum;		// + 0x08

public:
	unsigned int get();
	void set(unsigned int* value);
};

class EncodedFloat : public EncodedInt
{
public:
	float get();
	void set(float value);
};

 

EncodedType.cpp

#include "EncodedType.hpp"

#include <intrin.h>

/* EncodedType */
bool EncodedType::initialized()
{
	return ((this->flags & 1) != 0);
}

void EncodedType::set_flags()
{
	this->flags |= 1;

	unsigned short* flag_pointer = reinterpret_cast<unsigned short*>(this->flags & 0xFFFFFFFE);

	if (flag_pointer)
		*flag_pointer |= 1;
}

/* EncodedShort */
unsigned short EncodedShort::get() 
{
	unsigned short decrypted_data = this->data;

	decrypted_data ^= reinterpret_cast<unsigned short>(&this->data);
	decrypted_data ^= this->data_key;

	return _rotr16(decrypted_data, 3);
}

void EncodedShort::set(unsigned short* value)
{
	if (this->get() != *value)
	{
		unsigned short encrypted_data = _rotl16(*value, 3);
			
		encrypted_data ^= reinterpret_cast<unsigned short>(&this->data);
		encrypted_data ^= this->data_key;

		this->data = encrypted_data;
		this->checksum = encrypted_data ^ this->checksum_key;

		this->set_flags();
	}
}

/* EncodedInt */
unsigned int EncodedInt::get()
{
	unsigned int decrypted_data = this->data;

	decrypted_data ^= reinterpret_cast<unsigned int>(&this->data);
	decrypted_data ^= this->data_key;

	return _rotr(decrypted_data, 3);
}

void EncodedInt::set(unsigned int* value)
{
	if (this->get() != *value)
	{
		unsigned int encrypted_data = _rotl(*value, 3);
			
		encrypted_data ^= reinterpret_cast<unsigned int>(&this->data);
		encrypted_data ^= this->data_key;

		this->data = encrypted_data;
		this->checksum = encrypted_data ^ this->checksum_key;

		this->set_flags();
	}
}

/* EncodedFloat */
float EncodedFloat::get()
{
	unsigned int integer = this->EncodedInt::get();
	return *reinterpret_cast<float*>(&integer);
}

void EncodedFloat::set(float value)
{
	unsigned int integer = *reinterpret_cast<unsigned int*>(&value);
	return this->EncodedInt::set(&integer);
}

 

This is necessary to change values in the game. Here's a few examples of how to use it:

class AmmunitionVtbl
{
public:
	typedef unsigned int (__fastcall* get_clip_capacity_t)(void* ecx, void* edx);

	padding(0x18C);
	get_clip_capacity_t get_clip_capacity;
};

#pragma pack(push, 1)
class __declspec(align(2)) Ammunition
{
public:
	AmmunitionVtbl* vtable;
	padding_sub(0x9E8, sizeof(AmmunitionVtbl*));
	unsigned short clip;
};
#pragma pack(pop)

static_assert_size(sizeof(AmmunitionVtbl), 0x18C + 4);
static_assert_size(sizeof(Ammunition), 0x9E8 + 2);

bool Hook_unlimited_ammo(bool enable)
{
	typedef int (__fastcall* set_ammunition_clip_t)(Ammunition* ecx, void* edx, unsigned int clip, bool check_capacity);
	static set_ammunition_clip_t set_ammunition_clip = reinterpret_cast<set_ammunition_clip_t>(module_start + 0x906000); // 8B 44 24 04 8D 51 04 ? ? BF 9E 1A 00 00 0F B7 (2nd)
		
	static set_ammunition_clip_t set_ammunition_clip_hook = [](Ammunition* ecx, void* edx, unsigned int clip, bool check_capacity) -> int
	{
		if (check_capacity)
		{
			unsigned int capacity = ecx->vtable->get_clip_capacity(ecx, nullptr);

			if (clip < capacity && !OverlayMenu::get_instance().is_enabled("Unlimited Ammunition"))
				capacity = clip;

			return (ecx->clip = capacity);
		}
		else
		{
			return (ecx->clip = clip);
		}
	};
		
	typedef void (__fastcall* set_ammunition_t)(EncodedShort* ecx, void* edx, WORD* ammo_ptr);
	static set_ammunition_t set_ammunition = reinterpret_cast<set_ammunition_t>(module_start + 0x107B250); // 8B 44 24 04 8D 51 04 ? ? BF 9E 1A 00 00 0F B7 (2nd)
		
	static set_ammunition_t set_ammunition_hook = [](EncodedShort* ecx, void* edx, WORD* ammo_ptr) -> void
	{
		if (OverlayMenu::get_instance().is_enabled("Unlimited Ammunition") && ecx->get() > *ammo_ptr)
			*ammo_ptr = ecx->get();

		return set_ammunition(ecx, edx, ammo_ptr);
	};
		
	return detours::redirect(enable, reinterpret_cast<void**>(&set_ammunition_clip), set_ammunition_clip_hook) &&
		detours::redirect(enable, reinterpret_cast<void**>(&set_ammunition), set_ammunition_hook);
}

bool Hook_unlimited_energy(bool enable)
{
	typedef float (__fastcall* get_max_energy_t)(void* ecx, void* edx);
	static get_max_energy_t get_max_energy = reinterpret_cast<get_max_energy_t>(module_start + 0x108A400); // 51 8B 81 ? ? 00 00 8B 00 85 C0 74 ? 80 B9 ? ? 00 00 00 74 ? 8B C8 83 (start)
		
	static get_max_energy_t get_max_energy_hook = [](void* ecx, void* edx) -> float
	{
		float max_energy = get_max_energy(ecx, edx);
			
		if (OverlayMenu::get_instance().is_enabled("Unlimited Energy"))
			reinterpret_cast<EncodedFloat*>(reinterpret_cast<unsigned char*>(ecx) + 0x22D0)->set(max_energy);
			
		return max_energy;
	};

	return detours::redirect(enable, reinterpret_cast<void**>(&get_max_energy), get_max_energy_hook);
}
	
bool Hook_unlimited_health(bool enable)
{
	typedef unsigned int (__fastcall* get_max_health_t)(void* ecx, void* edx, int unknown);
	static get_max_health_t get_max_health = reinterpret_cast<get_max_health_t>(module_start + 0xE31A20); // 51 56 57 8B F9 8B B7 ? ? 00 00 8D (start)
		
	static get_max_health_t get_max_health_hook = [](void* ecx, void* edx, int unknown) -> unsigned int
	{
		unsigned int max_health = get_max_health(ecx, edx, unknown);
			
		if (OverlayMenu::get_instance().is_enabled("Unlimited Health"))
			reinterpret_cast<EncodedInt*>(reinterpret_cast<unsigned char*>(ecx) + 0x62C)->set(&max_health);

		return max_health;
	};

	return detours::redirect(enable, reinterpret_cast<void**>(&get_max_health), get_max_health_hook);
}

bool Hook_unlimited_shield(bool enable)
{
	typedef unsigned int (__fastcall* get_max_shield_t)(void* ecx, void* edx, int unknown);
	static get_max_shield_t get_max_shield = reinterpret_cast<get_max_shield_t>(module_start + 0xD3E340); // 83 EC ? 53 55 56 8B F1 33 D2 8B (start)
		
	static get_max_shield_t get_max_shield_hook = [](void* ecx, void* edx, int unknown) -> unsigned int
	{
		unsigned int max_shield = get_max_shield(ecx, edx, unknown);
			
		if (OverlayMenu::get_instance().is_enabled("Unlimited Shield"))
			reinterpret_cast<EncodedInt*>(reinterpret_cast<unsigned char*>(ecx) + 0x12C0)->set(&max_shield);

		return max_shield;
	};

	return detours::redirect(enable, reinterpret_cast<void**>(&get_max_shield), get_max_shield_hook);
}

 

Edited by NewSprux2.0?
Added C highlight.
  • Like 5

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×