Repository: earthquake/UniversalDVC Branch: master Commit: 9b2f5c0b4bb5 Files: 30 Total size: 98.6 KB Directory structure: gitextract_jle45i16/ ├── .gitattributes ├── .gitignore ├── LICENSE.md ├── README.md ├── UDVC-Plugin/ │ ├── Resource.h │ ├── UDVC-Plugin.cpp │ ├── UDVC-Plugin.def │ ├── UDVC-Plugin.h │ ├── UDVC-Plugin.rc │ ├── UDVC-Plugin.rgs │ ├── UDVC-Plugin.vcxproj │ ├── UDVC-Plugin.vcxproj.filters │ ├── UDVC-PluginPS.vcxproj │ ├── UDVC-PluginPS.vcxproj.filters │ ├── UDVC-Pluginps.def │ ├── UDVCPlugin.idl │ ├── compreg.cpp │ ├── compreg.h │ ├── dllfunc.cpp │ ├── dllmain.cpp │ ├── dllmain.h │ ├── stdafx.cpp │ ├── stdafx.h │ └── targetver.h ├── UDVC-Plugin.reg ├── UDVC-Plugin.sln └── UDVC-Server/ ├── UDVC-Server.cpp ├── UDVC-Server.vcxproj ├── UDVC-Server.vcxproj.filters └── targetver.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ ############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### * text=auto ############################################################################### # Set default behavior for command prompt diff. # # This is need for earlier builds of msysgit that does not have it on by # default for csharp files. # Note: This is only used by command line ############################################################################### #*.cs diff=csharp ############################################################################### # Set the merge driver for project and solution files # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS # the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below ############################################################################### #*.sln merge=binary #*.csproj merge=binary #*.vbproj merge=binary #*.vcxproj merge=binary #*.vcproj merge=binary #*.dbproj merge=binary #*.fsproj merge=binary #*.lsproj merge=binary #*.wixproj merge=binary #*.modelproj merge=binary #*.sqlproj merge=binary #*.wwaproj merge=binary ############################################################################### # behavior for image files # # image files are treated as binary by default. ############################################################################### #*.jpg binary #*.png binary #*.gif binary ############################################################################### # diff behavior for common document formats # # Convert binary document formats to text before diffing them. This feature # is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain #*.DOC diff=astextplain #*.docx diff=astextplain #*.DOCX diff=astextplain #*.dot diff=astextplain #*.DOT diff=astextplain #*.pdf diff=astextplain #*.PDF diff=astextplain #*.rtf diff=astextplain #*.RTF diff=astextplain ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ [Xx]64/ [Xx]86/ [Bb]uild/ bld/ [Bb]in/ [Oo]bj/ # Visual Studio 2015 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # DNX project.lock.json artifacts/ *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db # Visual Studio profiler *.psess *.vsp *.vspx *.sap # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # TODO: Un-comment the next line if you do not want to checkin # your web deploy settings because they may include unencrypted # passwords #*.pubxml *.publishproj # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config # NuGet v3's project.json files produces more ignoreable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directory AppPackages/ BundleArtifacts/ # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ # Others ClientBin/ [Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview *.pfx *.publishsettings node_modules/ orleans.codegen.cs # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files *.mdf *.ldf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # LightSwitch generated files GeneratedArtifacts/ ModelManifest.xml # Paket dependency manager .paket/paket.exe # FAKE - F# Make .fake/ /UDVC-Server/ReadMe.txt ================================================ FILE: LICENSE.md ================================================ MIT License Copyright (c) 2020 Balazs Bucsay Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Universal Dynamic Virtual Channel connector for Remote Desktop Services (UDVC) # Terminal Services (or Remote Desktop Services) are offering many hidden features for those who want to dig deeper. One of these services is the Dynamic Virtual Channel that enables us to communicate over an open RDP connection without the need to open a new socket, connection or a port on a firewall. These channels can be used to hide data from active network devices, to bypass firewalls, to implement device drivers over networks or just to help penetration testers to transfer data. The possibilities are endless. The real reason why this project was created is [XFLTReaT](https://github.com/earthquake/XFLTReaT). This could be used to build up a "VPN" over segregated networks and finally it enables testing over jumpboxes without requesting firewall changes. In a nutshell it makes penetration testers' life easier. ### How does this work? ### You need to install a plugin (*.dll*) on your client computer that you use to connect to the RDP server. On the RDP server you need to use the other half of the project the *.exe*, which creates the channel between the plugin and the server executable. If you want to know more details, please scroll down. ### Installation ### **It is Windows only.** Dynamic Virtual Channels were introduced in **Window Server 2008 & Windows Vista SP1**. These **and** anything **newer** than these should be good to go. You can grab the whole project and compile it by yourself or just use the compiled binaries from the [Releases section](https://github.com/earthquake/UniversalDVC/releases). It is important that the correct binary is used in all cases, please select the correct one for the corresponding architecture (if your client is 32bit but the server is 64bit then grab the 32bit dll and 64bit exe). The *.dll* needs to be placed on the client computer in any directory (for long-term use, you can put it into the %SYSROOT%\\system32\\ or %SYSROOT%\\SysWoW64\\) and install it with the following command as an elevated user (a.k.a Administrator): `regsvr32.exe UDVC-Plugin.dll` If your user is not an administrator, you need to import the registry settings under your user too. Please use the *UDVC-Plugin.reg* file for that. If you wish to remove it: `regsvr32.exe /u UDVC-Plugin.dll` **Every time you connect to an RDP server from now on, this plugin will be loaded and will configure itself as it was specified in the registry (see below).** The *.exe* needs to be put on the RDP server and run as any user. ### Modes supported ### Both sides support three modes at the moment: #### Socket server mode (0 - default) When this mode is enabled, then a listener will be set up on the defined port and interface (IP address). #### Socket client mode (1) In this mode a connection will be made towards a listener on the defined IP address and port. #### Named Pipe mode (2) This mode sets up a Named Pipe with the specified name. As an example: this mode can be used for other tools to do IPC communication over RDP. Unfortunately, Named Pipes are written to the disk so it is considered slow compared to the socket modes. **If you care about the bandwith, please use the socket modes.** ### Options/Configuration ### Both the client and the server binary act the same way and it can be configured with the same options. * **enabled**: *0* disabled, *1* enabled (plugin only). By default it is enabled and will tell you in a messagebox every time you initiate a connection. * **mode**: *0* for listen(), *1* for connect() and *2* for creating a Named Pipe * **ip**: which IP to connect to or bind to * **port**: which port to connect to or bind to * **namedpipename**: name of the named pipe * **priority** (server binary only) *LOW, MEDIUM, HIGH, REAL* priorities for data transmission. *REAL* priority could severely affect the accessibility of the session in case of an intense data transfer, since the protocol prioritizes data over the control. The server binary will read the options from the command line. ``` PS C:\Users\UDVC\> .\UDVC-Server.exe -h Universal Dynamic Virtual Channel server application Usage: C:\Users\UDVC\UDVC-Server.exe [-s | -c [-p port [-h ip]] | -m [-n name]] [-0 | -1 | -2 | -3] Socket server mode -s (default) OR Socket client mode -c: -p port port to bind the listener (default: 31337) -i ip ip to bind the listener (default: 127.0.0.1) Named pipe mode -m: -n name name of the named pipe (by default: "\\.\pipe\UDVC_{RDP SESSION NUMBER}") Data transfer priority parameters: -0 real time (WTS_CHANNEL_OPTION_DYNAMIC_PRI_REAL) -1 high priority (WTS_CHANNEL_OPTION_DYNAMIC_PRI_HIGH) - default -2 medium priority (WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED) -3 low priority (WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW) ``` The client *.dll* reads all the options from the registry, the values can be found under the following key: `HKEY_CURRENT_USER\SOFTWARE\Microsoft\Terminal Server Client\Default\AddIns\UDVC-Plugin` Every time the module is enabled and before the connection is made a reminder warning is showed. Just like this: ![warning](https://github.com/earthquake/UniversalDVC/blob/master/wiki/warning.png?raw=true) This warning ensures that the user knows about the plugin is loaded and with what settings. ### Usage The listeners, connections or named pipes are only created when the server executable was able to connect to the plugin dll. It depends on your configuration, but by default when the Virtual Channel connection was made (the plugin was loaded properly, the server binary was executed) it listens on the localhost:31337 on both endpoints. When you connect to these ports and send data through the socket, it will show up on the other side. ### Example use cases Just to show a few uses cases where this tool can be used. Very basic port forwarding. The Segregated 1 machine has a HTTP service on tcp/80. That network is not routed from the 192.168.0.0/24 network, the dual homed jump box must be used to access. Listen mode is configured on the client side on 0.0.0.0:31337 and the server binary was executed with the connect mode settings to create a connection to the web server. The user on the RDP client can use its browser to open http://127.0.0.1:31337 to access the content from http://10.13.37.2:80. ![scenario1](https://github.com/earthquake/UniversalDVC/blob/master/wiki/scenario1.png?raw=true) A bit more advanced scenario to transfer files. Both endpoints are configured to listen on 0.0.0.0:31337. First the Hacking box connects to the RDP client and waits for the input. Then the Segregated 2 machine connects to the Jump box and reads the whole file into the socket. ![scenario2](https://github.com/earthquake/UniversalDVC/blob/master/wiki/scenario2.png?raw=true) As an extra, Named Pipes can be used as well. In this case both the RDP client and Jump box create a Named Pipe on both sides (hIPC-client and hIPC-server) and the other machines can connect to these pipes. Whatever is written on the pipes it will show up on the other end. It is not really different from the listen mode example above, except it is using Named Pipes instead of TCP sockets. ![scenario3](https://github.com/earthquake/UniversalDVC/blob/master/wiki/scenario3.png?raw=true) ### Issues In case the plugin does not load or the executable does not run because it is missing some DLLs for example the VCRUNTIME140.DLL, you might want to install the [Visual C++ Redistributable for Visual Studio 2015](https://www.microsoft.com/en-us/download/details.aspx?id=48145) package. ================================================ FILE: UDVC-Plugin/Resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by UDVC-Plugin.rc // #define IDS_PROJNAME 100 #define IDR_UDVCPLUGIN 101 #define IDR_UDVCCLIENTPLUGIN 102 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 201 #define _APS_NEXT_COMMAND_VALUE 32768 #define _APS_NEXT_CONTROL_VALUE 201 #define _APS_NEXT_SYMED_VALUE 106 #endif #endif ================================================ FILE: UDVC-Plugin/UDVC-Plugin.cpp ================================================ /* * MIT License * * Copyright(c) 2018-2020 Balazs Bucsay * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files(the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and / or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions : * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "stdafx.h" #include "resource.h" #include "UDVC-Plugin.h" #pragma comment(lib, "Ws2_32.lib") #define UDVC_CHANNEL_NAME "UniversalDVC" struct arguments { DWORD enabled; DWORD mode; // 0 sock listen(); 1 sock connect(); 2 namedpipe WCHAR *namedpipename; WCHAR *ip; WCHAR *port; }; struct threadhandles { SOCKET sock = NULL; SOCKET sockserver = NULL; HANDLE pipe = NULL; }; struct threadargs { struct arguments *running_args; struct threadhandles *threadhandle; IWTSVirtualChannel *m_ptrChannel = NULL; HANDLE hThread = NULL; }; WSADATA wsaData; using namespace ATL; #define CHECK_QUIT_HR( _x_ ) if(FAILED(hr)) { return hr; } class ATL_NO_VTABLE UDVCPlugin : public CComObjectRootEx, public CComCoClass, public IWTSPlugin, public IWTSVirtualChannelCallback, public IWTSListenerCallback { public: CComPtr m_ptrChannel; DECLARE_REGISTRY_RESOURCEID(IDR_UDVCPLUGIN) BEGIN_COM_MAP(UDVCPlugin) COM_INTERFACE_ENTRY(IWTSPlugin) COM_INTERFACE_ENTRY(IWTSVirtualChannelCallback) COM_INTERFACE_ENTRY(IWTSListenerCallback) END_COM_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() { return S_OK; } void FinalRelease() { } // IWTSPlugin. // HRESULT STDMETHODCALLTYPE Initialize(IWTSVirtualChannelManager *pChannelMgr); HRESULT STDMETHODCALLTYPE Connected(); HRESULT STDMETHODCALLTYPE Disconnected(DWORD dwDisconnectCode) { // Prevent C4100 "unreferenced parameter" warnings. WSACleanup(); dwDisconnectCode; return S_OK; } HRESULT STDMETHODCALLTYPE Terminated() { return S_OK; } VOID SetChannel(IWTSVirtualChannel *pChannel, struct threadargs *pTa); // IWTSVirtualChannelCallback // HRESULT STDMETHODCALLTYPE OnDataReceived(ULONG cbSize, __in_bcount(cbSize) BYTE *pBuffer); HRESULT STDMETHODCALLTYPE OnClose() { DebugPrint(0, L"[*] Terminating thread, closing socket and channel"); if (pta->threadhandle->sockserver) closesocket(pta->threadhandle->sockserver); TerminateThread(pta->hThread, 0); return S_OK;// m_ptrChannel->Close(); } HRESULT STDMETHODCALLTYPE OnNewChannelConnection( __in IWTSVirtualChannel *pChannel, __in_opt BSTR data, __out BOOL *pbAccept, __out IWTSVirtualChannelCallback **ppCallback); // non-inherited ones struct threadargs ta, *pta; struct arguments running_args; struct threadhandles threadhandle; static VOID UDVCPlugin::DebugPrint(HRESULT hrDbg, __in_z LPWSTR fmt, ...); LONG UDVCPlugin::GetDWORDRegKey(HKEY hKey, WCHAR *strValueName, DWORD *nValue); LONG UDVCPlugin::GetStringRegKey(HKEY hKey, WCHAR *strValueName, WCHAR **strValue); BOOL UDVCPlugin::GetRegistrySettings(); static DWORD WINAPI UDVCPlugin::ListenerThread(PVOID param); static DWORD WINAPI UDVCPlugin::RsWcThread(PVOID param); }; OBJECT_ENTRY_AUTO(__uuidof(CompReg), UDVCPlugin) VOID UDVCPlugin::DebugPrint(HRESULT hrDbg, __in_z LPWSTR fmt, ...) { HRESULT hr; TCHAR Buffer[DEBUG_PRINT_BUFFER_SIZE]; size_t Len; hr = StringCchPrintf(Buffer, DEBUG_PRINT_BUFFER_SIZE, TEXT("[hr=0x%8x]"), hrDbg); assert(SUCCEEDED(hr)); // buffer is sure to be big enough hr = StringCchLength(Buffer, DEBUG_PRINT_BUFFER_SIZE, &Len); assert(SUCCEEDED(hr)); // StringCchPrintf is supposed to always NULL term va_list argptr; va_start(argptr, fmt); hr = StringCchVPrintf(Buffer + Len, DEBUG_PRINT_BUFFER_SIZE - Len, fmt, argptr); // the above could fail but we don't care since we // should get a NULL terminated partial string // insert terminating eol (despite failure) hr = StringCchLength(Buffer, DEBUG_PRINT_BUFFER_SIZE, &Len); assert(SUCCEEDED(hr)); // again there should be a NULL term if (Len < DEBUG_PRINT_BUFFER_SIZE - 1) { Len++; Buffer[Len] = TEXT('\0'); } Buffer[Len - 1] = TEXT('\n'); OutputDebugString(Buffer); } LONG UDVCPlugin::GetDWORDRegKey(HKEY hKey, WCHAR *strValueName, DWORD *nValue) { DWORD dwBufferSize(sizeof(DWORD)); DWORD nResult; LONG nError; if ((nError = RegQueryValueEx(hKey, strValueName, 0, NULL, (LPBYTE)&nResult, &dwBufferSize)) == ERROR_SUCCESS) { *nValue = nResult; } return nError; } LONG UDVCPlugin::GetStringRegKey(HKEY hKey, WCHAR *strValueName, WCHAR **strValue) { LPVOID szTemp = NULL; DWORD buflen = 255; LONG nError; if ((szTemp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (size_t)buflen)) == NULL) { DebugPrint(GetLastError(), L"[-] Error allocating heap for read buffer %ld", GetLastError()); return -1; } if ((nError = RegQueryValueExW(hKey, strValueName, 0, NULL, (LPBYTE)szTemp, &buflen)) != ERROR_SUCCESS) { HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, szTemp); szTemp = NULL; } *strValue = (WCHAR *)szTemp; return nError; } BOOL UDVCPlugin::GetRegistrySettings() { HKEY hKey; LONG lRes; WCHAR *szTemp; if ((lRes = RegOpenKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Terminal Server Client\\Default\\AddIns\\UDVC-Plugin\\", 0, KEY_READ, &hKey)) != ERROR_SUCCESS) { DebugPrint(lRes, L"[-] Error opening registry hive/key"); return FALSE; } GetDWORDRegKey(hKey, L"enabled", &running_args.enabled); GetDWORDRegKey(hKey, L"mode", &(running_args.mode)); if ((running_args.mode == 0) || (running_args.mode == 1)) { GetStringRegKey(hKey, L"ip", &szTemp); if (szTemp != NULL) { if (wcslen(szTemp) < 16) { running_args.ip = szTemp; } else { MessageBox(NULL, L"IP too long. Please fix it under the following key:\r\nHKCU\\SOFTWARE\\Microsoft\\Terminal Server Client\\Default\\AddIns\\UDVC-Plugin\\", L"Registry value error", MB_OK); } } GetStringRegKey(hKey, L"port", &szTemp); if (szTemp != NULL) { if (wcslen(szTemp) < 6) { running_args.port = szTemp; } else { MessageBox(NULL, L"Port too long. Please fix it under the following key:\r\nHKCU\\SOFTWARE\\Microsoft\\Terminal Server Client\\Default\\AddIns\\UDVC-Plugin\\", L"Registry value error", MB_OK); } } } if (running_args.mode == 2) { GetStringRegKey(hKey, L"namedpipename", &szTemp); if (szTemp != NULL) { if (wcsncmp(szTemp, L"\\\\.\\pipe\\", 9)) { MessageBox(NULL, L"Named pipe name has to start with: \\\\.\\pipe\\\r\nPlease fix it under the following key:\r\nHKCU\\SOFTWARE\\Microsoft\\Terminal Server Client\\Default\\AddIns\\UDVC-Plugin\\", L"Registry value error", MB_OK); } else { running_args.namedpipename = szTemp; } } } return TRUE; } // IWTSPlugin::Initialize implementation. HRESULT UDVCPlugin::Initialize(__in IWTSVirtualChannelManager *pChannelMgr) { HRESULT hr; CComObject *pListenerCallback; CComPtr ptrListenerCallback; CComPtr ptrListener; WCHAR enabledmsg[256]; int ret; running_args.enabled = 0; running_args.mode = 0; running_args.port = L"31337"; running_args.namedpipename = L"\\\\.\\pipe\\UDVC_default"; running_args.ip = L"127.0.0.1"; if (!GetRegistrySettings()) { DebugPrint(-1, L"[-] Could not access the registry settings"); } if (!running_args.enabled) { DebugPrint(0, L"[*] Plugin disabled"); return -1; } if ((ret = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) { DebugPrint(ret, L"WSAStartup() failed with error: %ld", ret); return -1; } if (running_args.mode == 0) wnsprintf(enabledmsg, 255, L"The UDVC plugin is enabled. When the server binary gets executed, it will listen on: %s:%s", running_args.ip, running_args.port); if (running_args.mode == 1) wnsprintf(enabledmsg, 255, L"The UDVC plugin is enabled. When the server binary gets executed, it will connect to: %s:%s", running_args.ip, running_args.port); if (running_args.mode == 2) wnsprintf(enabledmsg, 255, L"The UDVC plugin is enabled. When the server binary gets executed, it will listen on: %s", running_args.namedpipename); MessageBox(NULL, enabledmsg, L"UDVC plugin is enabled", MB_OK | MB_ICONWARNING); // Create an instance of the CSampleListenerCallback object. hr = CComObject::CreateInstance(&pListenerCallback); CHECK_QUIT_HR("CSampleListenerCallback::CreateInstance"); ptrListenerCallback = pListenerCallback; // Attach the callback to the endpoint. hr = pChannelMgr->CreateListener( UDVC_CHANNEL_NAME, 0, (UDVCPlugin*)ptrListenerCallback, &ptrListener); CHECK_QUIT_HR("CreateListener"); return hr; } HRESULT STDMETHODCALLTYPE UDVCPlugin::Connected() { return S_OK; } DWORD UDVCPlugin::ListenerThread(PVOID param) { struct threadargs *threadarg = (struct threadargs *)param; ADDRINFOW *result = NULL; ADDRINFOW hints; SOCKET s, c; HANDLE hNamedPipe = NULL; int ret; u_long blocking = 0; if (threadarg->running_args->mode == 0) { DebugPrint(0, L"[*] Setting up server socket"); ZeroMemory(&hints, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; if ((ret = GetAddrInfoW(threadarg->running_args->ip, threadarg->running_args->port, &hints, &result)) != 0) { DebugPrint(ret, L"[-] GetAddrInfoW() failed with error: %ld", ret); return -1; } if ((s = socket(result->ai_family, result->ai_socktype, result->ai_protocol)) == INVALID_SOCKET) { DebugPrint(WSAGetLastError(), L"[-] socket() failed with error: %ld", WSAGetLastError()); FreeAddrInfoW(result); return -1; } threadarg->threadhandle->sockserver = s; if ((ret = bind(s, result->ai_addr, (int)result->ai_addrlen)) == SOCKET_ERROR) { DebugPrint(WSAGetLastError(), L"[-] bind() failed with error: %ld", WSAGetLastError()); FreeAddrInfoW(result); closesocket(s); return -1; } FreeAddrInfoW(result); DebugPrint(0, L"[*] Listening on: %s:%s", threadarg->running_args->ip, threadarg->running_args->port); if ((ret = listen(s, SOMAXCONN)) == SOCKET_ERROR) { DebugPrint(WSAGetLastError(), L"[-] listen() failed with error: %ld", WSAGetLastError()); closesocket(s); return -1; } if ((c = accept(s, NULL, NULL)) == INVALID_SOCKET) { DebugPrint(WSAGetLastError(), L"[-] accept() failed with error: %ld", WSAGetLastError()); closesocket(s); return -1; } DebugPrint(0, L"[+] Client connected"); closesocket(s); threadarg->threadhandle->sockserver = NULL; ret = ioctlsocket(c, FIONBIO, &blocking); if (ret != NO_ERROR) { DebugPrint(ret, L"[-] ioctlsocket() failed with error: %ld", ret); closesocket(c); return -1; } threadarg->threadhandle->sock = c; } if (threadarg->running_args->mode == 1) { DebugPrint(0, L"[*] Setting up client socket"); ZeroMemory(&hints, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; if ((ret = GetAddrInfoW(threadarg->running_args->ip, threadarg->running_args->port, &hints, &result)) != 0) { DebugPrint(ret, L"[-] GetAddrInfoW() failed with error: %ld", ret); return -1; } if ((c = socket(result->ai_family, result->ai_socktype, result->ai_protocol)) == INVALID_SOCKET) { DebugPrint(WSAGetLastError(), L"[-] socket() failed with error: %ld", WSAGetLastError()); FreeAddrInfoW(result); return -1; } if ((ret = connect(c, result->ai_addr, (int)result->ai_addrlen)) == SOCKET_ERROR) { DebugPrint(WSAGetLastError(), L"[-] connect() failed with error: %ld", WSAGetLastError()); FreeAddrInfoW(result); closesocket(c); return -1; } FreeAddrInfoW(result); DebugPrint(0, L"[*] Connected to: %s:%s", threadarg->running_args->ip, threadarg->running_args->port); ret = ioctlsocket(c, FIONBIO, &blocking); if (ret != NO_ERROR) { DebugPrint(ret, L"[-] ioctlsocket() failed with error: %ld", ret); closesocket(c); return -1; } threadarg->threadhandle->sock = c; } if (threadarg->running_args->mode == 2) { DebugPrint(0, L"[*] Setting up named pipe"); if ((hNamedPipe = CreateNamedPipe(threadarg->running_args->namedpipename, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, 1, 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL)) == INVALID_HANDLE_VALUE) { DebugPrint(GetLastError(), L"[-] CreateNamedPipe() failed with: %ld", GetLastError()); return -1; } DebugPrint(0, L"[*] Listening on pipe: %s\n", threadarg->running_args->namedpipename); if (!ConnectNamedPipe(hNamedPipe, NULL)) { DebugPrint(GetLastError(), L"[-] ConnectNamedPipe() failed with: %ld", GetLastError()); return -1; } threadarg->threadhandle->pipe = hNamedPipe; DebugPrint(0, L"[+] Client connected to the pipe."); } return RsWcThread(param); } DWORD WINAPI UDVCPlugin::RsWcThread(PVOID param) { struct threadargs *threadarg = (struct threadargs *)param; DWORD dw; BOOL bSucc; HANDLE hEvent_pipe; BYTE *readBuf; DWORD heapsize = 4096; if ((readBuf = (BYTE *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, heapsize)) == NULL) { DebugPrint(GetLastError(), L"[-] Error allocating heap for read buffer %ld", GetLastError()); return -1; } hEvent_pipe = CreateEvent(NULL, FALSE, FALSE, NULL); OVERLAPPED Overlapped_pipe = { 0 }; Overlapped_pipe.hEvent = hEvent_pipe; while (TRUE) { if (threadarg->threadhandle->sock) { if ((dw = recv(threadarg->threadhandle->sock, (char *)readBuf, heapsize, 0)) == INVALID_SOCKET) { DebugPrint(WSAGetLastError(), L"[-] [RsWc] recv() failed with error %d, exiting thread...\n", WSAGetLastError()); return -1; } if (dw == 0) { DebugPrint(WSAGetLastError(), L"[-] [RsWc] socket closed, exiting thread...\n", WSAGetLastError()); return -1; } } if (threadarg->threadhandle->pipe) { bSucc = ReadFile(threadarg->threadhandle->pipe, readBuf, heapsize, &dw, &Overlapped_pipe); if (!bSucc) { if (GetLastError() == ERROR_IO_PENDING) { dw = WaitForSingleObject(Overlapped_pipe.hEvent, INFINITE); bSucc = GetOverlappedResult(threadarg->threadhandle->pipe, &Overlapped_pipe, &dw, FALSE); } } if (!bSucc) { DebugPrint(GetLastError(), L"[-] [RsWc] ReadFile()/WaitForSingleObject() error: %ld\n", GetLastError()); return -1; } if (ResetEvent(Overlapped_pipe.hEvent) == FALSE) { DebugPrint(GetLastError(), L"[-] [RsWc] ResetEvent() failed with error = %d\n", GetLastError()); return -1; } } if (threadarg->m_ptrChannel != NULL) threadarg->m_ptrChannel->Write(dw, readBuf, NULL); else return -1; } return 0; } // IWTSListenerCallback::OnNewChannelConnection implementation. HRESULT UDVCPlugin::OnNewChannelConnection(__in IWTSVirtualChannel *pChannel, __in_opt BSTR data, __out BOOL *pbAccept, __out IWTSVirtualChannelCallback **ppCallback) { HRESULT hr; DWORD dwThreadId; CComObject *pCallback; CComPtr ptrCallback; // Prevent C4100 "unreferenced parameter" warnings. data; *pbAccept = FALSE; hr = CComObject::CreateInstance(&pCallback); CHECK_QUIT_HR("UDVCPlugin::CreateInstance"); ptrCallback = pCallback; ptrCallback->SetChannel(pChannel, &ta); ta.running_args = &running_args; ta.threadhandle = &threadhandle; ta.m_ptrChannel = pChannel; running_args.enabled = 0; running_args.mode = 0; running_args.port = L"31337"; running_args.namedpipename = L"\\\\.\\pipe\\UDVC_default"; running_args.ip = L"127.0.0.1"; if (!GetRegistrySettings()) { DebugPrint(-1, L"[-] Could not access the registry settings"); } HANDLE hListenerThread = CreateThread( NULL, 0, &UDVCPlugin::ListenerThread, &ta, 0, &dwThreadId); ta.hThread = hListenerThread; *ppCallback = ptrCallback; (*ppCallback)->AddRef(); *pbAccept = TRUE; return hr; } VOID UDVCPlugin::SetChannel(IWTSVirtualChannel *pChannel, struct threadargs *pTa) { m_ptrChannel = pChannel; pta = pTa; } HRESULT STDMETHODCALLTYPE UDVCPlugin::OnDataReceived(ULONG cbSize, __in_bcount(cbSize) BYTE *pBuffer) { DWORD ret, dw; HANDLE hEvent; BOOL bSucc; hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); OVERLAPPED Overlapped = { 0 }; Overlapped.hEvent = hEvent; if (pta->threadhandle->sock) { if ((ret = send(pta->threadhandle->sock, (char *)pBuffer, cbSize, 0)) == SOCKET_ERROR) { DebugPrint(WSAGetLastError(), L"[-] [RsWc] send() failed with error %ld", WSAGetLastError()); m_ptrChannel->Close(); return -1; } } if (pta->threadhandle->pipe) { bSucc = WriteFile(pta->threadhandle->pipe, pBuffer, cbSize, &ret, &Overlapped); if (!bSucc) { if (GetLastError() == ERROR_IO_PENDING) { dw = WaitForSingleObject(Overlapped.hEvent, INFINITE); bSucc = GetOverlappedResult(pta->threadhandle->pipe, &Overlapped, &ret, FALSE); } } if (!bSucc) { DebugPrint(GetLastError(), L"[-] [RsWc] WriteFile()/WaitForSingleObject() error: %ld", GetLastError()); m_ptrChannel->Close(); return -1; } } return ret; } ================================================ FILE: UDVC-Plugin/UDVC-Plugin.def ================================================ ; UDVC-Plugin.def : Declares the module parameters. LIBRARY EXPORTS DllCanUnloadNow PRIVATE DllGetClassObject PRIVATE DllRegisterServer PRIVATE DllUnregisterServer PRIVATE DllInstall PRIVATE ================================================ FILE: UDVC-Plugin/UDVC-Plugin.h ================================================ // TsClientPlgn.h : Declaration of the CTsClientPlgn #pragma once #include "stdafx.h" #include "resource.h" // main symbols #include "UDVCPlugin_i.h" // debug #include #include #if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) #error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." #endif // CTsClientPlgn class ATL_NO_VTABLE CTsClientPlgn : public CComObjectRootEx, public CComCoClass, public IDispatchImpl, public IWTSPlugin, public IWTSListenerCallback, public IWTSVirtualChannelCallback { public: CTsClientPlgn(): _hCurrentFile(INVALID_HANDLE_VALUE) { } DECLARE_REGISTRY_RESOURCEID(IDR_UDVCCLIENTPLUGIN) BEGIN_COM_MAP(CTsClientPlgn) COM_INTERFACE_ENTRY(IComponentRegistrar) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(IWTSPlugin) COM_INTERFACE_ENTRY(IWTSListenerCallback) COM_INTERFACE_ENTRY(IWTSVirtualChannelCallback) END_COM_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() { return S_OK; } void FinalRelease() { } // IWTSPlugin public: /* * Called immediately after instantiating the COM class */ STDMETHOD(Initialize)( IWTSVirtualChannelManager *pChannelMgr ); /* * Called when the TS client is connected to the TS server */ STDMETHOD(Connected)(); /* * Called when the TS client is disconnected to the TS server * Might be followed by another Connected() call */ STDMETHOD(Disconnected)( DWORD dwDisconnectCode ); /* * The last method called by the TS client before * terminating the object */ STDMETHOD(Terminated)(); // IWTSListenerCallback public: VOID CTsClientPlgn::SetChannel(IWTSVirtualChannel *pChannel); public: /* * Called whenever a request for new channel connection * from the server is received. */ STDMETHOD(OnNewChannelConnection)( IWTSVirtualChannel *pChannel, BSTR data, // optional data passed as part of the connect method BOOL *pbAccept, // the callee should return TRUE if connection is accepted IWTSVirtualChannelCallback **ppCallback // connection related events ); // IWTSVirtualChannelCallback public: /* * Called whenever a full message from the server is received * The message is fully reassembled and has the exact size * as the Write() call on the server */ STDMETHOD(OnDataReceived)( ULONG cbSize, // size of data in bytes BYTE *pBuffer // data buffer ); /* * The channel is disconnected, all Write() calls will fail * no more incomming data is expected. */ STDMETHOD(OnClose)(); private: HRESULT CleanState(); HRESULT StartFile( __in_z LPWSTR szFileName, BOOL bDir); HRESULT WriteData( __in_bcount(usLen) PBYTE pData, USHORT usLen); HRESULT EndFile(BOOL bDir); CComPtr _spListener; CComPtr _spChannel; HANDLE _hCurrentFile; WStringVector _vDirList; }; //OBJECT_ENTRY_AUTO(__uuidof(CompReg), CTsClientPlgn) // DEBUG: #define DEBUG_PRINT_BUFFER_SIZE 1024 ================================================ FILE: UDVC-Plugin/UDVC-Plugin.rgs ================================================ HKCR { CLSID { UDVC-Plugin.UDVC-Plugin.1 = s 'UDVC-Plugin Class' { CLSID = s '{3C8458A3-2EBE-4840-BB07-3BA5BF810588}' } UDVC-Plugin.UDVC-Plugin = s 'UDVC-Plugin Class' { CLSID = s '{3C8458A3-2EBE-4840-BB07-3BA5BF810588}' CurVer = s 'UDVC-Plugin.UDVC-Plugin.1' } ForceRemove {3C8458A3-2EBE-4840-BB07-3BA5BF810588} = s 'UDVC-Plugin Class' { ProgID = s 'UDVC-Plugin.UDVC-Plugin.1' VersionIndependentProgID = s 'UDVC-Plugin.UDVC-Plugin' ForceRemove 'Programmable' InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Free' } 'TypeLib' = s '{392B9DEE-7E00-4C58-831B-50C58EAA887F}' } } } HKCU { Software { Microsoft { 'Terminal Server Client' { Default { AddIns { UDVC-Plugin { val Name = s '{3C8458A3-2EBE-4840-BB07-3BA5BF810588}' val namedpipename = s '\\.\pipe\UDVC_default' val ip = s '127.0.0.1' val port = s '31337' val mode = d '0' val enabled = d '1' } } } } } } } ================================================ FILE: UDVC-Plugin/UDVC-Plugin.vcxproj ================================================  Debug Win32 Release Win32 Debug x64 Release x64 {9402DF45-A060-4881-9F64-D16E094B97A7} 8.1 AtlProj DynamicLibrary true v140 Unicode DynamicLibrary false v140 Unicode DynamicLibrary true v140 Unicode DynamicLibrary false v140 Unicode true true $(SolutionDir)$(Configuration)\$(Platform)\ $(Platform)\$(Configuration)\ true true $(SolutionDir)$(Configuration)\$(Platform)\ true false $(SolutionDir)$(Configuration)\$(Platform)\ $(Platform)\$(Configuration)\ true false $(SolutionDir)$(Configuration)\$(Platform)\ Use Level3 Disabled WIN32;_WINDOWS;_DEBUG;_USRDLL;%(PreprocessorDefinitions) true false Win32 _DEBUG;%(PreprocessorDefinitions) UDVCPlugin_i.h UDVCPlugin_i.c UDVCPlugin_p.c true $(IntDir)UDVCPlugin.tlb true 0x0409 $(IntDir);%(AdditionalIncludeDirectories) _DEBUG;%(PreprocessorDefinitions) Windows .\UDVC-Plugin.def comsvcs.lib;%(AdditionalDependencies) true Use Level3 Disabled _WINDOWS;_DEBUG;_USRDLL;%(PreprocessorDefinitions) true false _DEBUG;%(PreprocessorDefinitions) UDVCPlugin_i.h UDVCPlugin_i.c UDVCPlugin_p.c true $(IntDir)UDVCPlugin.tlb true 0x0409 $(IntDir);%(AdditionalIncludeDirectories) _DEBUG;%(PreprocessorDefinitions) Windows .\UDVC-Plugin.def comsvcs.lib;%(AdditionalDependencies) true Use Level3 MaxSpeed WIN32;_WINDOWS;NDEBUG;_USRDLL;%(PreprocessorDefinitions) true false Win32 NDEBUG;%(PreprocessorDefinitions) UDVCPlugin_i.h UDVCPlugin_i.c UDVCPlugin_p.c true $(IntDir)UDVCPlugin.tlb true 0x0409 $(IntDir);%(AdditionalIncludeDirectories) NDEBUG;%(PreprocessorDefinitions) Windows .\UDVC-Plugin.def comsvcs.lib;%(AdditionalDependencies) true true true Use Level3 MaxSpeed _WINDOWS;NDEBUG;_USRDLL;%(PreprocessorDefinitions) true false NDEBUG;%(PreprocessorDefinitions) UDVCPlugin_i.h UDVCPlugin_i.c UDVCPlugin_p.c true $(IntDir)UDVCPlugin.tlb true 0x0409 $(IntDir);%(AdditionalIncludeDirectories) NDEBUG;%(PreprocessorDefinitions) Windows .\UDVC-Plugin.def comsvcs.lib;%(AdditionalDependencies) true true true false false false false Create Create Create Create false false false false ================================================ FILE: UDVC-Plugin/UDVC-Plugin.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {2467f173-a17f-4363-a3f3-5f66776727f8} False Source Files Source Files Source Files Generated Files Source Files Source Files Header Files Header Files Header Files Header Files Generated Files Header Files Header Files Resource Files Resource Files Source Files Source Files ================================================ FILE: UDVC-Plugin/UDVC-PluginPS.vcxproj ================================================  Debug Win32 Release Win32 Debug x64 Release x64 {15DEE2D8-6972-49C0-9369-35730A29A2CF} AtlPSProj 8.1 DynamicLibrary true v140 Unicode DynamicLibrary false v140 Unicode DynamicLibrary true v140 Unicode DynamicLibrary false v140 Unicode $(Platform)\$(Configuration)PS\ $(SolutionDir)$(Configuration)\$(Platform)\ $(Platform)\$(Configuration)PS\ $(SolutionDir)$(Configuration)\$(Platform)\ $(Platform)\$(Configuration)PS\ $(SolutionDir)$(Configuration)\$(Platform)\ $(Platform)\$(Configuration)PS\ $(SolutionDir)$(Configuration)\$(Platform)\ WIN32;REGISTER_PROXY_DLL;_DEBUG;%(PreprocessorDefinitions) kernel32.lib;rpcns4.lib;rpcrt4.lib;oleaut32.lib;uuid.lib;ole32.lib;advapi32.lib;comsvcs.lib;%(AdditionalDependencies) UDVC-PluginPS.def true if exist dlldata.c goto :END echo Error: MIDL will not generate DLLDATA.C unless you have at least 1 interface in the main project. Exit 1 :END Checking for required files REGISTER_PROXY_DLL;_DEBUG;%(PreprocessorDefinitions) kernel32.lib;rpcns4.lib;rpcrt4.lib;oleaut32.lib;uuid.lib;ole32.lib;advapi32.lib;comsvcs.lib;%(AdditionalDependencies) UDVC-PluginPS.def true if exist dlldata.c goto :END echo Error: MIDL will not generate DLLDATA.C unless you have at least 1 interface in the main project. Exit 1 :END Checking for required files MaxSpeed WIN32;REGISTER_PROXY_DLL;NDEBUG;%(PreprocessorDefinitions) kernel32.lib;rpcns4.lib;rpcrt4.lib;oleaut32.lib;uuid.lib;ole32.lib;advapi32.lib;comsvcs.lib;%(AdditionalDependencies) UDVC-PluginPS.def true true true if exist dlldata.c goto :END echo Error: MIDL will not generate DLLDATA.C unless you have at least 1 interface in the main project. Exit 1 :END Checking for required files MaxSpeed REGISTER_PROXY_DLL;NDEBUG;%(PreprocessorDefinitions) kernel32.lib;rpcns4.lib;rpcrt4.lib;oleaut32.lib;uuid.lib;ole32.lib;advapi32.lib;comsvcs.lib;%(AdditionalDependencies) UDVC-PluginPS.def true true true if exist dlldata.c goto :END echo Error: MIDL will not generate DLLDATA.C unless you have at least 1 interface in the main project. Exit 1 :END Checking for required files ================================================ FILE: UDVC-Plugin/UDVC-PluginPS.vcxproj.filters ================================================  {3ae88138-7c28-4919-a9b2-4b5e1473c72b} {d3ce00e0-04ef-4a7b-ad63-435441b697a5} False Generated Files Generated Files Generated Files ================================================ FILE: UDVC-Plugin/UDVC-Pluginps.def ================================================ LIBRARY EXPORTS DllGetClassObject PRIVATE DllCanUnloadNow PRIVATE DllRegisterServer PRIVATE DllUnregisterServer PRIVATE ================================================ FILE: UDVC-Plugin/UDVCPlugin.idl ================================================ // UDVCPlugin.idl : IDL source for UDVC-Plugin // // This file will be processed by the MIDL tool to // produce the type library (UDVCPlugin.tlb) and marshalling code. import "oaidl.idl"; import "ocidl.idl"; [ object, uuid(a817e7a2-43fa-11d0-9e44-00aa00b6770a), dual, pointer_default(unique) ] interface IComponentRegistrar : IDispatch { [id(1)] HRESULT Attach([in] BSTR bstrPath); [id(2)] HRESULT RegisterAll(); [id(3)] HRESULT UnregisterAll(); [id(4)] HRESULT GetComponents([out] SAFEARRAY(BSTR)* pbstrCLSIDs, [out] SAFEARRAY(BSTR)* pbstrDescriptions); [id(5)] HRESULT RegisterComponent([in] BSTR bstrCLSID); [id(6)] HRESULT UnregisterComponent([in] BSTR bstrCLSID); }; [ uuid(392B9DEE-7E00-4C58-831B-50C58EAA887F), version(1.0), custom(a817e7a1-43fa-11d0-9e44-00aa00b6770a,"{3C8458A3-2EBE-4840-BB07-3BA5BF810588}") ] library UDVCPluginLib { importlib("stdole2.tlb"); [ uuid(3C8458A3-2EBE-4840-BB07-3BA5BF810588) ] coclass CompReg { [default] interface IComponentRegistrar; }; }; ================================================ FILE: UDVC-Plugin/compreg.cpp ================================================ // compreg.cpp : Implementation of CCompReg #include "stdafx.h" #include "compreg.h" // CCompReg ================================================ FILE: UDVC-Plugin/compreg.h ================================================ // compreg.h : Declaration of the CCompReg #pragma once #include "resource.h" // main symbols #include "UDVCPlugin_i.h" ================================================ FILE: UDVC-Plugin/dllfunc.cpp ================================================ /* * MIT License * * Copyright(c) 2018 Balazs Bucsay * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files(the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and / or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions : * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "stdafx.h" #include "resource.h" #include "UDVCPlugin_i.h" #include "dllmain.h" #include "compreg.h" using namespace ATL; // Used to determine whether the DLL can be unloaded by OLE. STDAPI DllCanUnloadNow(void) { return _AtlModule.DllCanUnloadNow(); } // Returns a class factory to create an object of the requested type. _Check_return_ STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID* ppv) { return _AtlModule.DllGetClassObject(rclsid, riid, ppv); } // DllRegisterServer - Adds entries to the system registry. STDAPI DllRegisterServer(void) { // registers object, typelib and all interfaces in typelib HRESULT hr = _AtlModule.DllRegisterServer(); return hr; } // DllUnregisterServer - Removes entries from the system registry. STDAPI DllUnregisterServer(void) { HRESULT hr = _AtlModule.DllUnregisterServer(); return hr; } // DllInstall - Adds/Removes entries to the system registry per user per machine. STDAPI DllInstall(BOOL bInstall, _In_opt_ LPCWSTR pszCmdLine) { HRESULT hr = E_FAIL; static const wchar_t szUserSwitch[] = L"user"; if (pszCmdLine != NULL) { if (_wcsnicmp(pszCmdLine, szUserSwitch, _countof(szUserSwitch)) == 0) { ATL::AtlSetPerUserRegistration(true); } } if (bInstall) { hr = DllRegisterServer(); if (FAILED(hr)) { DllUnregisterServer(); } } else { hr = DllUnregisterServer(); } return hr; } ================================================ FILE: UDVC-Plugin/dllmain.cpp ================================================ /* * MIT License * * Copyright(c) 2018 Balazs Bucsay * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files(the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and / or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions : * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "stdafx.h" #include "resource.h" #include "UDVCPlugin_i.h" #include "dllmain.h" #include "compreg.h" CUDVCPluginModule _AtlModule; // DLL Entry Point extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { hInstance; return _AtlModule.DllMain(dwReason, lpReserved); } ================================================ FILE: UDVC-Plugin/dllmain.h ================================================ // dllmain.h : Declaration of module class. class CUDVCPluginModule : public ATL::CAtlDllModuleT< CUDVCPluginModule > { public : DECLARE_LIBID(LIBID_UDVCPluginLib) DECLARE_REGISTRY_APPID_RESOURCEID(IDR_UDVCPLUGIN, "{B8DC075B-7F8D-4B06-8733-7EB586CA06F0}") }; extern class CUDVCPluginModule _AtlModule; ================================================ FILE: UDVC-Plugin/stdafx.cpp ================================================ /* * MIT License * * Copyright(c) 2018 Balazs Bucsay * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files(the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and / or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions : * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "stdafx.h" ================================================ FILE: UDVC-Plugin/stdafx.h ================================================ // stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, // but are changed infrequently #pragma once #ifndef STRICT #define STRICT #endif #include "targetver.h" #define _ATL_APARTMENT_THREADED #define _ATL_NO_AUTOMATIC_NAMESPACE #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit #define _ATL_REGISTER_PER_USER // This setting must be consistent with the project's RGS file #include "resource.h" //#include #include #include #include using namespace ATL; // adtn'l includes #include #include #include #include #include #include #include #include typedef std::basic_ofstream ByteFile; typedef std::basic_string WString; typedef std::vector WStringVector; ================================================ FILE: UDVC-Plugin/targetver.h ================================================ #pragma once // Including SDKDDKVer.h defines the highest available Windows platform. // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. #include ================================================ FILE: UDVC-Plugin.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UDVC-Plugin", "UDVC-Plugin\UDVC-Plugin.vcxproj", "{9402DF45-A060-4881-9F64-D16E094B97A7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UDVC-PluginPS", "UDVC-Plugin\UDVC-PluginPS.vcxproj", "{15DEE2D8-6972-49C0-9369-35730A29A2CF}" ProjectSection(ProjectDependencies) = postProject {9402DF45-A060-4881-9F64-D16E094B97A7} = {9402DF45-A060-4881-9F64-D16E094B97A7} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UDVC-Server", "UDVC-Server\UDVC-Server.vcxproj", "{C7E1D0A7-0ADA-4DF4-99DA-8527E856670F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {9402DF45-A060-4881-9F64-D16E094B97A7}.Debug|x64.ActiveCfg = Debug|x64 {9402DF45-A060-4881-9F64-D16E094B97A7}.Debug|x64.Build.0 = Debug|x64 {9402DF45-A060-4881-9F64-D16E094B97A7}.Debug|x86.ActiveCfg = Debug|Win32 {9402DF45-A060-4881-9F64-D16E094B97A7}.Debug|x86.Build.0 = Debug|Win32 {9402DF45-A060-4881-9F64-D16E094B97A7}.Release|x64.ActiveCfg = Release|x64 {9402DF45-A060-4881-9F64-D16E094B97A7}.Release|x64.Build.0 = Release|x64 {9402DF45-A060-4881-9F64-D16E094B97A7}.Release|x86.ActiveCfg = Release|Win32 {9402DF45-A060-4881-9F64-D16E094B97A7}.Release|x86.Build.0 = Release|Win32 {15DEE2D8-6972-49C0-9369-35730A29A2CF}.Debug|x64.ActiveCfg = Debug|x64 {15DEE2D8-6972-49C0-9369-35730A29A2CF}.Debug|x86.ActiveCfg = Debug|Win32 {15DEE2D8-6972-49C0-9369-35730A29A2CF}.Release|x64.ActiveCfg = Release|x64 {15DEE2D8-6972-49C0-9369-35730A29A2CF}.Release|x86.ActiveCfg = Release|Win32 {C7E1D0A7-0ADA-4DF4-99DA-8527E856670F}.Debug|x64.ActiveCfg = Debug|x64 {C7E1D0A7-0ADA-4DF4-99DA-8527E856670F}.Debug|x64.Build.0 = Debug|x64 {C7E1D0A7-0ADA-4DF4-99DA-8527E856670F}.Debug|x86.ActiveCfg = Debug|Win32 {C7E1D0A7-0ADA-4DF4-99DA-8527E856670F}.Debug|x86.Build.0 = Debug|Win32 {C7E1D0A7-0ADA-4DF4-99DA-8527E856670F}.Release|x64.ActiveCfg = Release|x64 {C7E1D0A7-0ADA-4DF4-99DA-8527E856670F}.Release|x64.Build.0 = Release|x64 {C7E1D0A7-0ADA-4DF4-99DA-8527E856670F}.Release|x86.ActiveCfg = Release|Win32 {C7E1D0A7-0ADA-4DF4-99DA-8527E856670F}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: UDVC-Server/UDVC-Server.cpp ================================================ /* * MIT License * * Copyright(c) 2018-2020 Balazs Bucsay * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files(the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and / or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions : * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include #include #include #pragma comment(lib, "wtsapi32.lib") #pragma comment(lib, "Ws2_32.lib") #define UDVC_CHANNEL_NAME "UniversalDVC" DWORD OpenDynamicChannel(LPCSTR szChannelName, HANDLE *phFile); DWORD WINAPI RcWsThread(PVOID param); DWORD WINAPI RsWcThread(PVOID param); struct arguments { DWORD mode; // 0 socket; 1 namedpiep WCHAR *namedpipename; WCHAR *ip; WCHAR *port; BYTE priority; } running_args; struct threadhandles { HANDLE hRDP = NULL; SOCKET sock = NULL; HANDLE pipe = NULL; }; HANDLE hEvent_RDP_global; VOID usage(WCHAR *cmdname) { wprintf(L"Usage: %s [-s | -c [-p port [-i ip]] | -m [-n name]] [-0 | -1 | -2 | -3]\n" "Socket server mode -s (default)\n" "\t-p port\t port to bind the listener (default: 31337)\n" "\t-i ip\t ip to bind the listener (default: 127.0.0.1)\n\n" "OR \n" "Socket client mode -c:\n" "\t-p port\t port to connect to\n" "\t-i ip\t ip to connect to\n\n" "Named pipe mode -m:\n" "\t-n name\t name of the named pipe (by default: \"\\\\.\\pipe\\UDVC_{RDP SESSION NUMBER}\")\n\n" "Data transfer priority parameters:\n" "\t-0\t real time\t\t(WTS_CHANNEL_OPTION_DYNAMIC_PRI_REAL)\n" "\t-1\t high priority\t\t(WTS_CHANNEL_OPTION_DYNAMIC_PRI_HIGH) - default\n" "\t-2\t medium priority\t(WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED)\n" "\t-3\t low priority\t\t(WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW)\n", cmdname); return; } BOOL parse_argv(INT argc, __in_ecount(argc) WCHAR **argv) { int num = 0; while (num < argc - 1) { num++; if (wcsncmp(argv[num], L"-", 1)) { wprintf(L"[-] Invalid argument: %s\n", argv[num]); usage(argv[0]); return FALSE; } switch (argv[num][1]) { case 'h': case '?': usage(argv[0]); return FALSE; case 'c': running_args.mode = 1; break; case 'm': running_args.mode = 2; break; case 'n': num++; if (wcsncmp(argv[num], L"\\\\.\\pipe\\", 9)) { wprintf(L"[-] Named pipe name has to start with: \\\\.\\pipe\\\n"); usage(argv[0]); return FALSE; } running_args.namedpipename = argv[num]; break; case 's': running_args.mode = 0; break; case 'p': num++; running_args.port = argv[num]; break; case 'i': num++; running_args.ip = argv[num]; break; case '0': running_args.priority = WTS_CHANNEL_OPTION_DYNAMIC_PRI_REAL; break; case '1': running_args.priority = WTS_CHANNEL_OPTION_DYNAMIC_PRI_HIGH; break; case '2': running_args.priority = WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED; break; case '3': running_args.priority = WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW; break; default: wprintf(L"[-] Invalid argument: %s\n", argv[num]); usage(argv[0]); return FALSE; } } return TRUE; } ULONG GetCurrentSessionId(void) { LPTSTR pBuf; DWORD len; ULONG ret; if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSSessionId, &pBuf, &len)) { return -1; } ret = (ULONG)*pBuf; WTSFreeMemory(pBuf); return ret; } INT _cdecl wmain(INT argc, __in_ecount(argc) WCHAR **argv) { HANDLE hFile; WSADATA wsaData; ADDRINFOW *result = NULL; ADDRINFOW hints; SOCKET s, c; WCHAR tempnamepipename[24]; HANDLE hNamedPipe = NULL; ULONG sessionId; int ret; struct threadhandles threadhandle; sessionId = GetCurrentSessionId(); wsprintf(tempnamepipename, L"\\\\.\\pipe\\UDVC_%08X", sessionId); running_args.mode = 0; running_args.port = L"31337"; running_args.priority = 4; running_args.namedpipename = tempnamepipename; running_args.ip = L"127.0.0.1"; wprintf(L"Universal Dynamic Virtual Channel server application\n\n"); if (argc > 1) if (!parse_argv(argc, argv)) return -1; if ((ret = OpenDynamicChannel(UDVC_CHANNEL_NAME, &hFile)) != ERROR_SUCCESS) { if (ret == 31) wprintf(L"[-] Could not open Dynamic Virtual Channel, plugin was not loaded on the client side: %ld\n", ret); else wprintf(L"[-] Could not open Dynamic Virtual Channel: %ld\n", ret); return -1; } if (running_args.mode == 0) { wprintf(L"[*] Setting up server socket\n"); if ((ret = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) { wprintf(L"[-] WSAStartup() failed with error: %ld\n", ret); return -1; } ZeroMemory(&hints, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; if ((ret = GetAddrInfoW(running_args.ip, running_args.port, &hints, &result)) != 0) { wprintf(L"[-] GetAddrInfoW() failed with error: %ld\n", ret); WSACleanup(); return -1; } if ((s = socket(result->ai_family, result->ai_socktype, result->ai_protocol)) == INVALID_SOCKET) { wprintf(L"[-] socket() failed with error: %ld\n", WSAGetLastError()); FreeAddrInfoW(result); WSACleanup(); return -1; } if ((ret = bind(s, result->ai_addr, (int)result->ai_addrlen)) == SOCKET_ERROR) { wprintf(L"[-] bind() failed with error: %ld\n", WSAGetLastError()); FreeAddrInfoW(result); closesocket(s); WSACleanup(); return -1; } FreeAddrInfoW(result); wprintf(L"[*] Listening on: %s:%s\n", running_args.ip, running_args.port); if ((ret = listen(s, SOMAXCONN)) == SOCKET_ERROR) { wprintf(L"[-] listen() failed with error: %ld\n", WSAGetLastError()); closesocket(s); WSACleanup(); return -1; } if ((c = accept(s, NULL, NULL)) == INVALID_SOCKET) { wprintf(L"[-] accept() failed with error: %ld\n", WSAGetLastError()); closesocket(s); WSACleanup(); return -1; } wprintf(L"[+] Client connected\n"); closesocket(s); u_long blocking = 0; ret = ioctlsocket(c, FIONBIO, &blocking); if (ret != NO_ERROR) { wprintf(L"[-] ioctlsocket() failed with error: %ld\n", ret); closesocket(c); WSACleanup(); return -1; } threadhandle.sock = c; } if (running_args.mode == 1) { wprintf(L"[*] Setting up client socket\n"); if ((ret = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) { wprintf(L"[-] WSAStartup() failed with error: %ld\n", ret); return -1; } ZeroMemory(&hints, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; if ((ret = GetAddrInfoW(running_args.ip, running_args.port, &hints, &result)) != 0) { wprintf(L"[-] GetAddrInfoW() failed with error: %ld\n", ret); WSACleanup(); return -1; } if ((c = socket(result->ai_family, result->ai_socktype, result->ai_protocol)) == INVALID_SOCKET) { wprintf(L"[-] socket() failed with error: %ld\n", WSAGetLastError()); FreeAddrInfoW(result); WSACleanup(); return -1; } if ((ret = connect(c, result->ai_addr, (int)result->ai_addrlen)) == SOCKET_ERROR) { wprintf(L"[-] connect() failed with error: %ld\n", WSAGetLastError()); FreeAddrInfoW(result); closesocket(c); WSACleanup(); return -1; } FreeAddrInfoW(result); wprintf(L"[*] Connected to: %s:%s\n", running_args.ip, running_args.port); u_long blocking = 0; ret = ioctlsocket(c, FIONBIO, &blocking); if (ret != NO_ERROR) { wprintf(L"[-] ioctlsocket() failed with error: %ld\n", ret); closesocket(c); WSACleanup(); return -1; } threadhandle.sock = c; } if (running_args.mode == 2) { wprintf(L"[*] Setting up named pipe\n"); if ((hNamedPipe = CreateNamedPipe(running_args.namedpipename, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, 1, 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL)) == INVALID_HANDLE_VALUE) { wprintf(L"[-] CreateNamedPipe() failed with: %ld", GetLastError()); return -1; } wprintf(L"[*] Listening on pipe: %s\n", running_args.namedpipename); if (!ConnectNamedPipe(hNamedPipe, NULL)) { wprintf(L"[-] ConnectNamedPipe() failed with: %ld", GetLastError()); return -1; } threadhandle.pipe = hNamedPipe; wprintf(L"[+] Client connected to the pipe.\n"); } threadhandle.hRDP = hFile; wprintf(L"[*] Starting thread RsWc\n"); DWORD dwThreadId; HANDLE hReadThread = CreateThread( NULL, 0, RsWcThread, &threadhandle, 0, &dwThreadId); wprintf(L"[*] Starting thread RcWs\n"); HANDLE hWriteThread = CreateThread( NULL, 0, RcWsThread, &threadhandle, 0, &dwThreadId); HANDLE ah[] = { hReadThread, hWriteThread }; printf("[*] Waiting for threads to exit...\n"); WaitForMultipleObjects(2, ah, TRUE, INFINITE); if (running_args.mode) { if ((ret = shutdown(c, SD_BOTH)) == SOCKET_ERROR) { wprintf(L"[-] shutdown() failed with error: %d\n", WSAGetLastError()); closesocket(c); WSACleanup(); return -1; } closesocket(c); WSACleanup(); } else { CloseHandle(hNamedPipe); } CloseHandle(hReadThread); CloseHandle(hWriteThread); CloseHandle(hFile); return 0; } /* * Open a dynamic channel with the name given in szChannelName. * The output file handle can be used in ReadFile/WriteFile calls. */ DWORD OpenDynamicChannel(LPCSTR szChannelName, HANDLE *phFile) { HANDLE hWTSHandle = NULL; HANDLE hWTSFileHandle; PVOID vcFileHandlePtr = NULL; DWORD len; DWORD rc = ERROR_SUCCESS; BOOL fSucc; hWTSHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, (LPSTR)szChannelName, WTS_CHANNEL_OPTION_DYNAMIC | running_args.priority); if (NULL == hWTSHandle) { rc = GetLastError(); goto exitpt; } fSucc = WTSVirtualChannelQuery(hWTSHandle, WTSVirtualFileHandle, &vcFileHandlePtr, &len); if (!fSucc) { rc = GetLastError(); goto exitpt; } if (len != sizeof(HANDLE)) { rc = ERROR_INVALID_PARAMETER; goto exitpt; } hWTSFileHandle = *(HANDLE *)vcFileHandlePtr; fSucc = DuplicateHandle(GetCurrentProcess(), hWTSFileHandle, GetCurrentProcess(), phFile, 0, FALSE, DUPLICATE_SAME_ACCESS); if (!fSucc) { rc = GetLastError(); goto exitpt; } rc = ERROR_SUCCESS; exitpt: if (vcFileHandlePtr) { WTSFreeMemory(vcFileHandlePtr); } if (hWTSHandle) { WTSVirtualChannelClose(hWTSHandle); } return rc; } /* * Thread that reads the socket or named pipe and writes the stream to the * RDP virtual channel. */ DWORD WINAPI RsWcThread(PVOID param) { struct threadhandles *handles = (struct threadhandles *)param; DWORD dwWritten; DWORD dw; BOOL bSucc; HANDLE hEvent_rdp, hEvent_pipe; char *readBuf; DWORD heapsize = 4096; if ((readBuf = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, heapsize)) == NULL) { wprintf(L"[-] Error allocating heap for read buffer %ld\n", GetLastError()); return -1; } hEvent_rdp = CreateEvent(NULL, FALSE, FALSE, NULL); OVERLAPPED Overlapped = { 0 }; Overlapped.hEvent = hEvent_rdp; hEvent_pipe = CreateEvent(NULL, FALSE, FALSE, NULL); OVERLAPPED Overlapped_pipe = { 0 }; Overlapped_pipe.hEvent = hEvent_pipe; while (TRUE) { if (handles->sock) { if ((dw = recv(handles->sock, readBuf, heapsize, 0)) == SOCKET_ERROR) { wprintf(L"[-] [RsWc] recv() failed with error %d, exiting thread...\n", WSAGetLastError()); SetEvent(hEvent_RDP_global); return -1; } if (dw == 0) { wprintf(L"[-] [RsWc] socket closed, exiting thread...\n"); SetEvent(hEvent_RDP_global); return -1; } } if (handles->pipe) { bSucc = ReadFile(handles->pipe, readBuf, heapsize, &dw, &Overlapped_pipe); if (!bSucc) { if (GetLastError() == ERROR_IO_PENDING) { dw = WaitForSingleObject(Overlapped_pipe.hEvent, INFINITE); bSucc = GetOverlappedResult(handles->pipe, &Overlapped_pipe, &dw, FALSE); } } if (!bSucc) { wprintf(L"[-] [RsWc] ReadFile()/WaitForSingleObject() error: %ld\n", GetLastError()); return -1; } if (ResetEvent(Overlapped_pipe.hEvent) == FALSE) { wprintf(L"[-] [RsWc] ResetEvent() failed with error = %ld\n", GetLastError()); return -1; } } bSucc = WriteFile(handles->hRDP, readBuf, dw, &dwWritten, &Overlapped); if (!bSucc) { if (GetLastError() == ERROR_IO_PENDING) { dw = WaitForSingleObject(Overlapped.hEvent, INFINITE); bSucc = GetOverlappedResult(handles->hRDP, &Overlapped, &dwWritten, FALSE); } } if (!bSucc) { wprintf(L"[-] [RsWc] WriteFile()/WaitForSingleObject() error: %ld\n", GetLastError()); return -1; } } return 0; } /* * Thread that reads the RDP virtual channel and writes the stream to the * socket or named pipe. */ DWORD WINAPI RcWsThread(PVOID param) { struct threadhandles *handles = (struct threadhandles *)param; BYTE ReadBuffer[CHANNEL_PDU_LENGTH]; CHANNEL_PDU_HEADER *pHdr = (CHANNEL_PDU_HEADER *)ReadBuffer; PBYTE pData; DWORD dwRead, ret, Flags, dw; BOOL bSucc; char *bufWrite; DWORD bufWritelen; hEvent_RDP_global = CreateEvent(NULL, FALSE, FALSE, NULL); OVERLAPPED Overlapped = { 0 }; DWORD TotalRead = 0; Overlapped.hEvent = hEvent_RDP_global; while (TRUE) { bSucc = ReadFile(handles->hRDP, ReadBuffer, sizeof(ReadBuffer), &dwRead, &Overlapped); if (!bSucc) { if (GetLastError() == ERROR_IO_PENDING) { dw = WaitForSingleObject(Overlapped.hEvent, INFINITE); bSucc = GetOverlappedResult(handles->hRDP, &Overlapped, &dwRead, FALSE); } } pData = (PBYTE)(pHdr + 1); if (!bSucc) { wprintf(L"[-] [RcWs] ReadFile()/WaitForSingleObject() error: %ld\n", GetLastError()); if (handles->sock) closesocket(handles->sock); return -1; } /* // Event was created with bManualReset FALSE, no need to reset it. if ((ret = ResetEvent(Overlapped.hEvent)) == FALSE) { wprintf(L"[-] [RcWs] ResetEvent() failed with error = %ld\n", GetLastError()); return -1; }*/ // no need to pass the header. bufWrite = (char *)(pHdr + 1); /* WSAdata.len = pHdr->length; pHdr->length stores the full length of the packet, we only need that was received. Ignoring the header flags as well, we just proxy the bytes. This is not that nice though. */ bufWritelen = dwRead - sizeof(CHANNEL_PDU_HEADER); Flags = 0; if (handles->sock) { if ((ret = send(handles->sock, bufWrite, bufWritelen, 0)) == SOCKET_ERROR) { wprintf(L"[-] [RsWc] send() failed with error %ld\n", WSAGetLastError()); return -1; } } if (handles->pipe) { bSucc = WriteFile(handles->pipe, bufWrite, bufWritelen, &ret, &Overlapped); if (!bSucc) { if (GetLastError() == ERROR_IO_PENDING) { dw = WaitForSingleObject(Overlapped.hEvent, INFINITE); bSucc = GetOverlappedResult(handles->pipe, &Overlapped, &ret, FALSE); } } if (!bSucc) { wprintf(L"[-] [RsWc] WriteFile()/WaitForSingleObject() error: %ld\n", GetLastError()); return -1; } } } return 0; } ================================================ FILE: UDVC-Server/UDVC-Server.vcxproj ================================================  Debug Win32 Release Win32 Debug x64 Release x64 {C7E1D0A7-0ADA-4DF4-99DA-8527E856670F} Win32Proj UDVCServer 8.1 Application true v140 Unicode Application false v140 true Unicode Application true v140 Unicode Application false v140 true Unicode true $(SolutionDir)$(Configuration)\$(Platform)\ $(Platform)\$(Configuration)\ true $(SolutionDir)$(Configuration)\$(Platform)\ false $(SolutionDir)$(Configuration)\$(Platform)\ $(Platform)\$(Configuration)\ false $(SolutionDir)$(Configuration)\$(Platform)\ NotUsing Level3 Disabled WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true NotUsing Level3 Disabled _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true Level3 NotUsing MaxSpeed true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true true true Level3 NotUsing MaxSpeed true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true true true ================================================ FILE: UDVC-Server/UDVC-Server.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Header Files Source Files ================================================ FILE: UDVC-Server/targetver.h ================================================ #pragma once // Including SDKDDKVer.h defines the highest available Windows platform. // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. #include