mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-07-10 17:49:40 +00:00
602 lines
16 KiB
C++
602 lines
16 KiB
C++
/**
|
|
* @file namedpipe.cpp
|
|
* @author Sina Karvandi (sina@hyperdbg.org)
|
|
* @brief Server and Client communication over NamedPipes
|
|
* @details
|
|
* @version 0.1
|
|
* @date 2020-07-15
|
|
*
|
|
* @copyright This project is released under the GNU Public License v3.
|
|
*
|
|
*/
|
|
#include "pch.h"
|
|
|
|
/**
|
|
* @brief Connect and transfer buffers via named pipe
|
|
*
|
|
* @return UINT32
|
|
*/
|
|
UINT32
|
|
NamedPipeConnectingAndTransferringBuffers()
|
|
{
|
|
// HANDLE PipeHandle;
|
|
// BOOLEAN SentMessageResult;
|
|
// UINT32 ReadBytes;
|
|
// char * Buffer;
|
|
//
|
|
// Buffer = (char *)malloc(TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE);
|
|
//
|
|
// if (!Buffer)
|
|
// {
|
|
// printf("err, could not allocate communication buffer\n");
|
|
// _getch();
|
|
// return 1;
|
|
// }
|
|
//
|
|
// RtlZeroMemory(Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE);
|
|
// strcpy_s(Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE, "Hey there, Are you HyperDbg?");
|
|
//
|
|
// //
|
|
// // Perform our shaking with HyperDbg
|
|
// //
|
|
//
|
|
// //
|
|
// // It's not called directly, it's probably from HyperDbg
|
|
// //
|
|
// PipeHandle = NamedPipeClientCreatePipe("\\\\.\\Pipe\\HyperDbgTests");
|
|
//
|
|
// if (!PipeHandle)
|
|
// {
|
|
// //
|
|
// // Unable to create handle
|
|
// //
|
|
// free(Buffer);
|
|
//
|
|
// printf("err, unable to create handle\n");
|
|
// _getch();
|
|
// return 1;
|
|
// }
|
|
//
|
|
// SentMessageResult =
|
|
// NamedPipeClientSendMessage(PipeHandle, Buffer, (int)strlen(Buffer) + 1);
|
|
//
|
|
// if (!SentMessageResult)
|
|
// {
|
|
// //
|
|
// // Sending error
|
|
// //
|
|
// free(Buffer);
|
|
//
|
|
// printf("err, unable to send message\n");
|
|
// _getch();
|
|
// return 1;
|
|
// }
|
|
//
|
|
// ReadBytes = NamedPipeClientReadMessage(PipeHandle, Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE);
|
|
//
|
|
// if (!ReadBytes)
|
|
// {
|
|
// //
|
|
// // Nothing to read
|
|
// //
|
|
// free(Buffer);
|
|
//
|
|
// printf("err, unable to read message\n");
|
|
// _getch();
|
|
// return 1;
|
|
// }
|
|
//
|
|
// if (strcmp(Buffer,
|
|
// "Hello, Dear Test Process... Yes, I'm HyperDbg Debugger :)") ==
|
|
// 0)
|
|
// {
|
|
// //
|
|
// // *** Connected to the HyperDbg debugger ***
|
|
// //
|
|
//
|
|
// //
|
|
// // Now we should request the test case number from the HyperDbg Debugger
|
|
// //
|
|
// RtlZeroMemory(Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE);
|
|
//
|
|
// strcpy_s(
|
|
// Buffer,
|
|
// TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE,
|
|
// "Wow! I miss you... Would you plz send test cases?");
|
|
//
|
|
// SentMessageResult =
|
|
// NamedPipeClientSendMessage(PipeHandle, Buffer, (int)strlen(Buffer) + 1);
|
|
//
|
|
// if (!SentMessageResult)
|
|
// {
|
|
// //
|
|
// // Sending error
|
|
// //
|
|
// free(Buffer);
|
|
//
|
|
// printf("err, sending error\n");
|
|
// _getch();
|
|
// return 1;
|
|
// }
|
|
//
|
|
// //
|
|
// // Read the test case number
|
|
// //
|
|
// RtlZeroMemory(Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE);
|
|
// ReadBytes = NamedPipeClientReadMessage(PipeHandle, Buffer, TEST_CASE_MAXIMUM_BUFFERS_TO_COMMUNICATE);
|
|
//
|
|
// if (!ReadBytes)
|
|
// {
|
|
// //
|
|
// // Nothing to read
|
|
// //
|
|
// free(Buffer);
|
|
//
|
|
// printf("err, nothing to read\n");
|
|
// _getch();
|
|
// return 1;
|
|
// }
|
|
//
|
|
// //
|
|
// // Dispatch the test case number
|
|
// //
|
|
//
|
|
// /// TestCreateLookupTable(PipeHandle, (PVOID)Buffer, ReadBytes);
|
|
// printf("!!!! Read to run the test cases !!!!");
|
|
// _getch();
|
|
//
|
|
// //
|
|
// // Close the pipe connection
|
|
// //
|
|
// NamedPipeClientClosePipe(PipeHandle);
|
|
//
|
|
// //
|
|
// // Make sure to exit the test program
|
|
// //
|
|
// exit(0);
|
|
// }
|
|
//
|
|
// free(Buffer);
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Server Side //
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* @brief Create a named pipe server
|
|
*
|
|
* @param PipeName
|
|
* @param OutputBufferSize
|
|
* @param InputBufferSize
|
|
* @return HANDLE
|
|
*/
|
|
HANDLE
|
|
NamedPipeServerCreatePipe(LPCSTR PipeName, UINT32 OutputBufferSize, UINT32 InputBufferSize)
|
|
{
|
|
HANDLE hPipe;
|
|
|
|
hPipe = CreateNamedPipeA(PipeName, // pipe name
|
|
PIPE_ACCESS_DUPLEX, // read/write access
|
|
PIPE_TYPE_MESSAGE | // message type pipe
|
|
PIPE_READMODE_MESSAGE | // message-read mode
|
|
PIPE_WAIT, // blocking mode
|
|
PIPE_UNLIMITED_INSTANCES, // max. instances
|
|
OutputBufferSize, // output buffer size
|
|
InputBufferSize, // input buffer size
|
|
NMPWAIT_USE_DEFAULT_WAIT, // client time-out
|
|
NULL); // default security attribute
|
|
|
|
if (INVALID_HANDLE_VALUE == hPipe)
|
|
{
|
|
printf("err, occurred while creating the pipe (%x)\n",
|
|
GetLastError());
|
|
return NULL;
|
|
}
|
|
return hPipe;
|
|
}
|
|
|
|
/**
|
|
* @brief wait for client connection
|
|
*
|
|
* @param PipeHandle
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
NamedPipeServerWaitForClientConnection(HANDLE PipeHandle)
|
|
{
|
|
//
|
|
// Wait for the client to connect
|
|
//
|
|
BOOLEAN ClientConnected = ConnectNamedPipe(PipeHandle, NULL);
|
|
|
|
if (FALSE == ClientConnected)
|
|
{
|
|
printf("err, occurred while connecting to the client (%x)\n",
|
|
GetLastError());
|
|
CloseHandle(PipeHandle);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Client connected
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief read client message from the named pipe
|
|
*
|
|
* @param PipeHandle
|
|
* @param BufferToSave
|
|
* @param MaximumReadBufferLength
|
|
* @return UINT32
|
|
*/
|
|
UINT32
|
|
NamedPipeServerReadClientMessage(HANDLE PipeHandle, CHAR * BufferToSave, INT32 MaximumReadBufferLength)
|
|
{
|
|
DWORD BytesTransferred;
|
|
|
|
//
|
|
// We are connected to the client.
|
|
// To communicate with the client
|
|
// we will use ReadFile()/WriteFile()
|
|
// on the pipe handle - hPipe
|
|
//
|
|
|
|
//
|
|
// Read client message
|
|
//
|
|
BOOLEAN Result = ReadFile(PipeHandle, // handle to pipe
|
|
BufferToSave, // buffer to receive data
|
|
MaximumReadBufferLength, // size of buffer
|
|
&BytesTransferred, // number of bytes read
|
|
NULL); // not overlapped I/O
|
|
|
|
if ((!Result) || (0 == BytesTransferred))
|
|
{
|
|
printf("err, occurred while reading from the client (%x)\n",
|
|
GetLastError());
|
|
CloseHandle(PipeHandle);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Number of bytes that the client sends to us
|
|
//
|
|
return BytesTransferred;
|
|
}
|
|
|
|
/**
|
|
* @brief Send a message to the client over named pipe
|
|
*
|
|
* @param PipeHandle Handle of the named pipe
|
|
* @param BufferToSend Buffer containing the message to send
|
|
* @param BufferSize Size of the buffer to send
|
|
* @return BOOLEAN TRUE if successful, FALSE otherwise
|
|
*/
|
|
BOOLEAN
|
|
NamedPipeServerSendMessageToClient(HANDLE PipeHandle,
|
|
CHAR * BufferToSend,
|
|
INT32 BufferSize)
|
|
{
|
|
DWORD BytesTransferred;
|
|
|
|
//
|
|
// Reply to client
|
|
//
|
|
BOOLEAN Result =
|
|
WriteFile(PipeHandle, // handle to pipe
|
|
BufferToSend, // buffer to write from
|
|
BufferSize, // number of bytes to write, include the NULL
|
|
&BytesTransferred, // number of bytes written
|
|
NULL); // not overlapped I/O
|
|
|
|
if ((!Result) || (BufferSize != (INT32)BytesTransferred))
|
|
{
|
|
printf("err, occurred while writing to the client (%x)\n",
|
|
GetLastError());
|
|
CloseHandle(PipeHandle);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Close handle of server's named pipe
|
|
*
|
|
* @param PipeHandle
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
NamedPipeServerCloseHandle(HANDLE PipeHandle)
|
|
{
|
|
CloseHandle(PipeHandle);
|
|
}
|
|
|
|
//**************************************************************************
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Client Side //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* @brief Create a client named pipe
|
|
* @details Pipe name format - \\servername\pipe\pipename
|
|
* This pipe is for server on the same computer,
|
|
* however, pipes can be used to connect to a remote server
|
|
*
|
|
* @param PipeName
|
|
* @return HANDLE
|
|
*/
|
|
HANDLE
|
|
NamedPipeClientCreatePipe(LPCSTR PipeName)
|
|
{
|
|
HANDLE hPipe;
|
|
|
|
//
|
|
// Connect to the server pipe using CreateFile()
|
|
//
|
|
hPipe = CreateFileA(PipeName, // pipe name
|
|
GENERIC_READ | // read and write access
|
|
GENERIC_WRITE,
|
|
0, // no sharing
|
|
NULL, // default security attributes
|
|
OPEN_EXISTING, // opens existing pipe
|
|
0, // default attributes
|
|
NULL); // no template file
|
|
|
|
if (INVALID_HANDLE_VALUE == hPipe)
|
|
{
|
|
printf("err, occurred while connecting to the server (%x)\n",
|
|
GetLastError());
|
|
//
|
|
// One might want to check whether the server pipe is busy
|
|
// This sample will error out if the server pipe is busy
|
|
// Read on ERROR_PIPE_BUSY and WaitNamedPipe() for that
|
|
//
|
|
|
|
//
|
|
// Error
|
|
//
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
return hPipe;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Send client message over named pipe
|
|
*
|
|
* @param PipeHandle Handle of the named pipe
|
|
* @param BufferToSend Buffer containing the message to send
|
|
* @param BufferSize Size of the buffer to send
|
|
* @return BOOLEAN TRUE if successful, FALSE otherwise
|
|
*/
|
|
BOOLEAN
|
|
NamedPipeClientSendMessage(HANDLE PipeHandle, CHAR * BufferToSend, INT32 BufferSize)
|
|
{
|
|
//
|
|
// We are done connecting to the server pipe,
|
|
// we can start communicating with
|
|
// the server using ReadFile()/WriteFile()
|
|
// on handle - hPipe
|
|
//
|
|
|
|
DWORD BytesTransferred;
|
|
|
|
//
|
|
// Send the message to server
|
|
//
|
|
BOOLEAN Result =
|
|
WriteFile(PipeHandle, // handle to pipe
|
|
BufferToSend, // buffer to write from
|
|
BufferSize, // number of bytes to write, include the NULL
|
|
&BytesTransferred, // number of bytes written
|
|
NULL); // not overlapped I/O
|
|
|
|
if ((!Result) || (BufferSize != (INT32)BytesTransferred))
|
|
{
|
|
printf("err, occurred while writing to the server (%x)\n",
|
|
GetLastError());
|
|
CloseHandle(PipeHandle);
|
|
|
|
//
|
|
// Error
|
|
//
|
|
CloseHandle(PipeHandle);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Read a message from the server over named pipe
|
|
*
|
|
* @param PipeHandle Handle of the named pipe
|
|
* @param BufferToRead Buffer to store the received message
|
|
* @param MaximumSizeOfBuffer Maximum size of the receive buffer
|
|
* @return UINT32 number of bytes read, or 0 on failure
|
|
*/
|
|
UINT32
|
|
NamedPipeClientReadMessage(HANDLE PipeHandle, CHAR * BufferToRead, INT32 MaximumSizeOfBuffer)
|
|
{
|
|
DWORD BytesTransferred;
|
|
|
|
//
|
|
// Read server response
|
|
//
|
|
BOOLEAN Result = ReadFile(PipeHandle, // handle to pipe
|
|
BufferToRead, // buffer to receive data
|
|
MaximumSizeOfBuffer, // size of buffer
|
|
&BytesTransferred, // number of bytes read
|
|
NULL); // not overlapped I/O
|
|
|
|
if ((!Result) || (0 == BytesTransferred))
|
|
{
|
|
printf("err, occurred while reading from the server (%x)\n",
|
|
GetLastError());
|
|
CloseHandle(PipeHandle);
|
|
return 0; // Error
|
|
}
|
|
|
|
//
|
|
// Success
|
|
//
|
|
return BytesTransferred;
|
|
}
|
|
|
|
/**
|
|
* @brief close named pipe handle of client
|
|
*
|
|
* @param PipeHandle
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
NamedPipeClientClosePipe(HANDLE PipeHandle)
|
|
{
|
|
CloseHandle(PipeHandle);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Example Server //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* @brief An example of how to use named pipe as a server
|
|
*
|
|
* @return INT32
|
|
*/
|
|
INT32
|
|
NamedPipeServerExample()
|
|
{
|
|
HANDLE PipeHandle;
|
|
BOOLEAN SentMessageResult;
|
|
UINT32 ReadBytes;
|
|
const INT32 BufferSize = 1024;
|
|
CHAR BufferToRead[BufferSize] = {0};
|
|
CHAR BufferToSend[BufferSize] = "test message to send from server !!!";
|
|
|
|
printf("create name pipe\n");
|
|
PipeHandle = NamedPipeServerCreatePipe("\\\\.\\Pipe\\HyperDbgTests",
|
|
BufferSize,
|
|
BufferSize);
|
|
if (!PipeHandle)
|
|
{
|
|
//
|
|
// Error in creating handle
|
|
//
|
|
return 1;
|
|
}
|
|
|
|
printf("success!\n");
|
|
printf("wait for the client connection\n");
|
|
|
|
if (!NamedPipeServerWaitForClientConnection(PipeHandle))
|
|
{
|
|
//
|
|
// Error in connection
|
|
//
|
|
return 1;
|
|
}
|
|
|
|
printf("client connected\n");
|
|
printf("read client message\n");
|
|
|
|
ReadBytes =
|
|
NamedPipeServerReadClientMessage(PipeHandle, BufferToRead, BufferSize);
|
|
|
|
if (!ReadBytes)
|
|
{
|
|
//
|
|
// Nothing to read
|
|
//
|
|
return 1;
|
|
}
|
|
|
|
printf("Message from client : %s\n", BufferToRead);
|
|
|
|
SentMessageResult = NamedPipeServerSendMessageToClient(
|
|
PipeHandle,
|
|
BufferToSend,
|
|
(INT32)strlen(BufferToSend) + 1);
|
|
|
|
if (!SentMessageResult)
|
|
{
|
|
//
|
|
// error in sending
|
|
//
|
|
return 1;
|
|
}
|
|
|
|
NamedPipeServerCloseHandle(PipeHandle);
|
|
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Example Client //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* @brief An example of how to use named pipe as a client
|
|
*
|
|
* @return INT32
|
|
*/
|
|
INT32
|
|
NamedPipeClientExample()
|
|
{
|
|
HANDLE PipeHandle;
|
|
BOOLEAN SentMessageResult;
|
|
UINT32 ReadBytes;
|
|
const INT32 BufferSize = 1024;
|
|
CHAR Buffer[BufferSize] = "test message to send from client !!!";
|
|
PipeHandle = NamedPipeClientCreatePipe("\\\\.\\Pipe\\HyperDbgTests");
|
|
|
|
if (!PipeHandle)
|
|
{
|
|
//
|
|
// Unable to create handle
|
|
//
|
|
return 1;
|
|
}
|
|
|
|
SentMessageResult =
|
|
NamedPipeClientSendMessage(PipeHandle, Buffer, (INT32)strlen(Buffer) + 1);
|
|
|
|
if (!SentMessageResult)
|
|
{
|
|
//
|
|
// Sending error
|
|
//
|
|
return 1;
|
|
}
|
|
|
|
ReadBytes = NamedPipeClientReadMessage(PipeHandle, Buffer, BufferSize);
|
|
|
|
if (!ReadBytes)
|
|
{
|
|
//
|
|
// Nothing to read
|
|
//
|
|
return 1;
|
|
}
|
|
|
|
printf("Server sent the following message: %s\n", Buffer);
|
|
|
|
NamedPipeClientClosePipe(PipeHandle);
|
|
|
|
return 0;
|
|
}
|