13

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

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

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

2 回答 2

7

正如雷米所说,这不是微不足道的。您必须为系统中的每个进程调用OpenProcesswith PROCESS_DUP_HANDLE。您可能还需要PROCESS_QUERY_INFORMATIONand 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's a TCP Socket */ }

几年前,我自己和另一个人也做过类似的事情。我们使用互斥锁和事件来替代 Sockets,从他们的用户态 UI 程序(与 IPC 的特权组件共享句柄)中崩溃特权防病毒组件。见老狗和新把戏:你知道你的把手在哪里吗?.

于 2013-05-02T04:34:02.460 回答
4

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

  • 一开始我查看了程序的反汇编并找出了对 WS2_32 Send 函数的调用。

反汇编代码

如图所示,在 0x467781 处调用了 Socket 发送函数,并将 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 发送我的自定义数据包:)

于 2013-05-02T11:49:16.280 回答