Сейчас на форуме: bartolomeo, tyns777 (+5 невидимых)

 eXeL@B —› Программирование —› INVALID_KERNEL_HANDLE
Посл.ответ Сообщение


Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 04 февраля 2011 11:06 · Поправил: ARCHANGEL
· Личное сообщение · #1

Привет всем. Пишу драйвер, который периодически закрывает дескрипторы других процессов (типа продвинутого анлокера). Так вот проблема в том, что дескриптор, который ещё мгновенье назад был валидным, может быть закрыт владельцем, или может быть защищён от закрытия, тогда через ZwClose его не закрыть. В этом случае последняя генерит иксепшн, который приводит к бсоду. Более подробно я прочитал --> Здесь <--. Но вот в чём проблема - как можно перехватить данное исключение, чтоб оно не приводило к бсоду? Нужны какие-то документированные методы, если такие есть. Патчить ничего нельзя. У кого какие предложения? Товарищи, убедительная просьба не просить исходный код, т.к. и выкладывать-то нечего - обычный вызов ZwClose с одним параметром.

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 419.0 (мудрец), 647thx
Активность: 0.460.51
Статус: Участник
"Тибериумный реверсинг"

Создано: 04 февраля 2011 19:39
· Личное сообщение · #2

Но ведь можно в ядро не лезть, чтоб не рисковать. С таким же успехом ZwClose(в NTDLL) можно вызвать с прикладного уровня. Плюс накинуть себе привелегии и спокойно накрыть все это Seh-обработчиком.




Ранг: 793.4 (! !), 568thx
Активность: 0.740
Статус: Участник
Шаман

Создано: 04 февраля 2011 19:57
· Личное сообщение · #3

Не знаю как там в ядре, в юзермоде можно чекнуть хендл на валидность, думаю нечто подобное можно сделать и в кернел моде, ну и конечно замутить монопольное исполнение кода, чтобы проверка+закрытие отработали в одной транзакции.

-----
Yann Tiersen best and do not fuck




Ранг: 255.8 (наставник), 19thx
Активность: 0.150.01
Статус: Участник
vx

Создано: 04 февраля 2011 21:52
· Личное сообщение · #4

Ресурс должен освободить тот, кто его запросил. Стороннее закрытие описателей не легально и асинхронно.




Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 05 февраля 2011 03:01
· Личное сообщение · #5

Проблему решил, позже опишу, как

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 255.8 (наставник), 19thx
Активность: 0.150.01
Статус: Участник
vx

Создано: 05 февраля 2011 15:06 · Поправил: Clerk
· Личное сообщение · #6

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




Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 07 февраля 2011 10:37
· Личное сообщение · #7

Clerk
Как показали эксперименты, то ни фильтры, ни перехват здесь не нужны, так как вероятность обратиться к невалидному дескриптору ничтожно мала - ведь анлок нужен для долгосрочно удерживаемых дескрипторов, которые не будут освобождены в произвольный момент времени.

Проблему с INVALID_KERNEL_HANDLE удалось решить так – вначале надо вызвать ZwQueryObject, если вернётся STATUS_SUCCESS, то проверяем поле ProtectFromClose, если оно установлено, то сбрасываем вызовом ZwSetInformationObject. Более подробно – исходники.

Прикладываю код драйвера и простенького управляющего приложения, выполняющего (по идее они должны выполнять) функции анлокера. Суть в том, что это всё почему-то не работает. Т.е не то, чтоб почему-то – всё совершенно ясно, почему. Ещё Рэм писал в своей статье про 3 метода работы с занятыми файлами, что:

«при вызове ZwQueryInformationFile для хэндла открытого именованного канала, (в случае если этот канал работает в блокирующем режиме) вызывающий поток будет ждать поступления сообщения в канал, а это событие может никогда и не произойти.»

Здесь нет ZwQueryInformationFile, но ситуация аналогична. Самое интересное, что когда я стал дебажить настоящий анлокер, то он тоже завесился именно на таком именованном канале. Я уже и поток отдельный сделал, который прибивается по таймауту – ничего не помогает. Перепробовал несколько вариантов (там один ещё есть закомментированный – тоже не работает).
Теперь подробнее, что же не работает. В общем, почти всё работает – имена объектов получаются, дескрипторы в чужих процессах закрываются, но есть одно но – когда приложение с помощью драйвера пытается получить имя объекта этого долбанного именованного канала, то либо всё приложение, либо вообще система перестают на что-то реагировать.
Как быть в такой ситуации?


c6f6_06.02.2011_CRACKLAB.rU.tgz - UnlockProject.rar

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 255.8 (наставник), 19thx
Активность: 0.150.01
Статус: Участник
vx

Создано: 07 февраля 2011 21:12
· Личное сообщение · #8

ARCHANGEL
> надо вызвать ZwQueryObject, если вернётся STATUS_SUCCESS, то проверяем поле ProtectFromClose, если оно установлено, то сбрасываем вызовом ZwSetInformationObject. Более подробно – исходники.
Во первых какие есчо исходники, это базовый функционал для работы с описателями.
Во вторых ваше решение асинхронно. Тоесть нет никаких гарантий что после валидации описателя он не будет закрыт другим тредом. У вас реально бредовый подход к решениею системных задач.




Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 08 февраля 2011 10:06
· Личное сообщение · #9

Clerk
Ну так а как не бредово это реализовать? Добавьте в свои посты конструктив, вашу точку зрения по поводу всей этой затеи я уже понял. Рад пояснениям с примерами, исходниками, статьями...

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 255.8 (наставник), 19thx
Активность: 0.150.01
Статус: Участник
vx

Создано: 08 февраля 2011 18:58
· Личное сообщение · #10

ARCHANGEL
Давайте логически подумаем. Так как менеджер закрывает описатель асинхронно, значит нужно както синхронизировать, причём не нарушив работу менеджера. Значит нужно получить управление гдето внутри менеджера в процессе закрытия описателя. Тогда можно направить ход исполнения по необходимому пути(control flow.. ?). Само просто видимо поставить колбек на тип(OkayToCloseProcedure). В нём выполнять необходимые действия. Для начала пойдёт.




Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 09 февраля 2011 10:08
· Личное сообщение · #11

Clerk
lkd> dt _object_type 89e22ca0
nt!_OBJECT_TYPE
+0x000 Mutex : _ERESOURCE
+0x038 TypeList : _LIST_ENTRY [ 0x89e22cd8 - 0x89e22cd8 ]
+0x040 Name
+0x048 DefaultObject : (null)
+0x04c Index : 5
+0x050 TotalNumberOfObjects : 0x31
+0x054 TotalNumberOfHandles : 0x1e0
+0x058 HighWaterNumberOfObjects : 0x32
+0x05c HighWaterNumberOfHandles : 0x1e4
+0x060 TypeInfo : _OBJECT_TYPE_INITIALIZER
+0x0ac Key : 0x636f7250
+0x0b0 ObjectLocks : [4] _ERESOURCE
lkd> dt _OBJECT_TYPE_INITIALIZER 89e22ca0+60
nt!_OBJECT_TYPE_INITIALIZER
+0x000 Length : 0x4c
+0x002 UseDefaultObject : 0 ''
+0x003 CaseInsensitive : 0 ''
+0x004 InvalidAttributes : 0xb0
+0x008 GenericMapping : _GENERIC_MAPPING
+0x018 ValidAccessMask : 0x1f0fff
+0x01c SecurityRequired : 0x1 ''
+0x01d MaintainHandleCount : 0 ''
+0x01e MaintainTypeList : 0 ''
+0x020 PoolType : 0 ( NonPagedPool )
+0x024 DefaultPagedPoolCharge : 0x1000
+0x028 DefaultNonPagedPoolCharge : 0x290
+0x02c DumpProcedure : (null)
+0x030 OpenProcedure : (null)
+0x034 CloseProcedure : (null)
+0x038 DeleteProcedure : 0x805d2cd0
+0x03c ParseProcedure : (null)
+0x040 SecurityProcedure : 0x805f9144
+0x044 QueryNameProcedure : (null)
+0x048 OkayToCloseProcedure : (null)

Если я правильно понял, то асинхронно не удаление описателя из таблицы дескрипторов, а удаление самого неиспоьзуемого объекта, т.е. того, на которого уже нет ссылок. Т.е. юзермодная CloseHandle (и соответственно NtClose в ядре) не вернёт управление, пока не удалит (грубо говоря) указатель на объект и не уменьшит через ObpDereferenceObject число ссылок в нём. Но когда число ссылок равно нулю, объект асинхронно удаляется, так? Дизасм NtClose говорит, что где-то так, но это противоречит логике, ведь тогда зачем делать CloseProcedure и OkayToCloseProcedure? И почему вы, Clerk, утверждаете, что юзать надо именно OkayToCloseProcedure? Я хз, как проверить на деле (во время отладки) все эти гипотезы, ибо не смотря на возможную асинхронность (ведь, скорее всего, так и есть, т.к. поля объекта CloseProcedure и OkayToCloseProcedure содержат null), закрытие описателя происходит быстро, и я не могу проверить, было ли оно асинхронно.

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 255.8 (наставник), 19thx
Активность: 0.150.01
Статус: Участник
vx

Создано: 09 февраля 2011 19:17 · Поправил: Clerk
· Личное сообщение · #12

ARCHANGEL
> асинхронно не удаление описателя из таблицы дескрипторов, а удаление самого неиспоьзуемого объекта
Асинхронна работа с описателями. Пока один тред его изменяет другой получает предыдущее состояние, что далее ведёт к исключениям и пр.

> И почему вы, Clerk, утверждаете, что юзать надо именно OkayToCloseProcedure?
Не утверждаю что нужно именно это юзать, просто пример привёл, более того вполне вероятно что этот колбек не подходит(хз до валидации описателя он вызывается или после нужно смореть).
Пытаюсь обьяснить саму модель отложенного вызова, что из него вы будите делать не имеет значения(например таже синхронизация).

Допустим имеется часть графа, где для удобства макро именовано [i][j][k]. Причём NL(i) > NL(j) > NL(k). Мы получаем управление на j, целевой код k. Нужно както пропустить(выполнить и после этого получить управление) j наиболее эффективным способом, в частности не использовать исключения при переходе к k. Это достигается переключением на отморфленный код(тоесть перемещённый и изменённый), например новый граф [i'][j'][f][k'], i -> i', тогда после прохода j до перехода на k исполнится наш код f. Выбор i зависит от выбранного механизма.




Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 10 февраля 2011 11:39
· Личное сообщение · #13

Clerk
Грубо говоря, вы описываете метод сплайсинга, т.е. нужно что-то запатчить, чтоб получить управление после закрытия описателя? Ну, допустим, буду пробовать разные методы, отпишусь позже о результате.

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 255.8 (наставник), 19thx
Активность: 0.150.01
Статус: Участник
vx

Создано: 10 февраля 2011 17:32
· Личное сообщение · #14

ARCHANGEL
Какой есчо сплайсинг. Я патч рассматриваю как запрещённую манипуляцию, так как целостность модулей нарушается, тоесть образ портится. MS также это рассматривает и борется с этим посредством патчгварда. Забудте про изменение кодосекций.

> получить управление после закрытия описателя?
Подойдёт любое место в процессе обработки, в частности колбеки и референсы. Я не могу обьяснить проще, чем описал выше.




Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 11 февраля 2011 10:13
· Личное сообщение · #15

Забудте про изменение кодосекций.

Уже забыл

Подойдёт любое место в процессе обработки, в частности колбеки и референсы

Понял, буду дерзать. Всё, что от вас зависело, вы сделали. Дальше буду копаться в Винде. Сэнкс.

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: -0.9 (гость)
Активность: 0.010
Статус: Участник

Создано: 11 февраля 2011 13:03
· Личное сообщение · #16

Попробуй работать только с валидными кернел хендлами.




Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 11 февраля 2011 13:34
· Личное сообщение · #17

kannabis
Конкретно с инвалидными дескрипторами проблема уже решена. В принципе, уже почти решился вопрос с объектами, работа с которыми приводила к зависанию потока, получающего имя объектов. Остался только один вопрос (теоретического характера) - чем конкретно плоха асинхронность работы с описателями?

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: -0.9 (гость)
Активность: 0.010
Статус: Участник

Создано: 11 февраля 2011 16:26
· Личное сообщение · #18

Если ограничиться пользовательскими описателями и вызывать NtClose вместо ZwClose то исключений не должно быть.




Ранг: 793.4 (! !), 568thx
Активность: 0.740
Статус: Участник
Шаман

Создано: 11 февраля 2011 16:33
· Личное сообщение · #19

kannabis верной дорогой идешь к бану

-----
Yann Tiersen best and do not fuck





Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 18 марта 2011 10:38
· Личное сообщение · #20

Вот ещё нашёл кодес, может, кому пригодится:

Code:
  1. #include "stdafx.h"
  2.  
  3. UCHAR FileObjectTypeIndex = 0;
  4. //--------------------------------------------------------------------------------------
  5. UCHAR GetFileObjectTypeIndex(PUNICODE_STRING usSomeFileName)
  6. {
  7.     UCHAR Ret = 0;
  8.     OBJECT_ATTRIBUTES ObjAttr;
  9.     HANDLE hFile;
  10.     IO_STATUS_BLOCK StatusBlock;
  11.  
  12.     InitializeObjectAttributes(&ObjAttr, usSomeFileName, OBJ_CASE_INSENSITIVE , NULL, NULL);
  13.  
  14.     // we need a handle of some file
  15.     NTSTATUS ns = ZwOpenFile(
  16.         &hFile, 
  17.         FILE_READ_DATA | SYNCHRONIZE, 
  18.         &ObjAttr, &StatusBlock, 
  19.         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 
  20.         FILE_SYNCHRONOUS_IO_NONALERT
  21.     );
  22.     if (NT_SUCCESS(ns))
  23.     {
  24.         // get list of all handles in system
  25.         PSYSTEM_HANDLE_INFORMATION Info = (PSYSTEM_HANDLE_INFORMATION)GetSysInf(SystemHandleInformation);
  26.         if (Info)
  27.         {
  28.             HANDLE CurrentProcessId = PsGetCurrentProcessId();
  29.  
  30.             // find our handle in list
  31.             for (ULONG i = 0; i < Info->NumberOfHandles; i++)
  32.             {
  33.                 if (Info->Handles[i].UniqueProcessId == (USHORT)CurrentProcessId &&
  34.                     Info->Handles[i].HandleValue == (USHORT)hFile)
  35.                 {
  36.                     // return value of object type index (for file object)
  37.                     Ret = Info->Handles[i].ObjectTypeIndex;
  38.                     break;
  39.                 }
  40.             }
  41.  
  42.             M_FREE(Info);
  43.         }
  44.  
  45.         ZwClose(hFile);
  46.     }    
  47.     else
  48.     {
  49.         DbgMsg(__FILE__, __LINE__, "ZwOpenFile() fails; status: 0x%.8x\n", ns);
  50.     }
  51.  
  52.     return Ret;
  53. }
  54. //--------------------------------------------------------------------------------------
  55. BOOLEAN CloseFileHandlesByName(PUNICODE_STRING usFileName)
  56. {
  57.     if (FileObjectTypeIndex == 0)
  58.     {
  59.         UNICODE_STRING usSomeFileName;
  60.         RtlInitUnicodeString(&usSomeFileName, L"\SystemRoot\system32\ntdll.dll");
  61.  
  62.         FileObjectTypeIndex = GetFileObjectTypeIndex(&usSomeFileName);
  63.         if (FileObjectTypeIndex == 0)
  64.         {
  65.             DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Invalid FileObjectTypeIndex\n");
  66.             return FALSE;
  67.         }        
  68.     }
  69.  
  70.     DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Closing all handles for '%wZ'\n", usFileName);
  71.  
  72.     // get list of all handles in system
  73.     PSYSTEM_HANDLE_INFORMATION Info = (PSYSTEM_HANDLE_INFORMATION)GetSysInf(SystemHandleInformation);
  74.     if (Info)
  75.     {
  76.         for (ULONG i = 0; i < Info->NumberOfHandles; i++)
  77.         {
  78.             if (Info->Handles[i].ObjectTypeIndex == FileObjectTypeIndex)
  79.             {
  80.                 PFILE_OBJECT FileObject = (PFILE_OBJECT)Info->Handles[i].Object;
  81.                 // volume parameters block is not present in named pipes
  82.                 // dirty trick, but working
  83.                 if (FileObject->Vpb)
  84.                 {
  85.                     // get name of the object
  86.                     POBJECT_NAME_INFORMATION NameInfo = GetObjectName(FileObject);
  87.                     if (NameInfo)
  88.                     {                        
  89.                         if (RtlEqualUnicodeString(&NameInfo->Name, usFileName, TRUE))
  90.                         {
  91.                             DbgMsg(__FILE__, __LINE__, " ProcessId: %d, Handle: "IFMT"\n", 
  92.                                 Info->Handles[i].UniqueProcessId, Info->Handles[i].HandleValue);
  93.  
  94.                             if (Info->Handles[i].UniqueProcessId == 4)
  95.                             {
  96.                                 // don't close handles in system process
  97.                                 goto skip;
  98.                             }
  99.  
  100.                             PEPROCESS Process;
  101.                             // get process pointer
  102.                             NTSTATUS ns = PsLookupProcessByProcessId((HANDLE)Info->Handles[i].UniqueProcessId, &Process);
  103.                             if (NT_SUCCESS(ns))
  104.                             {
  105.                                 KAPC_STATE ApcState;
  106.                                 // attach to a target process
  107.                                 KeStackAttachProcess(Process, &ApcState);
  108.  
  109.                                 __try
  110.                                 {
  111.                                     // close handle of our file
  112.                                     ZwClose((HANDLE)Info->Handles[i].HandleValue);
  113.                                 }
  114.                                 __except (EXCEPTION_EXECUTE_HANDLER)
  115.                                 {
  116.                                     DbgMsg(__FILE__, __LINE__, __FUNCTION__"() EXCEPTION\n");
  117.                                 }
  118.                                 
  119.                                 KeUnstackDetachProcess(&ApcState);
  120.  
  121.                                 ObDereferenceObject(Process);
  122.                             }
  123.                             else
  124.                             {
  125.                                 DbgMsg(__FILE__, __LINE__, "PsLookupProcessByProcessId() fails; status: 0x%.8x\n", ns);
  126.                             }
  127.                         }
  128. skip:
  129.                         M_FREE(NameInfo);
  130.                     }
  131.                 }                
  132.             }
  133.         }
  134.  
  135.         M_FREE(Info);
  136.  
  137.         return TRUE;
  138.     }
  139.  
  140.     return FALSE;
  141. }
  142. //--------------------------------------------------------------------------------------
  143. // EoF


Оригинал вот здесь --> Kill a handle from kernelmode <--

-----
Stuck to the plan, always think that we would stand up, never ran.



 eXeL@B —› Программирование —› INVALID_KERNEL_HANDLE
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати