Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Reversing number

Moderator
Staff member
Moderator
Joined
Feb 22, 2008
Messages
2,404
Reaction score
723
Assuming this code:


int EDI = 0x1505;
for( int i = 0; i < lstrlen(dir); i++ )
{
if ( dir != '.' && dir != '\' )
{
EDX = EDI * 32;
EDX = EDX + EDI;
EDX = EDX + dir;
EDI = EDX;
}
}

Is it possible to get the string from the generated number? A game that I am developing uses these numbers to access the files inside a bigger file.
I am trying to create a map-tree view of that file, so I guess I will need to decode the numbers to get the actual path.

I already asked in stackoverflow and didnt get good answers, but one guy said it would be possible and gave a pseudo-code, but I can't make it work.

He said this:
So it would be only possible to reverse strings when dir would be inside a range of 33 (e.g. 0-32 or 97 - 129) and EDX does not overflow.
So, if you could assume that the string only has minuscles (which are ascii 97-122, it might be possible:

  • First, subtract 0x1505 from VAL
  • Then, calculate ch = VAL % 33
  • Calculate ch = ch + n*33. Choose n in a way to get ch into the range 97-129, this is the next char.
  • Subtract this char from VAL and divide by 33: VAL = (VAL - ch) / 33
  • Iterate from step 2 until VAL is 0.
This can be further improved by bringing ch into other ranges of the ascii range (e.g. numbers, uppercase letters) if you feel, that the calculated char is incorrect. But this makes the algorithm heuristic then.




I did this ( ) but "2520255578" is not returning the correct string, which would be "data\map\realworld_r\01_yokohama\105\map_data\105.emr". (Without " )
 
Joined
Jun 23, 2010
Messages
2,318
Reaction score
2,195
And you are sure the given function works correct?

I can't seem to reproduce the given path to that certain number.



Uhm, the number "2520255578" is incorrect.

Worked on it some more and the function you provided works like how that dude explains (sort of).
It had some minor issues like his first step.

For me it works, encoding and decoding, except that number of yours :p

Comment rule 35 and uncomment rule 36 to run it with your number.

PHP:
<?php

    /*
    int EDI = 0x1505;
    for( int i = 0; i < lstrlen(dir); i++ )
    {
        if ( dir[i] != '.' && dir[i] != '\' )
        {
            EDX = EDI * 32;
            EDX = EDX + EDI;
            EDX = EDX + dir[i];
            EDI = EDX;
        }
    }
    */

    $dir = 'test\data';

    $EDI = 0x1505;
    
    for ($i = 0; $i < strlen($dir); $i++) // STRLEN
    {
        if ($dir[$i] != '.' && $dir[$i] != '\\')
        {
            $a = $EDI * 32;
            $b = $a + $EDI;
            $c = $b + ord($dir[$i]);
            
            $EDI = $c;
        }
    }
    
    echo 'result: ' . $EDI . PHP_EOL;

    $value = $EDI;
    //$value = 2520255578;
    
    $result = '';

    while ($value > 0x1505)
    {
        $ch = $value % 33;
        
        while ($ch < 97)
        {
            $ch += 33;
        }
        
        if ($ch > 129)
        {
            echo 'Data failure ' . $ch . PHP_EOL;
            
            exit;
        }
        
        $value = floor(($value - $ch) / 33);

        $result .= chr($ch);
    }
    
    $result = strrev($result);
    
    echo $result . PHP_EOL;
 
Moderator
Staff member
Moderator
Joined
Feb 22, 2008
Messages
2,404
Reaction score
723
@Joopie

Sorry for the function, but this one is working fine:

Code:
unsigned int __fastcall sub_4547A0(int a1, const char *a2)
{
    unsigned int v2; // edi@1
    unsigned int v3; // esi@1
    unsigned int v4; // kr00_4@1
    int i; // ecx@1
    char v6; // al@2
    unsigned int v7; // ecx@6
    char v8; // al@7

    char Dst[0x400];

    v2 = strlen(a2);
    v3 = 5381;
    strcpy_s(Dst, 0x400u, a2);
    v4 = strlen(Dst);

    for (i = 0; i < (signed int)(v4 + 1); ++i)
    {
        v6 = *(Dst + i);
        if (v6 >= 65 && v6 <= 90)
            *(Dst + i) = v6 + 32;
    }
    v7 = 0;
    if (v2)
    {
        do
        {
            v8 = *(Dst + v7);
            if (v8 != 46 && v8 != 92)
                v3 = v8 + 33 * v3;
            ++v7;
        } while (v7 < v2);
    }
    memset(&Dst, 0, 0x400u);
    return v3;
}

If you do
Code:
    char dir[] = "data\\map\\realworld_r\\01_yokohama\\105\\map_data\\105.emr";

    unsigned int values = sub_4547A0(1, dir);
You will get that number I told, 2520255578.
 
Joined
Jun 23, 2010
Messages
2,318
Reaction score
2,195
Still not able to get to that number, even manually calculating it is failing for me.

PHP:
v8 = *(Dst + v7);
if (v8 != 46 && v8 != 92)
    v3 = v8 + 33 * v3;

After 4 chars I'm already over your number, 2520255578.
Something about your fomula, noted above, isn't right.

Code:
d = 100
a = 97
t = 116
a = 97

result = 5381

result (177673) = d (100) + 33 * result (5381)
result (5863306) = a (97) + 33 * result (177673)
result (193489214) = t (116) + 33 * result (5863306)
result (6385144159) = a (97) + 33 * result (193489214)

result (6.385.144.159) > 2.520.255.578

Or I'm just doing something wrong, which is also a possibility!
 
Moderator
Staff member
Moderator
Joined
Feb 22, 2008
Messages
2,404
Reaction score
723
Are you using Multi-Byte charset? I don't know but that might be an issue...

I also tried to run your PHP code, it didn't matched too. lol

But it is really weird that for me its an output and for you another one... weird.
 
Initiate Mage
Joined
Feb 16, 2016
Messages
5
Reaction score
1
Well, the number got overflow and the steps are continued. The "formula" dont care about the overflow, so you cant deduce that your formula is incorrect just by the path: "data".
 
Joined
Jun 23, 2010
Messages
2,318
Reaction score
2,195
Well, the number got overflow and the steps are continued. The "formula" dont care about the overflow, so you cant deduce that your formula is incorrect just by the path: "data".

My point was that when you do the data part, you already had a bigger number than he stated. My reason of saying so was, like you pointed out, that I never thought about a overflow. Thanks for pointing that out.

So I guess in remove line 28 and change the condition of the do while loop on line 41 to "value != 5381" it might work?
.. I think
 
Initiate Mage
Joined
Feb 16, 2016
Messages
5
Reaction score
1
I tested here and it does not work, it shows "hi{d", the inverse of the old code.

Sad :(
 
Joined
Jun 23, 2010
Messages
2,318
Reaction score
2,195
I tested here and it does not work, it shows "hi{d", the inverse of the old code.

Sad :(

It works if you have the whole number.

Code:
38260988133767770757751706102424708488397652359015616981186101000246135898
// above number mod 4294967296 (2 ^32) which is the max value for a unsigned interger you get 2520255578

rmewpq▒sad▒oamwpq▒lahokoy▒rpp▒clrowlaerpamatad

Also because the function adds 32 to the characters between 65 ... 90 and skips out the characters 46 "." and 92 "" you can't reconstruct the truely original string.

I think you have to rework you approach on how you're going to make that tree view.


The python test code

PHP:
def encode(string):
    result = 5381
    
    for i in range(len(string)):
        char = ord(string[i])
        
        if char >= 65 and char <= 90:
            char += 32
            
        if char != 46 and char != 92:
            result = (char + 33 * result)
    
    return result

def decode(number):
    result = ""
    
    i = 0
    while number != 5381:
        char = number % 33;
        
        while char < 97:
            char += 33
            
        if char > 129:
            print("Data failure {0}".format(char))
            
            exit()
            
        number = (number - char) / 33
        
        result += chr(char)
        
    return result

encoded = encode("data\\map\\realworld_r\\01_yokohama\\105\\map_data\\105.emr")

print(encoded)
print(encoded % 4294967296) # mod for making a unsigned int (32bit)
print(decode(encoded))
 
Initiate Mage
Joined
Jul 17, 2013
Messages
90
Reaction score
18
What game is this? I might have a useful solution.
 
Initiate Mage
Joined
Jul 17, 2013
Messages
90
Reaction score
18
dTantra The game is Digimon Masters Online
Is the feature in question version dependent? If so what version are you using? Also if you have a current unpacked exe or an exe that launches with arguments for debugging purposes that would be helpful. Also an outline of your current goal or why you need this information, just because I may be able to come up with a different solution for the same problem. I had assumed you were trying to unpack the packing system. Nevermind about the outline, I see what you are attempting to do, I am testing things now.
 
Last edited:
Initiate Mage
Joined
Jul 17, 2013
Messages
90
Reaction score
18
Can you tell us/me how you did it?

Haha sure, I just used a different approach since generating the string from the hash is not really on the table at this time.

First list itself is generated from the game launcher / updater. I CC'ed the function that processes the files and dumped the hash + hashed content to file for every file patched since version 99 (earliest I can tell). This resulted in the 9k some entries, but only works for patched content which does not cover everything since it only resulted in 2gb-3gb worth of content vs the 5gb that the game has.

I had to find another way to get the rest..

Since the client requests them every time it needs one, I simply CC'ed the function that is called and dumped the hash + the hashed content to file. This allows you to walk around in game wherever you want the files for or near people with equipment etc. or whatever your desires to capture them.

General code can be found below, while not the cleanest, it gets the job done.


Code:
struct FileInfo
{
    DWORD Hash;
    const char * Filename;
};

FileInfo cFileInfo;

void ProcessFileHashInfo()
{
    ofstream myfile;
    myfile.open("filenames.txt", std::ios_base::app);
        myfile << cFileInfo.Hash << "\t" << cFileInfo.Filename << "\n";
    myfile.close();
}


__declspec(naked) void CC_ExtractFileHashInfo(void)
{
    __asm 
    {    
        POP RetAddr
            PUSH  0x00A04148
            POP cFileInfo.Filename
            PUSH cFileInfo.Filename
            MOV cFileInfo.Hash, EDX
            PUSHAD
        PUSHFD
    }
    ProcessFileHashInfo();
    __asm
    {
        POPFD
            POPAD
            PUSH RetAddr
        ret
    }
}

AddCodeCave(CC_ExtractFileHashInfo, 0x0045483D, 5);


Here is another 5k-6k dumped from sitting in game in the starting area since I do not have a character or access to other areas since I just installed the game yesterday.

 
Last edited:
Moderator
Staff member
Moderator
Joined
Feb 22, 2008
Messages
2,404
Reaction score
723
Nice. As I think there is no way of getting the string from the hash, I think the only solution to make a file explorer for the "packed" files is to hard-code a list with the corresponding path. I will update my program to see how many hashes is missing.

__edit__

Only 1 hash missing for the 03 file, and 9791 for the 01 file. Nice. ;D
The annoying thing is that for every new added file, we have to edit the program...
 
Last edited:
Initiate Mage
Joined
Jul 17, 2013
Messages
90
Reaction score
18
Nice. As I think there is no way of getting the string from the hash, I think the only solution to make a file explorer for the "packed" files is to hard-code a list with the corresponding path. I will update my program to see how many hashes is missing.

__edit__

Only 1 hash missing for the 03 file, and 9791 for the 01 file. Nice. ;D
The annoying thing is that for every new added file, we have to edit the program...

Not really, all you need to do is modify the launcher itself to spit out an updated txt file for every patch, that way every new patch you have the new data automatically.

As to the missing data, you have to realize I am using a lvl 5 account so I have very limited access to the areas, it would be much better if you do it yourself on a leveled account that way it has access to higher areas and players with higher gear etc.
 
Moderator
Staff member
Moderator
Joined
Feb 22, 2008
Messages
2,404
Reaction score
723
Nice man. Would have any knoledge in the 3D files of this game, the *.nifs ? If you want to help us emulating this game, send me a PM with your skype, maybe we can work something out. ^_^
 
Initiate Mage
Joined
Jul 17, 2013
Messages
90
Reaction score
18
Nice man. Would have any knoledge in the 3D files of this game, the *.nifs ? If you want to help us emulating this game, send me a PM with your skype, maybe we can work something out. ^_^

Ah I just downloaded this game yesterday or the day before to give you a hand with the hash, I do not know anything really about the game itself. Pretty sure there is some information about modding the older version of the game online if you check that out it should still apply once you get the files out of the pack.
 
Initiate Mage
Joined
Jul 17, 2013
Messages
90
Reaction score
18
Nice man. Would have any knoledge in the 3D files of this game, the *.nifs ? If you want to help us emulating this game, send me a PM with your skype, maybe we can work something out. ^_^

By the way do you still want more of the hash's?
 
Back
Top