使用现有的 TCP 连接发送数据包
Posted
技术标签:
【中文标题】使用现有的 TCP 连接发送数据包【英文标题】:Using an existent TCP connection to send packets 【发布时间】:2014-05-12 23:14:58 【问题描述】:我正在使用 WPE PRO,我可以捕获数据包并将其发回。我尝试使用 WinSock 2(WPE PRO 使用的同一个库),但我不知道如何像 WPE PRO 那样将数据包发送到现有的 TCP 连接。
http://wpepro.net/index.php?categoryid=2
我该怎么做?
【问题讨论】:
在不知道 WPE 的实现的情况下,我只能猜测它可能正在使用 RAW 套接字并伪造自己的 TCP/IP 标头。 【参考方案1】:您是在问如何让其他人的程序通过其现有的 Winsock 连接发送数据?
我确实做到了这一点,但遗憾的是目前手头没有代码。如果您给我一两个小时,我可以使用 C 提出一个工作示例; 如果您需要,请告诉我,我会的。
编辑: 如果您或其他人愿意,可以在页面底部测试示例 DLL;我不能。我所知道的是它可以编译。您只需要下载(或编写!)一个免费的 DLL 注入程序来测试它;那里有很多。
同时,你需要研究的是:
-
EXE 执行方式的基础知识。
DLL 注入
API 挂钩
Windows 套接字 API
1。执行 EXE 的基本原理:
我将要向您解释的整个过程都归结为这个原则。当您双击一个可执行文件时,Windows 会解析它并将其代码等加载到 内存 中。这是关键。编译后的代码全部放入 RAM。这意味着什么?好吧,如果应用程序的代码都在 RAM 中,我们可以在应用程序运行时通过更改它的一些内存来更改应用程序的代码吗?毕竟只是一堆指令而已。
答案是是的,它将为我们提供与另一个应用程序混淆的方法 - 在这种情况下,告诉它通过其打开的套接字发送一些数据。
(这个原则也是你必须小心用 C 等低级语言编写程序的原因,因为如果你把坏东西放在 RAM 的坏部分,它可能会使程序崩溃或让你受到 shell 代码攻击) .
2。 DLL 注入:
问题是,我们如何知道要覆盖哪个内存?我们是否可以访问该程序的内存,尤其是包含我们想要更改的指令的部分?您可以写入另一个进程的内存,但它更复杂。更改它们的内存的最简单方法(再次,当我说内存时,我们指的是正在执行的机器代码指令)是在该进程中加载并运行一个 DLL。将您的 DLL 想象成一个 .c 文件,您可以添加到另一个程序并编写您自己的代码:您可以访问程序的变量、调用它的函数等等;因为它在进程中运行。
DLL 注入可以通过多种方法完成。通常是通过调用 CreateRemoteThread() API 函数。对此进行 Google 搜索。
3。 API 挂钩
什么是 API 挂钩?说得更通俗一点,就是“函数钩子”,我们恰好对钩子 API 调用感兴趣;在这种情况下,用于 Sockets 的那些(socket()、send() 等)。
让我们举个例子。使用 Winsock 用 C 语言编写的目标应用程序。让我们看看他们在做什么,然后展示一个我们想要做什么的例子:
他们创建套接字的原始源代码:
SOCKET ConnectSocket = INVALID_SOCKET;
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
现在,这是原始程序的源代码。我们的 DLL 无法访问它,因为它是在一个 EXE 中加载的,并且一个 EXE 被编译(duh!)。因此,假设他们对 socket() 的调用在编译为机器代码(程序集)后看起来像这样。我完全不了解组装,但这只是为了说明:
程序集/机器码:
PUSH 06 ; IPPROTO_TCP
PUSH 01 ; SOCK_STREAM
PUSH 02 ; AF_INET
CALL WS2_32.socket ; This is one of the parts our DLL will need to intercept ("hook").
为了让该程序发送数据(使用我们的 DLL),我们需要知道套接字的句柄。所以我们需要拦截他们对socket
函数的调用。以下是一些注意事项:
最后一条指令需要更改为:CALL OurOwnDLL.socket
。 CALL
指令只是内存中某处的一个值(还记得吗?),所以我们可以使用 WriteProcessMemory 来做到这一点。我们会解决的。
我们想要控制目标程序,不要让它崩溃或让它表现得异常。所以我们的代码需要透明。我们将要注入的 DLL 需要有一个与原始函数 相同 的 socket
函数,返回相同的值等。唯一的区别是,我们将记录返回值 (SocketHandle
)以便我们以后要发送数据时使用它。
我们还需要知道套接字是否/何时连接,因为我们无法发送数据,除非它是(假设我们像大多数应用程序一样使用 TCP)。这意味着我们还需要挂钩 Winsock connect
API 函数并还在我们的 DLL 中复制它。
注入和监视socket
和connect
函数的DLL(未经测试):
这个 C DLL 将具备一切挂钩和取消挂钩功能。我目前无法对其进行测试,而且我什至不是 C 程序员,所以如果您遇到任何问题,请告诉我。
不使用 Unicode 将其编译为 Windows DLL,并将其注入您知道使用 WS2_32 的 socket() 和 connect() 函数的进程中,并让我知道它是否有效。我没有办法测试,对不起。如果您需要进一步的帮助或修复,请告诉我。
/*
SocketHookDLL.c
Author: Daniel Elkins
License: Public Domain
Version: 1.0.0
Created: May 14th, 2014 at 12:23 AM
Updated: [Never]
Summary:
1. Link to the Winsock library so we can use its functions.
2. Export our own `socket` and `connect` functions so that
they can be called by the target application instead of
the original ones from WS2_32.
3. "Hook" the socket APIs by writing over the target's memory,
causing `CALL WS2_32.socket` to `CALL SocketHookDLL.socket`, using
WriteProcessMemory.
4. Make sure to keep a copy of the original memory for when we no
no longer want to hook those socket functions (i.e. DLL detaching).
*/
#pragma comment(lib, "WS2_32.lib")
#include <WinSock2.h>
/* These functions hook and un-hook an API function. */
unsigned long hookFunction (const char * dllModule, const char * apiFunction, unsigned char * memoryBackup);
unsigned int unHookFunction (const char * dllModule, const char * apiFunction, unsigned char * memoryBackup);
/*
These functions (the ones we want to hook) are copies of the original Winsock's functions from Winsock2.h.
1. Calls OurDLL.hooked_socket() (unknowingly).
2. OurDLL.hooked_socket() calls the original Winsock.socket() function.
3. We take note of the returned SOCKET handle so we can use it later to send data.
4. OurDLL.hooked_socket() returns the SOCKET back to the target app so everthing works as it should (hopefully!).
Note: You can change return values, parameters (like data being sent/received like WPE does), just be aware it will
also (hopefully, intendingly) change the behavior of the target application.
*/
SOCKET WSAAPI hooked_socket (int af, int type, int protocol);
int WSAAPI hooked_connect (SOCKET s, const struct sockaddr FAR * name, int namelen);
/* Backups of the original memory; need one for each API function you hook (if you want to unhook it later). */
unsigned char backupSocket[6];
unsigned char backupConnect[6];
/* Our SOCKET handle used by the target application. */
SOCKET targetsSocket = INVALID_SOCKET;
/* This is the very first code that gets executed once our DLL is injected: */
BOOL APIENTRY DllMain (HMODULE moduleHandle, DWORD reason, LPVOID reserved)
/*
We will hook the desired Socket APIs when attaching
to target EXE and UN-hook them when being detached.
*/
switch (reason)
case DLL_PROCESS_ATTACH:
/* Here goes nothing! */
hookFunction ("WS2_32.DLL", "socket", backupSocket);
hookFunction ("WS2_32.DLL", "connect", backupConnect);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_PROCESS_DETACH:
unHookFunction ("WS2_32.DLL", "socket", backupSocket);
unHookFunction ("WS2_32.DLL", "connect", backupConnect);
break;
case DLL_THREAD_DETACH:
break;
return TRUE;
unsigned long hookFunction (const char * dllModule, const char * apiFunction, unsigned char * memoryBackup)
/*
Hook an API function:
=====================
1. Build the necessary assembly (machine code) opcodes to get our DLL called!
2. Get a handle to the API we're hooking.
3. Use ReadProcessMemory() to backup the original memory to un-hook the function later.
4. Use WriteProcessMemory to make changes to the instructions in memory.
*/
HANDLE thisTargetProcess;
HMODULE dllModuleHandle;
unsigned long apiAddress;
unsigned long memoryWritePosition;
unsigned char newOpcodes[6] =
0xE9, 0x00, 0x00, 0x00, 0x00, 0xC3 // Step #1.
;
thisTargetProcess = GetCurrentProcess ();
// Step #2.
dllModuleHandle = GetModuleHandle (dllModule);
if (!dllModuleHandle)
return 0;
apiAddress = (unsigned long) GetProcAddress (dllModuleHandle, apiFunction);
if (!apiAddress)
return 0;
// Step #3.
ReadProcessMemory (thisTargetProcess, (void *) apiAddress, memoryBackup, 6, 0);
memoryWritePosition = ((unsigned long) apiFunction - apiAddress - 5);
memcpy (&newOpcodes[1], &apiAddress, 4);
// Step #4.
WriteProcessMemory (thisTargetProcess, (void *) apiAddress, newOpcodes, 6, 0);
return apiAddress;
unsigned int unHookFunction (const char * dllModule, const char * apiFunction, unsigned char * memoryBackup)
HANDLE thisTargetProcess;
HMODULE dllModuleHandle;
unsigned long apiAddress;
unsigned long memoryWritePosition;
thisTargetProcess = GetCurrentProcess ();
dllModuleHandle = GetModuleHandleA (dllModule);
if (!dllModuleHandle)
return 0;
apiAddress = (unsigned long) GetProcAddress (dllModuleHandle, apiFunction);
if (!apiAddress)
return 0;
if (WriteProcessMemory (thisTargetProcess, (void *) apiAddress, memoryBackup, 6, 0))
return 1;
return 0;
/* You may want to use a log file instead of a MessageBox due to time-outs, etc. */
SOCKET WSAAPI hooked_socket (int af, int type, int protocol)
targetsSocket = socket (af, type, protocol);
MessageBox (NULL, "(Close this quickly)\r\n\r\nThe target's socket was hooked successfully!", "Hooked SOCKET", MB_OK);
return targetsSocket;
int WSAAPI hooked_connect (SOCKET s, const struct sockaddr FAR * name, int namelen)
MessageBox (NULL, "(Close this quickly)\r\n\r\nThe target just connected to a remote address.", "Target Connected", MB_OK);
return connect (s, name, namelen);
【讨论】:
以上是关于使用现有的 TCP 连接发送数据包的主要内容,如果未能解决你的问题,请参考以下文章
在向服务器发送请求时发生传输级错误。 (provider: TCP 提供程序, error: 0 - 远程主机强迫关闭了一个现有的连接。)