我正在尝试对注入(inject)到进程中的 dll 进行逆向工程,它确实 Hook winsock send()
并通过 PipeStream
发送数据。
这是读取管道流的 C# 代码:
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct PipeHeader
{
[MarshalAs(UnmanagedType.I1)]
public byte command;
[MarshalAs(UnmanagedType.I4)]
public int sockid;
public int datasize;
}
public static object RawDeserializeEx(byte[] rawdatas, Type anytype)
{
int rawsize = Marshal.SizeOf(anytype);
if (rawsize > rawdatas.Length)
return null;
GCHandle handle = GCHandle.Alloc(rawdatas, GCHandleType.Pinned);
IntPtr buffer = handle.AddrOfPinnedObject();
object retobj = Marshal.PtrToStructure(buffer, anytype);
handle.Free();
return retobj;
}
private void PipeRead()
{
byte[] dbPipeMsgIn = new byte[9];
byte[] zero = new byte[] { 0 };
byte[] dbPipeMsgInData;
PipeLoop:
while (pipeIn.Read(dbPipeMsgIn, 0, 9) != 0)
{
strPipeMsgIn = (PipeHeader)RawDeserializeEx(dbPipeMsgIn, typeof(PipeHeader));
if (strPipeMsgIn.datasize != 0)
{
dbPipeMsgInData = new byte[strPipeMsgIn.datasize];
pipeIn.Read(dbPipeMsgInData, 0, dbPipeMsgInData.Length);
//do something with dbPipeMsgInData
}
}
if (pipeIn.IsConnected) goto PipeLoop;
}
到目前为止,我已经连接了 send()
函数,通过管道连接并发送消息。
问题是收到的数据不是我期望的数据,所以我可能以错误的方式发送。我需要帮助,因为我几乎没有 C++ 知识。
C++ 代码:
#pragma pack(1)
typedef struct
{
byte command;
int sockid;
int datasize;
} PipeHeader;
#pragma pack(0)
int WINAPI MySend(SOCKET s, const char* buf, int len, int flags)
{
PipeHeader ph;
string p(buf);
if(p.find("<TalkMsg") == 0){
byte cmd = 0;
ph.command = cmd;
ph.sockid = s;
ph.datasize = len;
char buffer[sizeof(ph)];
memcpy(buffer, &ph, sizeof(ph));
if(SendPipeMessage(buffer, sizeof(buffer))){
if(SendPipeMessage(buf, sizeof(buf))){
MessageBox(NULL,"Message Sent", NULL, NULL);
}
}
fopen_s(&pSendLogFile, "C:\\SendLog.txt", "a+");
fprintf(pSendLogFile, "%s\n", buf);
fclose(pSendLogFile);
}
return pSend(s, buf, len, flags);
}
BOOL SendPipeMessage(LPCVOID lpvMessage, DWORD ctToWrite){
// Send a message to the pipe server.
cbToWrite = sizeof(lpvMessage);
fSuccess = WriteFile(
hPipe, // pipe handle
lpvMessage, // message
cbToWrite, // message length
&cbWritten, // bytes written
NULL); // not overlapped
if ( ! fSuccess)
{
return false;
}else return true;
}
编辑,更多信息:
目标是通过管道发送一条包含 9 字节长 PipeHeader
结构的消息,然后发送另一条包含 winsock send()
数据的消息(buf
变量),在 C# 应用程序上读取管道并将第一条消息解析为获取下一条传入消息的 DataSize (即 datasize
的 PipeHeader
var),然后使用 datasize
再次读取管道以获取 send() 缓冲区。
我认为这是以这种方式工作的。我不太了解 Pipes 的工作原理。
无论如何,主要目标是将 send()
缓冲区从 C++ Dll 发送到 C# 应用程序。
更新:
似乎我必须首先以某种方式序列化 PipeHeader
结构,以便我可以在 C# 代码中使用 RawDeserializeEx()
反序列化它。
我尝试这样做:
char buffer[sizeof(ph)];
memcpy(buffer, &ph, sizeof(ph));
问题在于,在 C++ 中 sizeof(ph)
或 sizeof(buffer)
返回 12 个字节。
而在 C# 中,相同 Struct 的非托管大小 (Marshal.SizeOf()
) 返回 9 个字节。
更新 2: 通过更改结构包装解决了大小差异。 但我仍然没有在 C# 中得到正确的值。 代码已更新。
最佳答案
我的第一篇文章,所以请放轻松:-)
BOOL SendPipeMessage(LPCVOID lpvMessage){
// Send a message to the pipe server.
cbToWrite = sizeof(lpvMessage);
sizeof 使用不正确。它将返回 size of type LPCVOID 而不是您计划的缓冲区大小。当您想要发送 9 个字节时,您正在发送 4 个字节(在 x86 上)。
在我看来,您需要为您的 SendPipeMessage() 提供新参数
BOOL SendPipeMessage(LPCVOID lpvMessage, DWORD cbToWrite)
您可以在第一次调用时使用 sizeof。在第二次调用时,您可以使用 len 作为参数。
if(SendPipeMessage((LPCVOID)&ph, sizeof(ph))){
if(SendPipeMessage(buf, len)){
关于c# - 使用命名管道的 C++ 和 C# 通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30065738/