IDA Hex-Rays: Восстановление сломанного стека
От: Albeoris  
Дата: 21.10.18 17:51
Оценка:
Доброго времени суток!
Столкнулся с новой для себя проблемой разломанного стека функции в процессе ревёрса.
Приложение использует старенький DirectDraw для рисования.

  fun_directDrawCreateSurface
LPDIRECTDRAWSURFACE __usercall fun_directDrawCreateSurface@<eax>(int a1@<ebp>, unsigned __int16 width, unsigned __int16 height, int a4)
{
  int Dst; // [esp+8h] [ebp-6Ch]
  int v6; // [esp+Ch] [ebp-68h]
  int v7; // [esp+10h] [ebp-64h]
  int v8; // [esp+14h] [ebp-60h]
  char v9; // [esp+50h] [ebp-24h]
  LPDIRECTDRAWSURFACE surfacePtr; // [esp+6Ch] [ebp-8h]
  int v11; // [esp+70h] [ebp-4h]

  memset(&Dst, 0, 0x6Cu);
  v7 = height;
  Dst = 108;
  v8 = width;
  v6 = 4103;
  v11 = 64;
  qmemcpy(&v9, &unk_4DE5E8, 0x20u);
  if ( !a4 )
    v11 = 2112;
  if ( ((int (__cdecl *)(LPDIRECTDRAW, int *, unsigned __int16 *, _DWORD, int, int, int, int))lpDD->lpVtbl->CreateSurface)(
         lpDD,
         &Dst,
         &height,
         0,
         Dst,
         v6,
         v7,
         v8) )
  {
    return 0;
  }
  AM_BltSurface(a1, surfacePtr, 0);
  return surfacePtr;
}


Сигнатура функции CreateSurface очень простая, и в ней и не пахнет 7 параметрами:
HRESULT (__stdcall *CreateSurface)(IDirectDraw *This, LPDDSURFACEDESC, LPDIRECTDRAWSURFACE *, IUnknown *)


При этом легко заметить, что вначале расположена структура DDSURFACEDESC, размер которой как раз равен 0x6C.
Но есть проблема.

  Структура _DDSURFACEDESC
struct _DDSURFACEDESC
{
  DWORD dwSize;
  DWORD dwFlags;
  DWORD dwHeight;
  DWORD dwWidth;
  union
  {
    LONG lPitch;
    DWORD dwLinearSize;
  };
  DWORD dwBackBufferCount;
  union
  {
    DWORD dwMipMapCount;
    DWORD dwZBufferBitDepth;
    DWORD dwRefreshRate;
  };
  DWORD dwAlphaBitDepth;
  DWORD dwReserved;
  LPVOID lpSurface;
  DDCOLORKEY ddckCKDestOverlay;
  DDCOLORKEY ddckCKDestBlt;
  DDCOLORKEY ddckCKSrcOverlay;
  DDCOLORKEY ddckCKSrcBlt;
  DDPIXELFORMAT ddpfPixelFormat;
  DDSCAPS ddsCaps;
};


LPVOID lpSurface; расположена по смещению ebp-1Ch, а при сопоставлении со структурой LPDIRECTDRAWSURFACE surfacePtr; начинает указывать на DDPIXELFORMAT ddpfPixelFormat (ebp-8h).

  Получается вот такая каша.
LPDIRECTDRAWSURFACE __usercall fun_directDrawCreateSurface@<eax>(int a1@<ebp>, unsigned __int16 width, unsigned __int16 height, int a4)
{
  _DDSURFACEDESC Dst; // [esp+8h] [ebp-6Ch]

  memset(&Dst, 0, 0x6Cu);
  Dst.dwHeight = height;
  Dst.dwSize = 108;
  Dst.dwWidth = width;
  Dst.dwFlags = 4103;
  Dst.ddsCaps.dwCaps = 64;
  qmemcpy(&Dst.ddpfPixelFormat, &unk_4DE5E8, sizeof(Dst.ddpfPixelFormat));
  if ( !a4 )
    Dst.ddsCaps.dwCaps = 2112;
  if ( ((int (__cdecl *)(LPDIRECTDRAW, _DDSURFACEDESC *, unsigned __int16 *, _DWORD, DWORD, DWORD, DWORD, DWORD))lpDD->lpVtbl->CreateSurface)(
         lpDD,
         &Dst,
         &height,
         0,
         Dst.dwSize,
         Dst.dwFlags,
         Dst.dwHeight,
         Dst.dwWidth) )
  {
    return 0;
  }
  AM_BltSurface(a1, (LPDIRECTDRAWSURFACE)Dst.ddpfPixelFormat.dwRGBAlphaBitMask, 0);
  return (LPDIRECTDRAWSURFACE)Dst.ddpfPixelFormat.dwRGBAlphaBitMask;
}


Само собой, это рабочий код, который прекрасно функционирует.
В чём может быть проблема? Как её исправить? Насколько я понимаю, стек ломает вызов CreateSurface, но как подсказать Hex-Rays, что он неправ?
"Хаос всегда побеждает порядок, поскольку лучше организован." (с) Терри Пратчетт
ida hex-rays decompiler reverse engineering с\с++
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.