Долой импорт! Николай «GorluM» Андреев Хакер, номер #080, стр. 080-116-4 ... #define GMessageBeep pushargEx<user32, 0xABBEE6BC> #define GMessageBoxA pushargEx<user32, 0xABBC680D> #define GMessageBoxExA pushargEx<user32, 0x1A0256AE> #define GMessageBoxExW pushargEx<user32, 0x1A0256B8> ... Как ты уже понял, если добавить подобный хидер в программу вместе с описанными выше функциями, то для вызова API в обход таблицы импорта будет достаточно приписать к имени функции буковку G ;). Ну и, конечно, не забыть подгрузить в самом начале все библиотеки, назвав переменные с их хэндлами по левой части имени файла dll. [пример программы без таблицы импорта] #pragma comment(linker,"/ENTRY:WinMain") #include <windows.h> #include "kernel32.dll.h" #include "user32.dll.h" // хидер с функциями GetProcAddressEx, шаблонами и т.п. #include "noimport.h" HMODULE kernel32; HMODULE user32; int WINAPI WinMain(HINSTANCE, HINSTANCE, PTSTR, int) { kernel32 = GetKernel(); user32 = GLoadLibraryA ("user32.dll"); GMessageBox(0,"Hello world",0,0); return 0; } [тестируем] Ну, что в итоге мы получили, кроме того, что в PE-заголовке больше нельзя найти ссылки на таблицу импорта. Обычный определяемый любым дизассемблером вызов функции вроде этого: push 1000 call [Sleep] Изменился на: push 3D9972F5h push [esp+var_4] call sub_2AA026E4 push 1000 call eax В коде теперь мало что понятно, правда? И если покруче покопаться, то с дизассембером будет тоже самое. Но можно постепенно понять, что sub_2AA026E4 - это аналог функции GetProcAddress. Однако ищет функцию он не по имени, а по посчитанной хэш-функции от имени. Кошмар! Чтобы разобраться в том, что делает программа, написанная подобным образом, придется не один час просидеть с отладчиком и дизассемблером в руках, пытаясь сопоставить какому из подобных вызовов какой обычный API-вызов соответствует. Не одному только реверсеру, кстати, кошмар. Всяческие эвристики и подобная фигня на этом деле тоже вымрут - проверено. Взять, к примеру, NOD32. Я для теста написал маленькую программу, копирующую себя в системную директорию, в реестр и слушающую порт. NOD32 на параноидальном уровне безопасности тот час же окрестил ее как «вероятно вирус». Потом я заменил все вызовы на мои «хитрые». Угадай, что на это сказал антивирус? Ничего плохого! Скушал, буркнул «спасибо, вирусов не найдено, приходите еще», и на боковую. И это ведь только начало такой замечательной штуки как precompiled-метаморфизм (вероятно, термин я придумал дурацкий, зато достиг в этой штуке немалого). Компилятор можно научить таким офигенным штукам, какие и не снились обычным полиморфным или метаморфным движкам. Полная перестройка программы для них - пустяк. Главное - правильно оформить исходный код, то есть научить всему компилятор. Можно, к примеру, заставить его оформлять разные вызовы. Скажем, в зависимости от номера строки исходного кода вставлять либо call, либо push $+5\push addr\ret, либо еще что-нибудь. Хэш-функции использовать все время разные. Можно попробовать научить компилятор (о, недокументированные возможности, как вы прекрасны и ужасны одновременно) перегружать операторы стандартных типов. Ты представь только - подсунуть свой оператор присваивания вместо дефолтного, и впихивать в него все время кучу лишнего кода и каких-нибудь нехороших трюков еще на этапе компиляции. Можно написать отличную систему, которая позволяла бы обычные нормальные программы компилировать так, словно компилятор в задницу оса укусила, так что никакие протекторы и упаковщики не понадобятся. |