С++ Получить ручку открытых сокетов программы

Как можно получить Socket ID (Handle) созданных сокетов программы?

Я знаю, что я могу получить все открытые сокеты во всех программах с помощью GetTcpTable(), но у него есть две проблемы:

  • Он показывает все сокеты программ
  • Он не возвращает ID (Handle) сокетов

Ответ 1

Как сказал Реми, его нетривиально. Вы должны вызвать OpenProcess с помощью PROCESS_DUP_HANDLE для каждого процесса в системе. Вам также могут понадобиться PROCESS_QUERY_INFORMATION и PROCESS_VM_READ, но я никогда не нуждался в этом (я видел другой код, который его использует).

Для каждого процесса вы получаете доступ к таблице дескрипторов процесса-донора с помощью NtQuerySystemInformation (с информационным классом SystemHandleInformation). Наконец, вы вызываете DuplicateHandle, чтобы процесс обрабатывал ваш дескриптор тоже.

Вам нужно будет фильтровать типы дескрипторов при перечислении таблицы дескриптора процесса-донора. Для каждого дублирующегося дескриптора вызовите NtQueryObject с помощью ObjectTypeInformation. Если тип является сокетом, вы держите его открытым и помещаете в свой список. В противном случае закройте его и продолжайте.

Чтобы выполнить сравнение, код выглядит так, как показано ниже. Тип возвращается как UNICODE_STRING:

// info was returned from NtQueryObject, ObjectTypeInformation
POBJECT_TYPE_INFORMATION pObjectTypeInfo = (POBJECT_TYPE_INFORMATION)(LPVOID)info;

wstring type( pObjectTypeInfo->Name.Buffer, pObjectTypeInfo->Name.Length );
if( 0 != wcscmp( L"Socket", type.c_str() ) ) { /* Not a Socket */ }

Если нет типа Socket (я не помню), вы должны попытаться получить имя, связанное с дескриптором (его еще a UNICODE_STRING), и найдите \\Device\\Tcp. На этот раз вы будете использовать один и тот же дескриптор, но вызовите NtQueryObject с помощью ObjectNameInformation:

// info was returned from NtQueryObject, ObjectNameInformation
POBJECT_NAME_INFORMATION pObjectNameInfo = (POBJECT_NAME_INFORMATION)(LPVOID)info;

wstring name( pObjectNameInfo->Name.Buffer, pObjectNameInfo->Name.Length );
if( name.substr(0, 11) == "\\Device\\Tcp" ) ) { /* It a TCP Socket */ }

Сам себе другой парень сделал подобное несколько лет назад. Вместо Sockets мы использовали Mutexes и Events для сбоя привилегированных компонентов Антивируса из их пользовательской пользовательской программы (которая совместно использовала с привилегированным компонентом для IPC). Смотрите Старые собаки и новые трюки: знаете ли вы, где ваши ручки?.

Ответ 2

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

  • Сначала я просмотрел разборку программ и выяснил вызовы функции отправки WS2_32.

Disassembly Code

Как показано на рисунке, есть вызов функции отправки Socket в 0x467781 и дескриптор Socket, сохраненный в стеке в регистре EDX

  • Теперь мне нужно сделать, чтобы связать мой код с этой функцией.

    void GetSocket(int Flag,int DataSize, char* Data, SOCKET Socket)
     {
         sSocket = Socket;
         sFlag = Flag;
         sDataSize = DataSize;
         sData = Data;
         SendPacket(sSocket,Data,DataSize); //Send packets manually
     }
    
    __declspec(naked) void MyFunc()
     {
        __asm
          {
               PUSH EDX // Socket
               PUSH ECX // Buffer
               PUSH EAX // Buffer Size
               PUSH 0   // Flag
               CALL GetSocket
               MOV EAX, sDataSize
               MOV ECX, sData
               MOV EDX, sWowSocket
               JMP [JumpAddress] // JumpAddress = 0x467787 (After that CALL)
           }
     }
    

    И теперь мне все нужно сделать, чтобы изменить этот CALL (в 0x467781) на JMP на нашу функцию (MyFunc), и это можно сделать с помощью следующей функции:

    *(DWORD*)   (0x467781  + 0x01)  =   (DWORD)MyFunc- (0x467781  + 0x05);
    

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