5

How do I fix structures in IDA PRO so they show up properly in Hex-Rays plugin (C decompiler).

Similar question to: (But the solution doesn't work for me)
Struct with negative offset in IDA possible

Pretty much what happened is I compiled a very good program and it works right, after that I did many changes to it and now it works worse then the older version, I'm trying to figure out what I did wrong (since I lost the source code now) to revert back to the old version. (I also added below the original piece of the code written in C++, which didn't change between both versions).

Structure's addresses somehow optimized in IDA PRO Such as that

*(_BYTE *)(shipsStruct + 279) = 1; //Ships[i].used = true;

should really be [10x4]=40+255= 295

*(_BYTE *)(shipsStruct + 295) = 1;  //Ships[i].used = true;

You can tell the structure size right here (shipsStruct += 296;)

I'm guessing somehow the un-used structure members are stripped out (but why is the structure size valid?).
Seems the assembly somehow is offset wrongly (how do I add the proper offset deltas to the struct to fix this)?

When I try this tip http://www.hexblog.com/?p=63 My whole IDA PRO freezes up when I select the line mov edi, offset dword_10004C38 and press T (IDA PRO 6.1)

structoffset

Seems I made my struct incorrectly?

Here is how the code decompiled code looks like (without applying structure)

  if ( playerListBaseAddress && !IsBadReadPtr(playerListBaseAddress, 4u) )
  {
    shipsStruct = (int)dword_10004C38;
    while ( 1 )
    {
      playerPointer = (struct_v3 *)*((_DWORD *)playerListBaseAddress + maxPlayers);
      if ( !playerPointer )
        break;
      if ( IsBadReadPtr(playerPointer, 4u) )
        break;
      *(_DWORD *)(shipsStruct - 4) = playerPointer->ssXCoord;
      *(_DWORD *)shipsStruct = playerPointer->ssYCoord;
      *(_DWORD *)(shipsStruct + 4) = playerPointer->ssXSpeed;
      *(_DWORD *)(shipsStruct + 8) = playerPointer->ssYSpeed;
      *(_DWORD *)(shipsStruct - 8) = playerPointer->ssFreq;
      *(_DWORD *)(shipsStruct + 20) = playerPointer->ssShipNum;
      if ( playerPointer->ssPlayerName )
        strcpy_s((char *)(shipsStruct + 24), 0xFFu, &playerPointer->ssPlayerName);
      *(_BYTE *)(shipsStruct + 279) = 1;
      if ( v37 == playerPointer )
        break;
      shipsStruct += 296;
      ++maxPlayers;
      v37 = playerPointer;
      if ( shipsStruct >= (signed int)&unk_10017310 )
        goto finish;
    }
    v34 = maxPlayers;
    if ( maxPlayers < 255 )
    {
      v4 = (int)((char *)&unk_10004D4F + 296 * maxPlayers);
      do
      {
        *(_BYTE *)v4 = 0;
        v4 += 296;
      }
      while ( v4 < (signed int)&unk_10017427 );
    }

Here is the orginal code (not decompiled written in C++)

double currentTimer = GetTimer();
double timeElapsed = currentTimer - lastTimer;

int maxPlayers = 0;
DWORD lastPlayerPtr = 0;
if (playerListBaseAddress != NULL && !IsBadReadPtr((void *) playerListBaseAddress, sizeof(ULONG_PTR))) {
    for (int i = 0; i < 255; i++) { //populate player ship list.
    DWORD playerPtr = *(DWORD *) (playerListBaseAddress + (i * 4));

    if (playerPtr != NULL && !IsBadReadPtr((void *) playerPtr, sizeof(ULONG_PTR))) {
        Ships[i].XCoordinate = *(DWORD *) (playerPtr + 0x4);
        Ships[i].YCoordinate = *(DWORD *) (playerPtr + 0x8);
        Ships[i].XSpeed = *(signed long *) (playerPtr + 0x10);
        Ships[i].YSpeed = *(signed long *) (playerPtr + 0x14);
        Ships[i].Freq = *(DWORD *) (playerPtr + 0x58);
        Ships[i].ShipNum = *(BYTE *) (playerPtr + 0x5C)
        //memcpy(&(Ships[i].Name), (void*)((DWORD)playerPtr+0x6D), 19);
        if (!*(BYTE *) (playerPtr + 0x6D) == NULL)
        strcpy_s(Ships[i].Name, (char *) ((DWORD) playerPtr + 0x6D));
        Ships[i].used = true;

        if (lastPlayerPtr == playerPtr)
        goto finishList;
        lastPlayerPtr = playerPtr;
    } else {
      finishList:
        maxPlayers = i;
        for (int j = i; j < 255; j++)
        Ships[j].used = false;
        break;
    }
}

Here is before and after (applying my custom struct)
I did the custom struct by doing a bunch of Arrays (* key), then setting proper sizes. (Guessing this isn't the proper way to make a structure in IDA PRO?) struct
Before:
before
After:
after
ASM:
asm
Edit Function
edit function
Double clicked local variable
dbl click local variables

SSpoke
  • 759
  • 1
  • 7
  • 19

2 Answers2

5

This feature is supported since Hex-Rays 1.6:

http://www.hexblog.com/?p=544

(see section 3. CONTAINING_RECORD macro)

Igor Skochinsky
  • 36,553
  • 7
  • 65
  • 115
4

From above...

Decompiled:

*(_DWORD *)(shipsStruct - 4) = playerPointer->ssXCoord;
*(_DWORD *)shipsStruct = playerPointer->ssYCoord;
...

Original:

Ships[i].XCoordinate = *(DWORD *) (playerPtr + 0x4);
Ships[i].YCoordinate = *(DWORD *) (playerPtr + 0x8);
...

Based on these snippets, it looks like the structure in your stack variables is 8 bytes off. Can you share with us the stack variable list for that function? (Double-click on one of the local variables in the decompilation to open the stack view.)

Jason Geffner
  • 20,681
  • 1
  • 36
  • 75
  • Talking about this? http://i.stack.imgur.com/2rANk.png here: http://i.stack.imgur.com/9vKkW.png – SSpoke Dec 31 '13 at 02:45
  • Should I risk deleting those db ? ;undefined above? and how did IDA analysis mess on this. Seems 12 bytes off (All functions decompile without errors btw) – SSpoke Dec 31 '13 at 02:53
  • Okay I changed from 0x68 to 0x5C now all undefined are gone begins from var_5C still generates same C code and everything seems the same, except for when clicking the stack variables no more undefined variables there. – SSpoke Dec 31 '13 at 03:06
  • Is shipsStruct a local variable or a global variable? – Jason Geffner Dec 31 '13 at 03:44
  • Well shipsStruct is declared locally from (int)dword_10004C38 which seems to be a global location in memory that location in memory I guess somehow should represent the offsetted structure. shipsStruct is the name I gave it it's really suppose to be casted to ShipStruct. Becomes like this when I convert it to struct* shipsStruct = (ShipStruct *)dword_10004C38; – SSpoke Dec 31 '13 at 03:51
  • Even if it's just a local pointer to a global structure, it's odd that it's not in the stack variable listing for the function. Are you sure you posted the screenshot for the right function's stack listing? – Jason Geffner Dec 31 '13 at 03:59
  • Yes I did it's not in the Local Stack Variables. It seems to get generated during decompilng in Hex-Rays. it's register edi ShipStruct *shipsStruct; // edi@3 after converting to struct and before it looks like this int shipsStruct; // edi@3, It generates about 48 local variables even those the stack shows only 13. – SSpoke Dec 31 '13 at 04:00
  • Re opened the file and now it generates this without any editing anything. v1 = (signed int)dword_10004C38; signed int v1; // edi@3 (still not in the local stack variable listing) – SSpoke Dec 31 '13 at 04:42