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 с\с++
Re: IDA Hex-Rays: Восстановление сломанного стека
От: reversecode google
Дата: 21.10.18 18:27
Оценка:
idb или программу давайте
а то получается как лечение по фотографии
Re[2]: IDA Hex-Rays: Восстановление сломанного стека
От: Albeoris  
Дата: 21.10.18 19:07
Оценка:
Здравствуйте, reversecode, Вы писали:

R>idb или программу давайте

R>а то получается как лечение по фотографии

Не вопрос, это оригинальный exe'ик:
https://yadi.sk/d/vl6WF--76HGTmw

Собственно, вот непосредственный вызов функции lpDD->lpVtbl->CreateSurface.

.text:00403BEA loc_403BEA:                             ; CODE XREF: fun_directDrawCreateSurface+60↑j
.text:00403BEA mov     eax, lpDD
.text:00403BEF mov     ecx, [eax]
.text:00403BF1 push    0
.text:00403BF3 lea     edx, [esp+70h+height]
.text:00403BF7 push    edx
.text:00403BF8 lea     edx, [esp+74h+Dst]
.text:00403BFC push    edx
.text:00403BFD push    eax
.text:00403BFE mov     eax, [ecx+18h]
.text:00403C01 call    eax
"Хаос всегда побеждает порядок, поскольку лучше организован." (с) Терри Пратчетт
Re: IDA Hex-Rays: Восстановление сломанного стека
От: reversecode google
Дата: 21.10.18 19:28
Оценка:
Options->General->Stack pointer[x]->OK
g .text:00403C01 OK
Alt+K 0x10 OK
F5
Re[2]: IDA Hex-Rays: Восстановление сломанного стека
От: reversecode google
Дата: 21.10.18 21:41
Оценка: 6 (1)
Здравствуйте, reversecode, Вы писали:


R>Options->General->Stack pointer[x]->OK

R>g .text:00403C01 OK

промахнулся взглядом .text:00403C03 правильный

R>Alt+K 0x10 OK

R>F5

int *__cdecl TEST_sub_403B80(unsigned __int16 a1, unsigned __int16 a2, int a3)
{
  DDSURFACEDESC surf; // [esp+8h] [ebp-6Ch]

  memset(&surf, 0, 0x6Cu);
  surf.dwHeight = a2;
  surf.dwSize = 108;
  surf.dwWidth = a1;
  surf.dwFlags = 4103;
  surf.ddsCaps.dwCaps = 64;
  qmemcpy(&surf.ddpfPixelFormat, &surf_stru_4DE5A0.ddpfPixelFormat, sizeof(surf.ddpfPixelFormat));
  if ( !a3 )
    surf.ddsCaps.dwCaps = 2112;
  if ( lpDD->lpVtbl->CreateSurface(lpDD, &surf, (LPDIRECTDRAWSURFACE *)&a2, 0) )
    return 0;
  BitBlt_sub_402710((LPDIRECTDRAWSURFACE)a2, 0);
  return (int *)a2;
}
Re[3]: IDA Hex-Rays: Восстановление сломанного стека
От: Albeoris  
Дата: 21.10.18 22:18
Оценка:
Спасибо!

R>Options->General->Stack pointer[x]->OK

R>g .text:00403C01 OK
R>промахнулся взглядом .text:00403C03 правильный
Нет, правильный как раз 00403C01 (во всяком случае, только он даёт нужный результат

Если можно, объясни эту магию. Что случилось со стеком? Зачем его приходится двигать руками? Как вычислить это неправильное значение? Как найти другие места, где вылезают неверные смещения?
"Хаос всегда побеждает порядок, поскольку лучше организован." (с) Терри Пратчетт
Отредактировано 21.10.2018 22:21 Albeoris . Предыдущая версия .
Re[4]: IDA Hex-Rays: Восстановление сломанного стека
От: reversecode google
Дата: 21.10.18 22:28
Оценка: 2 (1)
помоему там и так очевидно
cdecl vs stdcall conversion
ida определила что функция cdecl и разметила стек под нее не вытолкнув 4 аргумента в dword (4+4+4+4=16=0x10)
поэтому нужно было ей сказать что на call eax нужно снять 4 аргумента обратно со стека потому что это stdcall

так же видно было до этого когда включили указатели стека
о том что на retn предупреждение что стек не выровнен, на retn должен быть 0
Re[5]: IDA Hex-Rays: Восстановление сломанного стека
От: Albeoris  
Дата: 21.10.18 22:40
Оценка:
Здравствуйте, reversecode, Вы писали:

R>помоему там и так очевидно

R>cdecl vs stdcall conversion
R>ida определила что функция cdecl и разметила стек под нее не вытолкнув 4 аргумента в dword (4+4+4+4=16=0x10)
R>поэтому нужно было ей сказать что на call eax нужно снять 4 аргумента обратно со стека потому что это stdcall

R>так же видно было до этого когда включили указатели стека

R>о том что на retn предупреждение что стек не выровнен, на retn должен быть 0

Понял! Спасибо!
"Хаос всегда побеждает порядок, поскольку лучше организован." (с) Терри Пратчетт
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.