【问题标题】:C++ Get Handle of Open Sockets of a ProgramC++ 获取程序打开套接字的句柄
【发布时间】:2013-04-22 03:26:29
【问题描述】:

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

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

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

【问题讨论】:

  • 您可以枚举进程中的所有对象(PID 可以通过 GetExtendedTcpTable 和 TCP_TABLE_OWNER_PID_ALL 获得)并查找名为“Device\Tcp”的句柄(参见github.com/dzzie/SysAnalyzer/blob/master/source/sysanalyzer/…powerbasic.com/support/forums/Forum4/HTML/012185.html) .使用 Process Explorer 进行的快速扫描表明,这种命名方案在 Windows 8 上不再适用。你需要插座手柄做什么?也许还有其他不涉及劫持套接字句柄的方法来解决您的问题。
  • @DanielStelter 我只是想用他们的套接字发送数据包
  • @Shahriyar:您所要求的并非微不足道。为了让一个进程访问另一个进程的套接字,源进程必须在自己的套接字上调用WSADuplicateSocket(),然后通过IPC将该信息传递给目标进程。然后目标将信息传递给WSASocket() 以访问源的现有连接。除非您同时编写这两个应用程序,否则源应用程序不会为您调用WSADuplicateSocket(),因此您必须将自己的代码注入源进程,例如使用CreateRemoteThread(),才能调用WSADuplicateSocket() 并取回信息.
  • @RemyLebeau - 即使他设法使用 CreateRemoteThread 将代码注入另一个进程,他仍然没有套接字值可以传递给对 WSADuplicateSocket 的调用。
  • @selbie:这就是原始问题的全部目的 - 如何获取另一个进程的套接字句柄。 Daniel 回答说 - 枚举进程的内核对象以查找 Device\Tcp 对象,直到找到所需的句柄。

标签: c++ winapi


【解决方案1】:

正如雷米所说,这不是微不足道的。您必须为系统中的每个进程调用OpenProcessPROCESS_DUP_HANDLE。您可能还需要PROCESS_QUERY_INFORMATIONPROCESS_VM_READ,但我从来不需要它(我见过使用它的其他代码)。

对于每个进程,您可以使用NtQuerySystemInformation(信息类为SystemHandleInformation)访问施主进程的句柄表。最后,您调用DuplicateHandle 使进程的句柄也成为您的句柄。

在枚举施主进程的句柄表时,您必须过滤句柄类型。对于您复制的每个句柄,使用ObjectTypeInformation 调用NtQueryObject。如果类型是套接字,则将其保持打开状态并将其放入列表中。否则,关闭它并继续。

要执行比较,代码如下所示。类型返回为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 类型(我不记得了),您应该尝试获取与句柄关联的名称(它仍然是 UNICODE_STRING),然后查找 \\Device\\Tcp。这一次,您将使用相同的句柄,但使用ObjectNameInformation 调用NtQueryObject

// 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 的特权组件共享句柄)中使特权防病毒组件崩溃。见Old Dogs and New Tricks: Do You Know Where Your Handles Are?

【讨论】:

  • 另见 Sysinternals 论坛上的Socket Handles
  • 谢谢,但是如果该程序有多个套接字会怎样?
  • Shahriyar - 您将获得句柄表中的所有套接字。
【解决方案2】:

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

  • 起初我查看了程序的反汇编并找出了对 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 发送我的自定义数据包:)

【讨论】:

  • "... 所要做的就是改变那个 CALL" - 我相信 Detours Library 会为你做这件事 ;)
猜你喜欢
  • 2011-02-14
  • 2014-05-25
  • 2013-11-30
  • 1970-01-01
  • 2011-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多