so okay i have the epic store version, but i dont think this a problem:
VampTY's script has only 1 AOB script (Detection) and its working.
notpikachu's script is scanning for a E8 (Call) and then a address, you didn't use wildcards so its not working coz of different address ^^
so i guess my scripts here with wildcard AOBs should work for all.
so okay my quick look:
i assumed that there is some global stuff that is used to calculate the time.
i've found a spot that shows the current map string.
Main Menu = "Production\Frontend"
New Game First Level = "Production\BSP_Torrens"
Challenge Mode Basement Level = "Production\DLC\ChallengeMap16"
below this string are 2 static doubles.
first static counts up if you are ingame, and gets a reset if you are in the main menu
second static counts up if you are in the pause menu or main menu
i've increased the first double and the time was going over 30 mins and the challenge failed, so this confirmed that this value is used to calculate all the stuff.
to find the global value use this script and then add [CodeCave] address as double type and you can access it.
Code: Select all
{$lua}
if syntaxcheck then return end
function aobScanEx( aob )
--https://forum.cheatengine.org/viewtopic.php?t=577536 - thanks panraven!
local p, a, n, s, e = nil or '*X*W', nil or fsmNotAligned, nil or '0', getAddress( process ) or 0x0, ( getAddress( process ) + getModuleSize( process ) ) or 0xffffffffffffffff
local ms = pb and createMemScan( pb ) or createMemScan()
local fl = createFoundList( ms )
ms.firstScan( soExactValue, vtByteArray, nil, aob, nil, s, e, p, a, n, true, false, false, false )
ms.waitTillDone()
fl.initialize()
local result = nil
if fl ~= nil and fl.getCount() > 0 then
result = createStringlist()
for i = 1, fl.getCount() do result.add( fl.getAddress( i - 1 ) ) end
end
fl.destroy()
ms.destroy()
return result
end
function string.fromhex( s )
return ( s:gsub( '..', function ( cc )
return string.char( tonumber( cc, 16 ) )
end ) )
end
function aobScanSmall( aob, s, e )
local i = byteTableToString( readBytes( s, e, true ) ):find( string.fromhex( aob ), 1, true )
if i == nil then i = 1 end
return ( s + i - 1 )
end
[ENABLE]
--Cave Stuff to store and access the static value
local qBase = getAddressSafe( process )
local dOffset = 0x500
qCaveAdd = qBase + dOffset
fullAccess( qCaveAdd, 0x500)
executeCodeEx( 0, nil, getAddressSafe( "RtlZeroMemory" ), qCaveAdd, 0x500 )
unregisterSymbol( "CodeCave" )
registerSymbol( "CodeCave", qCaveAdd, true )
--End Cave Stuff
--get movsd [mem],xmm1
--mem = global timer as double
local aobGetGlobalTimer = "F2 0F 11 0D ** ** ** ** F2 0F 11 15 ** ** ** ** 66 0F "
aobGetGlobalTimer = aobScanEx( aobGetGlobalTimer)
if aobGetGlobalTimer == nil then showMessage("No AOB For Global Timer") error("") return end
unregisterSymbol( "aobGlobalTimer" )
registerSymbol( "aobGlobalTimer", aobGetGlobalTimer[0], true )
local MovsdAddress = tonumber(aobGetGlobalTimer[0],16)
local GlobalTimer = readInteger(MovsdAddress + 0x04 )
writeQword(qCaveAdd, GlobalTimer)
[DISABLE]
local pCodeCave = getAddressSafe( "CodeCave" )
executeCodeEx( 0, nil, getAddressSafe( "RtlZeroMemory" ), pCodeCave, 0x500 )
unregisterSymbol( "aobGlobalTimer" )
if script is activ you can also use the aobGlobalTimer symbol to find the spot that shows the current map and the 2 doubles, or just scan for
F2 0F 11 0D ** ** ** ** F2 0F 11 15 ** ** ** ** 66 0F ( it will show 2 results with the same static double address, only one of them is used to execute)
okay (without surprise) lots of shit is reading from this global time value, i looked through some of them and found a spot that is reading from the static value if the timer start, and then subtracting from it and finally doing a compare, i killed the subtract and now the game won't trigger a gameover if the ingame timer is > 30 mins:
it will endless count up
script for that:
Code: Select all
[ENABLE]
// ignores the gameover if the timer is > 30 mins
aobscanmodule(aobCheckTimerForGameOver,AI.exe,F2 0F 5C C2 66 0F 2F C8)
aobCheckTimerForGameOver:
db 90 90 90 90
registersymbol(aobCheckTimerForGameOver)
[DISABLE]
aobCheckTimerForGameOver:
db F2 0F 5C C2
unregistersymbol(aobCheckTimerForGameOver)
so okay then i looked for another read that is only accessed if the timer runs:
Code: Select all
// sets the timer to 10 secs
aobscanmodule(aobTimer,AI.exe,C0 F3 0F 5C 41 0C) // should be unique
alloc(newmem,$1000)
label(code)
label(return)
label(somef)
newmem:
code:
subss xmm0,[ecx+0C]
movss xmm0,[somef]
jmp return
somef:
dd (float)10
aobTimer+01:
jmp newmem
return:
registersymbol(aobTimer)
[DISABLE]
aobTimer+01:
db F3 0F 5C 41 0C
unregistersymbol(aobTimer)
dealloc(newmem)
this freezes the timer at 10 secs, i ended the level with it:
now it shows always by best time (10 secs)
so okay now you know that there are different calculations based on the global time, one method that is reading that is only checking "is timer > 30 mins?" and another one that is used to count up for the endscreen.
//
btw game does not have settings to set it to english, so every screenshot text is german
if i start it with x64dbg and "-epiclocale=eng" then it does not connect to the leaderboard....
good job devs, is it so hard to make a ingame menu to change the language? im also wondering why they are using 32 bit
//
@VampTY i can't reply to your PM coz "Some users couldn’t be added as they have disabled private message receipt."
i'll disableit, it still counts, meaning with the values frozen it still counts up,
yep thats coz the counter gets calculated every frame from the global time variable, there is not much you can do about it except looking what is reading from it and change the calculation (like my 2 scripts)
if you freeze / decrease the global time then the game will fuck up.
(for testing purpose ) if you freeze the global time then the 3 timers on the top right corner will also freeze, so you can also find that caluclation if you do a "find out what accesses this address"
//
edit: okay looks like i got somekind of leadboard ban lol
its now everything empty everytime i start the game