Сrackme, прячущий код на API-функциях

       

Устанавливаем и удаляем thunk


Остается заточить несложную процедуру, устанавливающую jump на thunk и восстанавливающую содержимое API-функции перед ее вызовом. Эта функция называется memcpy. Ну… почти memcpy. Чтобы установка jump'а завершилась успехом необходимо вызвать VirtualProtect с флагом PAGE_READWRITE, что слегка усложняет реализацию, однако, не столь радикально, чтобы впадать в депрессию. Это можно запрограммировать как на ассемблере, так и на Си. На Ассамблее — круче, на Си — быстрее.

Ниже приводится ассемблерный листинг с несколькими интересными хаками:

// устанавливает/удаляет thunk

//============================================================================

 __declspec( naked )  _do_asm(char *src)

{

__asm

{

       ; сохраняем регистры, которые будут изменены

       push ecx

       push esi

       push edi

      



       ; резервируем место под локальные переменные

       push esp                          ; резервируем место под old-old (hack!!!)

       push eax                          ; резервируем место под old

      

       ; вызываем VirtualProtect(p,0x1000,PAGE_READWRITE, &old);

       ; присваивая себе атрибут записи

       push esp                          ; &old

       push PAGE_READWRITE               ; нельзя

PAGE_EXECUTE_READWRITE!

       push

0x1000                       ; size

       push

[p]                          ; указатель на регион

       call ds:VirtualProtect

      

       ; копируем память из src

в p

двойными словами

       mov ecx, JUMP_SZ/4                 ; size в дв. словах

       mov esi, [esp+18h]                ; src !!!следить за смещением!!!

       mov edi, [p]                       ; dst

       rep movsd                         ; копируем!

      

       ; вызываем VirtualProtect(p,0x1000,old,&old-old)

       ; восстанавливая прежние атрибуты зашиты

       push esp                          ; old (hack!!!)

       push

1000h                        ; size

       push

[p]                          ; указатель на регион


       call ds:VirtualProtect    

      

       pop eax                                  ; выталкиваем old

       ;pop eax                          ; old-old уже вытолкнут v_prot

      

       ; восстанавливаем измененные регистры

       pop edi

       pop esi

       pop ecx

      

       ; выходим

       retn

       }

}

Листинг 6 ассемблерный код процедуры, устанавливающей и снимающий thunk с API

Хак номер один. Резервирование места под локальные переменные командой push. Ну это и не хак вовсе. Так даже компиляторы поступают! Инструкция push eax забрасывает на верхушку стека содержимое регистра eax, а команда push esp заталкивает указатель на eax, передавая его как аргумент функции VirtualProtect, которая записывает сюда текущие атрибуты, выталкивая указатель из стека по завершении. А это значит, что на вершине стека вновь оказывается локальная переменная, с прежними атриумами. Вот только передать ее функции VirtualProtect через push esp уже не получится, поскольку она ожидается во втором слева аргументе. Компилятор (даже самый оптимизирующий) наверняка влепил бы сюда команды типа push eax/push esp/push [esp+8], что слишком длинно и вообще маст дай.

Вот если бы в стеке уже содержался указатель на фиктивную ячейку памяти, которую было можно передать VirtualProtect, но, к сожалению, его там нет… Но! Ведь его можно очень легко сделать! Для этого достаточно лишь передать аргумент до первого вызова VirtualProtect, что и делаем команда push esp с комментарием "hack!!!". Да! Аргумент для второго вызова VirtualProtect заносится в стек в первую очередь, экономя целых три машинных команды. Почему три? Да потому, что одну из двух локальных переменных выталкивает сама функция VirtualProtect и это второй хак!

Вот оно — отличие между ассемблером и языками высокого уровня. На ассемблере мы можем писать намного более эффективно и компактно, пускай даже ценою потерянного времени, но зато как интересно оптимизировать программы, выкидывая из них все ненужное!


Содержание раздела