Skip to content

Commit

Permalink
Start exposing in-process DVC client APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
Marc-André Moreau authored and awakecoding committed Jun 7, 2024
1 parent 8576130 commit a4dbc74
Show file tree
Hide file tree
Showing 16 changed files with 932 additions and 3 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ include_directories("${CMAKE_SOURCE_DIR}/com")
if(WITH_NATIVE)
add_subdirectory(dll)
add_subdirectory(exe)
add_subdirectory(channels)
endif()

if(WITH_DOTNET)
Expand Down
5 changes: 5 additions & 0 deletions channels/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

add_executable(DvcServer
DvcServer.cpp)

target_link_libraries(DvcServer wtsapi32.lib)
173 changes: 173 additions & 0 deletions channels/DvcServer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
#include <windows.h>
#include <wtsapi32.h>
#include <pchannel.h>
#include <crtdbg.h>
#include <stdio.h>

DWORD OpenVirtualChannel(const char* channelName, HANDLE* phFile)
{
HANDLE hWTSHandle = NULL;
HANDLE hWTSFileHandle;
PVOID vcFileHandlePtr = NULL;
DWORD len;
DWORD rc = ERROR_SUCCESS;

hWTSHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, (LPSTR)channelName, WTS_CHANNEL_OPTION_DYNAMIC);

if (!hWTSHandle)
{
rc = GetLastError();
printf("WTSVirtualChannelOpenEx API Call Failed: GetLastError() = %d\n", GetLastError());
goto exitpt;
}

BOOL bSuccess = WTSVirtualChannelQuery(hWTSHandle, WTSVirtualFileHandle, &vcFileHandlePtr, &len);

if (!bSuccess)
{
rc = GetLastError();
goto exitpt;
}

if (len != sizeof(HANDLE))
{
rc = ERROR_INVALID_PARAMETER;
goto exitpt;
}

hWTSFileHandle = *(HANDLE*)vcFileHandlePtr;

bSuccess = DuplicateHandle(GetCurrentProcess(),
hWTSFileHandle, GetCurrentProcess(), phFile, 0, FALSE, DUPLICATE_SAME_ACCESS);

if (!bSuccess)
{
rc = GetLastError();
goto exitpt;
}

rc = ERROR_SUCCESS;
exitpt:
if (vcFileHandlePtr)
{
WTSFreeMemory(vcFileHandlePtr);
}
if (hWTSHandle)
{
WTSVirtualChannelClose(hWTSHandle);
}
return rc;
}

DWORD WriteVirtualChannelMessage(HANDLE hFile, ULONG cbSize, BYTE* pBuffer)
{
BYTE WriteBuffer[1024];
DWORD dwWritten;
BOOL bSuccess;
HANDLE hEvent;

hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

OVERLAPPED overlapped = { 0 };
overlapped.hEvent = hEvent;

bSuccess = WriteFile(hFile, pBuffer, cbSize, &dwWritten, &overlapped);

if (!bSuccess)
{
if (GetLastError() == ERROR_IO_PENDING)
{
DWORD dwStatus = WaitForSingleObject(overlapped.hEvent, 10000);
bSuccess = GetOverlappedResult(hFile, &overlapped, &dwWritten, FALSE);
}
}

if (!bSuccess)
{
DWORD error = GetLastError();
return error;
}

return 0;
}

DWORD HandleVirtualChannel(HANDLE hFile)
{
BYTE ReadBuffer[CHANNEL_PDU_LENGTH];
DWORD dwRead;
BYTE b = 0;
CHANNEL_PDU_HEADER* pHdr = (CHANNEL_PDU_HEADER*)ReadBuffer;
BOOL bSuccess;
HANDLE hEvent;

const char* cmd = "whoami";
ULONG cbSize = strlen(cmd) + 1;
BYTE* pBuffer = (BYTE*)cmd;
WriteVirtualChannelMessage(hFile, cbSize, pBuffer);

hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

do
{
OVERLAPPED overlapped = { 0 };
DWORD TotalRead = 0;

do {
overlapped.hEvent = hEvent;
bSuccess = ReadFile(hFile, ReadBuffer, sizeof(ReadBuffer), &dwRead, &overlapped);

if (!bSuccess)
{
if (GetLastError() == ERROR_IO_PENDING)
{
DWORD dwStatus = WaitForSingleObject(overlapped.hEvent, INFINITE);
bSuccess = GetOverlappedResult(hFile, &overlapped, &dwRead, FALSE);
}
}

if (!bSuccess)
{
DWORD error = GetLastError();
return error;
}

printf("read %d bytes\n", dwRead);

ULONG packetSize = dwRead - sizeof(*pHdr);
TotalRead += packetSize;
PBYTE pData = (PBYTE)(pHdr + 1);

printf(">> %s\n", (const char*)pData);

} while (0 == (pHdr->flags & CHANNEL_FLAG_LAST));

} while (true);

return 0;
}

INT _cdecl wmain(INT argc, __in_ecount(argc) WCHAR** argv)
{
DWORD rc;
HANDLE hFile;
const char* channelName = "DvcSample";

printf("Opening %s dynamic virtual channel\n", channelName);
rc = OpenVirtualChannel(channelName, &hFile);

if (ERROR_SUCCESS != rc)
{
printf("Failed to open %s dynamic virtual channel\n", channelName);
return 0;
}
else
{
printf("%s dynamic virtual channel is opened\n", channelName);
}

HandleVirtualChannel(hFile);

CloseHandle(hFile);

return 0;
}
2 changes: 2 additions & 0 deletions dll/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ set(MSRDPEX_SOURCES
RdpProcess.cpp
RdpInstance.cpp
RdpSettings.cpp
RdpDvcClient.cpp
RdpDvcClient.h
TSObjects.cpp
TSObjects.h
MsRdpEx.cpp
Expand Down
18 changes: 16 additions & 2 deletions dll/MsRdpEx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@

#include <MsRdpEx/Environment.h>

#include <MsRdpEx/RdpInstance.h>

#include <MsRdpEx/Detours.h>

#include <stdarg.h>
#include <comutil.h>

#include "RdpDvcClient.h"

static HMODULE g_hModule = NULL;

static bool g_AxHookEnabled = true;
Expand All @@ -30,9 +34,19 @@ HRESULT STDAPICALLTYPE DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* p
HRESULT hr = E_UNEXPECTED;
char clsid[MSRDPEX_GUID_STRING_SIZE];
char iid[MSRDPEX_GUID_STRING_SIZE];
const GUID* pclsid = reinterpret_cast<const GUID*>(&rclsid);
const GUID* piid = reinterpret_cast<const GUID*>(&riid);

MsRdpEx_GuidBinToStr(pclsid, clsid, 0);
MsRdpEx_GuidBinToStr(piid, iid, 0);

MsRdpEx_GuidBinToStr((GUID*)&rclsid, clsid, 0);
MsRdpEx_GuidBinToStr((GUID*)&riid, iid, 0);
CMsRdpExInstance* instance = MsRdpEx_InstanceManager_FindBySessionId((GUID*) pclsid);

if (instance) {
hr = DllGetClassObject_DvcPlugin(rclsid, riid, ppv, (void*) instance);
MsRdpEx_LogPrint(DEBUG, "DllGetClassObject_DvcPlugin(%s, %s) with instance %p, hr = 0x%08X", clsid, iid, hr, instance);
return hr;
}

if (g_IsClientProcess) {
if (g_IsOOBClient) {
Expand Down
Loading

0 comments on commit a4dbc74

Please sign in to comment.