[LUA] My collection of helpers

Upload *YOUR* gamehacking tools/helpers here
Post Reply
Frouk
Expert Cheater
Expert Cheater
Posts: 90
Joined: Wed Jun 30, 2021 10:21 am
Reputation: 18

[LUA] My collection of helpers

Post by Frouk »

Classes/structures

Code: Select all

function GameClass(baseAddress, structure)
    local cls = {
        base = getAddressSafe(baseAddress),
        structure = structure
    }

    function cls:getBaseAddress()
        return rawget(self, "base")
    end

    function cls:getFieldAddress(field)
        return cls:getBaseAddress() + self.structure[field].offset
    end

    local function setStructureInheritance(structure)
        if structure._parent then
            setStructureInheritance(structure._parent)
            for key, field in pairs(structure._parent) do
                if not structure[key] and key ~= "_parent" then
                    structure[key] = field
                end
            end
        end
    end

    if structure._parent then
        setStructureInheritance(structure)
    end

    if not cls.base or cls.base == 0 then
        return nil
    end

    setmetatable(cls, {
        __index = function(self, key)
            local function readBasedOnType(self, field, type)
                if field.type == "byte" then
                    return readByte(self.base + field.offset)
                elseif field.type == "short" then
                    return readSmallInteger(self.base + field.offset)
                elseif field.type == "int" then
                    return readInteger(self.base + field.offset)
                elseif field.type == "long" then
                    return readQword(self.base + field.offset)
                elseif field.type == "float" then
                    return readFloat(self.base + field.offset)
                elseif field.type == "double" then
                    return readDouble(self.base + field.offset)
                elseif field.type == "string" then
                    return readString(self.base + field.offset, field.length) or ""
                elseif field.type == "pointer" then
                    local pointerAddress = readPointer(self.base + field.offset)
                    if pointerAddress == nil or pointerAddress == 0 then
                        return nil
                    elseif field.structure == "self" then
                        return GameClass(pointerAddress, self.structure)
                    elseif field.structure then
                        return GameClass(pointerAddress, field.structure)
                    else
                        return pointerAddress
                    end
                elseif field.type == "class" or field.type == "struct" then
                    local structAddr = getAddress(self.base + field.offset)
                    if field.structure then
                        return GameClass(structAddr, field.structure)
                    else
                        return structAddr
                    end
                elseif field.type == "array" then
                    local array = {}
                    local elemSize = field.elemSize or 4
                    local numElem = field.num
                    local elemType = field.elemType
                    local baseAddr = self.base + field.offset

                    for i = 0, numElem - 1 do
                        local elemAddr = baseAddr + i * elemSize
                        if elemType == "byte" then
                            table.insert(array, readByte(elemAddr))
                        elseif elemType == "short" then
                            table.insert(array, readSmallInteger(elemAddr))
                        elseif elemType == "int" then
                            table.insert(array, readInteger(elemAddr))
                        elseif elemType == "long" then
                            table.insert(array, readQword(elemAddr))
                        elseif elemType == "float" then
                            table.insert(array, readFloat(elemAddr))
                        elseif elemType == "double" then
                            table.insert(array, readDouble(elemAddr))
                        elseif elemType == "pointer" then
                            table.insert(array, readPointer(elemAddr))
                        elseif elemType == "class" or elemType == "struct" then
                            table.insert(array, GameClass(elemAddr, field.elemStructure))
                        else
                            error("Unsupported array element type: " .. elemType)
                        end
                    end

                    return array
                else
                    error("Unsupported type: " .. field.type)
                end
            end

            local field = self.structure[key]

            if type(field) == "function" then
                return field
            end

            if (type(field) ~= "table") then
                return rawget(self, key)
            end

            if not field then
                error("Field '" .. key .. "' does not exist!")
            end

            return readBasedOnType(self, field, field.type)
        end,
        __newindex = function(self, key, value)
            local field = self.structure[key]
            if not field then
                error("Field '" .. key .. "' does not exist or is not writable!")
            end

            if field.type == "byte" then
                writeByte(self.base + field.offset, value)
            elseif field.type == "short" then
                writeSmallInteger(self.base + field.offset, value)
            elseif field.type == "int" then
                writeInteger(self.base + field.offset, value)
            elseif field.type == "long" then
                writeQword(self.base + field.offset, value)
            elseif field.type == "float" then
                writeFloat(self.base + field.offset, value)
            elseif field.type == "double" then
                writeDouble(self.base + field.offset, value)
            elseif field.type == "string" then
                writeString(self.base + field.offset, value, field.length)
            elseif field.type == "pointer" then
                error("Cannot directly write to a pointer field!") -- Optional safety
            else
                error("Unsupported type: " .. field.type)
            end
        end,
        __eq = function(self, other)
            if (type(other) == "table") then
                return self.base == other.base
            end

            return self.base == other
        end
    })

    return cls
end

-- How it works?
-- Simple as it is

-- Let's say we want to declare a structure

PlayerBase = 
{
	m_fHealth = {type = "float", offset = 0x80},
	m_fMaxHealth = {type = "float", offset = 0x84}
	m_Info = {type = "pointer", offset = 0x90, structure = { -- Can be also treated as `structure = SomeClass`
			m_Ammo = {type = "int", offset = 0x14},
			m_CurrentWeapon = {type = "int", offset = 0x4}
		}
	} 
}

local Player = GameClass(0x12345678, PlayerBase) -- And if it didn't initialized, the Player will be nil

Player.m_fHealth = 50.0
Player.m_Info.m_Ammo = 900

printf("Now we have %f health", Player.m_fHealth)
printf("And some ammo(probably too much) %d", Player.m_Info.m_Ammo)

-- For inheritance
-- Let's take the example below

BaseEntity = 
{
	m_iHealth = {type = "int", offset = 0x50},
	m_iMaxHealth = {type = "int", offset = 0x54}
}

BasePlayer = 
{
	_parent = BaseEntity,
	m_iAmmo = {type = "int", offset = 0x60},
	m_Weapons = {type = "array", elemSize = 4, elemType = "pointer", num = 6, offset = 0x80} -- accessed like a typical table if it's not type of `class` or `struct`
}

-- The whole explanation:
-- [[
The main code accesses the structure of a player to get appropriate type with offsets
The values of fields are being changed according to their type and setted value, so you don't need to write functions like writeXXXXX
GameClass constructor takes the first argument for a base of a structure located in the memory
-- ]]
Virtual Table Method Navigation

Code: Select all

function GetVMT(object, index)
  if (not index) then
      return readPointer(object)
  end
  return function(...) return executeMethod(0, nil, readPointer(GetVMT(object, nil) + (targetIs64Bit() and 8 or 4) * index), object, ...) end
end

-- To access any virtual table method at the moment
local setHealth = GetVMT(player, 16) -- Or 0x40 / 4 assuming that the target is 32 bit
setHealth(128)
-- Or
GetVMT(player, 16)(128)

Post Reply

Who is online

Users browsing this forum: The Mogician