如何编辑可执行文件的“.data”段?

逆向工程 部件 反编译 调试 记忆
2021-06-23 14:12:18

这是一个与我前几天问的另一个问题相关的问题;我建议您在这里快速阅读它因为它可以包含有用的信息。无论如何,我的目标可执行文件中有两个静态类(ECXregister 总是在类的方法中发现),很明显第一个包含第二个:

.data:0190BD08 CFG_DB db ; DATA XREF: sub_40FFF0:loc_410049o
// 4 Bytes
.data:0190BD0C CFG_DB_TABLE<struct CFG_ENTRY[500], unsigned int> db ; DATA XREF: sub_A3DDD0+2Co
// 30 Bytes
.data:0190BD3C dword_190BD3C dd ? ; int dword_190BD3C[] DATA XREF: sub_5F5F70+B2r

With sub_40FFF0:loc_410049o =
    CFG_DB_TABLE_Reset((int)&CFG_DB);

这是Virtual Function Table第一个的:

.rdata:0137A1F0 dd offset CFG_DB
.rdata:0137A1F4 ??_7CFG_DB@@6B@ dd offset CFG_DB_Constructor
.rdata:0137A1F4     ; DATA XREF: CFG_DB_CreateInstance+8o
.rdata:0137A1F8 dd offset nullsub_008EF050
.rdata:0137A1FC dd offset sub_8EAB30
.rdata:0137A200 dd offset sub_8EF060
.rdata:0137A204 dd offset CFG_DB_TABLE_Reset
.rdata:0137A208 dd offset CFG_DB_ParseData
.rdata:0137A20C dd offset CFG_DB_ReadFile

Virtual Function Table第二个:

.rdata:0137A1D4 dd offset CFG_DB_TABLE
.rdata:0137A1D8 ??_7?$CFG_DB_TABLE@UCFG_ENTRY@@$0BPE@I@@6B@ dd offset CFG_DB_TABLE_Constructor
.rdata:0137A1D8     ; DATA XREF: CFG_DB_TABLE_Destructor+1Do
.rdata:0137A1D8     ; DATA XREF: CFG_DB_TABLE_CreateInstance+38o
.rdata:0137A1DC dd offset nullsub_008EF050
.rdata:0137A1E0 dd offset sub_8EAB30
.rdata:0137A1E4 dd offset sub_8EF060
.rdata:0137A1E8 dd offset CFG_DB_TABLE_Reset
.rdata:0137A1EC dd offset CFG_DB_ParseData

在伪代码中,所有这些都应该是这样的:

static CFG_DB cfgDB;

class CFG_DB
{
    int memoryAddress;
    static CFG_DB_TABLE _DBTable;
    // more data?
};

struct CFG_DB_TABLE
{
    int memoryAddress;
    CFG_ENTRY cfgEntries[500];
    int       filledSlotsCount;
    // more data...
};

所有我想要做的是增加的大小CFG_ENTRY位于结构的阵列CFG_DB_TABLE5001000知道CFG_ENTRY结构的大小(它是996字节),这似乎是一项非常简单的任务。由于filledSlotsCount(在代码中多次引用)放置在结构的末尾,我可以使用两种不同的方法进行处理:

  1. 增加现有cfgEntriesto的大小1000并将每个指针引用filledSlotsCount和其他变量增加 996*500。
  2. 将 a 附加CFG_ENTRY newCfgEntries[1000]到结构的末尾并cfgEntries通过 sizeof(CFG_DB_TABLE)-(996*1000)设置每个指针引用这个好像比较简单。

因此,例如,使用第一种方法,这一小段CFG_DB_ParseData代码:

while (true)
{
    currentFilledSlotsCount = *(_DWORD *)(pointerToCFG_DB_TABLE + 498004);

    if ( currentFilledSlotsCount >= 500 )
        break;

    *(_DWORD *)(pointerToCFG_DB_TABLE + 498004) = currentFilledSlotsCount + 1;

    if (!CFG_DB_ParseEntry((void *)(pointerToCFG_DB_TABLE + 996 * currentFilledSlotsCount + 4), v5) )
    {

变成:

while (true)
{
    currentFilledSlotsCount = *(_DWORD *)(pointerToCFG_DB_TABLE + 996004);

    if ( currentFilledSlotsCount >= 1000 )
        break;

    *(_DWORD *)(pointerToCFG_DB_TABLE + 996004) = currentFilledSlotsCount + 1;

    if (!CFG_DB_ParseEntry((void *)(pointerToCFG_DB_TABLE + 996 * currentFilledSlotsCount + 4), v5) )
    {

方法的代码CFG_DB_TABLE_CreateInstance变为:

int __thiscall CFG_DB_TABLE_CreateInstance(int this)
{
    int v1; // esi@1
    int v2; // [sp+18h] [bp-28h]@1

    v1 = this;
    v2 = this;

    *(_DWORD *)this = &CFG_DB_TABLE<CFG_ENTRY_500_unsigned_int>::_vftable_;
    unknown_libname_2672((void *)(this + 4), 996, 1000, sub_8EECA0, sub_8EEA00);

现在......做这些修改我避免了内存重叠/覆盖到类本身,但我仍然需要处理.data segment它本身,对吗?事实上,我认为我必须将其大小扩展 996*500,并且正如在我之前的问题中帮助我的其他用户所建议的那样,我也应该移动:

.data:0190BD08 CFG_DB db
.data:0190BD0C CFG_DB_TABLE<struct CFG_ENTRY[500], unsigned int> db

到底部.data segment,对吧?否则,这些静态类的内存可能会超过段中位于它们之后的静态实例的内存。

我的问题很简单:

1)如果 (data:0190BD3C - data:0190BD0C)中的静态大小包含最小字节(但可能更多,因为我看到一些从它开始的指针引用),它怎么可能CFG_DB_TABLE只有 30 个字节我在计算中是否遗漏了一些非常重要的东西?.data segment4+996*500*4=498008this+502036

2) 如何将.data segment996*500的大小移动扩展我是否必须手动编辑 PE 标头值?

3)如果这是真的有必要......我怎么能就动静态数据的引用CFG_DBCFG_DB_TABLE实例,从中间向底部.data segment本身?是否有任何工具可以做到这一点,同时还可以重写对它们的每个引用?

1个回答

你的第一个问题有很多令人困惑的事情。对于第二和第三个问题,我认为答案是绝对可能的,但它需要很多工作(手动)。您可以使用一些 PE 工具(PE 编辑器工具 - Lord PE 就是一个很好的例子)来调整该部分的大小并修改该部分中的数据(以二进制十六进制模式)。并且为了验证你的旧结构指针的所有引用,你可以使用一些反汇编工具如 IDA、OllyDbg 来找到所有引用的位置并在十六进制模式下修改它。

简而言之,我总结了我的解决方案如下:

  1. 使用 PE Editor (Lord PE) 调整 .data 部分和您将修改的任何部分的大小(打开这些部分中的写入标志)。
  2. 在某些情况下,PE 编辑器不会更新 PE 标头,因此您必须手动更新以获得有效图像(可以加载到内存中并运行)。
  3. 使用 OllyDbg 来编辑、修改内存中的二进制数据(支持反汇编:))来改变你的数据结构和所有引用,以便更容易跟踪、调试。在你所有的修改之后,你应该转储并修复 IAT(比如解压 PE 文件)。在某些情况下,您的修改在 OllyDbg 中不起作用,您应该使用 Hex Editor 或 Lord PE(再次)手动添加二进制数据。

这并不难,但需要勤奋和细心,祝你好运!