HyperDbg/hyperdbg/hprdbgctrl/code/debugger/communication/forwarding.cpp
Behrooz Abbassi f817cbb801
Refactor: Improve projects configurations
- Improve Precompiled header usage
- Change "Output Directory" and "Intermediate Directory" of all projects to the same values
- Discard pdb files from release file
2022-05-04 16:38:21 -07:00

490 lines
14 KiB
C++

/**
* @file forwarding.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Event source forwarding
* @details
* @version 0.1
* @date 2020-11-16
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
//
// Global Variables
//
extern UINT64 g_OutputSourceTag;
extern LIST_ENTRY g_OutputSources;
/**
* @brief Get the output source tag and increase the
* global variable for tag
*
* @return UINT64
*/
UINT64
ForwardingGetNewOutputSourceTag()
{
return g_OutputSourceTag++;
}
/**
* @brief Opens the output source
* @param SourceDescriptor Descriptor of the source
*
* @return DEBUGGER_OUTPUT_SOURCE_STATUS return status of the opening function
*/
DEBUGGER_OUTPUT_SOURCE_STATUS
ForwardingOpenOutputSource(PDEBUGGER_EVENT_FORWARDING SourceDescriptor)
{
//
// Check if already closed
//
if (SourceDescriptor->State == EVENT_FORWARDING_CLOSED)
{
return DEBUGGER_OUTPUT_SOURCE_STATUS_ALREADY_CLOSED;
}
//
// check if already opened
//
if (SourceDescriptor->State == EVENT_FORWARDING_STATE_OPENED)
{
return DEBUGGER_OUTPUT_SOURCE_STATUS_ALREADY_OPENED;
}
//
// Set the status to opened
//
SourceDescriptor->State = EVENT_FORWARDING_STATE_OPENED;
//
// Now, it's time to open the source based on its type
//
if (SourceDescriptor->Type == EVENT_FORWARDING_FILE)
{
//
// Nothing special to do here, file is opened with CreateFile
// and nothing should be called to open the handle
//
return DEBUGGER_OUTPUT_SOURCE_STATUS_SUCCESSFULLY_OPENED;
}
else if (SourceDescriptor->Type == EVENT_FORWARDING_NAMEDPIPE)
{
//
// Nothing special to do here, namedpipe is opened with CreateFile
// and nothing should be called to open the handle
//
return DEBUGGER_OUTPUT_SOURCE_STATUS_SUCCESSFULLY_OPENED;
}
else if (SourceDescriptor->Type == EVENT_FORWARDING_TCP)
{
//
// Nothing special to do here, tcp socket is opened with
// CommunicationClientConnectToServer and nothing should be
// called to open the socket
//
return DEBUGGER_OUTPUT_SOURCE_STATUS_SUCCESSFULLY_OPENED;
}
return DEBUGGER_OUTPUT_SOURCE_STATUS_UNKNOWN_ERROR;
}
/**
* @brief Closes the output source
* @param SourceDescriptor Descriptor of the source
*
* @return DEBUGGER_OUTPUT_SOURCE_STATUS return status of the closing function
*/
DEBUGGER_OUTPUT_SOURCE_STATUS
ForwardingCloseOutputSource(PDEBUGGER_EVENT_FORWARDING SourceDescriptor)
{
//
// Check if already closed
//
if (SourceDescriptor->State == EVENT_FORWARDING_CLOSED)
{
return DEBUGGER_OUTPUT_SOURCE_STATUS_ALREADY_CLOSED;
}
//
// Check if not opened
//
if (SourceDescriptor->State == EVENT_FORWARDING_STATE_NOT_OPENED ||
SourceDescriptor->State != EVENT_FORWARDING_STATE_OPENED)
{
//
// Not opennd ? or state other than opened ?
//
return DEBUGGER_OUTPUT_SOURCE_STATUS_UNKNOWN_ERROR;
}
//
// Set the state
//
SourceDescriptor->State = EVENT_FORWARDING_CLOSED;
//
// Now, it's time to close the source based on its type
//
if (SourceDescriptor->Type == EVENT_FORWARDING_FILE)
{
//
// Close the hanlde
//
CloseHandle(SourceDescriptor->Handle);
//
// Return the status
//
return DEBUGGER_OUTPUT_SOURCE_STATUS_SUCCESSFULLY_CLOSED;
}
else if (SourceDescriptor->Type == EVENT_FORWARDING_TCP)
{
//
// Shutdown connection
//
CommunicationClientShutdownConnection(SourceDescriptor->Socket);
//
// Cleanup
//
CommunicationClientCleanup(SourceDescriptor->Socket);
//
// Return the status
//
return DEBUGGER_OUTPUT_SOURCE_STATUS_SUCCESSFULLY_CLOSED;
}
else if (SourceDescriptor->Type == EVENT_FORWARDING_NAMEDPIPE)
{
//
// Close the file
//
NamedPipeClientClosePipe(SourceDescriptor->Handle);
//
// Return the status
//
return DEBUGGER_OUTPUT_SOURCE_STATUS_SUCCESSFULLY_CLOSED;
}
return DEBUGGER_OUTPUT_SOURCE_STATUS_UNKNOWN_ERROR;
}
/**
* @brief Create a new source (create handle from the source)
* @param SourceType Type of the source
* @param Description Description of the source
* @param Socket Socket object in the case of TCP connection
*
* @details If the target connection is a tcp connection then there
* is no handle and instead there is a socket, this way we pass a
* valid value for handle (TRUE) which is not a valid handle but it
* indicates that the operation was successful and the caller can use
* the pointer that it passed as the socket.
* On anything other than tcp sockets, the socket pointer in not
* modified; thus, it's not value
*
* @return HANDLE returns handle of the source
*/
HANDLE
ForwardingCreateOutputSource(DEBUGGER_EVENT_FORWARDING_TYPE SourceType,
const string & Description,
SOCKET * Socket)
{
string IpPortDelimiter;
string Ip;
string Port;
if (SourceType == EVENT_FORWARDING_FILE)
{
//
// Create a new file
//
HANDLE FileHandle = CreateFileA(Description.c_str(), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
//
// The handle might be INVALID_HANDLE_VALUE which will be
// checked by the caller
//
return FileHandle;
}
else if (SourceType == EVENT_FORWARDING_NAMEDPIPE)
{
HANDLE PipeHandle = NamedPipeClientCreatePipe(Description.c_str());
if (!PipeHandle)
{
//
// Unable to create handle
//
return INVALID_HANDLE_VALUE;
}
return PipeHandle;
}
else if (SourceType == EVENT_FORWARDING_TCP)
{
//
// Check if the port is included in the description string or not
//
if (Description.find(':') != std::string::npos)
{
//
// Split the ip and port by : delimiter
//
IpPortDelimiter = ':';
size_t find = Description.find(IpPortDelimiter);
Ip = Description.substr(0, find);
Port = Description.substr(find + 1, find + Description.size());
//
// Connect to server, in this function 0 means there was no error
// and 1 means there was an error
//
if (CommunicationClientConnectToServer(Ip.c_str(), Port.c_str(), Socket) == 0)
{
//
// Send a fake handle just to avoid sending INVALID_HANDLE_VALUE
// because this functionality doesn't work with handlers; however,
// send 1 or TRUE is a valid handle
//
return (HANDLE)TRUE;
}
else
{
//
// There was an error in connecting to the server
// so return an invalid handle
//
return INVALID_HANDLE_VALUE;
}
}
else
{
//
// Invalid address format
//
return INVALID_HANDLE_VALUE;
}
}
//
// By default, handle is invalid
//
return INVALID_HANDLE_VALUE;
}
/**
* @brief Send the event result to the corresponding sources
* @param EventDetail Description saved about the event in the
* user-mode
* @param MessageLength Length of the message
* @details This function will not check whether the event has an
* output source or not, the caller if this function should make
* sure that the following event has valid output sources or not
*
* @return BOOLEAN whether sending results was successful or not
*/
BOOLEAN
ForwardingPerformEventForwarding(PDEBUGGER_GENERAL_EVENT_DETAIL EventDetail,
CHAR * Message,
UINT32 MessageLength)
{
BOOLEAN Result = FALSE;
PLIST_ENTRY TempList = 0;
for (size_t i = 0; i < DebuggerOutputSourceMaximumRemoteSourceForSingleEvent;
i++)
{
//
// Check whether we reached to the end of the events
//
if (EventDetail->OutputSourceTags[i] == NULL)
{
return Result;
}
//
// If we reach here then the output tag is not null
// means that we should find the event tag from list
// of tags
//
TempList = &g_OutputSources;
while (&g_OutputSources != TempList->Flink)
{
TempList = TempList->Flink;
PDEBUGGER_EVENT_FORWARDING CurrentOutputSourceDetails = CONTAINING_RECORD(
TempList,
DEBUGGER_EVENT_FORWARDING,
OutputSourcesList);
if (EventDetail->OutputSourceTags[i] ==
CurrentOutputSourceDetails->OutputUniqueTag)
{
//
// Indicate that we found a tag that matches this item
// Now, we should check whether the output is opened or
// not closed
//
if (CurrentOutputSourceDetails->State ==
EVENT_FORWARDING_STATE_OPENED)
{
switch (CurrentOutputSourceDetails->Type)
{
case EVENT_FORWARDING_NAMEDPIPE:
Result = ForwardingSendToNamedPipe(
CurrentOutputSourceDetails->Handle,
Message,
MessageLength);
break;
case EVENT_FORWARDING_FILE:
Result = ForwardingWriteToFile(CurrentOutputSourceDetails->Handle,
Message,
MessageLength);
break;
case EVENT_FORWARDING_TCP:
Result = ForwardingSendToTcpSocket(
CurrentOutputSourceDetails->Socket,
Message,
MessageLength);
break;
default:
break;
}
}
//
// No need to search through the list anymore
//
break;
}
}
}
return FALSE;
}
/**
* @brief Write the output results to the file
* @param FileHandle Handle of the target file
* @param Message The message that should be written to file
* @param MessageLength Length of the message
* @details This function will not check whether the event has an
* output source or not, the caller if this function should make
* sure that the following event has valid output sources or not
*
* @return BOOLEAN whether the writing to the file was successful or not
*/
BOOLEAN
ForwardingWriteToFile(HANDLE FileHandle, CHAR * Message, UINT32 MessageLength)
{
DWORD BytesWritten = 0;
BOOL ErrorFlag = FALSE;
ErrorFlag = WriteFile(FileHandle, // open file handle
Message, // start of data to write
MessageLength, // number of bytes to write
&BytesWritten, // number of bytes that were written
NULL); // no overlapped structure
if (ErrorFlag == FALSE)
{
//
// Err, terminal failure: Unable to write to file
//
return FALSE;
}
else
{
if (BytesWritten != MessageLength)
{
//
// This is an error because a synchronous write that results in
// success (WriteFile returns TRUE) should write all data as
// requested. This would not necessarily be the case for
// asynchronous writes.
//
return FALSE;
}
else
{
//
// Successfully wrote
//
return TRUE;
}
}
//
// by default we assume there was an error
//
return FALSE;
}
/**
* @brief Send the output results to the namedpipe
* @param NamedPipeHandle Handle of the target namedpipe
* @param Message The message that should be sent to namedpipe
* @param MessageLength Length of the message
* @details This function will not check whether the event has an
* output source or not, the caller if this function should make
* sure that the following event has valid output sources or not
*
* @return BOOLEAN whether the sending to the namedpipe was successful or not
*/
BOOLEAN
ForwardingSendToNamedPipe(HANDLE NamedPipeHandle, CHAR * Message, UINT32 MessageLength)
{
BOOLEAN SentMessageResult;
SentMessageResult =
NamedPipeClientSendMessage(NamedPipeHandle, Message, MessageLength);
if (!SentMessageResult)
{
//
// Sending error
//
return FALSE;
}
//
// Successfully sent
//
return TRUE;
}
/**
* @brief Send the output results to the tcp socket
* @param TcpSocket Socket object of the target tcp socket
* @param Message The message that should be sent to the tcp socket
* @param MessageLength Length of the message
* @details This function will not check whether the event has an
* output source or not, the caller if this function should make
* sure that the following event has valid output sources or not
*
* @return BOOLEAN whether the sending to the tcp socket was successful or not
*/
BOOLEAN
ForwardingSendToTcpSocket(SOCKET TcpSocket, CHAR * Message, UINT32 MessageLength)
{
if (CommunicationClientSendMessage(TcpSocket, Message, MessageLength) != 0)
{
//
// Failed to send
//
return FALSE;
}
//
// Successfully sent
//
return TRUE;
}