0

I am hoping someone can help me with a question or two.

Essentially I used to be a computer programmer who always wanted to get into a bit of game hacking, having not done any serious programming for a few years I had an itch for a technical endeavour. I decided on football (soccer) manager and wanted to do two things.

  1. Decipher their file format for tactics. Essentially this has changed from tac to fmf in the last version or so
  2. When a game is being played hook into the DirectX calls to essentially record a match, or figure out the format of their saved matches which can be shown to others

Now as I have no experience of DirectX I went to do number 1 first and have made good progress, but I am at the point where I need a bit of help and pointing in the right direction. Here's what I have deciphered so far with screenshots.

The start of the fmf file is written (always 02 01 61 66 65 afe) to start, so essentially the file header

start of FMF file

Then actually the old TAC format is written to disk though the user never sees it unless you breakpoint it, as it puts the tactic on the file, reads it back in and then deletes it again

enter image description here

enter image description here

The TAC file is read back in and a new section of the fmf is written

enter image description here

Now this looks similar in size to the previous tac file and is written after the tac file is read back in by the application, it also seems to have section separators in the FMF file so it is its own section.

enter image description here

If you look carefully you can see that this section is what was written after it read the tac file back in, now this section appears to be compressed/encrypted but I would guess that this is the tac, and you can clearly see distinct sections in the file separated by

10 00 00 00 10 00 00 00

So it is easy to break the file up. Now my question is, this section is the area of interest.

enter image description here

The actual data always seems to be around rcx+8 which points to an address with a QWORD pointer which points to the data. I tried decompiling this function and got the following:

struct s0 {
    uint32_t f0;
    int8_t[4] pad8;
    uint32_t f8;
    int8_t[4] pad16;
    uint32_t f16;
    uint32_t f20;
};

int32_t fun_146da5dd0();

/* function-which-calls-write */
uint32_t function_which_calls_write(int64_t rcx, uint32_t rdx, int64_t r8);

/* unknown 1 */
int64_t unknown_1(struct s0* rcx) {
    uint32_t eax2;
    uint32_t eax3;
    uint32_t edi4;
    uint32_t rsi5;
    int64_t rax6;
    int32_t eax7;
    int64_t rcx8;
    int64_t r8_9;
    uint32_t eax10;
    uint32_t eax11;

    eax2 = rcx->f20;    
    if ((*(uint8_t*)&eax2 & 3) != 2 || ((eax3 = rcx->f20, (*(uint8_t*)&eax3 & 0xc0) == 0) || (edi4 = rcx->f0 - rcx->f8, rcx->f16 = 0, rsi5 = rcx->f8, rcx->f0 =     rsi5, (uint1_t)((int32_t)edi4 < (int32_t)0) | (uint1_t)(edi4 == 0)))) {
        addr_0x146d9e917_2:
        *(uint32_t*)&rax6 = 0;
        *(int32_t*)((int64_t)&rax6 + 4) = 0;
    } else {
        eax7 = fun_146da5dd0();
        *(int32_t*)&rcx8 = eax7;
        *(int32_t*)((int64_t)&rcx8 + 4) = 0;
        *(uint32_t*)&r8_9 = edi4;
        *(int32_t*)((int64_t)&r8_9 + 4) = 0;
        eax10 = function_which_calls_write(rcx8, rsi5, r8_9);
        if (edi4 == eax10) {
            eax11 = rcx->f20 >> 2;
            if (*(uint8_t*)&eax11 & 1) {
                rcx->f20 = rcx->f20 & 0xfffffffd;
                goto addr_0x146d9e917_2;
            }
        } else {
            rcx->f20 = rcx->f20 | 16;
            *(uint32_t*)&rax6 = 0xffffffff;
            *(int32_t*)((int64_t)&rax6 + 4) = 0;
        }
    }
    return rax6;
}

So obvious it seems like a struct, especially with the +number on the registers.

Another useful thing to note is that these sections in the fmf file are always different, ALWAYS, so if I make a tactic, save it, load in the tactic again (exact same one) and resave it is totally different content in between the constant separators 10 00 00 00 and the signature at the start of the file. So that leads me to believe it is some form of compression/encryption but with additional seed, such as the time added.

My question is I have located this data in the function I showed above, but obviously, there is data loaded in before this place in the function or in a previous function in the call stack. Is there any quick way of following where this data comes from? Once I find the exact point it originates I should obviously be able to conclude that is the encryption/compression function which produces it.

Thanks a lot.

1

If you know where the data is going to be before it's written, you can set a write hardware breakpoint and it should stop whenever that memory location is populated.
Otherwise, you'll to reverse engineer where RCX comes by going up the stack frame judging by the decompiled output.

  • Thanks for commenting NotGI, are there any techniques you can share, for example compiled output, you mean using a tool such as IDE Pro? I have checked the "Call Stack" tab but sometimes it doesn't appear accurate. – Tim Feb 18 at 15:00
  • @Tim, In order to determine the function from which you came from, you can use gdb/ollydbg for debugging and given a standard calling convention in a 32 bits system the saved EIP should be in $ebp+4 and for 64 bits $rbp+8. – NotGI Feb 18 at 21:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.