c# - 使用命名管道的 C++ 和 C# 通信

标签 c# c++ named-pipes

我正在尝试对注入(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 (即 datasizePipeHeader 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/

相关文章:

c++ - 在 C++ 中,为什么 struct 实际上是类?

c# - readData 用于 24 位 FLAC 和 WAV 文件

c++ - nullptr 不能在 valarray 中使用

c# - 想知道 async/await 解决方案是否干净

c++ - 30fps 的大型点云数据渲染查看器

java - 在 Java/Linux 中使用命名管道时流未正确关闭

.net - NamedpipeClientStream 无法连接,一直超时

sql-server - 使用SMO .net通过DeviceType.Pipe进行备份和恢复

c# - 如何在选项工具提示的下拉列表中使用对象属性?

c# .NET 2.0 缩放滚动条