Skip to content

acs_cosim_server

Simone Bondi edited this page Sep 28, 2024 · 7 revisions

Applying the patch

I expect it is illegal to distribute the patched executable directly, so instead i distribute a patchfile, which you can obtain from the releases page of this repo (or of course you can create your own - see Creating the patch from scratch).

The patch can be applied by using bspatch, another free utility from the bsdiff project. It is available on the Ubuntu official APT repos, so i suggest you to just use an UNIX system.

Backup the original acs.exe: mv acs.exe acs.exe.ori

Apply the patch: bspatch acs.exe.ori acs.exe patchfile

Move the newly patched acs.exe in your Assetto Corsa installation folder.

Creating the patch from scratch

The patched executable must be first crafted by hand. I used Ghidra. Kunos Simulazioni s.r.l was kind enough to leave the .pdb file in the Assetto Corsa installation folder (thanks), so you should also load that into your tool.

Look for the PhysicsDriveThread::run function, and remove all logic related to synchronization with the wall clock. You should be left with a busy loop which polls the input, advances the current time, performs a physics step, and then calls the physics step completed handlers. Also, i did not remove the pause logic.

You need some space on the stack to store the two event HANDLEs (8 bytes each). Some of the registers (most XMM registers) will become unused, so you can remove the logic which saves and restores them. There should be enough space to initialize both HANDLEs to 0 during the stack frame setup.

You should be left with three huge NOP-slides - two of them can be used to insert the new logic; the other one, instead is between the call to the physics step and the call to the step completed handlers - you should not use it, as the one of the handlers is the component which updates the shared memory area (which we need).

You'll also need two names for the events. I used some strings which i found in the binary:

  • go: "GODRAYS"
  • done: "DOUBLESIDED"

At this point you can fit the new logic. In the first NOP-slide (before step):

  MOV        RAX,qword ptr [RSP + go_evt_handle]

  TEST       RAX,RAX
  JNZ        wait_for_go

  LEA        R9, [u_GODRAYS]
  XOR        R8D,R8D
  XOR        ECX,ECX
  XOR        EDX,EDX
  CALL       qword ptr [->KERNEL32.DLL::CreateEventW]
  TEST       RAX,RAX
  JNZ        wait_for_go

go_error:
  CALL       qword ptr [->KERNEL32.DLL::GetLastError]
  MOV        ECX,EAX
  CALL       qword ptr [->MSVCR120.DLL::exit]
  
wait_for_go:
  MOV        EDX,0xffffffff
  MOV        RCX,RAX
  CALL       qword ptr [->KERNEL32.DLL::WaitForSingleObject]
  CMP        EAX,-0x1
  JZ         go_error

and in the second:

  MOV        RAX,qword ptr [RSP + done_evt_handle]

  TEST       RAX,RAX
  JNZ        set_done

  LEA        R9,[u_DOUBLESIDED]
  XOR        R8D,R8D
  XOR        ECX,ECX
  XOR        EDX,EDX
  CALL       qword ptr [->KERNEL32.DLL::CreateEventW]
  TEST       RAX,RAX
  JNZ        set_done

done_error:
  CALL       qword ptr [->KERNEL32.DLL::GetLastError]
  MOV        ECX,EAX
  CALL       qword ptr [->MSVCR120.DLL::exit]

set_done:
  MOV        RCX,RAX
  CALL       qword ptr [->KERNEL32.DLL::SetEvent]
  TEST       EAX,EAX
  JZ         done_error

At this point you have your executable, so you don't really need to create a patchfile.

Anyhow, if you want, you could use bsdiff (see Applying the patch) to create it: bsdiff acs.exe.ori acs.exe.patched patchfile

Clone this wiki locally