Draw magic text is incorrect:
Ottenuto: 7 Scan magia
It should be:
Ottenuto: magia Scan, 7 unità
Detect Ottenuto:
and replace it with Ottenuto: magia
7 Scan
with Scan, 7
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
Change language to IT. I don’t have launcher ready, so I’ll just edit the config files.
Open demaster_manager to quickly navigate to saves/config files:
Open config.txt
and change language
value to IT
Start the game. It should be in Italiana. Let’s get to battle and scan something:
magia
to the Ottenuto:
message, but it also requires moving the draw magic name before the countScanning via Cheat Engine for Ottenuto
results in no results:
Ottenuto
looks completely different in-game.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 toolset
source code, as it contains the Rosetta stone
feature, 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();
}
I have ported the chartable to Python:
I have ported the chartable to Python:
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
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'
Let’s encode Ottenuto
, with the result of: Srrclsrm
.
Let’s find it now in the memory:
We have to navigate through every address and hit on the Find out what accesses this ddress
button:
I’ve quickly found that all battle messages final text is managed on 0x06A0FFA8
buffer, 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:
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]
We just only have to click the Show disassembler
button, so it shows the address in different styles:
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:
FFVIII_EFIGS.dll+4EE2B
. In IDA go to Segments
and take a look at the .text
segment. In my case it’s 0x10001000
. Subtract 0x1000
from the .text
segment 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'
If we get one one those addresses and see cross references via CTRL+X
, then we will get horrendous amount of references:
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