C ++获取程序的开放套接字的句柄

时间:2013-04-28 10:54:16

标签: c++ winapi

如何获取程序创建的套接字的套接字ID(句柄)?

我知道我可以通过GetTcpTable()获取所有程序中的所有开放套接字,但它有两个问题:

  1. 显示所有程序套接字
  2. 它不会返回套接字的ID(句柄)

2 个答案:

答案 0 :(得分:6)

正如雷米所说,这不是微不足道的。对于系统中的每个进程,您必须使用OpenProcess调用PROCESS_DUP_HANDLE。您可能还需要PROCESS_QUERY_INFORMATIONPROCESS_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 */ }

如果没有套接字类型(我不记得),你应该尝试获取与句柄相关联的名称(它仍然是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's a TCP Socket */ }
几年前,我和另一个人做了类似的事。我们使用互斥锁和事件来替代特权的防病毒组件,而不是套接字,这些组件来自其用户区域UI程序(与IPC的特权组件共享句柄)。请参阅Old Dogs and New Tricks: Do You Know Where Your Handles Are?

答案 1 :(得分:4)

好的,感谢所有试图解决我问题的人 经过大量的工作,我得到了自己如何处理它,这就是我试图获得指定套接字的方式:

  • 第一次,我查看了程序的反汇编,找出了对WS2_32发送功能的调用。

Disassembly Code

如图所示,在0x467781处调用Socket发送功能,并且在EDX寄存器中将Socket句柄保存到堆栈中

  • 现在我需要做的是将我的代码挂钩到该功能。

    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);
    

现在我已经完成了,我可以很容易地看到它发送到服务器的每个数据包并在必要时更改它们并且还发送我的自定义数据包,其插座就是:)