Операция “перехват”. Используем открытый сокет другого процесса.

Меня всегда интересовало, а можно ли похитить сокет другой программы и использовать его в своих целях? Еще как можно!

Обход фаервола, установка скрытых соединений, чтение конфиденциальных данных – это лишь немногое, что можно сделать, обладая сокетом.

Метод перехвата прост и широко обсуждаем в интернете. Нам не потребуется глубоких знаний Windows, потому что все осуществимо из User Mode (ring 3), но для понимания основы знать просто необходимо. RTFM Джеффри Рихтер “Windows для профессионалов: создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows”, глава 3

Метод заключатся в следующем
  1. Получить список описателей (хэндлов - handle) открытых нужным процессом
  2. Найти среди них сокеты
  3. Скопировать их в свой процесс
В листинге, представленном ниже, я использовал функцию ZwQuerySystemInformation (Native API)

Код:
NTSTATUS ZwQuerySystemInformation(
  SYSTEM_INFORMATION_CLASS SystemInformationClass,
  PVOID SystemInformation,
  ULONG SystemInformationLength,
  PULONG ReturnLength);

для получения списка открытых описателей, передав ей в качестве первого аргумента SystemHandleInformation

Для получения типа описателя функцию NtQueryObject (Native API)

Код:
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 

#include  // нужный заголовочек с полезными структурами
#include  // структура NTSTATUS

// подключаем сокеты для использования функций преобразования IP адреса и порта
#include 
#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;iNumberOfHandles;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_VALU  E, &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

P.S: впервые статья была опубликована мной 31.05.2009, 19:15 на ачате, а патом на хабрхабаре попала в песочницу, н инвайт мне так и не прислали

Комментарии

Популярные сообщения из этого блога

Сказ об убунте заморской

Работа с HTTP

FileZilla shortcut