Broken Axxxx (A Unity Game) Reverse Engineering

***Remove the game name to prevent Google Search and people using as hack which against EULA.

Disclaimer:Just for study and testing purpose, any usage againt Broken Arrow’s EULA is not allowed.

Game Engine

Developed using Unity 6.x, with IL2CPP. Currently has no anti-cheat, which saved a lot time reversing the game.

Tool used

il2cppdumper Dump the game dlls. Use pre-release since global-metadata is not support in Latest stable build
dnSpy A .NET assembly editor. Read dumped dll file to find game functions.
MelonLoader To load the UnityExporer. Universal Loader for Unity IL2CPP
UnityExporer TryUse .net6.0 version for MelonLoader 6.x+
CheatEngine(CE) The GOD TOOL

Features

  1. Unlimited Money:
    Most easy to make, using CE searching the value(float point 8B), find 2 address one for UI one for memory, hook them both and by the time some instruction access the address, we can detriming the which one is for memory (game tick is 1hz somehow).

    Try to lock the value using CE but not work, get into assembly code and just NOP the address that change the address value, injecting NOP to replace mov [rcx+r8+20],al at "GameAssembly.dll"+CE5088

  2. Unlimited Ammo:
    Find a unit using single ammo instead of magainzes(a mortar), repeat the same step as unlimited money but for 4B int value. Lock the value only work for that single unit, so go deep into assembly. Find sub [rcx+1C],edx at "GameAssembly.dll"+C603CC. Obviously it is subtract ammo from the ammo reserve, inject the code and add mov edx, #0. NOP the funtion will sometime resulting in SF Flag setting to NG (0 ammo left) and crash game.
  3. Unlimited Decoy:
    Same logic as ammo, this time instead of sub, dec [rbx+10] is used, just NOP it and good to go.
  4. Make Far Unit Stay Visiable:
    Find assembly address for BrokenArrow.Client.Ecs.FogOfWar.Systems.HideInvisibleSystem.OnVisibilityChanged() at "GameAssembly.dll"+B80930, replace the very first insturtcion with ret to stop excuting.

  5. Rapid Fire:

    1. Make aim time 0:
      This is done with the help dnSpy, finding BrokenArrow.Client.Ecs.BattleSystem.Components.WeaponComponent.GenerateRandomAimTime() and using CE to find its assembly code"GameAssembly.dll"+CA3682. Set a breakpoint and trace insturtcions. In game spawn a single unit and remember its aiming times. Turns out it move minimum aim time to xmm6(float register) and maximum aim time to xmm7(float register) then call a random float generator. Just make xmm6 and 7 to a very small float number(1.0e-5 works great) and injecting them before it call the generator function.

      Move a float number direct into a xmm register is not allowed, in CE auto assemble, first need allocate a new memory reaginalloc(name,size,where) in this case alloc(float_1,4,"GameAssembly.dll"+CA3682) then declear a float point using dd (float) 0.00001 first d as declear, second d as double word. Then you can movess xmm6 [float_1]. Repeat same for xmm7. Remember to deallocate the memory in [Disable] dealloc(float_1)

    2. Make reload time 0:
      Very similar to aim time 0, infact the assembly code is also very similar. Find BrokenArrow.Client.Ecs.BattleSystem.Components.WeaponComponent.GenerateRandomMagazineReloadTime() at "GameAssembly.dll"+CA3762 and make xmm6 and 7 to a small enough number.