C++ 端口监视器 (mfilemon.dll) RDP 虚拟通道代码未执行

C++ Port Monitor (mfilemon.dll) RDP Virtual Channel code not executing

我最近开始使用开源 mfilemon.dll 并尝试向其添加其他功能。

我要添加的功能是通过虚拟通道传输数据。我写了一个小的控制台 exe 来测试代码,我在下面成功发送了数据(我在另一边收到了一个消息弹出窗口)。

当此代码放入 mfilemon.dll 时,没有任何反应。 DLL 的所有其他功能都正常工作,但只是没有执行此代码。我认为后台处理程序服务以及 windows 中的某些内容正在阻止某些 API 调用,但很高兴能确定。

这是我编写的 exe 代码,它成功地通过我的虚拟通道发送数据(我的项目是针对 Win8.1 的,所以我必须将 legacy_stdio_definitions.lib 添加到链接器输入文件)。

#include "stdafx.h"
#include "conio.h"
#include "iostream"
struct IUnknown; // Workaround for "combaseapi.h(229): error C2187: syntax error: 'identifier' was unexpected here" when using /permissive-
#include "windows.h"
#include "WtsApi32.h"
#pragma comment(lib, "wtsapi32.lib")

int main()
{
    std::cout << "Testing";

    const char* data = "You just printed data!";

    HANDLE mHandle;
    mHandle = WTSVirtualChannelOpen(NULL, (DWORD)-1, (LPSTR)"PRINTWP");
    PULONG written = 0;
    bool ret = WTSVirtualChannelWrite(mHandle, (PCHAR)data, 22, written);

    if (!ret || written == (PULONG)13)
    {

    }
    else
    {

    }

    ret = WTSVirtualChannelClose(mHandle);

    _getch();
    return 0;
}

这是我的虚拟频道DLL代码。

#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <Shellapi.h>
#include <Cchannel.h> // Contains the definition for PCHANNEL_ENTRY_POINTS
#include <string.h>
#include <winspool.h>
#include <fstream>
#include <iostream>

PCHANNEL_ENTRY_POINTS gpEntryPoints;
LPHANDLE gphChannel;
void VCAPITYPE VirtualChannelInitEventProc(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength);

void VCAPITYPE VirtualChannelOpenEvent_PRINTWP(DWORD openHandle, UINT event, LPVOID pdata, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags);
DWORD gdwOpenChannel_PRINTWP;
const char* channel_PRINTWP = "PRINTWP";

BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
{
    MessageBox(NULL, TEXT("RDP Virtual channel DLL Loaded."), TEXT("Hosted Channel"), MB_OK);

    gpEntryPoints = (PCHANNEL_ENTRY_POINTS)LocalAlloc(LPTR, pEntryPoints->cbSize);
    CopyMemory(gpEntryPoints, pEntryPoints, pEntryPoints->cbSize);

    UINT rc_channel;
    CHANNEL_DEF channel_def[1]; // This is where you can increase the number of registered virtual channels assuming you define them later.

    ZeroMemory(&channel_def[0], sizeof(CHANNEL_DEF));
    CopyMemory(channel_def[0].name, channel_PRINTWP, strlen(channel_PRINTWP));

    rc_channel = gpEntryPoints->pVirtualChannelInit((LPVOID *)&gphChannel, channel_def, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, (PCHANNEL_INIT_EVENT_FN)VirtualChannelInitEventProc);

    if (rc_channel != CHANNEL_RC_OK)
    {
        MessageBox(NULL, TEXT("RDP Virtual Channel registration has failed!"),TEXT("Channel Message"), MB_OK);
        return FALSE;
    }

    if (channel_def[0].options != CHANNEL_OPTION_INITIALIZED)
    {
        MessageBox(NULL, TEXT("RDP Virtual Channel options initialization failure!"), TEXT("Channel Message"), MB_OK);
        return FALSE;
    }

    MessageBox(NULL, TEXT("RDP Virtual Channel initialized."), TEXT("Channel Message"), MB_OK);
    return TRUE;
}

void VCAPITYPE VirtualChannelInitEventProc(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength)
{
    UINT rc_channel_HLINK;
    UINT rc_channel_PREVIEW;
    UINT rc_channel_PRINTWP;

    switch (event)
    {
    case CHANNEL_EVENT_INITIALIZED:
        break;
    case CHANNEL_EVENT_CONNECTED:

        rc_channel_PRINTWP = gpEntryPoints->pVirtualChannelOpen(gphChannel, &gdwOpenChannel_PRINTWP, (PCHAR)channel_PRINTWP, (PCHANNEL_OPEN_EVENT_FN)VirtualChannelOpenEvent_PRINTWP);

        if (rc_channel_PRINTWP != CHANNEL_RC_OK)
        {
            MessageBox(NULL, TEXT("Open of RDP virtual channel failed"), TEXT("Channel Message"), MB_OK);
        }
        else
        {
            MessageBox(NULL, TEXT("Open of RDP virtual channel success"), TEXT("Channel Message"), MB_OK);
        }

        break;

    case CHANNEL_EVENT_V1_CONNECTED:
        MessageBox(NULL, TEXT("Connecting to a non Windows 2000 Terminal Server"), TEXT("Channel Message"), MB_OK);
        break;

    case CHANNEL_EVENT_DISCONNECTED:
        break;

    case CHANNEL_EVENT_TERMINATED:
        LocalFree((HLOCAL)gpEntryPoints);
        break;

    default:
        break;
    }
}

void VCAPITYPE VirtualChannelOpenEvent_PRINTWP(DWORD openHandle, UINT event, LPVOID pdata, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
{
    switch (event)
    {
    case CHANNEL_EVENT_DATA_RECEIVED:

        MessageBox(NULL, TEXT("Data received."), TEXT("Channel Message"), MB_OK);

        char* data;
        data = (char*)malloc(dataLength + 1);
        CopyMemory(data, pdata, dataLength);
        data[dataLength] = '[=12=]';

        MessageBoxA(NULL, data, "PRINTWP", MB_OK);

        free(data);

        break;

    default:
        break;
    }
}

def 文件:

LIBRARY FrzHostedChannel
EXPORTS
VirtualChannelEntry

dllmain:

#include "stdafx.h"

使用上述代码需要更改注册表,以便 mstsc.exe 知道加载此插件。

如果有人熟悉端口监视器和执行除创建文件之外的其他操作的代码,那就太棒了。

Spoolsv.exe 是一项服务,因此在与通过 RDP 连接的会话不同的会话中运行。使用的任何 DLL 和生成的子进程也是该会话的一部分。

mHandle = WTSVirtualChannelOpen(NULL, (DWORD)-1, (LPSTR)"PRINTWP");

需要将 (DWORD)-1 更改为通过 RDP 连接的实际会话。