Amateur and back-engineering. Part 1: Paths and Files

    How many of the progres did projects based on the games they played? I think a lot. You may be told that the game is so-so that you don’t have to spend time on a meaningless project, it will not be useful to anyone anyway, but it doesn’t matter to you, because it was cool, and at least somehow you want to repeat those emotions.

    At one time, I played a lot in “Tales of pirates” (hereinafter TOP) from Moli, more precisely in its Russian localization from Nival — “Pirate”. Smart, as for me, a game. Yes, not WOW, but I didn’t know anything about him either. Many years passed, the "Pirate" was closed, I grew up, but in the ocean of memory the forgotten conqueror of the seas still floats on a level 54 boat.

    image

    After I found out that they had closed the Russian server, and at that moment I had not played a couple of years, the excitement woke up again. After a couple of months, I figured out a bit in the world of fan servers, tried to set up my own on LAN, and began to understand the file structure. And then it started. At first I decided to learn how to work with models. For a couple of hours I found some code on Pastebin that, after the file, could open models, albeit with problems. But besides the models in the game, the textures were encrypted.

    Fortunately, there was one program, Gemini Decompiler, which was able to convert the textures of the game into normal and common pictures. Even more fortunate that this program was written in .Net. After the decompiler, it turned out that the normal texture was divided into 3 blocks - the first 44 bytes, the last 44 bytes, and the rest - the last 44 bytes first went in the encrypted texture, then the main part, then the first 44 bytes, and another 4 bytes are unknown for what.

    Based on the code with Pastebin and the texture converter, it turned out to be a model viewer. Horrible of course, but still. He just read only the simplest models, such as swords \ staves \ daggers, characters and decor elements without animation.

    image

    And I wanted movement. And I started looking for disassemblers to parse the TOP engine library into pieces. Found a pirated IDA Pro. And he began to break ... Comfortable general programm, especially the fact that she is able to adequately dereference names after processing by the compiler and converts the result to the pseudo dizasembera, very similar to C. In the article about Caesar 3 of this remembrance .

    I worked with varying success for about two months. Well, how he worked, played. I found the code with mathematical operations, began to stick structures from the model viewer into the IDA database, then I found that you can import .pdb (and it is, apparently for feedback, if there are errors), the code and structures were issued, which were issued by the pseudocode designer. But it was felt that everything was not right. I have .pdb, and there, as far as I knew, there is information about the project. I found a bunch of different programs, but all of them gave out only general information. Then I began to consider Debug Interface Access (hereinafter referred to as DIA), if it also came with the Express version of Visual studio. In short, I am writing on the Professional edition. Having compiled the dia2dump example, I went nuts. I had a bunch of service information on hand. A little over 30 megabytes of text. For example, there is a list of everyone. obj files that are fed to the linker, in addition to each .obj file there is a list of sources that enter there. In general, in one day the code for creating files from the TOP engine project was ready. And then there will be the creation of structures and the connection of inclusions via .pdb ...

    So it goes.

    For starters - additional code for dia2dump. Code for counting the number of .obj in a project, outputting files in each .obj, and creating project folders and files using .pdb.
    Open the result of the encoder
    int total=0;
    bool AQLCreateDirectory(WCHAR * sPathTo)
    {
      while(CreateDirectory(sPathTo, NULL) == FALSE)
      {
        WCHAR sTemp[MAX_PATH];
        int k = wcslen(sPathTo);
        wcscpy(sTemp, sPathTo);
        while(CreateDirectory(sTemp, NULL) != TRUE)
        {
          while(sTemp[--k] != L'\\')            
    	  {
            if(k<=1)                        
              return FALSE;
    		sTemp[k] = NULL;
    	  }
        }
      }
      return TRUE;
    };
    void Process(IDiaSession *pSession, IDiaSymbol *pGlobal)
    {
    	int total=0;
    	IDiaEnumSymbols *pEnumSymbols;
    	if (FAILED(pGlobal->findChildren(SymTagCompiland, NULL, nsNone, &pEnumSymbols)))
    		return;
    	IDiaSymbol *pCompiland;
    	ULONG celt = 0;
    	while (SUCCEEDED(pEnumSymbols->Next(1, &pCompiland, &celt)) && (celt == 1)) 
    	{
    		pCompiland->Release();
    		total++;
    	}
    	fwprintf(pFileout,L"%i\n", total);
    	pEnumSymbols->Release();
    	if (FAILED(pGlobal->findChildren(SymTagCompiland, NULL, nsNone, &pEnumSymbols)))
    		return;
    	celt = 0;
    	while (SUCCEEDED(pEnumSymbols->Next(1, &pCompiland, &celt)) && (celt == 1)) 
    	{
    		BSTR bstrName;
    		if (pCompiland->get_name(&bstrName) == S_OK) 
    		{
    			fwprintf(pFileout,L"%s\n", bstrName);
    			SysFreeString(bstrName);
    		}
    		int num=0;
    		IDiaEnumSourceFiles *pEnumSourceFiles;
    		if (SUCCEEDED(pSession->findFile(pCompiland, NULL, nsNone, &pEnumSourceFiles))) 
    		{
    			IDiaSourceFile *pSourceFile;
    			while (SUCCEEDED(pEnumSourceFiles->Next(1, &pSourceFile, &celt)) && (celt == 1)) 
    			{
    				num++;
    				pSourceFile->Release();
    			}
    			pEnumSourceFiles->Release();
    			fwprintf(pFileout,L"%i\n", num);
    		}
    		if (SUCCEEDED(pSession->findFile(pCompiland, NULL, nsNone, &pEnumSourceFiles))) 
    		{
    			IDiaSourceFile *pSourceFile;
    			while (SUCCEEDED(pEnumSourceFiles->Next(1, &pSourceFile, &celt)) && (celt == 1)) 
    			{
    				BSTR bstrSourceName;
    				if (pSourceFile->get_fileName(&bstrSourceName) == S_OK) 
    				{
    					fwprintf(pFileout,L"%s\n", bstrSourceName);
    					WCHAR *path = new WCHAR[wcslen(bstrSourceName)+8];
    					wcscpy(path,L"c:\\test\\");
    					wcscat(path,bstrSourceName+2);
    					WCHAR *filename = new WCHAR[wcslen(path)+1];
    					wcscpy(filename,path);
    					for(int k=wcslen(path)-1;k>=0&&path[k]!=L'\\';k--)path[k]=0;
    					bool ok = AQLCreateDirectory(path);
    					FILE *file = _wfopen(filename,L"w");
    					fclose(file);
    					delete(filename);
    					delete(path);
    					SysFreeString(bstrSourceName);
    				}
    				pSourceFile->Release();
    			}
    			pEnumSourceFiles->Release();
    		}
    		pCompiland->Release();
    	}
    	pEnumSymbols->Release();
    }
    


    Also popular now: