Page 1 of 1

Unity : ACTk

Posted: Wed Dec 18, 2019 12:18 am
by cfemen
ACTk = Anti Cheat Toolkit.
Most common anti cheat plugin for Unity thats obfuscating vars and spawns fake values.

i guess for some its interesting if i share some infos about ACTk, i hacked some games in the past with it and analyzed it :)

if the game has mono:
open assembly.dll
search for ObsfuscatedInt/ObfuscatedFloat

change the code so thats only the return is left on follow functions:
Decrypt Function:
return value;
Encrypt Function:
return value;
return 0;
return hiddenValue;

thats it now you can scan for the real values.
if you found the real values, find out what writes to this address and save the mono symbols of the address.
now start game again with the original dll -> go to the symbol and write your inject :)

dont let you fool from ATKc :?
if you are searching for a Integer in the function/method that you found you would expect:

Code: Select all

mov [rax+4],ecx // something typical for Integers
ATKc may obfuscates this into something like this:

Code: Select all

movups [rdi+40],xmm0 // ACTk method to write a Integer
the real value is on rdi+44 or rdi+3C (4 bytes plus/minus)

Actually you can use the "Anti-Cheat" to cheat more, and with more i mean finding values that would be hard to find (very rare items with only 1 or 2 in the inventory -> not enough to scan for it)
Especially useful for special items that dont use the same shared instructions like the normal items in the inventory.

How To Do?

Use Mono and find InternalDecrypt(every type has its own!) from ACTk now look for the XOR
(sample from my machine, your InternalDecrypt may be slightly different coz JIT)

Code: Select all

  movsxd  rax,dword ptr [rsi+04]
  movsxd  rcx,dword ptr [rsi]
  mov rdi,rax
  xor edi,ecx

every obfuscated(Integer) value will use this function!
set a breakpoint after the xor edi,ecx to see the real value.
if its the same amount as the value you are looking for -> copy the value from rsi+4 convert it to decimal and you can now scan for a exact value and bypass the complete obfuscation/fake values.

or you can just write a filter to set the amount to 999 or more:

Code: Select all

xor edi,ecx
cmp edi,2 // 2 of the rare items
jne @f
mov edi,3E7
now do trigger the game to read/write the value you are looking for and you will get 999.

ok how about IL2CPP?

IL2CPP generates completly different AOBs than Mono, and you cant just edit the DLL or see symbols.
But the AOBs will be the same on every machine :)

i searched for ACTk's InternalDecrypt on some IL2CPP+ACTk games to find the important AOBs, and i created some own projects with ACTk and compiled some tests, the AOBs never changed.

you may get more than 1 result -> just return the function or NOP the XOR and if nothing happens with the values then its not the right spot :lol:

Code: Select all

// Integer
//04 33 3B E8 will lead to this InternalDecrypt:
mov edi,[rbx+04]
xor edi,[rbx]

Code: Select all

// Floats
//33 C9 31 44 24 40 will lead to this InternalDecrypt:
xor ecx,ecx
xor [rsp+40],eax

Code: Select all

// Doubles
//48 31 44 24 50 will lead to this InternalDecrypt:
xor ecx,ecx
xor [rsp+50],rax
and yeah every value in game will use one of the InternalDecrypt functions :) now you can use breakpoints to see the real value and copy the obfuscated value, convert it to scan for it or just let it run to the RET to find the game function thats read/writes the value.

last but not least:


after the RET from InternalDecrypt is always a call
this call on the screenshot is GenerateCryptoKey for Integers right after the RET from InternalDecrypt for Integers.

inject on the beginning of GenerateCryptoKey -> return 0 -> now you can scan for the real value and easily change every integer.

Floats/Doubles are a bit harder coz ACTk spawns a lot more fake values and the values in InternalDecrypt are always on the stack.
but i think you got the idea how useful it is if you are in the InternalDecrypt function and you can see/manipulate/backtrace all obfuscated vars.

so thats it :)

The Il2CPP AOBs are for the ACTk 2.x
just updated ACTk to newest version, its still the same
i will update this post if somethings change and add the AOBs :)

Re: Unity : ACTk

Posted: Mon Dec 23, 2019 11:35 pm
by cfemen
Some additionally tips:

i just created an table for Ape Out and i couldnt find with my AOBs the InternalDecrypt, so i show another way that i used to find it (Ape Out uses IL2CPP)

every ObscuredInt / Float / Double has an ToString Function ( and several overloadings for it)

search for:

33 D2 E8 ** ** ** ** 33 D2 89 44 24 30 48 8D 4C

44 24 30 E8 ** ** ** ** 33 D2 F3 0F 11 44 24 30

44 24 30 E8 ** ** ** ** 33 D2 F2 0F 11 44 24 30

and you will find ToString

screenshot from my sample with an float:

first call in the ToString is always InternalDecrypt

screenshot from Ape Out with same AOBs for floats ( game does not show any UI values, its just an example for the AOBs to find InternalDecrypt)

and again : these AOBs are only for IL2CPP compiled games, if the game uses Mono look first post how to find the things :)


Another trick:

you already know how to find GenerateKey, return 0 is mostly enough to find/scan for Ints.
for floats/doubles its good to get rid of the fakes:

find ObscuredCheatingDetector:IsRunning
go into InternalDecrypt and the call after the xor is it:


return 0 and the fake values are killed :)

now you can scan for ints/floats/doubles, but keep in mind floats/doubles might using some additionally math.

example floats:
ingame value : 13 = 10.21000004
ingame value : 29 = 24.73872185
ingame value : 81 = 106.8166885

but with return 0 on GenerateKey and return 0 on ObscuredCheatingDetector you can now easily scan for values and change them without injecting.