CreateRemoteThread из kernel-mode

Тема в разделе "WASM.NT.KERNEL", создана пользователем Sherlock, 19 окт 2006.

  1. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Sherlock
    Была ссылка на страницу со всеми индексами для всех версий виндов. В понедельник выложу

    Есть еще способ - послать kernel-mode APC в callback`е которой вызвать функцию ожиданию в юзер-моде, типа, KeDelayExecution(UserMode, NULL) (сорри за ошибки в прототипе, под рукой нет ддк). Примеры здесь:
    www.codeproject.com/threads/QueueUserAPCEx.asp
    www.codeproject.com/threads/QueueUserAPCEx_v2.asp.

    Только в любом случае если поток находился в NON-alertable state, то ожидание будет прервано, а это не есть гуд. Например, если перевести в alertable smss.exe, то система упадет.

    Оригинально! :)))
     
  2. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    она даже и на форуме где то валялась
     
  3. Sherlock

    Sherlock New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2006
    Сообщения:
    28
    Благодарю, поставил на закачку. Надеюсь не оборвётся. Из любопытства, каков смысл конспирации линка на файлпост?
     
  4. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    ссылки на варез запрещён
     
  5. Sherlock

    Sherlock New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2006
    Сообщения:
    28
    Параллельно прощупываю оба варианта: APC и создание треда черед вызов функции в ntdll.dll Второй мне кажется более предпочтительным, т.к. упоминалось, что если поток перевести в alertable система может упасть. Я написал простенькую консольную программу, которая выдаёт текущий адрес загрузки интересующей меня RtlCreateUserThread.
    Код (Text):
    1.     HMODULE hNtDll = ::GetModuleHandle("ntdll.dll");
    2.     if( hNtDll )
    3.     {
    4.         void* pfn = GetProcAddress(hNtDll, "RtlCreateUserThread");
    5.         cout << "ntdll.dll " << hex << hNtDll << "  RtlCreateUserThread " << pfn << endl;
    6.     }
    Консольную программу не закрываю. Далее в коде драйвера, предварительно сказав KeAttachProcess, делаю создание треда через хардкоднутое значение RtlCreateUserThread (в рантайме я ещё не научился находить адрес) - т.е.
    Код (Text):
    1. ...    // заталкиваем в стек нужные параметры
    2. mov eax, 0x77f6f46b  // RtlCreateUserThread в интересующем меня процессе
    3. call  eax
    Запускаю драйвер. Система не валится, однако всё просто жутко начинает тормозить. Тред не создаётся, по крайней мере не запускается моя callback функция, указанная в параметрах. Все адреса валидные - и RtlCreateUserThread, и callback'а. Вероятно я что-то забыл сделать перед вызовом функции ? Или может RtlCreateUserThread нельзя вызывать напрямую ?

    Подскажите плиз ...
     
  6. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Syscalls table:
    http://www.metasploit.com/users/opcode/syscalls.html

    Sherlock
    Сложно что-то сказать по такому описанию.
    1) какой код ошибки возвращает RtlCreateUserThread ?
    2) Как проверяешь вызов callbacka? Без регистрации в csrss нельзя вызывать никакие юзер-модные функции, в т.ч. мессаджбоксы и прочее. Про csrss поищи по форуму + Шрайбер (у него пример рабочий !только! для юзер-мода)
    3) покажи полностью код вызова RtlCreateUserThread
     
  7. Sherlock

    Sherlock New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2006
    Сообщения:
    28
    Спасибо !

    По RtlCreateUserThread, в драйвере:
    Код (Text):
    1. PEPROCESS pEProcess;
    2. HANDLE hThread = 0;
    3. CLIENT_ID cid;
    4. ULONG status;
    5.  
    6. PsLookupProcessByProcessId(processID, &pEProcess); // статус возврата == OK
    7. KeAttachProcess(pEProcess);
    8.  
    9. __asm // call RtlCreateUserThread
    10. {
    11.     lea         eax,[cid]
    12.     push        eax  
    13.     lea         ecx,[hThread]
    14.     push        ecx                      
    15.     push        0                         // нулевой юзер-параметр
    16.     mov         eax, 0x401000       // адрес callback процедура в юзермодной программе
    17.     push        eax  
    18.     push        0    
    19.     push        0    
    20.     push        0    
    21.     push        0    
    22.     push        0    
    23.     mov         ecx,dword ptr [hProc] // валидный hProc, определенный ранее через ZwOpenProcess
    24.     push        ecx  
    25.     mov         eax, 0x77f6f46b      // харкоднутый текущий адрес RtlCreateUserThread
    26.     call        eax
    27.     mov         dword ptr [status],eax
    28. }
    29. DbgPrint("CALLED, %d", status);
    30. ......
    Последний DbgPrint не вызывается, поэтому код возврата я не вижу. Вместо этого в системе начинаются тормоза. Но BSOD не наблюдается, а он был бы наверняка если б адреса были неверными.

    Сама процедура обратного вызова, та что находится по адресу 0x401000.
    Код (Text):
    1. void proc(char *p=0)
    2. {
    3.     OutputDebugString("CALLBACK OK\n");
    4.     ExitThread(0);
    5. }
    Юзермодная функция у меня вызывается, наверно дело в этом. Попробую поискать про регистрацию в csrss из kernel. Шрайбера на выходных я почитал, у него акцент на то как функции ядра задействовать в user-mode. А мне нужно ровно обратное.
     
  8. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Валится однозначно из-за ошибки в callback`е. После инжекта функции в процесс нужно выполнить relocation для всех вызываемых функций, так как совершенно не гарантируется, что адреса даже системных DLL не будут различаться. Плюс для вызова ExitThread нужно регистрировать в csrss. Если использовать только native API, регистрация не нужна, и может заработать даже без релокэйшенов.

    У Шрайбера есть пример создания потока в юзер-моде. Отличие для ядра состоит в том, что ядерный код должен обязательно выполняться в контексте нужного процесса. KeAttachThread в этом случае не катит из-за странностей CsrCreateRemoteThread.
     
  9. Sherlock

    Sherlock New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2006
    Сообщения:
    28
    Минимизировал код callback-а до
    Код (Text):
    1. __declspec(naked) proc()
    2. {
    3.     __asm int 3;
    4. }
    Те же эффекты наблюдаются. Я вот подумал, а точно все ф-ии ntdll.dll из kernel можно вызывать? Дело в том, что RtlCreateUserThread не проходит через шлюз int 2Eh. Смущяет меня это.
     
  10. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    RtlCreateUserThread вообще не проверяет, откуда она вызвана ==> ей по фигу. Вообще, не встречал ни одной нативной функции, у которой были бы проблемы с вызовом из ядра.
    Callback правильно инжектишь? RtlCreateUserThread вообще вызывается?
     
  11. Sherlock

    Sherlock New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2006
    Сообщения:
    28
    Вобщем ... в одной стороны вроде ошибиться трудно. Код асмовый я привёл выше, запихиваем в стэк параметры, дальше call. Адреса коллбэка и самой RtlCreateUserThread верные. Самое забавное что в юзер-моде это работает. Я могу выложить полный вариант: драйвер + консольное приложение, с которым я играюсь. До сих пор не сделал этого потому как не уверен был, что кто-то всерьёз захочет разбираться с моей проблемой. Если у тебя есть желание дай знать, пожалуйста, - я выложу исходники.
     
  12. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Разбираться с проблемой конечно не хочется :))) Но вопрос актуальный, потому что совсем недавно сам этим занимался и интересно посмотреть на возможные грабли. Так что клади :)
     
  13. Sherlock

    Sherlock New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2006
    Сообщения:
    28
    Выкладываю. В архиве 2 компонента: юзермодная часть alert.cpp и драйвер. Внутри alert'а можно локально проверить вызов RtlCreateUserThread если раскомментить #define DO_LOCAL_TEST.

    Как я уже писал, в ран-тайме адреса функций я пока определять не умею, они у меня хардкоднутые. С драйвером это тестируется след образом:
    1. запускается на выполнение alert.exe, он показывает адреса callback-а и RtlCreateUserThread в данном процессе
    2. эти адреса руками переносятся в драйвер, файл test.c
    3. драйвер компилируется build'ом из DDK, регистрируется, запускается.
     
  14. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    RtlCreateUserThread возвращал значение 0xc0000008 - INVALID_HANDLE_VALUE. Соответственно, хендл hProc не валиден во время вызова.
    В InitializeObjectAttributes нужно добавить флаг OBJ_KERNEL_HANDLE. Если этот флаг не указан, то хендл записывается в таблицу юзер-модных хендлов и доступен только из открывшего его контекста (контекст System в данном случае). Соответственно, после вызова KeAttachProcess мы переходим из контекста System в контекст alert.
    Падение же или зависание может быть вызвано тем, что в контексте alert берется хендл с таким же номером, но относящийся к левому объекту, и с ним уже производится недопустимая операция.

    ЗЫ: В приложении код, который у меня завелся
    ЗЗЫ: По абсолютным адресам функции можно вызывать без асмовских вставок
     
  15. Sherlock

    Sherlock New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2006
    Сообщения:
    28
    К сожалению у меня исправленный test.c не завёлся. Симптомы те же, что и раньше.
     
  16. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Не знаю :dntknw:((
     
  17. Sherlock

    Sherlock New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2006
    Сообщения:
    28
    Подумал я над этой мыслью, вот что мне непонятно. Что если сначала вызвать KeAttachProcess, а потом процесс открыть без этого флага? Контекст по-идее мы не меняем. Далее, смотрю имеющуюся документацию по DDK, относительно флага OBJ_KERNEL_HANDLE там пишут следующее
    И всё. Т.е. это как бы просто дополнительное ограничение.

    Напоследок, изначально после ZwOpenProcess(&hProc, ...) был код ZwAllocateVirtualMemory(hProc, ...). Что интересно, для аллокирования памяти хэндл был вполне валиден. Поскольку последующим копированием я записывал в процесс некие символы, которые были прекрасно видны в процессе. Правда память выделялась до вызова KeAttachProcess.
     
  18. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Совершенно правильно. Хендлы из kernel таблицы могут быть видны только из ядра. См. Comments там же: drivers that run in a process context other than that of the system process must set the OBJ_KERNEL_HANDLE. Хотя они далее говорят о проблемах безопасности, но на своем опыте могу сказать, что, например, использовать в DeviceDispatch глобальный хендл, открытый без этого флага, нельзя. Будут постоянно валиться ошибки INVALID_HANDLE_VALUE, потому что хендл будет сохранен в юзер-модной таблице.
    Попробуй ради интереса изменить порядок
     
  19. Sherlock

    Sherlock New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2006
    Сообщения:
    28
    Попробовал, не помогает. Также делал замену KeAttachProcess на KeStackAttachProcess (ранее кто-то указывал, что надо эту функцию использовать) - всё равно виснет на вызове Rtl... Мистика.

    У тебя какая ОС стоит ? Я тестирую на XP SP1 под vmware.
     
  20. Sherlock

    Sherlock New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2006
    Сообщения:
    28
    Проверил. ZwAllocateVirtualMemory при инициализации без флага OBJ_KERNEL_HANDLE, после KeAttachProcess выдаёт ту же ошибку - C0000008.