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

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

Метод перехвата прост и широко обсуждаем в интернете. Нам не потребуется глубоких знаний 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