|
Постоянный
Регистрация: 20.03.2009
Сообщений: 564
Провел на форуме: 991929
Репутация:
395
|
|
Операция “перехват”. Используем открытый сокет другого процесса.
Меня всегда интересовало, а можно ли похитить сокет другой программы и использовать его в своих целях? Еще как можно!
Обход фаервола, установка скрытых соединений, чтение конфиденциальных данных – это лишь немногое, что можно сделать, обладая сокетом.
Метод перехвата прост и широко обсуждаем в интернете. Нам не потребуется глубоких знаний Windows, потому что все осуществимо из User Mode (ring 3), но для понимания основы знать просто необходимо. RTFM Джеффри Рихтер “Windows для профессионалов: создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows”, глава 3
Метод заключатся в следующем - Получить список описателей (хэндлов - handle) открытых нужным процессом
- Найти среди них сокеты
- Скопировать их в свой процесс
В листинге, представленном ниже, я использовал функцию ZwQuerySystemInformation (Native API)
Код:
NTSTATUS ZwQuerySystemInformation(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength);
для получения списка открытых описателей, передав ей в качестве первого аргумента SystemHandleInformation
Для получения типа описателя функцию NtQueryObject
Код:
NTSTATUS NtQueryObject(
HANDLE ObjectHandle,
OBJECT_INFORMATION_CLASS ObjectInformationClass,
PVOID ObjectInformation,
ULONG Length,
PULONG ResultLength );
c параметром ObjectTypeInformation (нам нужны только ‘File’) и с параметром ObjectNameInformation для получения имени описателя (нам нужны сокеты ‘\Device\Afd’). Эти функции находятся в библиотеке ntdll.dll
Копировать описатель – сокет в наш процесс мы будем функцией DuplicateHandle
Листинг кода (VS2008 Win32->Console Project), демонстрирующий описанный выше метод для вывода всех открытых сокетов в системе.
Код:
#include "stdafx.h"
#include <windows.h>
#include <winternl.h> // нужный заголовочек с полезными структурами
#include <Ntstatus.h> // структура NTSTATUS
// подключаем сокеты для использования функций преобразования IP адреса и порта
#include <Winsock.h>
#pragma comment(lib, "ws2_32.lib")
#define BUF_SIZE 102400 // размер буффера под таблицу информации и имени описателя
// http://msdn.microsoft.com/en-us/library/aa492492.aspx эх, у меня нет DDK
typedef enum _POOL_TYPE
{
NonPagedPool = 0,
PagedPool = 1,
NonPagedPoolMustSucceed = 2,
DontUseThisType = 3,
NonPagedPoolCacheAligned = 4,
PagedPoolCacheAligned = 5,
NonPagedPoolCacheAlignedMustS = 6,
MaxPoolType = 7,
NonPagedPoolSession = 32,
PagedPoolSession = 33,
NonPagedPoolMustSucceedSession = 34,
DontUseThisTypeSession = 35,
NonPagedPoolCacheAlignedSession = 36,
PagedPoolCacheAlignedSession = 37,
NonPagedPoolCacheAlignedMustSSession = 38
} POOL_TYPE;
// структура необходимая для получения имени описателя - NtQueryObject(ObjectNameInformation)
typedef struct _OBJECT_NAME_INFORMATION {
UNICODE_STRING Name;
WCHAR NameBuffer[0];
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
// структура необходимая для получения типа описателя - NtQueryObject(ObjectTypeInformation)
typedef struct _OBJECT_TYPE_INFORMATION {
UNICODE_STRING TypeName;
ULONG TotalNumberOfHandles;
ULONG TotalNumberOfObjects;
WCHAR Unused1[8];
ULONG HighWaterNumberOfHandles;
ULONG HighWaterNumberOfObjects;
WCHAR Unused2[8];
ACCESS_MASK InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ACCESS_MASK ValidAttributes;
BOOLEAN SecurityRequired;
BOOLEAN MaintainHandleCount;
USHORT MaintainTypeList;
POOL_TYPE PoolType;
ULONG DefaultPagedPoolCharge;
ULONG DefaultNonPagedPoolCharge;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
//используется в NtQueryObject
typedef enum _OBJECT_INFORMATION_CLASS {
ObjectBasicInformation,
ObjectNameInformation,
ObjectTypeInformation,
ObjectAllInformation,
ObjectDataInformation
} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
//функции мы будем подключать динамически, поэтому их необохдимо описать :)
// ZwQuerySystemInformation
typedef NTSTATUS (CALLBACK *LPFNZwQuerySystemInformation)(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
LPFNZwQuerySystemInformation ZwQuerySystemInformation;
// NtQueryObject
typedef NTSTATUS (CALLBACK *LPFNNtQueryObject)(
HANDLE ObjectHandle,
OBJECT_INFORMATION_CLASS ObjectInformationClass,
PVOID ObjectInformation,
ULONG Length,
PULONG ResultLength );
LPFNNtQueryObject NtQueryObject;
#define SystemHandleInformation 16 //недокументированый enum SYSTEM_INFORMATION_CLASS
// структура используемая в ZwQuerySystemInformation
typedef struct _SYSTEM_HANDLE_INFORMATION {
USHORT ProcessId;
USHORT CreatorBackTraceIndex;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
// Расширенная структура для получения информации о всех описателях
typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
ULONG NumberOfHandles;
SYSTEM_HANDLE_INFORMATION Information[1];
} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
int _tmain(int argc, _TCHAR* argv[]) {
DWORD ret;
NTSTATUS ss;
PUNICODE_STRING us;
POBJECT_TYPE_INFORMATION ot;
int i,ress,rem_port,loc_port;
char *remaddr,*locaddr;
sockaddr_in sockname, locname;
WSAData WSData;
HANDLE hProcess,ObjHandle, hh;
HINSTANCE hNTdll = LoadLibrary(L"Ntdll.dll");
if(!hNTdll) return 1;
//ищем функции
ZwQuerySystemInformation = (LPFNZwQuerySystemInformation)
GetProcAddress(hNTdll, "ZwQuerySystemInformation");
NtQueryObject=(LPFNNtQueryObject)
GetProcAddress(hNTdll, "NtQueryObject");
WSAStartup(MAKEWORD(2,2), &WSData); // стартуем winsock 2.2
printf("There are the following sockets opened on system:\n");
// Получение числа описателей в системе
DWORD buffer_size = 0;
SYSTEM_HANDLE_INFORMATION_EX temp_info;
ss = ZwQuerySystemInformation(
(SYSTEM_INFORMATION_CLASS)SystemHandleInformation, &temp_info,
sizeof(temp_info), &buffer_size);
// выделяем память под информацию о описателях и
SYSTEM_HANDLE_INFORMATION_EX *system_handles =(SYSTEM_HANDLE_INFORMATION_EX*)malloc(buffer_size); // если C++ можно и (new BYTE[buffer_size])
ss = ZwQuerySystemInformation(
(SYSTEM_INFORMATION_CLASS)SystemHandleInformation,system_handles,
buffer_size, &buffer_size);
// выделяем память под сруктурки
ot=(POBJECT_TYPE_INFORMATION)malloc(BUF_SIZE);
us=(PUNICODE_STRING)malloc(BUF_SIZE);
// информацию о всех описателях мы получили теперь пробежимся по ним...
for(i=0;i<system_handles->NumberOfHandles;i++) {
/*
Тут можно вставить проверку на описатели определенного процесса,
PID которого можно получить кучей разных способов (см. ссылки в конце статьи)
*/
hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, system_handles->Information[i].ProcessId); // открываем процесс с нужными правами доступа
if (hProcess != INVALID_HANDLE_VALUE)
{
hh=(HANDLE)system_handles->Information[i].Handle; // у меня были проблемы с преобразованиями - для этого и завел новую переменную
// теперь копируем описатель в адресное пространство своего процесса
if(DuplicateHandle(hProcess,hh,INVALID_HANDLE_VALUE, &ObjHandle, DUPLICATE_SAME_ACCESS, 0, 0)) {
// вытаскиваем информацию о типе описателя
ss = NtQueryObject(ObjHandle,ObjectTypeInformation, ot, BUF_SIZE, &ret);
if (ss == STATUS_SUCCESS) {
//кстати таким образом можно перехватывать любые обьекты ядра заданые в таблице описателей процесса,
if(lstrcmp(ot->TypeName.Buffer,L"File")==0){ // но нам нужен только File
// вытаскиваем информацию о имени описателя
ss=NtQueryObject(ObjHandle,ObjectNameInformation, us, BUF_SIZE, &ret);
if(ss==STATUS_SUCCESS){
if(lstrcmp(us->Buffer,L"\\Device\\Afd")==0){ // если это сокет
/*
=================================================================================
Вот впринципе и все! мы нашли сокет и он уже находится во власти нашего процесса
теперь мы можем делать с ним все, что захотим! ;)
а я хочу вывысти информацию о нем и о том кому он пренадлежит.
=================================================================================
*/
ress = sizeof(sockaddr_in);//--- commenting this line would cause an 10014 error.
getpeername((SOCKET)ObjHandle, (sockaddr *)&sockname, &ress);
//--- определяем локальный IP и порт
ress = sizeof(sockaddr_in);//--- commenting this line would cause an 10014 error.
getsockname((SOCKET)ObjHandle, (sockaddr *)&locname, &ress);
//--- коевертируем в понятные для глаза данные )
remaddr = inet_ntoa(sockname.sin_addr);
rem_port = ntohs(sockname.sin_port);
locaddr = inet_ntoa(locname.sin_addr);
loc_port = ntohs(locname.sin_port);
// выводим информацию
wprintf(L"PID=%d; Local=%S:%d; Peer=%S:%d;\n",system_handles->Information[i].ProcessId,locaddr,loc_port,remaddr,rem_port);
}
} // --- name handle
}
} // --- type handle
} // -- duplicate handle
CloseHandle(hProcess);
}
} // --- for
// освобождаем память
free(ot);
free(us);
free(system_handles);
WSACleanup(); // отключаемс сокеты
FreeLibrary(hNTdll); // и выгружаем DLL
getchar(); // а это так для паузы )
return 0;
}
Полезные ссылки
Множество примеров использования Tool Help и ZwQuerySystemInformation
Недокументированные функции Windows NT/2K/XP/2003
|