Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


[HELP] Force CE Lua variable to be Int32, not Int64 (CE7.1)

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting
View previous topic :: View next topic  
Author Message
ApacheTech
Newbie cheater
Reputation: 0

Joined: 26 Jun 2020
Posts: 14

PostPosted: Wed Sep 02, 2020 12:26 pm    Post subject: [HELP] Force CE Lua variable to be Int32, not Int64 (CE7.1) Reply with quote

I'm trying to implement a JOAAT Hasher in Cheat Engine, and I can't seem to get it to work, because a "number" defaults to be an Int64. JOAAT requires the hash to be Int32. How do I define a LUA variable as an Int32?

This is the code I'm using:

Code:

JOAAT = {

    m_LookupTable =
    {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
        0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x2F, 0x5D, 0x5E, 0x5F,
        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
        0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
        0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
        0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
        0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
        0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
        0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
    },

    GetHashKeySubString = function(str, initialHash)
        local hash = initialHash or 0;
        for i = 1, str:len(), 1 do
            hash = hash + JOAAT.m_LookupTable[string.byte(str:sub(i,i))];
            hash = hash + hash << 10;
            hash = hash ~ hash >> 6;
        end
        return hash;
    end,

    GetHashKeyFinalize = function(str, initialHash)
        local hash = initialHash or 0;
        local  hash = JOAAT.GetHashKeySubString(str, initialHash);
        hash = hash + hash << 3;
        hash = hash ~ hash >> 11;
        hash = hash + hash << 15;
        return hash;
    end,

    GetHashKey = function(str, concat, initialHash)
        local hash = initialHash or 0;
        if type(concat) == "string" then
            return JOAAT.GetHashKeyFinalize(concat, GTAHasher.GetHashKeySubString(str, initialHash));
        else
            return JOAAT.GetHashKeyFinalize(str, initialHash);
        end
    end
};


Expected output:

Code:

print(JOAAT.GetHashKey("ApacheTech"));

-643040711


Actual output:

Code:

print(JOAAT.GetHashKey("ApacheTech"));

-4823534369646247936


The hash algorithm is correct, and it's attached to a 64 bit process, so switching to 32 bit CE won't help.

Looking online, I've seen that LUA doesn't really understand anything as simple and basic in terms of programming, as an integer, and just defaults everything to the equivalent of an Int64, and calls it a "number".

Is there anything in Cheat Engine that can help with this? I don't want to import libraries, or compile my own plugins. Just straight Cheat Engine OOBE, so if there is no way to jury rig it, I'll dump the whole class, and forget it. I just can't believe there's nothing so simple and obvious as an Int32 in LUA.
Back to top
View user's profile Send private message
Csimbi
I post too much
Reputation: 98

Joined: 14 Jul 2007
Posts: 3349

PostPosted: Wed Sep 02, 2020 1:34 pm    Post subject: Reply with quote

That lookup table seems to go from 0x00 to 0xFF.
Do you really need such a lookup table? The value will always equal the index - not quite what I would call an actual lookup.

Anyway, if you do need it, you can simply build it with a loop and this:
Code:
writeInteger(address,value) : Writes a 32-bit integer to the specified address. Returns true on success


If you don't like that, you could allocate (and fill) that buffer using AA instead of LUA.
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 472

Joined: 09 May 2003
Posts: 25866
Location: The netherlands

PostPosted: Wed Sep 02, 2020 1:47 pm    Post subject: Reply with quote

value=value & 0xffffffff will convert the value to a 32-bit value
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
ApacheTech
Newbie cheater
Reputation: 0

Joined: 26 Jun 2020
Posts: 14

PostPosted: Wed Sep 02, 2020 2:50 pm    Post subject: Reply with quote

Dark Byte wrote:
value=value & 0xffffffff will convert the value to a 32-bit value


Will this convert to Int32, or simply truncate the number? And does it output Int32, or UInt32?
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 472

Joined: 09 May 2003
Posts: 25866
Location: The netherlands

PostPosted: Wed Sep 02, 2020 3:45 pm    Post subject: Reply with quote

that will be uint32

if you wish int32 then check if the new value is higher than 7fffffff and if so do
Code:

value=value | 0xffffffff00000000

which will result in a signextended 32 bit value to 64 bit. the calculations will be correct. (just do it for every step)

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
ApacheTech
Newbie cheater
Reputation: 0

Joined: 26 Jun 2020
Posts: 14

PostPosted: Wed Sep 02, 2020 4:05 pm    Post subject: Reply with quote

I think the lookup table is an overhead saving measure. The class was converted over from .NET, and directly converting in this manner was faster than converting to lowercase, then casting to byte. This algorithm is deliberately case insensitive.

Last edited by ApacheTech on Wed Sep 02, 2020 4:58 pm; edited 4 times in total
Back to top
View user's profile Send private message
panraven
Grandmaster Cheater
Reputation: 62

Joined: 01 Oct 2008
Posts: 959

PostPosted: Wed Sep 02, 2020 4:17 pm    Post subject: Reply with quote

Hi,

1. << >> operator has higher precedence than + - but lower precedence than ~ & | etc, https://www.lua.org/manual/5.3/manual.html#3.4.8 it is better use bracket to avoid confusion;
2. string.byte(str:sub(i,i)) can be simplify as string.byte(str,i) or str:byte(i) for 1 byte/char ;
3. for operation significant with bit width, it can be mask to appropriate bits value before the operation, for instance,
Code:

original : hash = hash ~ hash >> 11
modified : hash = hash ~ (hash >> 11) & 0xffffffff

4. for signed result, may check the sign bit after masked with appropriate bit width (except 64 bit, 64 bit is always signed), eg.
Code:

function toSigned32(n)
  n = n & 0xffffffff -- assume n is an integer
  return 0~=(n & 0x80000000) and n - 0x100000000 or n
end

_________________
- Retarded.
Back to top
View user's profile Send private message
ApacheTech
Newbie cheater
Reputation: 0

Joined: 26 Jun 2020
Posts: 14

PostPosted: Wed Sep 02, 2020 4:58 pm    Post subject: Reply with quote

Here's the original, unrefactored C# class I've been converting over. This works exactly as it should.

Code:

/// <summary>
///     Represents a class for generating hash keys compatible with the JOAAT hash algorithm.
/// </summary>
public static class JOAAT
{   
    // copied directly from the game -- performs uppercase to lowercase conversions amongst other things   
    private static readonly byte[] m_LookupTable = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,       
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,       
        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,       
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,       
        0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,       
        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x2F, 0x5D, 0x5E, 0x5F,       
        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,       
        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,       
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,       
        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,       
        0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,       
        0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,       
        0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,       
        0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,       
        0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,       
        0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,   
    };
   
    private static uint GetHashKeySubString(string str, uint initialHash)
    {       
        var hash = initialHash;       
        for (int i = 0; i < str.Length; i++)       
        {           
            hash += m_LookupTable[str[i]];           
            hash += (hash << 10);           
            hash ^= (hash >> 6);       
        }       
        return hash;   
    }   
   
    private static uint GetHashKeyFinalize(string str, uint initialHash)   
    {       
        var hash = GetHashKeySubString(str, initialHash);
        hash += (hash << 3);
        hash ^= (hash >> 11);
        hash += (hash << 15);
        return hash;
    }
   
    /// <summary>
    ///     Gets the hash key of the specified string.
    /// </summary>
    /// <param name="str">The string used to generate a hash key.</param>
    /// <returns>A case-insensitive JOAAT hash key.</returns>
    public static uint GetHashKey(string str)
    {
        return GetHashKey(str, 0);
    }

    /// <summary>
    ///     Gets the hash key of the specified string, using an initial hash key value.
    /// </summary>
    /// <param name="str">The string used to generate a hash key.</param>
    /// <param name="initialHash">The initial hash key value used to generate the result.</param>
    /// <returns>A case-insensitive JOAAT hash key.</returns>
    public static uint GetHashKey(string str, uint initialHash)
    {
        return GetHashKeyFinalize(str, initialHash);
    }

    /// <summary>
    ///     Gets the hash key of the specified string concatenated with an additional string.
    /// </summary>
    /// <param name="str">The string used to generate a hash key.</param>
    /// <param name="concat">The additional string to concatenate to the input string.</param>
    /// <returns>A case-insensitive JOAAT hash key.</returns>
    public static uint GetHashKey(string str, string concat)
    {
        return GetHashKey(str, concat, 0);
    }
   
    /// <summary>
    ///     Gets the hash key of the specified string concatenated with an additional string, using an initial hash key value.
    /// </summary>
    /// <param name="str">The string used to generate a hash key.</param>
    /// <param name="concat">The additional string to concatenate to the input string.</param>
    /// <param name="initialHash">The initial hash key value used to generate the result.</param>
    /// <returns>A case-insensitive JOAAT hash key.</returns>
    public static uint GetHashKey(string str, string concat, uint initialHash)
    {
        return GetHashKeyFinalize(concat, GetHashKeySubString(str, initialHash));
    }
}


Having tested it with, and without the lookup table, I've determined that in order to get the correct outputs, regardless of casing, and with the concatenated inputs, the lookup table is necessary. I'm not quite sure how it breaks it without it, but test-cases show that it is needed.

The concatenation allows you to split the inputs, and get the same output, so:

Code:

JOAAT.GetHashKey("Apache", "Tech") == JOAAT.GetHashKey("ApacheTech")


I use this to add salt to hashes as an extra layer of security against rainbow tables, but also it allows to gather multiple entries, and search quickly through a list of hashes.

So, I've updated the LUA, thusly (I'll worry about adding the concatenation back in once the core algorithm works):

Code:

--- <summary>
---     Converts a generic LUA number to a UInt32.
--- </summary>
function UInt32(num)
    return num & 0xFFFFFFFF;
end

--- <summary>
---     Converts a generic LUA number to an Int32.
--- </summary>
function Int32(num)
    local n = num & 0xFFFFFFFF;
    return 0 ~= (n & 0x80000000) and n - 0x100000000 or n;
end

--- <summary>
---     Gets the hash key of the specified string.
--- </summary>
JOAAT = function(str)
    local hash = 0;
    local m_LookupTable = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
        0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x2F, 0x5D, 0x5E, 0x5F,
        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
        0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
        0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
        0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
        0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
        0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
        0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
    };
    for i = 1, str:len() do
        hash = Int32(hash + m_LookupTable[str:byte(i)]);
        hash = hash + Int32(hash << 10);
        hash = Int32(hash);
        hash = hash ~ Int32(hash >> 6);
        hash = Int32(hash);
    end
    hash = hash + Int32(hash << 3);
    hash = Int32(hash);
    hash = hash ~ Int32(hash >> 11);
    hash = Int32(hash);
    hash = hash + Int32(hash << 15);
    return UInt32(hash);
end


However, it's still coming out with the wrong results:

Code:

print(JOAAT("ApacheTech"));
-- Expected UInt32: 3651926585

3855580145
Back to top
View user's profile Send private message
panraven
Grandmaster Cheater
Reputation: 62

Joined: 01 Oct 2008
Posts: 959

PostPosted: Wed Sep 02, 2020 6:45 pm    Post subject: Reply with quote

Hi,
It seems I make a wrong suggestion, the mask bit thing should do like this
Code:
 hash = hash ~ ( ( hash & 0xffffffff) >> 11) 
instead, sorry. Otherwise the extra bit higher that 32th will enter the calculation in a right shift. ie. using UInt32 to mask the value instead ,
Code:
 hash = hash ~ ( UInt32( hash) >> 11) 


Your m_LookupTable in #c version either tried to make a custom joaat or you copy the table wrongly. In wiki standard joaat https://en.wikipedia.org/wiki/Jenkins_hash_function , such table seems not need.
Look at line begin with 0x40,0x61,0x62... , it make char 0x41 convert to byte 0x61 etc.

Anyway, if this table is used, the following modification has to be made since lua literal table as an array start index with 1 instead of 0.
Code:

hash = Int32(hash + m_LookupTable[ 1 + str:byte(i) ]);


In my implementation with the table, it give your expected result. https://pastebin.com/1AebL9SZ

_________________
- Retarded.
Back to top
View user's profile Send private message
ApacheTech
Newbie cheater
Reputation: 0

Joined: 26 Jun 2020
Posts: 14

PostPosted: Thu Sep 03, 2020 4:28 am    Post subject: Reply with quote

That fixed it. Thank you!. Very Happy Standard JOAAT is case sensitive, where this is case insensitive. The Lookup table is just an optimisation feature for character translation, and conversion. It skips out the entire step of "ToLower", so when used for bulk hashes, the overheads saved are pretty big.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites