eXeLab
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 3 апреля!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

Русский / Russian English / Английский

Сейчас на форуме: lx60, -Sanchez- (+3 невидимых)
 · Начало · Статистика · Регистрация · Поиск · ПРАВИЛА ФОРУМА · Язык · RSS · SVN ·

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

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

Создано: 14 сентября 2016 10:52 New!
Цитата · Личное сообщение · #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 помещает переменные в стек не друг за другом, как описано в коде? можно на это как-то повлиять настройками компилятора?

Ранг: 395.5 (мудрец)
Статус: Участник

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

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


Ранг: 516.5 (!)
Статус: Участник
Победитель турнира 2010

Создано: 14 сентября 2016 11:00 · Поправил: 14 сентября 2016 11:01 OKOB New!
Цитата · Личное сообщение · #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));

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


Ранг: 395.5 (мудрец)
Статус: Участник

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

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


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


Ранг: 516.5 (!)
Статус: Участник
Победитель турнира 2010

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

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

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

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

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

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

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


Ранг: 1003.3 (!!!!)
Статус: Участник

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

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

Ранг: 395.5 (мудрец)
Статус: Участник

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

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


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

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

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

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

Оригинальный DVD-ROM: eXeL@B DVD !

Вы находитесь на форуме сайта EXELAB.RU
Проект ReactOS