ANTICHAT.XYZ    VIDEO.ANTICHAT.XYZ    НОВЫЕ СООБЩЕНИЯ    ФОРУМ  
Баннер 1   Баннер 2

ANTICHAT — форум по информационной безопасности, OSINT и технологиям

ANTICHAT — русскоязычное сообщество по безопасности, OSINT и программированию. Форум ранее работал на доменах antichat.ru, antichat.com и antichat.club, сейчас доступен на antichat.xyz.
Вернуться   Форум АНТИЧАТ > Программирование > Реверсинг
   
 
 
Опции темы Поиск в этой теме Опции просмотра

Поиск KeServiceDescriptorTableShadow и восклицание об IsGUIThread
  #1  
Старый 15.05.2009, 20:24
desTiny
Reservists Of Antichat - Level 6
Регистрация: 04.02.2007
Сообщений: 1,152
Провел на форуме:
3008839

Репутация: 1502


По умолчанию Поиск KeServiceDescriptorTableShadow и восклицание об IsGUIThread

Диалог кода с Win XP:
Код: Загрузи драйвер!
XP: ОК!

Диалог кода с Win Vista:
Код: Загрузи драйвер!
Vista: не буду (
Код: Можно загрузить драйвер?
Vista: ну, можно..
Код: Загрузи драйвер!
Vista: ОК!

(из наблюдений)
00:begin
В предыдущем топике я что-то сказал об идее поиска KeServiceDescriptorTableShadow. И как-то код взял и написался...
10:interface

Напомню, в чём состояло предложение: ищем в тибе негуишного треда оффсет ServiceTable за счёт сравнения всей структурки с известной нам KeServiceDescriptorTableОбычнойСОчень ДлиннымНазванием, потом переводим поток в гуи и читаем по найденному оффсету, где уже находится указатель на KeServiceDescriptorTableShadowСЕщёБолееД линнымНазваниемЧемВыше
20:implementation
От слов к делу. Начнём с драйвера. Он будет принимать IOCTL запросы и выводить на них оффсет ServiceTable либо адрес одной из интересующих нас таблиц.

Для начала напишем код нахождения оффсета. А чтобы не сканировать многократно структурку, запишем его в структуру расширения устройства.
Ниже я опускаю всякие проверки, но это всё есть в прилагаемом исходнике.
Код:
        case IOCTL_FIND_OFFSET:
            //
            // Ищем офсет ServiceTable в ETHREAD
            //
      
            // тут проверка переданных параметров
            
            //указатель на буфер результата
            res = (ULONG *)Irp->AssociatedIrp.SystemBuffer; 
            
            //если ещё не искали оффсет, то там лежит -1, который записали в DriverEntry
            if (deviceExtension->ServiceTableOffset == -1)
            {
                //основной код сканирования на предмет KeSDT
                _asm
                {
                    push esi
                    mov esi, fs:[0x124] //esi = ETHREAD
                    push eax
                    mov eax, KeServiceDescriptorTable 
                    push ecx 
                    mov ecx, 0x200 //должно хватить - максимальный офсет
                    
                    find: //цикл поиска KeServiceDescriptorTable в ETHREAD
                      cmp dword ptr [esi], eax 
                      jz found
                      dec ecx
                      jz not_found
                      inc esi
                    jmp find
                    found:
                      sub esi, fs:[0x124] //offset
                      mov offs, esi //переменная оффсета
                      jmp end
                    not_found:  
                      mov offs, -1
                    end:
                      pop ecx
                      pop eax
                      pop esi
                }
            
                //не нашли...
                if ( offs == -1 )
                {
                    *res = -1;
                    DebugPrint(("\t\tOffset ServiceTable not found\n"));
                    break;
                }

                deviceExtension->ServiceTableOffset = offs;
            } 
      
            //всё ок!
            *res = deviceExtension->ServiceTableOffset;
            DebugPrint(("\t\tOffset ServiceTable 0x%x\n", deviceExtension->ServiceTableOffset));

            //длина вывода
            OutBytes = 4;

            break;
По коментариям должно быть ясно, что происходит.

Теперь кусок кода, выводящий то, что записано по этому оффсету (взятого из DeviceExtension) :
Код:
        case IOCTL_FIND_SSDT:
            //
            // Ищем KeServiceDescriptorTableShadow, зная офсет
            //

            //тут чекаем параметры
            
            //указатель на буффер результата
            res = (ULONG *)Irp->AssociatedIrp.SystemBuffer;
      
            //уже, вероятно, посчитанный офсет
            STOffset = deviceExtension->ServiceTableOffset;
      
            //а вдруг не посчитанный?
            if ( STOffset == -1 )
            {
                status = STATUS_ACCESS_DENIED;
                break;
            }
      
            //собственно, читаем
            _asm
            {
                 push eax
                 mov eax, fs:[0x124]
                 add eax, STOffset  //ETHREAD->ServiceTable
                 mov eax, [eax]     //надеемся, SSDT
                 push ecx
                 mov ecx, res
                 mov [ecx], eax     //записываем найденное SSDT в буфер
                 pop ecx
                 pop eax
            }
            
            //вернули 4 байта - дворд
            OutBytes = 4;
            break;
Ну и так, для проверки - вывод KeSDT обычной
Код:
case IOCTL_GET_SDT: 
            //
            // Тут просто возвращаем KeServiceDescriptorTable
            //

            //чекаем параметры
            
            //указатель на буффер результата
            res = (ULONG *)Irp->AssociatedIrp.SystemBuffer;
      
            *res = (ULONG)KeServiceDescriptorTable;

            OutBytes = 4;
            break;
На этом интересный код драйвера кончается. (На всякий случай, вышеприведённый код делался под спин-блокировкой).
30: Usermode, странность и баг в виндовском коде
Начнём со странности. Вроде я где-то читал, что поток в винде создаётся вначале как негуишный. Так вот - это не совсем правда ) Не знаю почему, но почему-то, на XP SP3 у меня стартовый поток загружается как негуишный, а на чужом XP SP3 почему-то уже при старте оказывается подгруженным User32.dll. Так что основной код будет выполняться под CreateThread'ом - он вроде везде нормально работает.

==> А теперь пара ласковых слов об IsGUIThread
По msdn'у эта функция должна проверить поток на гуишность (как от неё ожидается), а если ей передан параметр TRUE, то попытаться сделать его таковым. Но почему-то код с этой функцией работал криво (на XP SP3)...И её асм листинг отвечает на вопрос "почему":
Код:
  MOV EAX,DWORD PTR FS:[18] //указатель на TIB
  LEA ESI,DWORD PTR DS:[EAX+6CC] //LEA!!!
  NEG ESI
  SBB ESI,ESI
  NEG ESI //а вдруг esi == 0?
  JNZ SHORT label
  ...
  label: 
  mov eax, esi
  ret
Но задаёт другой: "ну как так можно??" Это замечательный код проверяет, не указывает ли fs:[18] случайно на -0x6cc. А так редко бывает) Вывод - не юзайте эту функу.

И ещё смешной момент - чтобы вызвать эту функцию, даже если бы она и работала, надо, чтобы к процессу была подгружена User32.dll, но которая в DllMain переводит вызывающий поток в гуй. Так что её (если бы она работала) имеет смысл использовать в одном потоке, только если она уже подгружена в другом.
<== IsGUIThread
Из-за сделанного замечания (а также из-за особенностей висты) main функция exe будет такой:
Код:
    HANDLE hThread;
    //функция для того, чтобы дров грузился в висте - получаем привилегию грузить дрова (см. эпиграф)
    if (!SetLoadDriverPrivilege()){
        printf("Couldn't set privilege.. Trying without\n");
    }    
    //почему-то иногда стартовый поток запускается как GUI, а это плохо. Поэтому делаем отдельный поток.
    hThread = CreateThread( 
            NULL,                   // default security attributes
            0,                      // use default stack size  
            find,       // thread function name
            NULL,          // argument to thread function 
            0,                      // use default creation flags 
            NULL);   // returns the thread identifier
    
    //ждём, пока он кончится
    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);
    _getch();
    return 0;
Теперь немного о реализации переход в гуи. IsGUIThread не работает. User32.dll бывает уже подгруженной и её DllMain второй раз в потоке не сработает. Так что же делать? А мы так поступим - при вызове некоторых (большинства, а вероятно и просто всех) функций USER32.DLL поток переводится в гуи. Так что можно воспользоваться любой подходящей функцией... Мне понравилась GetDesktopWindow без параметров.

Код:
DWORD WINAPI find( LPVOID lpParam ) 
/*

Thread function

*/
{
    HANDLE  hDevice;
    ULONG   ulReturnedLength;
    DWORD   errNum = 0;
    UCHAR   driverLocation[MAX_PATH];
    ULONG   offset;  //ServiceTable в ETHREAD
    BOOL    bStatus;
    ULONG   SDT_addr;
    ULONG   SSDT_addr;
    PVOID   user32func; //какая-нибудь функа для перхода в GUI

/*
    это закомменчено из-за бажности апишки :(

    if (IsGUIThread(FALSE)){
      printf("Is GUI. Terminating..\n");
      return 1;
    } else {
      printf("Is not GUI. Well..\n");
    }
*/

    
    //
    // тут код, грузящий драйвер
    // и открывающий его в hDevice


    // получаем и записываем офсет ServiceTable из EPROCESS
    bStatus = DeviceIoControl(
        hDevice,                // Handle to device
        IOCTL_FIND_OFFSET,        // IO Control code
        NULL,              // Input Buffer to driver.
        0,        // Length of input buffer in bytes.
        &offset,                   // Output Buffer from driver.
        sizeof(offset),                      // Length of output buffer in bytes.
        &ulReturnedLength,      // Bytes placed in buffer.
        NULL                    // synchronous call
    );

    if ( !bStatus ) {
        printf("Ioctl failed with code %d\n", GetLastError() );
    } else {
        //именно -1 означало Not Found
        bStatus = offset != -1;
    }
    
    if ( !bStatus ) {
        printf("ServiceTable offset not found :(\n");
    } else {
        printf("Found ServiceTable offset: 0x%x\n", offset );
        
        /* bStatus = IsGUIThread(TRUE); - баг */

        //поэтому переводимся в GUI вызовом простенькой гуишной функи типа GetDesktopWindow
        //она без параметров
        user32func = GetProcAddress(LoadLibraryA("user32.dll"), "GetDesktopWindow");
        //чтобы не преобразовывать :)
        _asm call user32func;

        //надеюсь, тут багов не возникло :)
        bStatus = TRUE;
    }

    if ( !bStatus ) {
        //вообще это не выполнится...
        printf("Couldn't convert to GUI Thread: error code %d\n", GetLastError() );
    } else {
        //Для справки SDT
        bStatus = DeviceIoControl(
            hDevice,                // Handle to device
            IOCTL_GET_SDT,        // IO Control code
            NULL,              // Input Buffer to driver.
            0,        // Length of input buffer in bytes.
            &SDT_addr,                   // Output Buffer from driver.
            sizeof(SDT_addr),                      // Length of output buffer in bytes.
            &ulReturnedLength,      // Bytes placed in buffer.
            NULL                    // synchronous call
        );
    }

    if ( !bStatus ) {
        printf("Couldn't get normal SDT: error code %d\n", GetLastError() );
    } else {
        //выведем
        printf("KeServiceDescriptorTable: 0x%.8x\n", SDT_addr );
    
        //Кульминация - SSDT!
        bStatus = DeviceIoControl(
            hDevice,                // Handle to device
            IOCTL_FIND_SSDT,        // IO Control code
            NULL,              // Input Buffer to driver.
            0,        // Length of input buffer in bytes.
            &SSDT_addr,                   // Output Buffer from driver.
            sizeof(SSDT_addr),                      // Length of output buffer in bytes.
            &ulReturnedLength,      // Bytes placed in buffer.
            NULL                    // synchronous call
        );
    }

    if ( !bStatus ) {
        printf("Ioctl failed with code %d\n", GetLastError() );
    } else {
        printf("Found KeServiceDescriptorTableShadow: 0x%.8x\n", SSDT_addr );
    }
    
    CloseHandle(hDevice);

    //
    // Выгружаем драйвер
    //

    return 0;
}
Ну вот: основной код закончен, детали реализации - в прилагаемом исходнике.
40: end
Вот вроде и всё... Исходник готов, программа и драйвер скомпилены... И вроде работают)

Вывод на XP SP3:
Код:
Found ServiceTable offset: 0xe0
KeServiceDescriptorTable: 0x80562520
Found KeServiceDescriptorTableShadow: 0x805624e0
Правильно...

//а от микрософта такой пакости с IsGUIThread не ожидал.
Спасибо всем принявшим участие в тестировании кода!

50: src + compiled

(всё компилилось под WDK. Кстати, если кому интересно, загрузка драйвера реализована в двух вариантах - через SCM и ZwLoadDriver)
Compiled: http://redxak.co.cc/ShadowSDT.rar
Sources: http://redxak.co.cc/ShadowSDT_src.rar
__________________
Bedankt euch dafür bei euch selbst.

H_2(S^3/((z1, z2)~(exp(2pi*i/p)z1, exp(2pi*q*i/p)z2)))=Z/pZ
 
Ответить с цитированием
 



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Paros - инструмент для исследования веб-приложений Kuzya Авторские статьи 2 10.04.2009 17:37
Перевод официальной документации Nikto 2 Kuzya Авторские статьи 2 25.03.2009 01:10
Nigma ищет музыку и химию PaLb14 Мировые новости 2 23.12.2008 19:06
Поиск PHP уязвимостей на примере phpBB _-[A.M.D]HiM@S-_ Статьи 1 29.10.2006 11:18



Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT.XYZ