Сейчас на форуме: -Sanchez- (+7 невидимых)

 eXeL@B —› Основной форум —› VS - размещение переменных в памяти
Посл.ответ Сообщение

Ранг: 1.0 (гость)
Активность: 0=0
Статус: Участник

Создано: 14 сентября 2016 10:52
· Личное сообщение · #1

Приветствую...новичок на этом форуме, если что упущу - сильно не пинайте...
по ряду причин пришлось заняться реверсом мелкомягкой библиотеки компрессии файлов для WinCE...опыта в реверсе не то, чтобы много, но набираюсь...столкнулся со следующей ситуацией...
имеем дизассемблированный IDA кусок функции, назовем ее CompressBlock:
Code:
  1. .text:100016A4 var_8           = dword ptr -8
  2. .text:100016A4 var_4           = dword ptr -4
  3. ....
  4. .text:100016F3                 push    8               ; 8u в стек
  5. ....
  6. .text:10001712                 mov     [ebp+var_4], ecx ; ecx содержит значение a3 = 0х1000, это значение помещаем в переменную v11
  7. .text:10001715                 lea     ecx, [ebp+var_8] ; в ecx помещаем адрес переменной v10
  8. .text:10001718                  push    ecx             ; ecx в стек
  9. .text:10001719                 push    eax             ; это первый аргумент вызова LZInitialize в стек
  10. .text:1000171A                 mov     [ebp+var_8], ebx ; по адресу переменной v10 кладем значение ebx, ebx содержит значение a1 = 10u
  11. .text:1000171D                 call    LZInitialize    ; LZInitialize((int)(v6 + 7), &v10, 8u);

тут мы четко видим, что в стеке переменные v10 и v11 идут друг за другом: [ebp+var_4] и [ebp+var_8]. Т.к. в VS я не нашел, как отображать смещения в стеке, то сравнил по адресам: [ebp+var_8] = 0054EDEC, [ebp+var_4] = 0054EDF0. Разница - 4 байта.
В функции LZInitialize метод qmemcpy перемещает 8 байт (8u) с адреса переменной v10 (&v10) по адресу первого аргумента функции. Соответственно перемещаются переменные v10 и v11 (т.к. они оба int и имеют размерность 4 байта).

теперь смотрим, как HexRays декомпилировал это место:
Code:
  1. int __cdecl CompressBlock(unsigned int a1, int a2, int a3, int a4, int *a5)
  2. {
  3. ....
  4.    unsigned int v10;
  5.    int v11;
  6. ....
  7.    v11 = a3;
  8.    v10 = a1;
  9.    v7 = LZInitialize((int)(v6 + 7), &v10, 8u);

в принципе, все нормально...но вот, что происходит, когда этот код компилирует VS:
Code:
  1.    mov         dword ptr [v11],edx   ; edx содержит значение a3 = 0х1000, это значение помещаем в переменную v11
  2. ....
  3.    mov         dword ptr [v10],eax  ; eax содержит значение a1 =10u, это значение помещаем в переменную v10
  4. ....
  5.    push        8  ; 8u в стек
  6.    lea         ecx,[v10]  ; в ecx помещаем адрес переменной v10
  7.    push        ecx  ; ecx в стек
  8. ....
  9.    push        edx  ; это первый аргумент вызова LZInitialize в стек
  10.    call        LZInitialize (010813B1h)  

и вроде все нормально, кроме того, что разница между адресами - [v11] = 0x0029E9A0, [v10] = 0x0029E998 - 8 байт! И когда метод qmemcpy в функции LZInitialize перемещает 8 байт с адреса переменной v10, то перемещается только переменная v10 и пустота за ней...

вопрос: как обойти такую ситуацию? почему VS помещает переменные в стек не друг за другом, как описано в коде? можно на это как-то повлиять настройками компилятора?



Ранг: 431.7 (мудрец), 389thx
Активность: 0.730.32
Статус: Участник

Создано: 14 сентября 2016 10:58
· Личное сообщение · #2

Объявите структуру.




Ранг: 527.7 (!), 381thx
Активность: 0.160.09
Статус: Участник
Победитель турнира 2010

Создано: 14 сентября 2016 11:00 · Поправил: OKOB
· Личное сообщение · #3

Возможно там была структура и тогда подойдет такой костыль

#pragma pack(push, 1)
struct Foo
{
unsigned int v10;
unsigned int v11;
};
#pragma pack(pop)

struct Foo x;
x.v10 = 10;
x.v11 = 0x1000;

v7 = LZInitialize((int)(v6 + 7), &x, sizeof(struct Foo));

-----
127.0.0.1, sweet 127.0.0.1


| Сообщение посчитали полезным: madlord

Ранг: 431.7 (мудрец), 389thx
Активность: 0.730.32
Статус: Участник

Создано: 14 сентября 2016 11:16 · Поправил: dosprog
· Личное сообщение · #4

OKOB пишет:
#pragma pack(push, 1)


Наверное, можно даже и без этого.
Данные-то DWORD, по DWORD и выравнивание.
.. хотя, конечно, не повредит




Ранг: 527.7 (!), 381thx
Активность: 0.160.09
Статус: Участник
Победитель турнира 2010

Создано: 14 сентября 2016 11:25
· Личное сообщение · #5

dosprog пишет:
Наверное, можно даже и без этого.

Больше сила привычки. Всегда обрамляю определение структур, когда перетягиваю код из АСМ в С. Мало ли что по ходу прийдется добросить в структуры, потом втыкать почему не работает. Если у исходной структуры было другое выравнивание, просто разбавляю char unk1[N1]; и т.п.

-----
127.0.0.1, sweet 127.0.0.1




Ранг: 1.0 (гость)
Активность: 0=0
Статус: Участник

Создано: 14 сентября 2016 11:30
· Личное сообщение · #6

большое спасибо...значит это последствия того, что IDA не видит структуры...
я, перед тем как решил разобраться в ситуации, обошел ее таким образом:
Code:
  1. int v10[2] = {(int)a1, a3};

так можно или лучше всё же структуру?...




Ранг: 1053.6 (!!!!), 1078thx
Активность: 1.060.81
Статус: Участник

Создано: 14 сентября 2016 11:38 · Поправил: reversecode
· Личное сообщение · #7

а как лучше сахар насыпать в чашку, ложкой или руками ?



Ранг: 431.7 (мудрец), 389thx
Активность: 0.730.32
Статус: Участник

Создано: 14 сентября 2016 11:42 · Поправил: dosprog
· Личное сообщение · #8

madlord пишет:
так можно или лучше всё же структуру?...


То же самое.
Но структура лучше и ближе к первоначальной логике.

А структуры дизассемблер "видит" тогда, когда это явно следует
из описаний аргументов стандартных функций, которые используют эти данные.



| Сообщение посчитали полезным: madlord
 eXeL@B —› Основной форум —› VS - размещение переменных в памяти
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати