Главная » C++ энциклопедия » C » С++. Защита программы от анализа. Нестандартные способы вызова функций.
Категория: C++ энциклопедия » C
  • 85

15 мая 2011

Автор: RZah

С++. Защита программы от анализа. Нестандартные способы вызова функций.
Иногда у программиста возникает необходимость защитить свою программу или какие-либо алгоритмы используемые в ней от анализа и последующего восстановления. В настоящее время существует множество упаковщиков, обфускаторов и другого софта, позволяющего в той или иной мере решать подобную задачу, однако, все они относятся к так называемым внешним (или пристыковочным) методам защиты, то есть тем, которые применяются к уже разработанной программе.
В своей статье я хочу познакомить читателя с некоторыми внутренними методами запутывания (теми, которые применяются программистом внутри программы), а именно нестандартными приемами вызова функций, которые вполне могут загнать в тупик дизассемблер, отладчик, а также взорвать мозг аналитику (крутому хакеру, решившему восстановить алгоритм работы программы). Все примеры будут на языке C/C++, иногда будут проскакивать ассемблерные вставки.

Итак, поехали:
1. Первый и самый простой способ – вызов функции через указатель на нее:

pFunction = Function;
...
a = pFunction (x, y, z);



Вместо обычного вызова функции:

a = Function (x, y, z);


Обычный вызов транслируется в машинные команды:

push z
push y
push x
call Function
mov eax,a


а вызов функции через указатель транслируется в машинные команды:

push z
push y
push x
call [pFunction]
mov eax,a


Дизассемблеру, анализирующему данный фрагмент кода, обычно не удается определить, что указатель pFunction указывает именно на функцию Function. Если функция Function нигде не вызывается обычным образом, дизассемблер, возможно, будет интерпретировать ее команды как данные. Развитием данного метода может быть преобразование указателя.

Например, в простейшем случае это может быть его уменьшение, а затем увеличение на одно и тоже число:

(DWORD) pFunction = (DWORD) Function - 68;
...
(DWORD) pFunction += 68;
a = pFunction (x, y, z);


2. Вызов функции с помощью машинной команды ret, осуществляющей возврат из функции:

push offset m
push Function
ret
m:


В этом примере сначала в стек помещается смещение метки m, затем помещается адрес функции Function. После ret будет выполняться код с адреса, помещенного последним в стек, то есть функция Function. Когда в теле функции Function произойдет вызов команды ret, управление будет передано на код после метки m.

3. Вызов функции через обработку исключения – простой и в тоже время интересный способ запутать как аналитика, так и отладчик. Например:

try
  {
    a = 1 / (a – a);
  }
__except(TRUE)
  {
    a = Function (x, y, z);
  }


Главное достоинство данного метода – возможность обработки исключений, специфичных для отладки программ. В качестве примера приведем следующий кусок кода:

__try
  {
    _asm int 3;
  }
__except(TRUE)
  {
    a = Function (x, y, z);
  }


Обычно отладчик, в процессе отладки методом Step-Trace (пошагово) последовательно устанавливает в код программы команду int 3 (программная точка останова), а прерывание с номером 3 обрабатывается отладчиком. Если проделать приведенный пример под отладчиком, то отработает блок __try и никакого исключения не возникнет, то есть программа не пойдет в блок except и функция вызвана не будет =).

4. Вызов функции в отдельном потоке. Пример:

s.x = x;
s.y = y;
s.z = z;
hThread = CreateThread (NULL, 0, Function, &s, 0,
                          &dw);
WaitForSingleObject (hThread, TIMEOUT);
GetExitCodeThread (hThread, &a);
CloseHandle (hThread);


5. вызов функции через пул потоков Wait Thread:

s.x = x;
s.y = y;
s.z = z;
s.ret = &a;
RtlRegisterWait (&hWait, hEvent1, Function, &s,
                   TIMEOUT1, 0);
SetEvent (hEvent1);
WaitForSingleObject (hEvent2, TIMEOUT2);


Функция Function перед возвратом управления должна сделать системный вызов SetEvent (hEvent2);

6. Вызов функции через передачу некоторому окну нестандартного сообщения:

s.x = x;
s.y = y;
s.z = z;
a = SendMessage (hwnd, WM_USER + HIDDEN_CALLS_GATE, Function, &s);


В этом случае в окне должен быть предусмотрен обработчик этого сообщения, который и вызовет функцию Function. Аналогичным образом для вызова функции Function можно использовать функцию SendMessageCallback.

7. Вызов функции по таймеру (предполагается, что текущий поток не создает никаких окон, g_s – глобальная структура):

g_s.x = x;
g_s.y = y;
g_s.z = z;
g_s.ret = &a;
n = SetTimer (NULL, 0, USER_TIMER_MINIMUM, Function);
GetMessage (&msg, NULL, 0, 0);
DispatchMessage (&msg);
KillTimer (n);


8. Вызов функции через перечисление дочерних окон окна, содержащего единственное дочернее окно:

s.x = x;
s.y = y;
s.z = z;
s.ret = &a;
EnumChildWindows (hwndWithSingleChild, Function, &s);


В результате один раз будет вызвана функция Function.

9. Похожий способ состоит в вызове функции через перечисление главных окон приложения, имеющего одно главное окно:

s.x = x;
s.y = y;
s.z = z;
s.ret = &a;
EnumThreadWindows (GetCurrentThreadId (), Function, &s);


10. Продолжая тему перечислений, никак нельзя обойти вниманием вызов функции через перечисление файлов подкачики системы. Функция будет вызвана столько раз, сколько в системе файлов подкачки.

s.x = x;
s.y = y;
s.z = z;
s.ret = &a;
EnumPageFiles (Function, &s);


11. вызов функции через асинхронный ввод-вывод:

s.x = x;
s.y = y;
s.z = z;
s.ret = &a;
memset (&o, 0, sizeof(OVERLAPPED));
o.hEvent = &s;
ReadFileEx (hFile, p, 0, &o, Function);


Здесь hFile – любой файловый объект, открытый в асинхронном режиме, p – произвольный адрес памяти, доступный для записи. Вместо ReadFileEx можно использовать функции WriteFileEx, NtReadFile, NtWriteFile, NtDeviceIoControlFile;

На этом нестандартные способы вызова функций не заканчиваются. Практически любую системную функцию, использующую CallBack-функции можно адаптировать под наши нужды, то есть с помощью нее скрыто вызвать ту функцию, которая нам необходима.

На этом пока закончим. Теперь даже самый начинающий программер сможет изрядно подпортить жизнь всяким дизассемблерам и кул хакерам, пытающимся расколупать его программку.
Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.
15 мая 2011 20:14
Avatar
  • admin

  • Группа: Администраторы
  • Публикаций: 773
  • Комментариев: 30
Спасибо за статью smile
Регистрация: 7.03.2011
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.