C++;和使用命名管道的C#通信
我正在尝试反向工程一个注入进程的dll,它会钩住winsockC++;和使用命名管道的C#通信,c#,c++,named-pipes,C#,C++,Named Pipes,我正在尝试反向工程一个注入进程的dll,它会钩住winsocksend(),并通过管道流发送数据 这是读取管道流的C代码: [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] public struct PipeHeader { [MarshalAs(UnmanagedType.I1)] public byte command; [M
send()
,并通过管道流发送数据
这是读取管道流的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()
func,通过管道连接并发送消息。
问题是,接收到的数据不是我期望的数据,因此可能是我以错误的方式发送的。我需要帮助,因为我对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;
}
问题是,在C++ <代码> siZoof(PH)< /C> >或<代码> siZOF(缓冲区)< /C> >返回12字节。
相反,在C#中,相同结构的非托管大小(Marshal.SizeOf()
)返回9个字节
更新2:
通过改变结构包装解决了尺寸差异。
但我仍然没有得到正确的C值。
代码更新。我的第一篇帖子,请对我放松点:-)
sizeof使用不正确。它将返回LPCVOID,而不是您计划的缓冲区大小。当您要发送9个字节时,您将发送4个字节(在x86上)
我认为,您需要为SendPipeMessage()提供新参数
您可以在第一次调用中使用sizeof。在第二次通话中,您可以使用len作为参数
if(SendPipeMessage((LPCVOID)&ph, sizeof(ph))){
if(SendPipeMessage(buf, len)){
没有检查全部代码,因为我现在没时间。但我注意到:
我确信你不能期望C++中的<代码> int /代码>总是4字节。当大小重要时,
int
不是最佳选择
您在C#code中忘记了成员datasize
的[marshallas(UnmanagedType.I4)]
。属性仅应用于下一个项目,而不是应用于以下所有项目
将SendPipeMessage(buffer,sizeof(buffer))
替换为SendPipeMessage((char*)&ph,sizeof(ph))
,以获得所需的结果。不需要memcpy
到那里的字符数组,正如M.L.提到的sizeof(buffer)
不是您想要的
将sizeof(buf)
替换为len
。您已经有了长度,为什么要使用sizeof?而且sizeof(buf)
也不是您想要的
您可以将末尾的返回代码简化为returnfsucces代码>。如果还有别的,就不需要了。或者只是返回WriteFile(…)代码>
为什么使用cbToWrite=sizeof(lpvMessage)代码>?这也不是您想要的,您已经传递了ctToWrite
,您应该在调用WriteFile
时使用它
我对你的问题不是特别清楚。我不确定问题是在处理管道还是序列化。我提供了以下完整的C++管道服务器代码和C管道客户端代码。我尽量使事情尽可能简单,以便演示对话。我使用了您的结构和反序列化代码,并添加了一个序列化方法。在这两个代码示例中,都有一个指向MS doc的链接,如果需要的话,可以轻松地反转客户机-服务器关系。服务器和客户端代码是独立的,设计用于在不同的进程(两个控制台应用程序)中运行。没有线程或线程,服务器不会处理多个连接
就简单(反/)序列化而言,我建议您使用结构中的BitConverter类和方法来手动转换字节数组。这为您提供了更好的控制级别,并且更易于调试。如果你有复杂的结构来表示,我建议你看看谷歌的“protobuf”。当然可以
C++管道服务器代码(Windows)
编译这两组代码。启动服务器代码,然后启动客户端。输出是最小的,但会显示数据交换,服务器会在发送回数据之前修改数据(显示双边数据交换)。除了以身作则,没有其他真正的目的
希望本例能提供解决问题所需的基本信息。在大多数32位和64位平台上,尤其是在我所知道的所有x64平台上,int是4字节。可能是真的,但在大小重要的地方使用
int
并不是一个好选择。我想这不是问题,但我想指出。你在这里不是最佳的选择是正确的,但是“尤其是64位它不是真的”的说法是错误的——尤其是如果你认为C通常是在Windows系统上使用的,在x86上,整数有4个字节,64位模式下的x64和安腾。sizeof(buf)-将返回类型指针的大小(通常为4)。buf长度以len为单位提供。这就是为什么你应该尝试<代码> SeDIPPIEMSEGE(BUF,LEN)< /COD>而不是<代码> SeDIPiMeMeSeAGE(BUF,sieZof(BUF))< /C>。请张贴整个C++代码。有许多变量未在代码中声明,如hPipe
或cbwrited
。什么是pSend
?
BOOL SendPipeMessage(LPCVOID lpvMessage){
// Send a message to the pipe server.
cbToWrite = sizeof(lpvMessage);
BOOL SendPipeMessage(LPCVOID lpvMessage, DWORD cbToWrite)
if(SendPipeMessage((LPCVOID)&ph, sizeof(ph))){
if(SendPipeMessage(buf, len)){
#include <stdio.h>
#include <stdint.h>
#include <winsock.h>
#include <string>
// see https://msdn.microsoft.com/en-us/library/bb546085(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
// for information on creating pipe clients and servers in c++
using namespace std;
#pragma pack(1)
typedef struct {
int8_t command;
int32_t sockid;
int32_t datasize;
} PipeHeader;
#pragma pack()
int wmain( int argc, wchar_t* argv[] ) {
auto pipename = "\\\\.\\pipe\\pipey"; // can be any name, but must start '\\.\pipe\'
printf("Create pipe '%s'\r\n", pipename);
auto pipeHandle = CreateNamedPipe(pipename,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_WAIT,
1, // # instances
64, // out buff
64, // in buff
0, // timeout, 0 = default of 50ms
NULL); // security attrs
printf("Waiting for pipe connect\r\n");
if (ConnectNamedPipe(pipeHandle, NULL)) {
printf("Pipe connected\r\n");
PipeHeader hdr;
DWORD bytesRead;
int8_t cmd = -1;
while (cmd != 0) {
if (ReadFile(pipeHandle, &hdr, sizeof(PipeHeader), &bytesRead, NULL)) {
// you can check or assert here that bytesRead == sizeof(PipeHeader)
printf("Read %d bytes from pipe, {command: %d, sockid: %d, datasize: %d}\r\n",
bytesRead, hdr.command, hdr.sockid, hdr.datasize);
if (hdr.command == 0) { // assume 0 is the exit cmd
break;
}
else if (hdr.command == 1) {
// do whatever cmd 1 is ...
}
hdr.command = 4;
hdr.sockid = 101;
hdr.datasize *= 2;
if (WriteFile(pipeHandle, &hdr, sizeof(PipeHeader), &bytesRead, NULL)) {
printf("Data written to pipe\r\n");
}
else {
printf("Pipe write failed\r\n");
break;
}
}
else {
printf("Read error: %d\r\n", GetLastError());
break; // exit
}
}
if (DisconnectNamedPipe(pipeHandle) == FALSE) {
printf("Disconnect error: %d\r\n", GetLastError());
}
}
else {
printf("Pipe connect failed\r\n");
}
CloseHandle(pipeHandle);
printf("Exiting program\r\n");
return 0;
}
using System;
using System.Runtime.InteropServices;
using System.IO.Pipes;
namespace Pipes {
// see https://msdn.microsoft.com/en-us/library/bb546085(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
// for information on creating pipe clients and servers in c#
class Program {
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct PipeHeader {
[MarshalAs(UnmanagedType.I1)]
public byte command;
[MarshalAs(UnmanagedType.I4)]
public Int32 sockid;
public Int32 datasize;
}
static void Main(string[] args) {
var pipename = "pipey";
var pipeClient = new NamedPipeClientStream(pipename);
Console.WriteLine("Connecting to server pipe '{0}'", pipename);
pipeClient.Connect();
var hdr = new PipeHeader();
var hdrSize = Marshal.SizeOf(hdr);
hdr.command = 1;
hdr.sockid = 1912;
hdr.datasize = 32;
var buf = Serialize(hdr);
Console.WriteLine("Writing to server pipe");
pipeClient.Write(buf, 0, hdrSize);
pipeClient.Read(buf, 0, hdrSize);
hdr = (PipeHeader) Deserialize(buf, hdr.GetType());
Console.WriteLine("Pipe read {{ command: {0}, sockid: {1}, datasize: {2} }}",
hdr.command, hdr.sockid, hdr.datasize);
hdr.command = 0; // tell server to disconnect
buf = Serialize(hdr);
Console.WriteLine("Sending disconnect");
pipeClient.Write(buf, 0, hdrSize);
pipeClient.Close();
Console.WriteLine("Pipe closed");
}
public static object Deserialize(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;
}
public static byte[] Serialize(object obj) {
int rawsize = Marshal.SizeOf(obj);
var rv = new byte[rawsize];
IntPtr ptr = Marshal.AllocHGlobal(rawsize);
Marshal.StructureToPtr(obj, ptr, true);
Marshal.Copy(ptr, rv, 0, rawsize);
Marshal.FreeHGlobal(ptr);
return rv;
}
}
}