Приховування програм в Visual C + +, Різне, Програмування, статті

Стеганографія не вирішує всіх проблем. Крім того, щоб зберігати файл з закодованими даними, треба, крім того, зберігати програму для кодування і розкодування. Її теж необхідно зберігати таємно, щоб не викликати підозр. Ясен пень, що зберігати її в закодованому вигляді безглуздо, так як сама себе вона не розкодує. Стало бути, завдання полягає в тому, щоб зберігати програму так, щоб вона запускалася без будь-яких спеціальних засобів, але при невиконанні заданих умов не давала зрозуміти своє істинне призначення і імітувала роботу будь-якої іншої програми.
Метод перший. Нехай є сішний исходник прихованою програми і исходник небудь нісенітниці, яку можна використовувати як програму-носій, тобто програму, в яку ми будемо ховати нашу програму. Нехай також обидві програми віконні і мають в якості точки входу функцію WinMain. Переробити цей приклад для консольних програм легко, замінивши WinMain на main.
Об’єднаємо обидва исходника в один проект і перейменуємо WinMain прихованою-програми в WinMain1, а WinMain програми-носія в WinMain2. Тепер напишемо нову WinMain такого змісту:






int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
if (Condition())
return WinMain1(hInstance, hPrevInstance, lpCmdLine, nCmdShow); else
return WinMain2(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
 

Як бачите, ідея проста: перевіряємо умову і запускаємо або одну, або іншу функцію, передаючи їй параметри, з якими була запущена наша програма. Це код ще навіть можна скоротити:

 





int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
return (Condition() ? WinMain1 : WinMain2)(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
 

Тепер про функції Condition (), тобто про те, яке може бути умова розкриття прихованої програми і як його перевіряти.
Як приклад нехай наша програма буде запускатися при натисненні певної комбінації клавіш. Перевірити, чи натиснута клавіша, можна за допомогою функції GetKeyState або GetAsyncKeyState. Різниця між ними в тому, що крім перевірки стану клавіші в момент виклику функції GetKeyState () перевіряє, чи включений CapsLock, NumLock або ScrollLock (якщо передати код однієї з цих клавіш), а GetAsyncKeyState перевіряє, чи була клавіша натиснута з моменту попереднього виклику. Так що якщо потрібно використовувати стану NumLock або CapsLock, то тільки GetKeyState (), інакше можна вибрати будь-яку з цих функцій.
Кожна з цих функцій приймає як параметр код віртуальної клавіші (virtual key code) і повертає значення типу SHORT, старший біт якого вказує, що клавіша натиснута зараз, а молодший біт вказує для GetKeyState (), чи включений CapsLock, NumLock або ScrollLock, а для GetAsyncKeyState, чи була клавіша натиснута з моменту попереднього виклику.
Необхідно врахувати, що користувачеві потрібно час для того, щоб натиснути на клавіші після запуску програми. Утримувати їх під час запуску не вийде в стандартній оболонці і найбільш поширених її альтернативи. Так що перед перевіркою умови викличемо Sleep (1000), щоб дати юзеру одну секунду.
Нехай нашої секретної комбінацією буде SHIFT + CTRL + A + D. Отже, виходить ось такий код:

 





BOOL Condition()
{
SHORT ks;

/ * Чекаємо секунду, щоб юзер встиг натиснути комбінацію клавіш * /
Sleep(1000);

/ * Перевіряємо, натиснуті чи SHIFT + CTRL + A + D * /
ks = GetKeyState(VK_SHIFT) &
GetKeyState(VK_CONTROL) &
GetKeyState(′A′) &
GetKeyState(′D′);

/ * Про натисканні клавіш в даний момент говорить старший біт * /
return (ks & 0x8000);
}
 


В исходниках ця програма лежить в папці cprog.

Метод другий, більш загальний. Не завжди є исходники потрібного софта. Це не заважає нам захований один ехешнік всередину іншого. За великим рахунком, для цього ми повинні повинні написати повноцінний ехе-Джойнер, з тією лише різницею, що запуск програм має відбуватися в залежності від натиснутих клавіш. Може бути, в одній з наступних статей я розповім про структуру ехе-файлів і про написання Джойнер, а зараз розглянемо більш просту річ, в якій, проте присутні інші важливі для нашої теми моменти.
Наша прихована програма буде написана на АСМЕ, і з неї ми зробимо сирої бінарники, в якому не буде ні релокацію, ні імпорту, ні секцій, а тільки код, точка входу якого знаходиться на початку і викликається як функція, в параметрах якої передаються покажчики на функції LoadLibrary, FreeLibrary і GetProcAddress (сподіваюся, не треба пояснювати, чому цих функцій достатньо для будь-якої програми). Іншими словами, покажчик на точку входу бінарники можна визначити так:

 





/ * Прототипи функцій системи * /
typedef HMODULE (WINAPI * pLoadLibrary) (LPCTSTR);
typedef FARPROC (WINAPI * pGetProcAddress) (HMODULE, LPCTSTR);
typedef BOOL (WINAPI * pFreeLibrary) (HMODULE);

/ * Прототип точки входу нашого бінарники * /
typedef int (WINAPI * pBinEntry) (pLoadLibrary, pGetProcAddress, pFreeLibrary);
 


Ще одна фішка, яку ми на цьому прикладі продемонструємо: зашіфруем бінарники. Може знадобитися приховувати програму не тільки від очей адміна, але і від антивіруса. Я зовсім не кажу про щось незаконне. Просто деякі виробники антивірусів додають в свої бази програми, які самі по собі не шкодять того компу, на якому знаходяться, але можуть не сподобатися аднінам. Шифрування приховає код від антивіруса на випадок, якщо ви збираєтеся працювати не у себе вдома. Будемо використовувати масив прапорів станів клавіш як ключ до шифру, розшифровувати бінарники і перевіряти його хеш. Якщо хеш збігається, передамо управління, а інакше запустимо фальшивку. Такий ключ, звичайно, слабкий, але антивіруси ніколи не ламають шифри перебором, а захищати код від людини, яка виявить факт його приховування, ми не будемо – у нас інша мета.
Сам зашифрований бінарники я помістив в ресурс. Код програми від цього буде більше, зате для заміни бінарники треба просто перезаписати файл у проекті.
Отже, це може виглядати так:

 





void GKS(PBYTE pb)
{
int i;

for (i = 1; i < ′Z′; i++) {
if (GetKeyState(i) & 0x8000) pb[i ]++;
}
}

int DecyptCheckAndRun()
{
int rv;
const void* pData;
void* pBuffer;
HRSRC hResource;
DWORD dwSize;
DWORD dwRSize;
HMODULE hThis;
RC6_WORD key[20*2+4];
BYTE ks[256];
SHA1Context ctx;
uint8_t hash[SHA1HashSize];
uint8_t RealHash[SHA1HashSize] = {195, 183, 15, 151, 251, 143, 113, 170, 15, 176, 25, 156, 18, 166, 233, 151, 155, 162, 96, 128};

rv = 0;
hThis = GetModuleHandle(NULL);
hResource = FindResource(hThis, MAKEINTRESOURCE(IDR_BINARY), MAKEINTRESOURCE(RT_RCDATA));
if (hResource) {
dwSize = SizeofResource(hThis, hResource);
pData = LockResource(LoadResource(hThis, hResource));
if (pData) {
dwRSize = (dwSize + 4095) & 0xFFFFF000; /* Round up to page */
pBuffer = VirtualAlloc(NULL, dwRSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

memset(pBuffer, 0, dwRSize);
memcpy(pBuffer, pData, dwSize);

/ * Отримаємо стану всіх клавіш * /
memset(ks, 0, 256);
GKS(ks);

/ * Сформуємо на його основі ключ шифру * /
rc6ks(key, ks, 20, 256);

/ * Розшифруємо код * /
rc6decrypt((LPRC6_WORD)pBuffer, key, 20, dwSize / RC6_BLOCK_SIZE);

/ * Порахуємо хеш * /
SHA1Reset(&ctx);
SHA1Input(&ctx, (uint8_t*)pBuffer, dwSize);
SHA1Result(&ctx, hash);

/ * Порівняємо значення хешей * /
if (memcmp(hash, RealHash, SHA1HashSize) == 0) {

/ * Викличемо код бінарники * /
(*(pBinEntry)pBuffer) (&LoadLibrary, &GetProcAddress, &FreeLibrary);

/ * Повертаємо прапор, який вказує, що не треба запускати носій * /
rv = 1;
}

VirtualFree(pBuffer, dwSize, MEM_FREE);
}
}
return rv;
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
/ * Чекаємо * /
Sleep(1000);

/ * Розшифруємо і виконаємо код і повернемо управління, при успіху * /
if (DecyptCheckAndRun()) return 0;

// …
}
 


У цій програмі використовується моя реалізація алгоритму шифрування RC6 і реалізація алгоритму хешування sha1 з RFC3174.
Для отримання стану всіх клавіш я написав функцію GKS. Взагалі-то в вінді є функція GetKeyboardState, але серед повертається їй інформації є не тільки поточні стану клавіш, і при її використанні умови запуску прихованої програми не обмежувалися б комбінацією клавіш.
В исходниках є тестовий бінарники (rawbinary), програма для його шифрування (encryptbin) і програма, в якій він зашифрований з ключовою комбінацією CTRL + SHIFT + S, яку треба натиснути втечение секунди (hiddenbin)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*