Draw magic text is incorrect:

Ottenuto: 7 Scan magia

It should be:

Ottenuto: magia Scan, 7 unità

  1. Detect Ottenuto: and replace it with Ottenuto: magia
  2. Then replace 7 Scan with Scan, 7
  3. Then replace magia with unita

Let’s start by testing. Let’s get into the game, change the language to Italiana, then locate the message drawn, hook into the buffer to obtain where it’s used in the code and try to hook it.

I’ll be using CheatEngine and IDA 9.0

  1. Change language to IT. I don’t have launcher ready, so I’ll just edit the config files.

    1. Open demaster_manager to quickly navigate to saves/config files:

      image.png

    2. Open config.txtand change language value to IT

  2. Start the game. It should be in Italiana. Let’s get to battle and scan something:

    image.png

    1. We should be fine with adding magiato the Ottenuto:message, but it also requires moving the draw magic name before the count
  3. Scanning via Cheat Engine for Ottenuto results in no results:

    image.png

    1. Why? Well… probably because the game have it’s own internal chartable, so ours Ottenuto looks completely different in-game.
  4. Let’s try to recreate the Ottenuto with the in-game chartable. I think the easiest for me would be to look at the Rinoa's toolsetsource code, as it contains the Rosetta stonefeature, where you can decode any text you want. Here’s the code snippet from the old Rinoa’s toolset:

        private readonly string _chartable =
        @" , ,1,2,3,4,5,6,7,8,9,%,/,:,!,?,…,+,-,=,*,&,「,」,(,),·,.,,,~,“,”,‘,#,$,',_,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,À,Á,Â,Ä,Ç,È,É,Ê,Ë,Ì,Í,Î,Ï,Ñ,Ò,Ó,Ô,Ö,Ù,Ú,Û,Ü,Œ,ß,à,á,â,ä,ç,è,é,ê,ë,ì,í,î,ï,ñ,ò";

        public CharTableProvider()
        {
            _charstable = _chartable.Split(',');
        }

        public string[] Decipher(byte[] _in)
        {
            if (_in.Length == 0)
                return null;

            string[] process = new string[_in.Length];
            int index = 0;
            foreach(byte a in _in)
            {
                if(a-31>=0 && a<_charstable.Length)
                    process[index] = _charstable[a - 31];
                index++;
            }
            return process;
        }
        public string Decipher(string _in)
        {
            if (_in.Length == 0)
                return null;
            StringBuilder sb = new StringBuilder(_in.Length);
            foreach (byte a in _in)
            {
                if (a - 31 >= 0 && a < _charstable.Length)
                    sb.Append(_charstable[a - 31]);
            }
            return sb.ToString();
        }
  1. I have ported the chartable to Python:

    1. I have ported the chartable to Python:

      image.png

    2. Let’s split the chartable with , and we will get them into array of characters. We know the index of every character and can match it with out string. Let’s write a function that returns the index of given character from the chartable. We will need it to construct ASCII character:

      search_str = 'Ottenuto'
      
      In [8]: def find_index(inputstr):
         ...:     for i in range(0,len(chartable)):
         ...:         if inputstr == chartable[i]:
         ...:             return i
         ...:
      
      In [9]: find_index('O')
      Out[9]: 52
      
    3. We now know that O is at index 52, which is totally different than on ASCII. By using chr(52)we can easily get the character we want, which is 4 in our case. Let’s write a function that will transform our input character to encoded one:

      def cipher(inputstr):
          ...:     buffer = ''
          ...:     for char in inputstr:
          ...:         index = find_index(char)
          ...:         buffer += chr(index+31)
          ...:     return buffer
          ...:
      
      In [13]: cipher('Test')
      Out[13]: 'Xcqr'
      
    4. Let’s encode Ottenuto , with the result of: Srrclsrm.

  2. Let’s find it now in the memory:

    image.png

    1. We have to navigate through every address and hit on the Find out what accesses this ddressbutton:

      image.png

    2. I’ve quickly found that all battle messages final text is managed on 0x06A0FFA8buffer, but as that is a dynamic memory, then we have to find code opcodes that do something with it. The window with debugger should display all opcodes that used the buffer:

      image.png

    3. Let’s write down those addresses:

      1004EE2B - 88 04 0A   - mov [edx+ecx],al
      1004EC88 - 8A 04 01   - mov al,[ecx+eax]
      1004EDDB - 89 04 0A   - mov [edx+ecx],eax
      1004EC68 - 66 8B 04 01   - mov ax,[ecx+eax]
      1004EDFC - 66 89 04 0A   - mov [edx+ecx],ax
      1004EC48 - 8B 04 01   - mov eax,[ecx+eax]
      
    4. We just only have to click the Show disassemblerbutton, so it shows the address in different styles:

      image.png

  3. Let’s jump to IDA and try to understand what’s happening. Check that the address we jump reflects the disassembly from CheatEngine. If it doesn’t, then either disable ASLR, or do manual calculations:

    image.png

    1. To do manual calculations, just write down the address in form of module address. See point 6, d. It shows FFVIII_EFIGS.dll+4EE2B. In IDA go to Segmentsand take a look at the .textsegment. In my case it’s 0x10001000. Subtract 0x1000from the .textsegment Start address, so you will get in my case: 0x10000000. Now add 0x4EE2B to the address and you should receive the final address in your database:
    hex(0x10001000+0x4EE2B-0x1000)
    Out[30]: '0x1004ee2b'
    
  4. If we get one one those addresses and see cross references via CTRL+X, then we will get horrendous amount of references:

    image.png

  5. That’s bad. We probably need to integrate more powerful approach. Let’s get back to Cheat Engine (I mean, IDA is fine too for that). Then grab the addresses that writes to our found address, then jump into memory view, select one byte and hit Break on write

    image.png