· Начало · Статистика · WASM.RU · Noir.Ru ·

 WASM Phorum (Оффлайн - 24.11.2003) —› WASM.WIN32 —› Беда с ZwQueryObject (виснет) ака "ничче не п

Посл.отвђт Сообщенiе


Дата: Авг 20, 2003 09:59:52

Простенькая программа по мотивам Undocumented NT.
программа энумерит хэндлы и выводит имя объекта. На некоторых объектах оно виснет внутри ZwQueryObject (при вызове sysenter ). Виснет пока не закрою процесс где этот хэндл породился.
Пример хэндлов (виснет не во всех, у меня как минимум в трех - прога для управления BlueTooth от microstar, в проге от Creative для SB Audigy, в AOL на каком-то named pipe (самое обидное т.к. его хэндлы и нужно проэнумерить))
Кроме того всякие TerminateProcess для моего процесса, энумерящего хэндлы - не работают - он висит пока процесс не закроется, из-за хэндла которого беда.
Если кто что может сказать по этому поводу - буду очень рад.
Ниже код который используется.
#include "stdafx.h"
#include "windows.h"
#include <iostream>
using namespace std;
typedef struct _SYSTEM_HANDLE_INFORMATION { // Information Class 16
    ULONG ProcessId;
    UCHAR ObjectTypeNumber;
    UCHAR Flags;  // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
    USHORT Handle;
    PVOID Object;
    ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING; 

typedef struct _OBJECT_NAME_INFORMATION {               
    UNICODE_STRING Name;                                
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;


#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004L
typedef long (__stdcall *tag_ZwQuerySystemInformation ) ( long SystemInformationClass,PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength = NULL);
typedef long (__stdcall *tag_ZwQueryObject) ( HANDLE ObjectHandle, long ObjectInformationClass,  PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength = NULL );
tag_ZwQuerySystemInformation ZwQuerySystemInformation;
tag_ZwQueryObject ZwQueryObject;
int main(int argc, char* argv[])
{
	HMODULE hntdll=LoadLibrary("ntdll.dll")	;
	ZwQuerySystemInformation=(tag_ZwQuerySystemInformation) GetProcAddress(hntdll,"ZwQuerySystemInformation");
	ZwQueryObject=(tag_ZwQueryObject) GetProcAddress(hntdll,"ZwQueryObject");
	ULONG n;
	PULONG p = new ULONG[n = 0x20000];
	ULONG x;
   while (STATUS_INFO_LENGTH_MISMATCH==ZwQuerySystemInformation(16, p, n * sizeof *p, &x))
		delete [] p, p = new ULONG[n *= 2];
	PSYSTEM_HANDLE_INFORMATION h = PSYSTEM_HANDLE_INFORMATION(p + 1);
	int i;
	x=x/sizeof(SYSTEM_HANDLE_INFORMATION);
	for(i=0;i<x;i++)
	{
	if (h->ProcessId==3032)
		{
                BYTE* r = new BYTE[1024];
                _OBJECT_NAME_INFORMATION& so_name = *(_OBJECT_NAME_INFORMATION*)r;

                ULONG size;
				HANDLE hProc=OpenProcess (PROCESS_DUP_HANDLE,FALSE,h->ProcessId);
				if (hProc)
				{
					HANDLE hObj;
					try
					{
						cout << "Before DuplicateHandle" << endl;
						{
						if (DuplicateHandle (hProc,(LPVOID)h->Handle,GetCurrentProcess(),&hObj,0,0,DUPLICATE_SAME_ACCESS))
						{
							cout << "Before QueryObject" << endl;
							cout << "Handle is " << h->Handle << endl;
							cout << "Process is " << h->ProcessId << endl;
							cout << "Type is " << (long)h->ObjectTypeNumber << endl;
	//Виснет тут						long rv = ZwQueryObject (hObj, 1, &so_name, 1024,&size);
							cout << "After QueryObject" << endl;
							if (!rv)
							{
								if (so_name.Name.Length>0)
									wcout <<so_name.Name.Buffer << endl;
							}
							cout << "Before CloseHandle" << endl;
							CloseHandle (hObj);
						}
						else 
						{
							cout << "Error duplicating handle" << endl;
						}
						}
					}
				}
				CloseHandle (hProc);
				delete  [] r;
		}
		h++;
	}
	return 0;
}



Дата: Авг 20, 2003 11:33:13

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

Есть еще метод получить список хендлов, но он требует определенной установки NtGlobalFlag.


Дата: Авг 20, 2003 12:26:24

А для NtGlobalFlag естественно нужны привилегии админа к примеру. так?


Дата: Авг 20, 2003 12:30:47

Да, а тогда - можно ли определить статус пайпа и т.д. перед запросом имени? чтоб "умно" обойти такие объекты?
что-нить типа QueryIoCompletionStatus и т.д.?
Либо тока в тредах их открывать и оставлять на произвол судьбы процесс?
кстати. а если я буду запрашивать имя из контекста того процесса, где он открыт? т.е. допустим если виснет из-за какого-то хэндла в aol.exe то если я в aol.exe сделаю поток, который проэнумерит его хэндлы?
и последнее - может кто-нить кинет в меня линком на то, где это описано все, чтоб не мучать вопросами?


Дата: Авг 20, 2003 13:06:58

Ладно, я кину линком на то место, откуда я почерпнул данную информацию. В WinNT Native Api Reference в конце есть примеры програм, в том числе и для энумерации хендлов.
Может чем помогет.

P.S. Ашот будет недоступен до конца месяца, так что придется полагаться на свои силы. :)


Дата: Авг 20, 2003 13:38:34

Дело в том, что я сейчас смотрю в Native API как раз в тот пример и вокруг QueryObject(ObjectNameInformation) нет никаких танцев с бубном.
А вот второй требует установки NtGlobalFlag - это вообще никак - т.к. должно работать под юзерскими привилегиями...
Есть ещё мнения у кого-нибудь? Ато придется склониться к тому, чтоб на каждый хэндл делать тред и если повиснет - ждать ребута системы... :((( Фактически мне нужно найти конкретный файл - \\Device\Serial0, который занят програмой и закрыть хэндл на этот файл внутри программы ( простой DuplicateHandle (CLOSE_SOURCE_HANDLE) ).
Может быть можно получить информацию об объектах, без зависания - к примеру спросить файл оно или named pipe? а так же для какого доступа открыты? (думал через тип объекта - но там один хрен все они файлы. )


Дата: Авг 22, 2003 15:32:56 · Поправил: Four-F

Полистал я тут Неббета и...

Из того, что написано во 2 главе явно следует только то, что ZwQueryObject обломится
на пайпе только если звать ее с ObjectNameInformation. С другим классом все будет
ОК. Проверить я это не могу, но на 99,99% уверен, что это так.
Т.е. мы зовем ее с ObjectTypeInformation, если
OBJECT_TYPE_INFORMATION.Name.Buffer == "File" - это наш клиент. Пайпы, к сожалению,
тоже имеют хендлы типа File. Теперь наша задача как-то отличить хендл порта от
пайпа без зависания ZwQueryObject. Если внимательно полистать Неббета, то там
иногда мелькают всякие функции, с помощью которых, возможно, можно будет определить
пайп это или нет. Например ZwQueryInformationFile с классами FilePipeInformation,
FilePipeLocalInformation, FilePipeRemoteInformation. Может и еще что-то есть. Либо
еще какие, с помощью которых можно определить тип объекта. А можно сделать так.
Всем объектам с типом "File" слать какой-нить безобидный управляющий код через
DeviceIoControl. Например так:
DeviceIoControl ,, IOCTL_SERIAL_GET_PROPERTIES...
И смотреть результаты. Т.к. мы не знаем заранее, какому девайсу шлем код, то
потенциально это опасно, но IOCTL_SERIAL_GET_*** из зарезервированного m$ диапазона
и вероятность совпадения с другим кодом минимальна, к тому же мы только читаем.

К сожалению мне не удалось обнаружить у ся процесса с висящим пайпом, так что
протестить на 100% не могу. В аттаче тестовый пример - у мень под 2000 работает.
SerialPort открывает comm и висит на MessageBox, а ListOpenProcessHandles <pid decimal>
ищет его хендл и закрывает через ZwDuplicateObject ,,, DUPLICATE_CLOSE_SOURCE.

В общем, я думаю шансы на успех у тя стремятся к 100%. Только надо очень
внимательно почитать литературу, подобрать нужные фильтры и коды и все заработает.
Возможно с правами надо будет еще повозиться.

Результаты сообчи.


Дата: Авг 22, 2003 15:41:19

Похоже там вообще полная задница с этими пайпами.
т.к. любая функция при обращении к нему виснет.
к примеру SetNamedPipeInformation или как-то так. короче все функции, кроме CloseHandle при обращении к пайпу виснут напрочь.


Дата: Авг 22, 2003 15:42:13


Дата: Авг 22, 2003 15:44:18

[ rst: короче все функции, кроме CloseHandle при обращении к пайпу виснут напрочь. ]

Т.е. и DeviceIoControl тоже?


Дата: Авг 22, 2003 16:02:01

Эту не пробовал... все остальные виснут.


Дата: Авг 23, 2003 15:09:53

попробовал DeviceIOControl - виснет.
кроме того у тебя в С-коде бага :) ты в DeviceIOControl даешь HANDLE из таблицы хэндлов, а не сдуплицированный - в результате всегда после DeviceIOControl получаем ERROR_INVALID_HANDLE. А если туда передать нормлаьный хэндл, то получится то же самое подвисание на пайпе.


Дата: Авг 23, 2003 17:03:39 · Поправил: Four-F

[ rst: попробовал DeviceIOControl - виснет. ]

:-( Похоже, шансы на успех начали стремиться к 0%.

[ rst: ...у тебя в С-коде бага :) ]

Запросто - я в попыхах собирал, но на моем тесте работало.


Дата: Авг 28, 2003 15:15:23

Из юзер моды варианта нет с такими хендлами возиться :( Время можно не тратить. Самое прикольное что можно получить, это под NT4 сообщение о нарушении целостности каких-то там лицензий (это когда в процессе system с хендлами шалишь)...

Только из драйвера, причем в драйвере тоже нельзя всем подряд бездумно ObQueryNameString делать, а то и драйвер повиснет :)


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.071