前言

当人们对未知文件格式进行逆向分析时,通常倾向于使用现成的提取器,但是,有时对于所讨论的格式并没有公共信息可用(例如,当开发公司使用自己特殊的格式来保护文件时),并且,文件格式可能存在巨大的差异,这时,我们就不得不自己动手进行逆向分析了。而本教程的目的,就是向读者展示逆向分析未知格式文件的基本步骤。

先决条件

为了顺利完成本文的任务,需要读者了解下列语言:

· C++语言

· x86汇编语言(Intel语法)

对于本文涉及内容,我会尽力给出通俗的解释,但是,读者最好对上述语言有所了解。

所需工具

本文中将用到以下工具:

· HexEdit(或其他十六进制编辑器)

· OllyDBG(需要用到Stealth64插件)

· IDA Pro(我使用的是6.8版本)和Hex-Rays Decompiler

这里,我们假设读者对于这些工具都能熟练使用。

那么,我们将要做些什么呢?

我们将分析Brawl Busters用于保护其数据的文件格式。Brawl Busters是一款动作格斗游戏,目前已经下架,幸运的是,我们可以通过Google搜索轻松找到它。

在本文中,我还将提供许多的伪代码,以演示如何通过我们的逆向分析结果来制作相应的提取器。

搭建实验环境

下载游戏后,先打开其安装文件夹,然后打开其中的“bin”文件夹。这时,将看到一个名为“pbclient.exe”的文件,它就是游戏客户端。

我已经上传了pbclient.exe的修补版本,这也是我一直在用的版本。实际上,我只是修补了一些条件跳转以防止XTrap被加载。在bin文件夹中,将pbclient.exe重命名为您喜欢的名称,然后将修补后的pbclient.exe放入该文件夹中。

· https://www.unknowncheats.me/forum/d…=file&id=26703

完成后上面的工作后,我们就准备好了完全一致的安装文件夹。好了,该动手了!

现在,请仔细考察根文件夹,看看能否找出实际游戏数据的存储位置。就本例来说,这似乎不是什么难事,因为其中有一个“Data”文件夹,所以,不妨打开该文件夹,看看里面到底是什么:

这里看起来确实像是游戏数据!如果向下滚动,还会看到一些配置文件(.ini)以及一些图像(例如Splash.png)。

这个文件夹中的大多数文件都有一个奇怪的.bus扩展名,似乎存储了大量的UI数据。而这些数据,正是我们感兴趣的内容。

对于初学者来说,.bus意味着什么呢?别忘了,该游戏的名称为“Brawl Busters”,因此“.bus”很可能就是“.busters”的简写。

到目前为止,虽然我们还没有进行太多的探索,但已经知道游戏将大部分数据都存储在.bus文件中,并且这些文件看起来像是采用了专有格式(因为从Google中搜不到任何这方面的信息)。

那么,这些格式的文件到底长啥样呢?现在,该十六进制编辑器上场了。在使用记事本之前,我总是先使用这些类型的编辑器,因为这些文件通常无法作为纯文本文件读取。让我们先打开一个身量较小的文件,比如“Anim.bus”:

这里好像看不出什么门道……数据好像是经过加密的。

让我们打开一个大一些的文件,比如“Anim_Mob_Zombie_Unique_Heavy.bus”:

好像还是看不出什么门道,不过,我们发现这两个文件有一个相似之处:每个文件的前33个字节都为0。如果我们打开更多的.bus文件,依然会看到,它们的前33个字节都是用0填充得。这可能是一个有用的细节,所以请记住它。

此外,还有另一个细节需要注意——如果向下滚动到0x4ED0,会看到一些纯文本:

这就更让人感兴趣了!如果我们在互联网上搜索“Gamebryo File Format, Version 20.6.0.0”,就会发现它是一种称为“NIF”(它代表的是NetImmerse File,但这并不重要)的已知格式。

这些NIF文件似乎是些模版(models),它们的纹理是使用DDS文件进行加载的。如果我们在HexEdit中搜索“DDS”,我们也会得到一些结果,例如"texname="FX_GhostTrail_A_00.dds"。这意味着某些.bus文件也会存储DDS文件。

同样,如果搜索“Gamebryo”关键词,也会返回一些搜索结果。我们可以从中得出什么结论呢?好吧,.bus文件似乎是存档(archives)文件,也就是说,它们会一次存储多个文件。文件数据之前的数据很可能是用于进行加密操作的元数据(有关存档本身及其内部文件的信息)。中国菜刀

让我们快速回顾一下我们已经获取的信息:

大部分游戏数据都存放在.bus文件中。

这些.bus文件可以同时存放多个文件,因此,它们实际上是文件存档。

该游戏使用Gamebryo引擎,因为存储的文件似乎是NIF/KFM/DDS格式的文件(如果您想验证这一点,可以打开其他文件并搜索这三个关键字)。

下一步该做些什么呢?我们必须弄清楚客户端是如何解密/加载这些文件的。这是我们更加感兴趣的方面。

利用IDA Pro进行静态分析

让我们回到“bin”文件夹,并通过IDA Pro打开pbclient.exe来分析该文件。

首先,我们要做的事情就是寻找导入函数。那么,我们要找哪些导入函数呢?好吧,既然客户端必须打开这些文件,因此很可能会使用诸如CreateFile或fopen之类的API。

下面,让我们开始搜索第一个导入函数:

CreateFileMapping会接受一个文件句柄,该文件通常由API(如CreateFile)返回,因此,让我们交叉引用该API。

我们找到的第一个引用就位于这个函数中:

(注意:为了便于理解,我将尽量使用反编译器,虽然我们不能完全信任其输出内容,但至少可以了解函数的大概作用)

    char __userpurge sub_50B409@<al>(int a1@<eax>, HANDLE *a2@<edi>, _DWORD *a3, DWORD a4){char v4; // bl@1HANDLE v5; // eax@1void *v6; // esi@1char v7; // ST18_1@2DWORD v9; // eax@5HANDLE v10; // eax@9char v11; // ST18_1@10LPVOID v12; // eax@11char v13; // ST18_1@12HANDLE hObject; // [sp+Ch] [bp-4h]@1v4 = 0;v5 = CreateFileA(*(LPCSTR *)(a1 + 20), 0x80000000, 1u, 0, 3u, 0, 0);v6 = v5;hObject = v5;if ( v5 == (HANDLE)-1 ){v7 = GetLastError();sub_40FB04();sub_4E7D8B(5, 16, "CreateFileA - Failed (%d)", v7);return 0;}v9 = GetFileSize(v5, 0);if ( a4 > 0 && v9 < a4 ){CloseHandle(v6);return 0;}v10 = CreateFileMappingA(v6, 0, 0x4000002u, 0, v9, 0);*a2 = v10;if ( !v10 ){v11 = GetLastError();sub_40FB04();sub_4E7D8B(5, 16, "CreateFileMappingA - Failed (%d)", v11);CloseHandle(hObject);return 0;}v12 = MapViewOfFile(v10, 4u, 0, 0, 0);*a3 = v12;if ( v12 ){v4 = 1;}else{v13 = GetLastError();sub_40FB04();sub_4E7D8B(5, 16, "MapViewOfFile - Failed (%d)", v13);CloseHandle(*a2);}CloseHandle(hObject);return v4;}

这个函数似乎是根据指定文件名来创建文件的(其中,a1是一个字符串,稍后会详细介绍)。如果没有发生错误,a3参数将包含内存映射文件(MapViewOfFile)的基地址。天空彩

让我们看一下CreateFileMappingA的第二个引用,它位于这个函数中:

    char __stdcall sub_52AE36(int a1, char a2, int a3, int a4, int a5, int a6, int a7){HANDLE v7; // eax@1void *v8; // edi@1int v9; // ecx@2DWORD v10; // eax@4const void *v11; // eax@6int v12; // esi@7const void *v13; // edi@9int v14; // ecx@11int v15; // eax@12int v16; // eax@12int v17; // esi@12int v18; // ecx@12int v19; // eax@15int v20; // eax@15char v21; // ST04_1@15int v22; // esi@15char v23; // bl@15int v24; // ecx@15int v26; // [sp-34h] [bp-148h]@15int v27; // [sp-30h] [bp-144h]@15int v28; // [sp-2Ch] [bp-140h]@15int v29; // [sp-28h] [bp-13Ch]@15int v30; // [sp-24h] [bp-138h]@15char v31; // [sp-20h] [bp-134h]@12int v32; // [sp-1Ch] [bp-130h]@12int v33; // [sp-18h] [bp-12Ch]@12int v34; // [sp-14h] [bp-128h]@12int v35; // [sp-10h] [bp-124h]@5int v36; // [sp-Ch] [bp-120h]@12LPCSTR v37; // [sp-8h] [bp-11Ch]@2char *v38; // [sp-4h] [bp-118h]@2char v39; // [sp+0h] [bp-114h]@13char v40; // [sp+Ch] [bp-108h]@15char v41; // [sp+20h] [bp-F4h]@12char v42; // [sp+24h] [bp-F0h]@15char v43; // [sp+3Ch] [bp-D8h]@15char v44; // [sp+50h] [bp-C4h]@12int v45; // [sp+68h] [bp-ACh]@12char v46; // [sp+74h] [bp-A0h]@15int *v47; // [sp+90h] [bp-84h]@15int v48; // [sp+94h] [bp-80h]@11char v49; // [sp+ACh] [bp-68h]@12char v50; // [sp+C4h] [bp-50h]@1char v51; // [sp+DCh] [bp-38h]@1LPCSTR lpFileName; // [sp+F0h] [bp-24h]@1LPCVOID lpBaseAddress; // [sp+F4h] [bp-20h]@6HANDLE hObject; // [sp+F8h] [bp-1Ch]@1HANDLE hFileMappingObject; // [sp+FCh] [bp-18h]@4char v56; // [sp+103h] [bp-11h]@1int v57; // [sp+104h] [bp-10h]@4int v58; // [sp+110h] [bp-4h]@1v58 = 1;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v50,Default,&v56);LOBYTE(v58) = 3;sub_44B825(&v51);LOBYTE(v58) = 4;v7 = CreateFileA(lpFileName, 0x80000000, 1u, 0, 3u, 0, 0);v8 = v7;hObject = v7;if ( v7 == (HANDLE)-1 ){v38 = (char *)GetLastError();v37 = lpFileName;sub_40FB04(v9);sub_4E7D8B(5, 16, "Invalid bus file - filename:(%s), Error:(%d)", (char)v37);LABEL_3:LOBYTE(v58) = 3;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::~basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v51);LOBYTE(v58) = 0;goto LABEL_21;}v57 = GetFileSize(v7, 0);v10 = GetFileSize(v8, 0);hFileMappingObject = CreateFileMappingA(v8, 0, 0x4000002u, 0, v10, 0);if ( !hFileMappingObject ){v38 = (char *)GetLastError();sub_40FB04(5);sub_4E7D8B(v35, 16, "CreateFileMappingA - Failed (%d)", (char)v38);CloseHandle(v8);goto LABEL_3;}v11 = operator new(0x90u);lpBaseAddress = v11;LOBYTE(v58) = 5;if ( v11 )v12 = sub_52B811(v11);elsev12 = 0;LOBYTE(v58) = 4;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::erase(v12 + 20,*(_DWORD *)(v12 + 40),*(_DWORD *)(v12 + 36));sub_40293D(*(_DWORD *)(a1 + 108));stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::operator=(v12 + 68, &v51);v13 = MapViewOfFile(hFileMappingObject, 4u, 0, 0, 0);lpBaseAddress = v13;if ( v13 ){sub_44BA2C(&v48);LOBYTE(v58) = 6;if ( (unsigned __int8)sub_52B8BA(v12, (void *)v13, v57, a1 + 32, (int)&v48) ){sub_498F89(&v49);LOBYTE(v58) = 7;v15 = stlp_std::locale::locale((stlp_std::locale *)&v57);LOBYTE(v58) = 8;sub_42E050(v15);LOBYTE(v58) = 7;stlp_std::locale::~locale((stlp_std::locale *)&v57);v16 = stlp_std::locale::locale((stlp_std::locale *)&v57);LOBYTE(v58) = 9;sub_50C2A7(&v49, v16);LOBYTE(v58) = 7;stlp_std::locale::~locale((stlp_std::locale *)&v57);v38 = (char *)v12;v57 = (int)&v32;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v32,&v49);LOBYTE(v58) = 7;v17 = sub_52B518(&v41, v31, v32, v33, v34, v35, v36, v37);LOBYTE(v58) = 11;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v44,v17);LOBYTE(v58) = 12;v45 = *(_DWORD *)(v17 + 24);LOBYTE(v58) = 13;v56 = *(_BYTE *)(sub_52B4C8(&v44) + 4);LOBYTE(v58) = 11;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::~basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v44);LOBYTE(v58) = 7;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::~basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v41);if ( v56 ){sub_498D74(&v46);LOBYTE(v58) = 16;v19 = stlp_std::locale::locale((stlp_std::locale *)&v57);LOBYTE(v58) = 17;sub_42E050(v19);LOBYTE(v58) = 16;stlp_std::locale::~locale((stlp_std::locale *)&v57);v20 = stlp_std::locale::locale((stlp_std::locale *)&v57);LOBYTE(v58) = 18;sub_50C2A7(&v46, v20);LOBYTE(v58) = 16;stlp_std::locale::~locale((stlp_std::locale *)&v57);v57 = (int)&v33;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v33,&v49);LOBYTE(v58) = 19;v47 = &v26;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v26,&v46);LOBYTE(v58) = 16;v22 = sub_52B564(&v43, v21, v26, v27, v28, v29, v30, v31);LOBYTE(v58) = 21;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v40,v22);LOBYTE(v58) = 22;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v42,v22 + 24);LOBYTE(v58) = 24;v23 = *(_BYTE *)(sub_4E75FD(&v40) + 4);LOBYTE(v58) = 21;sub_49324B(&v40);LOBYTE(v58) = 16;sub_52B331(&v43);if ( v23 ){LOBYTE(v58) = 7;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::~basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v46);LOBYTE(v58) = 6;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::~basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v49);UnmapViewOfFile(lpBaseAddress);CloseHandle(hFileMappingObject);CloseHandle(hObject);LOBYTE(v58) = 4;sub_402821(&v48);LOBYTE(v58) = 3;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::~basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v51);LOBYTE(v58) = 0;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::~basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v50);v58 = -1;sub_402821(&a2);return 1;}v38 = "std::make_pair(strLeaf, str) - Failed";v37 = (LPCSTR)16;v36 = 5;sub_40FB04(v24);sub_4E7D8B(v36, (int)v37, v38, v39);UnmapViewOfFile(lpBaseAddress);CloseHandle(hFileMappingObject);CloseHandle(hObject);LOBYTE(v58) = 7;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::~basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v46);}else{v38 = "std::make_pair(str, pPkg) - Failed";v37 = (LPCSTR)16;v36 = 5;sub_40FB04(v18);sub_4E7D8B(v36, (int)v37, v38, v39);UnmapViewOfFile(lpBaseAddress);CloseHandle(hFileMappingObject);CloseHandle(hObject);}LOBYTE(v58) = 6;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::~basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v49);}else{sub_40FB04(v14);sub_4E7D8B(5, 16, "Pkg Load Failed", v39);UnmapViewOfFile(v13);CloseHandle(hFileMappingObject);CloseHandle(hObject);}LOBYTE(v58) = 4;sub_402821(&v48);}else{v38 = (char *)GetLastError();sub_40FB04(5);sub_4E7D8B(v35, 16, "MapViewOfFile - Failed (%d)", (char)v38);CloseHandle(hFileMappingObject);CloseHandle(hObject);}LOBYTE(v58) = 3;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::~basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v51);LOBYTE(v58) = 0;LABEL_21:stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::~basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v50);v58 = -1;sub_402821(&a2);return 0;}

看来我们很幸运!客户端似乎正在使用CreateFileMappingA和MapViewOffile来映射.bus类型的文件。我们甚至可以看到一些错误消息字符串。

在我们继续之前,需要先把一行代码弄清楚。这行代码经常出现,并且看起来非常神秘(代码见第56行):

   stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(...)

下面,我们分开加以解释:

    stlp_std::

游戏客户端并没有直接使用C ++ STL,而是使用了stlport,这就是经常出现stlp_std的原因,它与std::非常像。

    basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::

如果我们使用Google搜索关键字Basic_String,可能会发现以下内容:

    template < class charT,class traits = char_traits<charT>,    // basic_string::traits_typeclass Alloc = allocator<charT>        // basic_string::allocator_type> class basic_string;

如您所见,“traits”和“Alloc”是默认参数,因此我们可以忽略它们。

在我们的例子中,char类型被用作charT参数,这意味着它会做同样的事情:

   stlp_std::basic_string<char>::

如果我们用谷歌搜索呢?

请看下面的代码:

   typedef basic_string<char> string;

好了,现在整个函数可以简化为:

具体代码如下所示:

   stlp_std::string::ctor_0(...) //std::string constructor, I added "_0" because std::string has different constructors

在IDA Pro中右键单击它,选择“Rename global item”,并将其改为“stlp_std::string::ctor_0”。现在,我们将会看到:

(注意:我们建议为std::string的每个构造函数/函数都执行该操作,这也是为它们编号的原因。这样的话,就能过让反编译器的输出代码更清晰一些。)

让我们再次回到这个函数上面来!接下来,我们感兴趣的是对MapViewOfFile的调用(见第100行)。如果您像了解其具体作用,请访问下列地址:

· https://msdn.microsoft.com/en-us/lib…(v=vs.85).aspx

在这个例子中,v13存放的是映射视图(被映射到内存中的整个文件)的基址。然后将它作为第二个参数传递给该函数:

    sub_52B8BA(v12, (void *)v13, v57, a1 + 32, (int)&v48);

我们来看看这个函数:

    char __stdcall sub_52B8BA(int a1, void *Src, int a3, int a4, int a5){int v5; // ebx@1void *v6; // esi@1int v7; // ecx@2int v8; // eax@2int v9; // eax@2int v10; // ecx@3int v11; // eax@3char *v12; // eax@3int v13; // esi@3int v14; // eax@4int v15; // eax@4int v16; // ecx@4char v17; // ST04_1@4int v19; // eax@9int v20; // edi@9int v21; // eax@11int v22; // eax@12int v23; // eax@12int v24; // ecx@12char v25; // ST04_1@12rsize_t v26; // eax@12int v27; // eax@16int v28; // [sp-3Ch] [bp-130h]@4int v29; // [sp-38h] [bp-12Ch]@4int v30; // [sp-34h] [bp-128h]@4int v31; // [sp-30h] [bp-124h]@4int v32; // [sp-2Ch] [bp-120h]@4int v33; // [sp-28h] [bp-11Ch]@4char v34; // [sp-24h] [bp-118h]@4char v35; // [sp-20h] [bp-114h]@4int v36; // [sp-1Ch] [bp-110h]@4char v37; // [sp-18h] [bp-10Ch]@4char *v38; // [sp-Ch] [bp-100h]@3rsize_t v39; // [sp-8h] [bp-FCh]@3char *v40; // [sp-4h] [bp-F8h]@2char v41; // [sp+10h] [bp-E4h]@4char v42; // [sp+50h] [bp-A4h]@4char *v43; // [sp+9Ch] [bp-58h]@12char v44; // [sp+A0h] [bp-54h]@3char v45; // [sp+B8h] [bp-3Ch]@4char v46; // [sp+D0h] [bp-24h]@12char v47; // [sp+D4h] [bp-20h]@12int v48; // [sp+D8h] [bp-1Ch]@2char *v49; // [sp+DCh] [bp-18h]@3int *v50; // [sp+E0h] [bp-14h]@8int v51; // [sp+E4h] [bp-10h]@3int v52; // [sp+F0h] [bp-4h]@3v5 = a1;v6 = Src;if ( Src ){v48 = 0;memcpy((void *)(a1 + 108), Src, 0x21u);v40 = *(char **)(v5 + 104);v8 = sub_40CF95(v7);sub_50B9A2(v8, (char *)v6 + 33, 0x110u, v40);v9 = *(_DWORD *)(v5 + 104);if ( v9 ){v10 = *(_DWORD *)(v9 + 264);v40 = *(char **)(v5 + 104);v39 = v5 + 20;v38 = &v44;*(_DWORD *)v5 = v10;v11 = sub_50C22C(v38, v39, v40);v52 = 0;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::operator=(a5, v11);v52 = -1;sub_402821(&v44);sub_4DC6D9();v12 = *(char **)(*(_DWORD *)(v5 + 104) + 268);v13 = 276 * *(_DWORD *)(*(_DWORD *)(v5 + 104) + 268) + 305;v49 = v12;v51 = v13;if ( !v12 ){sub_498D74(&v45);v52 = 1;v14 = stlp_std::locale::locale((stlp_std::locale *)&Src);LOBYTE(v52) = 2;sub_42E050(v14);LOBYTE(v52) = 1;stlp_std::locale::~locale((stlp_std::locale *)&Src);v15 = stlp_std::locale::locale((stlp_std::locale *)&Src);LOBYTE(v52) = 3;sub_50C2A7(&v45, v15);LOBYTE(v52) = 1;stlp_std::locale::~locale((stlp_std::locale *)&Src);a3 = 0;v51 = 0;v49 = &v34;BYTE3(Src) = 0;BYTE3(a1) = 1;sub_52C06B((char *)&a1 + 3, (char *)&Src + 3, &a3, v5 + 68);v29 = v16;v28 = v16;LOBYTE(v52) = 4;Src = &v28;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v28,&v45);LOBYTE(v52) = 1;sub_52BFEC(&v41, v17, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37);LOBYTE(v52) = 6;sub_52C09F(&v42);LOBYTE(v52) = 7;sub_52BCA1(&v42);LOBYTE(v52) = 6;sub_50CA47(&v42);LOBYTE(v52) = 1;sub_50CA47(&v41);sub_52BCF1(a5);v52 = -1;stlp_std::string::dtor(&v45);return 1;}a1 = 0;if ( !v12 )return 1;a5 = 276;while ( 1 ){v50 = (int *)operator new(0x114u);v52 = 8;if ( v50 ){v19 = sub_52B7F1();v13 = v51;v20 = v19;}else{v20 = 0;}v52 = -1;v40 = (char *)v20;v39 = 276;v38 = (char *)Src + v48 + 305;v21 = sub_40CF95(Src);sub_50B9A2(v21, v38, v39, v40);if ( v20 ){v48 = a5;sub_49C45F(&v44, v20);v52 = 9;sub_498D74(&v45);LOBYTE(v52) = 10;v22 = stlp_std::locale::locale((stlp_std::locale *)&v47);LOBYTE(v52) = 11;sub_42E050(v22);LOBYTE(v52) = 10;stlp_std::locale::~locale((stlp_std::locale *)&v47);v23 = stlp_std::locale::locale((stlp_std::locale *)&v46);LOBYTE(v52) = 12;sub_50C2A7(&v45, v23);LOBYTE(v52) = 10;stlp_std::locale::~locale((stlp_std::locale *)&v46);v50 = (int *)(v13 + *(_DWORD *)(v20 + 264));v43 = &v34;sub_52C06B(v20 + 273, v20 + 272, &v50, v5 + 68);v29 = v24;v28 = v24;LOBYTE(v52) = 13;v50 = &v28;stlp_std::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>::basic_string<char,stlp_std::char_traits<char>,stlp_std::allocator<char>>(&v28,&v45);LOBYTE(v52) = 10;sub_52BFEC(&v41, v25, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37);LOBYTE(v52) = 15;sub_52C09F(&v42);LOBYTE(v52) = 16;sub_52BCA1(&v42);LOBYTE(v52) = 15;sub_50CA47(&v42);LOBYTE(v52) = 10;sub_50CA47(&v41);v26 = *(_DWORD *)(v5 + 96);v40 = &v44;v39 = v26;if ( v26 == *(_DWORD *)(v5 + 100) ){sub_52BDBB(v39, v40);}else{sub_52C0F4(v39, v40);*(_DWORD *)(v5 + 96) += 24;}LOBYTE(v52) = 9;stlp_std::string::dtor(&v45);v52 = -1;sub_402821(&v44);v13 = v51;}v27 = *(_DWORD *)(v20 + 264) + *(_DWORD *)(v20 + 268);v40 = (char *)v20;if ( v13 + v27 > (unsigned int)a3 )break;operator delete(v40);++a1;a5 += 276;if ( a1 >= (unsigned int)v49 )return 1;}operator delete(v40);}}return 0;}

您可能已经发现了,这里忽略了许多的其他参数(以及许多其他函数)——因为我们只讨论密切相关的参数和函数。

我们已经知道,“Src”是我们的映射视图的地址。

    memcpy((void *)(a1 + 108), Src, 0x21u); //Src: address of mapped file view

0x21h的十进制值为33。等等,33……,看到这个值难道我们没有想起什么吗?没错,每个.bus文件的前33个字节都是用0填充的。这将从地址a1+0x108处复制33个字节。

下面这个函数只有三个参数:

    sub_50B9A2(v8, (char *)v6 + 33, 0x114u, v40); //v6 = Src

0x114h是十进制的272,并且它传递的地址等于源缓冲区的地址+33(跳过所有0值)。下面,让我们来看看它的作用:

    int __stdcall sub_50B9A2(int a1, void *Src, rsize_t DstSize, void *Dst){memcpy_s(Dst, DstSize, Src, DstSize);return sub_50B91E(a1, Dst, DstSize);}

现在其功能已经很清楚了,不是吗?我们现在知道,这里将处理272个字节。如果我们回到上一个函数,就可以对一些变量重新加以命名了:

我们仍然不知道v8是什么东东,不过,我们已经知道它是被下面的函数设置的:

    int __thiscall sub_40CF95(void *this){if ( !dword_F57C24 )sub_40D5EF();return dword_F57C24;}

这里看起来非常像单例设计模式。如果你不熟悉该模式的话,建议大家谷歌一下,此外,这里只做简单解释:

dword_XXXX是全局变量。首先,它检查dword_F57C24是否为空。如果为空的话,就会调用一个函数(类的构造函数)来进行初始化。当整个程序中只需要该类的一个实例时,这种设计模式会非常有用。

如果您考察了相应的虚函数表并检查了构造函数代码,就会注意到该类实际上就符合上面的设计模式。如果我们能从中获得RTTI信息(如果启用了RTTI的话),那就太好了。这个将在后面介绍。

由于篇幅过长,今天我们就介绍到这里。后续内容请随时关注我们。

(未完待续)

实例讲解未知游戏文件格式的逆向分析方法(上)相关推荐

  1. CRC原理及其逆向分析方法

    CRC原理及其逆向破解方法: 介绍: 这篇短文包含CRC原理介绍和其逆向分析方法,很多程序员和破解者不是很清楚了解 CRC的工作原理,而且几乎没人知道如何逆向分析它的方法,事实上它是非常有用的. 首先 ...

  2. iOS小技能:重签名、逆向分析方法、多开原理

    文章目录 前言 I 注入原理 1.1 mobileloader注入原理详细说明 1.2 重签名 1.3 小结 II.iOS逆向分析方法 2.1 网络分析 2.2 静态分析 2.3 动态分析 III 多 ...

  3. Fruit Ninja(水果忍者)游戏源代码下载、分析(上)---可运行Android,Ios,Window,Mac,Html5平台

    背景: 本来打算下一个游戏是涂鸦跳跃的,因为图片资源没准备好,暂时往后推迟.刚好笔者手头上有部分水果忍者的游戏素材,于是上周末花了一些时间把水果忍者实现了:以前读大学的时候这款游戏就风靡大街小巷,记得 ...

  4. 一文带你了解对游戏外挂的逆向分析的详细步骤。

    详细的逆向分析步骤,可以点击下面文字链接进行查看. 链接:游戏外挂样本逆向详细步骤

  5. 游戏窗口化的逆向分析

    目录 问题描述 逆向思路 逆向过程 逆向技巧 谈谈收获 问题描述 有很多游戏本身不支持用户设置窗口化,本文通过逆向分析,完成游戏的窗口化设置. 本文以Sword2游戏为例,该游戏内不支持用户设置窗口化 ...

  6. 病毒木马查杀实战第005篇:熊猫烧香之逆向分析(上)

    前言 对病毒进行逆向分析,可以彻底弄清楚病毒的行为,从而采取更有效的针对手段.为了节省篇幅,在这里我不打算将"熊猫烧香"进行彻底的分析,只会讲解一些比较重要的部分,大家只要掌握了这 ...

  7. meta分析森林图解读,实例讲解教你快速学会meta分析森林图解读!

    Meta分析一对一指导,符合学术规范,结课直接投稿,+tjzgBL哟! meta分析森林图里长长短短的横线和形状分别代表了什么?这就是我们本期需要解决的问题:meta分析森林图解读. 本文我以< ...

  8. 三菱fx2n做从站的modbus通讯_实例讲解三菱PLC编程及通讯设定方法

    三菱FX系列PLC作为三菱基本的PLC,它们之间的通讯有几种常用的方式,分别如下:CC-LINK,N:N网络连接,并联连接.1.CC-LINK连接 CC-LINK连接图如下: 对应的PLC可为FX1N ...

  9. 中职计算机PPT触发器使用的教案,PPT触发器使用全攻略-实例讲解PPT触发器的设置和使用方法(2)...

    案例二:弹出窗口 实现效果:点击页面中的图片和文字区域,弹出窗口,点击窗口,将窗口关闭. 准备素材:一张图片,一段说明文字. 制作过程: ①在页面中插入图片与文字.绘制弹出窗口,将弹出窗口各元素进行组 ...

最新文章

  1. 从0梳理1场CV缺陷检测赛事!
  2. 程序经编译连接后变为机器码
  3. javascript数据类型一览
  4. RocketMQ介绍与云服务器安装
  5. VTK修炼之道70:体绘制讨论_光照阴影、VTKLODProp3D
  6. 剑指 Offer 09. 用两个栈实现队列(相邻相同操作只需要移动一次)
  7. Android Binder机制的Native应用
  8. 【UOJ #351】新年的叶子(树的直径,期望)
  9. linux进程调度时间片算法,进程调度算法–时间片轮转调度算法
  10. MATLAB如何创建表格
  11. java myeclipse的好处,关于MyEclipse_MyEclipse用途_MyEclipse优势
  12. 郑明秋什么版本的MySQL_mysql数据库实用教程教学课件作者郑明秋代码数据库脚本代码9787568250825.docx...
  13. minecraft pythonapl_Minecraft API
  14. 电阻电路的等效变化(Ⅰ)
  15. latex tex studio 表格大小 整体缩小 过长 过宽 跨栏 跨页
  16. 【Qt炫酷动画】demo02-仿苹果对话框淡入淡出的动画
  17. JAVA中的protected的访问权限只有在本类同包类和子类吗?
  18. m基于ACO蚁群优化的FCM模糊聚类算法matlab仿真
  19. 计算机文字输入原理,也谈计算机汉字键盘设计“三原理”
  20. 计算机毕业设计JAVA汽车配件管理系统mybatis+源码+调试部署+系统+数据库+lw

热门文章

  1. 优漫动游达芬奇调色需要学习多长时间,难不难学呢?
  2. 深度挖掘文物价值,VR博物馆讲好文物故事
  3. DirectSound播放实时音频
  4. RestCloud·618福利预告
  5. SLAM中的位姿与轨迹评价指标:APE、RPE、ATE、RTE
  6. day17_ELJSTL
  7. 阿里巴巴Java笔试题很难_阿里巴巴Java笔试题和面试题答案
  8. TCP:三次握手,URG、ACK、PSH、RST、SYN、FIN 含义
  9. Springboot 使用freemaker导出word文档
  10. 7-3 括号匹配 (20分)(C语言版)