IDA PRO 结构指针计数器大数字不是从地址偏移量 0 开始,稍微降低一点但不是一直到 0

逆向工程 艾达 结构 职能
2021-06-30 01:42:59

我把整个问题放在 2 张图片中。从研究来看,我似乎需要使用Ctrl+ R,但我认为这不是我需要的,因为我无法进一步降低数字以达到 0。

我认为问题在于我没有structs正确创建

我想补充一些猜测,因为 PlayerPointers 数组是每个元素 4 个字节,所以数字下降到 16072。所以它下降了64288 / 4 = 16072
我仍然不知道那是什么意思。

问题一 汇编代码

ASM 代码:

.text:0040E040 ; =============== S U B R O U T I N E =======================================
.text:0040E040
.text:0040E040
.text:0040E040 ; struct_ARENA *__thiscall code(struct_PLAYER *player, const void *buf, unsigned int len, int a4)
.text:0040E040 sub_40E040      proc near               
.text:0040E040                                         
.text:0040E040
.text:0040E040 buf             = dword ptr  4
.text:0040E040 len             = dword ptr  8
.text:0040E040 a4              = dword ptr  0Ch
.text:0040E040
.text:0040E040                 push    ebx
.text:0040E041                 push    esi
.text:0040E042                 mov     esi, ecx
.text:0040E044                 mov     eax, [esi+1Ch]
.text:0040E047                 test    eax, eax
.text:0040E049                 jz      short loc_40E093
.text:0040E04B                 mov     ecx, [eax+0FF0Ch]
.text:0040E051                 xor     ebx, ebx
.text:0040E053                 test    ecx, ecx
.text:0040E055                 jle     short loc_40E093
.text:0040E057                 push    edi
.text:0040E058                 push    ebp
.text:0040E059                 mov     ebp, [esp+10h+a4]
.text:0040E05D                 mov     edi, 0FB20h
.text:0040E062
.text:0040E062 loc_40E062:                             
.text:0040E062                 mov     eax, [edi+eax]
.text:0040E065                 cmp     eax, esi
.text:0040E067                 jz      short loc_40E082
.text:0040E069                 mov     ecx, [eax+38h]
.text:0040E06C                 test    ecx, ecx
.text:0040E06E                 jnz     short loc_40E082
.text:0040E070                 mov     ecx, [esp+10h+len]
.text:0040E074                 mov     edx, [esp+10h+buf]
.text:0040E078                 push    ebp             ; a4
.text:0040E079                 push    ecx             ; len
.text:0040E07A                 push    edx             ; buf
.text:0040E07B                 mov     ecx, eax        ; this
.text:0040E07D                 call    SendPlayerReliablePacket
.text:0040E082
.text:0040E082 loc_40E082:                             
.text:0040E082                                         
.text:0040E082                 mov     eax, [esi+1Ch]
.text:0040E085                 inc     ebx
.text:0040E086                 add     edi, 4
.text:0040E089                 cmp     ebx, [eax+0FF0Ch]
.text:0040E08F                 jl      short loc_40E062
.text:0040E091                 pop     ebp
.text:0040E092                 pop     edi
.text:0040E093
.text:0040E093 loc_40E093:                            
.text:0040E093                                         
.text:0040E093                 pop     esi
.text:0040E094                 pop     ebx
.text:0040E095                 retn    0Ch
.text:0040E095 sub_40E040      endp
.text:0040E095 ; ---------------------------------------------------------------------------
.text:0040E098                 align 10h

这是一个看起来更好的结构,只有 1 个结构而不是 2 个,但仍然存在同样的问题

在此处输入图片说明

这是不看比赛但在玩游戏的玩家数量。

int __thiscall TotalPlayingPlayers(struct_ARENA *arena)
{
  int ArenaPlayerCount; // edx@1
  int result; // eax@1
  struct_PLAYER **eachPlayer; // ecx@2

  ArenaPlayerCount = arena->ArenaPlayerCount;
  result = 0;
  if ( ArenaPlayerCount > 0 )
  {
    eachPlayer = arena->playerPointersForSomething;// How could this be like this? this would only hold 251 4 bytes not enough for all players.
    do
    {
      if ( (*eachPlayer)->Ship != 8 )
        ++result;
      ++eachPlayer;                             // This means it really has to go up by 4 bytes the small 251 array.
      --ArenaPlayerCount;
    }
    while ( ArenaPlayerCount );
  }
  return result;
}

这是上面的图片

1个回答

在我看来,如果您假设 v7 是索引,那么您就错了 - v6 是。

原来的功能可能是这样的

int v6=0;
while (v6 < result->ArenaSubStruct.ArenaPlayerCount) {   // <-- what is a if/do while in your disassembly was originally a while
    eachPlayer = result->ArenaSubStruct.PlayerPointers[v6];
    if (eachPlayer != player)                            // <-- v4 and player are identical
        SendPlayerReliablePacket(eachPlayer, buf, len, a4);
    ++v6;
}

为了优化这一点,编译器引入了 v7 作为指向与循环变量对应的数组元素的指针。这样,处理器只需要访问一个指针(并将指针增加它指向的 int 的大小)而不是乘法和每个循环相加:

int v6=0;
int v7=offsetof(*result, ArenaSubStruct.PlayerPointers);
while (v6 < result->ArenaSubStruct.ArenaPlayerCount) {
    eachPlayer = *(int *)((char *)result+v7)
    if (eachPlayer != player)
        SendPlayerReliablePacket(eachPlayer, buf, len, a4);
    v6++;
    v7+=sizeof(ArenaSubStruct.PlayerPointers[0]);   // which is an it so sizeof returns 4
}

因此,您的 v7 不是应该降到 0 的 PlayerPointers 结构中的索引,相反,它是 ArenaSubStruct 结构中的“索引”,从 ArenaSubStruct 中 PlayerPointers 的偏移量开始。你不能在 IDA 中很好地恢复它,因为编译器所做的事情没有很好的 C 表示——看看我不得不做的丑陋的类型转换。