Search code examples
assemblycheat-engine

Read score from EAs FIFA 19


Hello fellow stack overflowers,

I'm up to create a program that plays the home teams goalhymn when it actually scored a goal in the football simulator FIFA 19.

I know there is no open API for the game itself. The only method I see to use is to actually poll the result from the memory. I do not know if this does comply with the end user license agreement of the game, but I have not in mind to actually cheat in any way.

For research I found and looked up the Cheat Engine Table from https://github.com/xAranaktu/FIFA-19---Career-Mode-Cheat-Table. It gives the ability to read or write the match score via Cheat Engine.

Sadly, I'm having trouble to reverse engineer the table. I've found the bit of code that reads the value from memory. But I'm having a hard time figuring out what each line does.

[ENABLE]
aobscanmodule(INJECT_matchScore,FIFA19.exe,48 8B 41 20 48 89 42 20 8B 41 28 89 42 28 41 8B 54) // should be unique
alloc(matchscore_cave,$1000,"FIFA19.exe"+2578D85)

alloc(ptrHomeTeamScore, 8)
registersymbol(ptrHomeTeamScore)
ptrHomeTeamScore:
dq 00

alloc(ptrAwayTeamScore, 8)
registersymbol(ptrAwayTeamScore)
ptrAwayTeamScore:
dq 00

label(code_matchscore)
label(home_matchscore)
label(away_matchscore)
label(return_matchscore)

matchscore_cave:
  pushf
  cmp rdx, 00
  je home_matchscore
  cmp rdx, 01
  je away_matchscore
  jmp code_matchscore

home_matchscore:
  mov [ptrHomeTeamScore], rcx
  jmp code_matchscore
away_matchscore:
  mov [ptrAwayTeamScore], rcx
  jmp code_matchscore

code_matchscore:
  mov r8d,[rcx+0000011C]
  popf
  jmp return_matchscore

INJECT_matchScore+5B:
  jmp matchscore_cave
  nop
  nop
return_matchscore:
registersymbol(INJECT_matchScore)

I have basic knowledge of what a pointer, a stack is and what assembler does. But I cannot understand the things going on here. Maybe you can give me a line by line description of what's going on.

Thank you in advance.


Solution

  • Essentially this is a hook which directs the code flow into your injected shellcode using the Cheat Engine scripting capability. I'm going to break down each line into it's basic purpose to help explain it. Learn more about it in the Cheat Engine Wiki

    aobscanmodule(INJECT_matchScore,FIFA19.exe,48 8B 41 20 48 89 42 20 8B 41 28 89 42 28 41 8B 54) // should be unique
    

    Scans the process for that specific pattern, stores the location of the matching pattern in INJECT_matchScore

    alloc(matchscore_cave,$1000,"FIFA19.exe"+2578D85)
    

    Allocates memory near "FIFA19.exe"+2578D85 that is 1000 bytes in size and stores the address of this memory inmatchscore_cave. This is where your shellcode will be placed

    alloc(ptrHomeTeamScore, 8)
    registersymbol(ptrHomeTeamScore)
    ptrHomeTeamScore:
    dq 00
    

    allocated 8 bytes to store a 64bit pointer, registers the variable symbol name and assigns it QWORD value of 0x0

    alloc(ptrAwayTeamScore, 8)
    registersymbol(ptrAwayTeamScore)
    ptrAwayTeamScore:
    dq 00
    

    same as above

    label(code_matchscore)
    label(home_matchscore)
    label(away_matchscore)
    label(return_matchscore)
    

    creatse some labels for assembly blocks that you can jmp to, defined below

    matchscore_cave:
        pushf
        cmp rdx, 00
        je home_matchscore
        cmp rdx, 01
        je away_matchscore
        jmp code_matchscore
    

    push flags if rdx == 0, jmp to home_matchscore else if rdx == 1, jmp to away_matchscore else jmp code_matchscore

    home_matchscore:
        mov [ptrHomeTeamScore], rcx
        jmp code_matchscore
    away_matchscore:
        mov [ptrAwayTeamScore], rcx
        jmp code_matchscore
    

    grab the pointer stored in rcx and store it in ptrHomeTeamScore

    code_matchscore:
      mov r8d,[rcx+0000011C]
      popf
      jmp return_matchscore
    

    At offset 0x11C from RCX, grab the value and store it in register r8d pop flags, restoring them to what they were before the initial hook jmp

    INJECT_matchScore+5B:
      jmp matchscore_cave
      nop
      nop
    

    overwrite the original assembly and jmp to your injected code, directing flow from the game code into your own code