mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-24 04:01:52 +08:00
feat: v2.1.0 核心重构与功能增强
## 架构重构
- 全局变量消除,迁移至 Config/State 对象
- SMB 插件融合(smb/smb2/smbghost/smbinfo)
- 服务探测重构,实现 Nmap 风格 fallback 机制
- 输出系统重构,TXT 实时刷盘 + 双写机制
- i18n 框架升级至 go-i18n
## 性能优化
- 正则表达式预编译
- 内存优化 map[string]struct{}
- 并发指纹匹配
- SOCKS5 连接复用
- 滑动窗口调度 + 自适应线程池
## 新功能
- Web 管理界面
- 多格式 POC 适配(xray/afrog)
- 增强指纹库(3139条)
- Favicon hash 指纹识别
- 插件选择性编译(Build Tags)
- fscan-lab 靶场环境
- 默认端口扩展(62→133)
## 构建系统
- 添加 no_local tag 支持排除本地插件
- 多版本构建:fscan/fscan-nolocal/fscan-web
- CI 添加 snapshot 模式支持仅测试构建
## Bug 修复
- 修复 120+ 个问题,包括 RDP panic、批量扫描漏报、
JSON 输出格式、Redis 检测、Context 超时等
## 测试增强
- 单元测试覆盖率 74-100%
- 并发安全测试
- 集成测试(Web/端口/服务/SSH/ICMP)
This commit is contained in:
@@ -0,0 +1,328 @@
|
||||
// +build ignore
|
||||
|
||||
// addins.go
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
openHandleSeq uint32
|
||||
freerdpClient2 = syscall.NewLazyDLL("freerdp-client2.dll")
|
||||
winpr2 = syscall.NewLazyDLL("winpr2.dll")
|
||||
freerdp2 = syscall.NewLazyDLL("freerdp2.dll")
|
||||
)
|
||||
|
||||
var (
|
||||
virtualChannelEntry = freerdpClient2.NewProc("VirtualChannelEntry")
|
||||
virtualChannelEntryEx = freerdpClient2.NewProc("VirtualChannelEntryEx")
|
||||
)
|
||||
|
||||
func VirtualChannelEntryEx(ex *ChannelEntryPointsEx, pInitHandle interface{}) (err error) {
|
||||
r0, _, ec := virtualChannelEntryEx.Call(uintptr(unsafe.Pointer(ex)),
|
||||
uintptr(unsafe.Pointer(&pInitHandle)))
|
||||
if r0 == 0 {
|
||||
err = error(ec)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ChannelsClientLoadEx(cs *rdpChannels) {
|
||||
var client ChannelClientData
|
||||
client.entryEx = VIRTUALCHANNELENTRYEX(VirtualChannelEntryEx)
|
||||
cs.clientDataList = append(cs.clientDataList, client)
|
||||
cs.clientDataCount++
|
||||
|
||||
var init ChannelInitData
|
||||
init.channels = cs
|
||||
init.openDataMap = make(map[uint32]*ChannelOpenData)
|
||||
cs.initDataList = append(cs.initDataList, init)
|
||||
cs.initDataCount++
|
||||
|
||||
ex := NewChannelEntryPointsEx()
|
||||
ex.PVirtualChannelInitEx = VIRTUALCHANNELINITEX(RdpVirtualChannelInitEx)
|
||||
ex.PVirtualChannelOpenEx = VIRTUALCHANNELOPENEX(RdpVirtualChannelOpenEx)
|
||||
ex.PVirtualChannelCloseEx = VIRTUALCHANNELCLOSEEX(RdpVirtualChannelCloseEx)
|
||||
ex.PVirtualChannelWriteEx = VIRTUALCHANNELWRITEEX(RdpVirtualChannelWriteEx)
|
||||
client.entryEx(ex, uintptr(unsafe.Pointer(&init)))
|
||||
}
|
||||
|
||||
type ChannelClientData struct {
|
||||
//PVIRTUALCHANNELENTRY entry;
|
||||
entryEx VIRTUALCHANNELENTRYEX
|
||||
// pChannelInitEventProc *CHANNEL_INIT_EVENT_FN
|
||||
pChannelInitEventProcEx CHANNEL_INIT_EVENT_EX_FN
|
||||
pInitHandle interface{}
|
||||
lpUserParam interface{}
|
||||
}
|
||||
type ChannelOpenData struct {
|
||||
name string
|
||||
OpenHandle uint32
|
||||
options uint32
|
||||
flags int
|
||||
pInterface interface{}
|
||||
channels *rdpChannels
|
||||
lpUserParam interface{}
|
||||
//pChannelOpenEventProc *CHANNEL_OPEN_EVENT_FN
|
||||
pChannelOpenEventProcEx *CHANNEL_OPEN_EVENT_EX_FN
|
||||
}
|
||||
type ChannelInitData struct {
|
||||
channels *rdpChannels
|
||||
pInterface interface{}
|
||||
openDataMap map[uint32]*ChannelOpenData
|
||||
}
|
||||
type rdpChannels struct {
|
||||
clientDataCount int
|
||||
clientDataList []ChannelClientData
|
||||
|
||||
openDataCount int
|
||||
openDataList []ChannelOpenData
|
||||
|
||||
initDataCount int
|
||||
initDataList []ChannelInitData
|
||||
|
||||
/* control for entry into MyVirtualChannelInit */
|
||||
can_call_init bool
|
||||
|
||||
/* true once freerdp_channels_post_connect is called */
|
||||
connected bool
|
||||
|
||||
/* used for locating the channels for a given instance */
|
||||
//freerdp* instance;
|
||||
|
||||
//wMessageQueue* queue;
|
||||
|
||||
//DrdynvcClientContext* drdynvc;
|
||||
//CRITICAL_SECTION channelsLock;
|
||||
}
|
||||
type ChannelOpenEvent struct {
|
||||
Data interface{}
|
||||
DataLength uint32
|
||||
UserData interface{}
|
||||
pChannelOpenData *ChannelOpenData
|
||||
}
|
||||
|
||||
func RdpVirtualChannelInitEx(lpUserParam interface{}, clientContext interface{},
|
||||
pInitHandle interface{}, pChannel []ChannelDef,
|
||||
channelCount int, versionRequested uint32,
|
||||
pChannelInitEventProcEx CHANNEL_INIT_EVENT_EX_FN) uint {
|
||||
var (
|
||||
//rdpSettings* settings;
|
||||
pChannelInitData *ChannelInitData
|
||||
pChannelClientData *ChannelClientData
|
||||
channels *rdpChannels
|
||||
)
|
||||
|
||||
if pInitHandle == nil {
|
||||
return CHANNEL_RC_BAD_INIT_HANDLE
|
||||
}
|
||||
|
||||
if pChannel == nil {
|
||||
return CHANNEL_RC_BAD_CHANNEL
|
||||
}
|
||||
|
||||
if (channelCount <= 0) || pChannelInitEventProcEx == nil {
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR
|
||||
}
|
||||
|
||||
pChannelInitData = pInitHandle.(*ChannelInitData)
|
||||
//WINPR_ASSERT(pChannelInitData);
|
||||
|
||||
channels = pChannelInitData.channels
|
||||
//WINPR_ASSERT(channels);
|
||||
|
||||
if !channels.can_call_init {
|
||||
return CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY
|
||||
}
|
||||
|
||||
if (channels.openDataCount + channelCount) > 30 {
|
||||
return CHANNEL_RC_TOO_MANY_CHANNELS
|
||||
}
|
||||
|
||||
if channels.connected {
|
||||
return CHANNEL_RC_ALREADY_CONNECTED
|
||||
}
|
||||
|
||||
if versionRequested != VIRTUAL_CHANNEL_VERSION_WIN2000 {
|
||||
}
|
||||
|
||||
for i := range pChannel {
|
||||
pChannelDef := &pChannel[i]
|
||||
if getChannelOpenDataByName(channels, pChannelDef.Name) == nil {
|
||||
return CHANNEL_RC_BAD_CHANNEL
|
||||
}
|
||||
}
|
||||
|
||||
pChannelClientData = &channels.clientDataList[channels.clientDataCount]
|
||||
pChannelClientData.pChannelInitEventProcEx = pChannelInitEventProcEx
|
||||
pChannelClientData.pInitHandle = pInitHandle
|
||||
pChannelClientData.lpUserParam = lpUserParam
|
||||
channels.clientDataCount++
|
||||
|
||||
//WINPR_ASSERT(channels->instance);
|
||||
//WINPR_ASSERT(channels->instance->context);
|
||||
//settings = channels.instance.context.settings
|
||||
//WINPR_ASSERT(settings);
|
||||
|
||||
for i := range pChannel {
|
||||
pChannelDef := &pChannel[i]
|
||||
var pChannelOpenData ChannelOpenData
|
||||
|
||||
//WINPR_ASSERT(pChannelOpenData)
|
||||
|
||||
pChannelOpenData.OpenHandle = atomic.AddUint32(&openHandleSeq, 1)
|
||||
pChannelOpenData.channels = channels
|
||||
pChannelOpenData.lpUserParam = lpUserParam
|
||||
if _, ok := pChannelInitData.openDataMap[pChannelOpenData.OpenHandle]; ok {
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR
|
||||
}
|
||||
|
||||
pChannelInitData.pInterface = clientContext
|
||||
|
||||
pChannelOpenData.flags = 1
|
||||
pChannelOpenData.name = pChannelDef.Name
|
||||
pChannelOpenData.options = pChannelDef.Options
|
||||
pChannelInitData.openDataMap[pChannelOpenData.OpenHandle] = &pChannelOpenData
|
||||
channels.openDataList = append(channels.openDataList, pChannelOpenData)
|
||||
channels.openDataCount++
|
||||
/*
|
||||
if settings.ChannelCount < 30 {
|
||||
channel := freerdp_settings_get_pointer_array_writable(
|
||||
settings, FreeRDP_ChannelDefArray, settings.ChannelCount)
|
||||
channel.name = pChannelDef.Name
|
||||
channel.options = pChannelDef.Options
|
||||
settings.ChannelCount++
|
||||
}*/
|
||||
|
||||
channels.openDataCount++
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK
|
||||
}
|
||||
func getChannelOpenDataByName(channel *rdpChannels, name string) *ChannelOpenData {
|
||||
for _, v := range channel.openDataList {
|
||||
if strings.EqualFold(name, v.name) {
|
||||
return &v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func RdpVirtualChannelOpenEx(pInitHandle interface{}, pOpenHandle *uint32, pChannelName string,
|
||||
pChannelOpenEventProcEx *CHANNEL_OPEN_EVENT_EX_FN) uint {
|
||||
pChannelInitData := pInitHandle.(*ChannelInitData)
|
||||
channels := pChannelInitData.channels
|
||||
pInterface := pChannelInitData.pInterface
|
||||
|
||||
if pOpenHandle == nil {
|
||||
return CHANNEL_RC_BAD_CHANNEL_HANDLE
|
||||
}
|
||||
if pChannelOpenEventProcEx == nil {
|
||||
return CHANNEL_RC_BAD_PROC
|
||||
}
|
||||
|
||||
if !channels.connected {
|
||||
return CHANNEL_RC_NOT_CONNECTED
|
||||
}
|
||||
|
||||
pChannelOpenData := getChannelOpenDataByName(channels, pChannelName)
|
||||
|
||||
if pChannelOpenData == nil {
|
||||
return CHANNEL_RC_UNKNOWN_CHANNEL_NAME
|
||||
}
|
||||
|
||||
if pChannelOpenData.flags == 2 {
|
||||
return CHANNEL_RC_ALREADY_OPEN
|
||||
}
|
||||
|
||||
pChannelOpenData.flags = 2 /* open */
|
||||
pChannelOpenData.pInterface = pInterface
|
||||
pChannelOpenData.pChannelOpenEventProcEx = pChannelOpenEventProcEx
|
||||
*pOpenHandle = pChannelOpenData.OpenHandle
|
||||
return CHANNEL_RC_OK
|
||||
}
|
||||
func RdpVirtualChannelCloseEx(pInitHandle interface{}, openHandle uint32) uint {
|
||||
if pInitHandle == nil {
|
||||
return CHANNEL_RC_BAD_INIT_HANDLE
|
||||
}
|
||||
pChannelInitData := pInitHandle.(*ChannelInitData)
|
||||
pChannelOpenData := pChannelInitData.openDataMap[openHandle]
|
||||
|
||||
if pChannelOpenData == nil {
|
||||
return CHANNEL_RC_BAD_CHANNEL_HANDLE
|
||||
}
|
||||
|
||||
if pChannelOpenData.flags != 2 {
|
||||
return CHANNEL_RC_NOT_OPEN
|
||||
}
|
||||
|
||||
pChannelOpenData.flags = 0
|
||||
|
||||
return CHANNEL_RC_OK
|
||||
}
|
||||
func RdpVirtualChannelWriteEx(pInitHandle interface{}, openHandle uint32,
|
||||
pData interface{}, dataLength uint32,
|
||||
pUserData interface{}) uint {
|
||||
|
||||
//wMessage message;
|
||||
|
||||
if pInitHandle == nil {
|
||||
return CHANNEL_RC_BAD_INIT_HANDLE
|
||||
}
|
||||
|
||||
pChannelInitData := pInitHandle.(*ChannelInitData)
|
||||
channels := pChannelInitData.channels
|
||||
|
||||
if channels == nil {
|
||||
return CHANNEL_RC_BAD_CHANNEL_HANDLE
|
||||
}
|
||||
|
||||
pChannelOpenData := pChannelInitData.openDataMap[openHandle]
|
||||
if pChannelOpenData == nil {
|
||||
return CHANNEL_RC_BAD_CHANNEL_HANDLE
|
||||
}
|
||||
|
||||
if !channels.connected {
|
||||
return CHANNEL_RC_NOT_CONNECTED
|
||||
}
|
||||
|
||||
if pData == nil {
|
||||
return CHANNEL_RC_NULL_DATA
|
||||
}
|
||||
|
||||
if dataLength == 0 {
|
||||
return CHANNEL_RC_ZERO_LENGTH
|
||||
}
|
||||
|
||||
if pChannelOpenData.flags != 2 {
|
||||
return CHANNEL_RC_NOT_OPEN
|
||||
}
|
||||
|
||||
pChannelOpenEvent := new(ChannelOpenEvent)
|
||||
|
||||
if pChannelOpenEvent == nil {
|
||||
return CHANNEL_RC_NO_MEMORY
|
||||
|
||||
}
|
||||
|
||||
pChannelOpenEvent.Data = pData
|
||||
pChannelOpenEvent.DataLength = dataLength
|
||||
pChannelOpenEvent.UserData = pUserData
|
||||
pChannelOpenEvent.pChannelOpenData = pChannelOpenData
|
||||
/*message.context = channels;
|
||||
message.id = 0;
|
||||
message.wParam = pChannelOpenEvent;
|
||||
message.lParam = NULL;
|
||||
message.Free = channel_queue_message_free;
|
||||
|
||||
if (!MessageQueue_Dispatch(channels->queue, &message))
|
||||
{
|
||||
free(pChannelOpenEvent);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}*/
|
||||
|
||||
return CHANNEL_RC_OK
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
package plugin
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/shadow1ng/fscan/mylib/grdp/glog"
|
||||
|
||||
"github.com/shadow1ng/fscan/mylib/grdp/core"
|
||||
"github.com/shadow1ng/fscan/mylib/grdp/emission"
|
||||
)
|
||||
|
||||
const (
|
||||
CHANNEL_RC_OK = 0
|
||||
CHANNEL_RC_ALREADY_INITIALIZED = 1
|
||||
CHANNEL_RC_NOT_INITIALIZED = 2
|
||||
CHANNEL_RC_ALREADY_CONNECTED = 3
|
||||
CHANNEL_RC_NOT_CONNECTED = 4
|
||||
CHANNEL_RC_TOO_MANY_CHANNELS = 5
|
||||
CHANNEL_RC_BAD_CHANNEL = 6
|
||||
CHANNEL_RC_BAD_CHANNEL_HANDLE = 7
|
||||
CHANNEL_RC_NO_BUFFER = 8
|
||||
CHANNEL_RC_BAD_INIT_HANDLE = 9
|
||||
CHANNEL_RC_NOT_OPEN = 10
|
||||
CHANNEL_RC_BAD_PROC = 11
|
||||
CHANNEL_RC_NO_MEMORY = 12
|
||||
CHANNEL_RC_UNKNOWN_CHANNEL_NAME = 13
|
||||
CHANNEL_RC_ALREADY_OPEN = 14
|
||||
CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY = 15
|
||||
CHANNEL_RC_NULL_DATA = 16
|
||||
CHANNEL_RC_ZERO_LENGTH = 17
|
||||
CHANNEL_RC_INVALID_INSTANCE = 18
|
||||
CHANNEL_RC_UNSUPPORTED_VERSION = 19
|
||||
CHANNEL_RC_INITIALIZATION_ERROR = 20
|
||||
)
|
||||
const (
|
||||
VIRTUAL_CHANNEL_VERSION_WIN2000 = 1
|
||||
)
|
||||
|
||||
const (
|
||||
CHANNEL_EVENT_INITIALIZED = 0
|
||||
CHANNEL_EVENT_CONNECTED = 1
|
||||
CHANNEL_EVENT_V1_CONNECTED = 2
|
||||
CHANNEL_EVENT_DISCONNECTED = 3
|
||||
CHANNEL_EVENT_TERMINATED = 4
|
||||
CHANNEL_EVENT_REMOTE_CONTROL_START = 5
|
||||
CHANNEL_EVENT_REMOTE_CONTROL_STOP = 6
|
||||
CHANNEL_EVENT_ATTACHED = 7
|
||||
CHANNEL_EVENT_DETACHED = 8
|
||||
CHANNEL_EVENT_DATA_RECEIVED = 10
|
||||
CHANNEL_EVENT_WRITE_COMPLETE = 11
|
||||
CHANNEL_EVENT_WRITE_CANCELLED = 12
|
||||
)
|
||||
|
||||
const (
|
||||
CHANNEL_OPTION_INITIALIZED = 0x80000000
|
||||
CHANNEL_OPTION_ENCRYPT_RDP = 0x40000000
|
||||
CHANNEL_OPTION_ENCRYPT_SC = 0x20000000
|
||||
CHANNEL_OPTION_ENCRYPT_CS = 0x10000000
|
||||
CHANNEL_OPTION_PRI_HIGH = 0x08000000
|
||||
CHANNEL_OPTION_PRI_MED = 0x04000000
|
||||
CHANNEL_OPTION_PRI_LOW = 0x02000000
|
||||
CHANNEL_OPTION_COMPRESS_RDP = 0x00800000
|
||||
CHANNEL_OPTION_COMPRESS = 0x00400000
|
||||
CHANNEL_OPTION_SHOW_PROTOCOL = 0x00200000
|
||||
CHANNEL_OPTION_REMOTE_CONTROL_PERSISTENT = 0x00100000
|
||||
)
|
||||
|
||||
type ChannelDef struct {
|
||||
Name string
|
||||
Options uint32
|
||||
}
|
||||
type CHANNEL_INIT_EVENT_EX_FN func(lpUserParam interface{},
|
||||
pInitHandle interface{}, event uint, pData uintptr, dataLength uint)
|
||||
type VIRTUALCHANNELINITEX func(lpUserParam interface{}, clientContext interface{},
|
||||
pInitHandle interface{}, pChannel []ChannelDef,
|
||||
channelCount int, versionRequested uint32,
|
||||
pChannelInitEventProcEx CHANNEL_INIT_EVENT_EX_FN) uint
|
||||
|
||||
type CHANNEL_OPEN_EVENT_EX_FN func(lpUserParam uintptr,
|
||||
openHandle uint32, event uint,
|
||||
pData uintptr, dataLength uint32, totalLength uint32, dataFlags uint32)
|
||||
type VIRTUALCHANNELOPENEX func(pInitHandle interface{}, pOpenHandle *uint32,
|
||||
pChannelName string,
|
||||
pChannelOpenEventProcEx *CHANNEL_OPEN_EVENT_EX_FN) uint
|
||||
|
||||
type VIRTUALCHANNELCLOSEEX func(pInitHandle interface{}, openHandle uint32) uint
|
||||
|
||||
type VIRTUALCHANNELWRITEEX func(pInitHandle interface{}, openHandle uint32, pData interface{},
|
||||
dataLength uint32, pUserData interface{}) uint
|
||||
|
||||
type ChannelEntryPointsEx struct {
|
||||
CbSize uint32
|
||||
ProtocolVersion uint32
|
||||
PVirtualChannelInitEx VIRTUALCHANNELINITEX
|
||||
PVirtualChannelOpenEx VIRTUALCHANNELOPENEX
|
||||
PVirtualChannelCloseEx VIRTUALCHANNELCLOSEEX
|
||||
PVirtualChannelWriteEx VIRTUALCHANNELWRITEEX
|
||||
}
|
||||
|
||||
func NewChannelEntryPointsEx() *ChannelEntryPointsEx {
|
||||
e := &ChannelEntryPointsEx{}
|
||||
e.CbSize = uint32(unsafe.Sizeof(e))
|
||||
e.ProtocolVersion = VIRTUAL_CHANNEL_VERSION_WIN2000
|
||||
return e
|
||||
}
|
||||
|
||||
type VIRTUALCHANNELENTRYEX func(pEntryPointsEx *ChannelEntryPointsEx,
|
||||
pInitHandle interface{}) error
|
||||
|
||||
/*
|
||||
type ChannelEntryPoints struct {
|
||||
CbSize uint32
|
||||
ProtocolVersion uint32
|
||||
PVirtualChannelInit PVIRTUALCHANNELINIT
|
||||
PVirtualChannelOpen PVIRTUALCHANNELOPEN
|
||||
PVirtualChannelClose PVIRTUALCHANNELCLOSE
|
||||
PVirtualChannelWrite PVIRTUALCHANNELWRITE
|
||||
}
|
||||
typedef VOID VCAPITYPE CHANNEL_INIT_EVENT_FN(LPVOID pInitHandle,
|
||||
UINT event, LPVOID pData, UINT dataLength);
|
||||
|
||||
typedef CHANNEL_INIT_EVENT_FN* PCHANNEL_INIT_EVENT_FN;
|
||||
typedef VOID VCAPITYPE CHANNEL_OPEN_EVENT_FN(DWORD openHandle, UINT event,
|
||||
LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags);
|
||||
|
||||
typedef CHANNEL_OPEN_EVENT_FN* PCHANNEL_OPEN_EVENT_FN;
|
||||
typedef UINT VCAPITYPE VIRTUALCHANNELINIT(LPVOID* ppInitHandle, PCHANNEL_DEF pChannel,
|
||||
INT channelCount, ULONG versionRequested,
|
||||
PCHANNEL_INIT_EVENT_FN pChannelInitEventProc);
|
||||
typedef VIRTUALCHANNELINIT* PVIRTUALCHANNELINIT;
|
||||
|
||||
typedef UINT VCAPITYPE VIRTUALCHANNELOPEN(LPVOID pInitHandle, LPDWORD pOpenHandle,
|
||||
PCHAR pChannelName,
|
||||
PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc);
|
||||
|
||||
typedef VIRTUALCHANNELOPEN* PVIRTUALCHANNELOPEN;
|
||||
|
||||
typedef UINT VCAPITYPE VIRTUALCHANNELCLOSE(DWORD openHandle);
|
||||
typedef VIRTUALCHANNELCLOSE* PVIRTUALCHANNELCLOSE;
|
||||
|
||||
typedef UINT VCAPITYPE VIRTUALCHANNELWRITE(DWORD openHandle, LPVOID pData, ULONG dataLength,
|
||||
LPVOID pUserData);
|
||||
typedef VIRTUALCHANNELWRITE* PVIRTUALCHANNELWRITE;
|
||||
|
||||
typedef UINT VCAPITYPE VIRTUALCHANNELINITEX(LPVOID lpUserParam, LPVOID clientContext,
|
||||
LPVOID pInitHandle, PCHANNEL_DEF pChannel,
|
||||
INT channelCount, ULONG versionRequested,
|
||||
PCHANNEL_INIT_EVENT_EX_FN pChannelInitEventProcEx);
|
||||
typedef VIRTUALCHANNELINITEX* PVIRTUALCHANNELINITEX;
|
||||
|
||||
typedef UINT VCAPITYPE VIRTUALCHANNELOPENEX(LPVOID pInitHandle, LPDWORD pOpenHandle,
|
||||
PCHAR pChannelName,
|
||||
PCHANNEL_OPEN_EVENT_EX_FN pChannelOpenEventProcEx);
|
||||
typedef VIRTUALCHANNELOPENEX* PVIRTUALCHANNELOPENEX;
|
||||
|
||||
|
||||
typedef UINT VCAPITYPE VIRTUALCHANNELCLOSEEX(LPVOID pInitHandle, DWORD openHandle);
|
||||
typedef VIRTUALCHANNELCLOSEEX* PVIRTUALCHANNELCLOSEEX;
|
||||
|
||||
typedef UINT VCAPITYPE VIRTUALCHANNELWRITEEX(LPVOID pInitHandle, DWORD openHandle, LPVOID pData,
|
||||
ULONG dataLength, LPVOID pUserData);
|
||||
typedef VIRTUALCHANNELWRITEEX* PVIRTUALCHANNELWRITEEX;
|
||||
*/
|
||||
|
||||
// static channel name
|
||||
const (
|
||||
CLIPRDR_SVC_CHANNEL_NAME = "cliprdr" //剪切板
|
||||
RDPDR_SVC_CHANNEL_NAME = "rdpdr" //设备重定向(打印机,磁盘,端口,智能卡等)
|
||||
RDPSND_SVC_CHANNEL_NAME = "rdpsnd" //音频输出
|
||||
RAIL_SVC_CHANNEL_NAME = "rail" //远程应用
|
||||
DRDYNVC_SVC_CHANNEL_NAME = "drdynvc" //动态虚拟通道
|
||||
REMDESK_SVC_CHANNEL_NAME = "remdesk" //远程协助
|
||||
)
|
||||
|
||||
const (
|
||||
RDPGFX_DVC_CHANNEL_NAME = "Microsoft::Windows::RDS::Graphics" //图形扩展
|
||||
)
|
||||
|
||||
var StaticVirtualChannels = map[string]int{
|
||||
CLIPRDR_SVC_CHANNEL_NAME: CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
|
||||
CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL,
|
||||
RDPDR_SVC_CHANNEL_NAME: CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP,
|
||||
RDPSND_SVC_CHANNEL_NAME: CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
|
||||
CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL,
|
||||
RAIL_SVC_CHANNEL_NAME: CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
|
||||
CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL,
|
||||
}
|
||||
|
||||
const (
|
||||
CHANNEL_CHUNK_LENGTH = 1600
|
||||
CHANNEL_FLAG_FIRST = 0x01
|
||||
CHANNEL_FLAG_LAST = 0x02
|
||||
CHANNEL_FLAG_SHOW_PROTOCOL = 0x10
|
||||
)
|
||||
|
||||
type ChannelTransport interface {
|
||||
GetType() (string, uint32)
|
||||
Sender(core.ChannelSender)
|
||||
Process(s []byte)
|
||||
}
|
||||
type ChannelClient struct {
|
||||
ChannelDef
|
||||
t ChannelTransport
|
||||
}
|
||||
|
||||
type Channels struct {
|
||||
emission.Emitter
|
||||
channels map[string]ChannelClient
|
||||
transport core.Transport
|
||||
buff *bytes.Buffer
|
||||
channelSender core.ChannelSender
|
||||
}
|
||||
|
||||
func NewChannels(t core.Transport) *Channels {
|
||||
c := &Channels{
|
||||
Emitter: *emission.NewEmitter(),
|
||||
channels: make(map[string]ChannelClient, 20),
|
||||
transport: t,
|
||||
buff: &bytes.Buffer{},
|
||||
}
|
||||
t.On("channel", c.process)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Channels) SetChannelSender(f core.ChannelSender) {
|
||||
c.channelSender = f
|
||||
}
|
||||
func (c *Channels) Register(t ChannelTransport) {
|
||||
name, option := t.GetType()
|
||||
_, ok := c.channels[name]
|
||||
if ok {
|
||||
glog.Warn("Already register channel:", name)
|
||||
return
|
||||
}
|
||||
t.Sender(c)
|
||||
c.channels[name] = ChannelClient{ChannelDef{name, option}, t}
|
||||
}
|
||||
|
||||
func (c *Channels) SendToChannel(channel string, s []byte) (int, error) {
|
||||
cli, ok := c.channels[channel]
|
||||
if !ok {
|
||||
glog.Warn("No register channel:", channel)
|
||||
return 0, fmt.Errorf("No register channel: %s", channel)
|
||||
}
|
||||
idx := 0
|
||||
ln := len(s)
|
||||
b := &bytes.Buffer{}
|
||||
for ln > 0 {
|
||||
var flag uint32 = 0
|
||||
if cli.Options&CHANNEL_OPTION_SHOW_PROTOCOL != 0 {
|
||||
flag |= CHANNEL_FLAG_SHOW_PROTOCOL
|
||||
}
|
||||
if idx == 0 {
|
||||
flag |= CHANNEL_FLAG_FIRST
|
||||
}
|
||||
|
||||
var ss []byte
|
||||
if ln > CHANNEL_CHUNK_LENGTH {
|
||||
ss = s[idx : idx+CHANNEL_CHUNK_LENGTH]
|
||||
idx += CHANNEL_CHUNK_LENGTH
|
||||
} else {
|
||||
flag |= CHANNEL_FLAG_LAST
|
||||
ss = s[idx : idx+ln]
|
||||
}
|
||||
glog.Debug("len:", len(ss), "flag:", flag)
|
||||
ln -= len(ss)
|
||||
b.Reset()
|
||||
core.WriteUInt32LE(uint32(len(s)), b)
|
||||
core.WriteUInt32LE(flag, b)
|
||||
b.Write(ss)
|
||||
c.channelSender.SendToChannel(channel, b.Bytes())
|
||||
}
|
||||
return ln, nil
|
||||
}
|
||||
|
||||
func (c *Channels) process(channel string, s []byte) {
|
||||
cli, ok := c.channels[channel]
|
||||
if !ok {
|
||||
glog.Warn("No found channel:", channel)
|
||||
return
|
||||
}
|
||||
r := bytes.NewReader(s)
|
||||
ln, _ := core.ReadUInt32LE(r)
|
||||
flags, _ := core.ReadUInt32LE(r)
|
||||
glog.Debugf("channel:%s length: %d, flags: %d", channel, ln, flags)
|
||||
if flags&CHANNEL_FLAG_FIRST == 0 || flags&CHANNEL_FLAG_LAST == 0 {
|
||||
if flags&CHANNEL_FLAG_FIRST != 0 {
|
||||
c.buff.Reset()
|
||||
}
|
||||
b, _ := core.ReadBytes(r.Len(), r)
|
||||
c.buff.Write(b)
|
||||
if flags&CHANNEL_FLAG_LAST == 0 {
|
||||
return
|
||||
}
|
||||
s = c.buff.Bytes()
|
||||
} else {
|
||||
s, _ = core.ReadBytes(r.Len(), r)
|
||||
}
|
||||
|
||||
cli.t.Process(s)
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package drdynvc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
|
||||
"github.com/shadow1ng/fscan/mylib/grdp/core"
|
||||
"github.com/shadow1ng/fscan/mylib/grdp/glog"
|
||||
"github.com/shadow1ng/fscan/mylib/grdp/plugin"
|
||||
)
|
||||
|
||||
const (
|
||||
ChannelName = plugin.DRDYNVC_SVC_CHANNEL_NAME
|
||||
ChannelOption = plugin.CHANNEL_OPTION_INITIALIZED |
|
||||
plugin.CHANNEL_OPTION_ENCRYPT_RDP
|
||||
)
|
||||
|
||||
const (
|
||||
MAX_DVC_CHANNELS = 20
|
||||
)
|
||||
|
||||
const (
|
||||
DYNVC_CREATE_REQ = 0x01
|
||||
DYNVC_DATA_FIRST = 0x02
|
||||
DYNVC_DATA = 0x03
|
||||
DYNVC_CLOSE = 0x04
|
||||
DYNVC_CAPABILITIES = 0x05
|
||||
DYNVC_DATA_FIRST_COMPRESSED = 0x06
|
||||
DYNVC_DATA_COMPRESSED = 0x07
|
||||
DYNVC_SOFT_SYNC_REQUEST = 0x08
|
||||
DYNVC_SOFT_SYNC_RESPONSE = 0x09
|
||||
)
|
||||
|
||||
type ChannelClient struct {
|
||||
}
|
||||
|
||||
type DvcClient struct {
|
||||
w core.ChannelSender
|
||||
channels map[string]ChannelClient
|
||||
}
|
||||
|
||||
func NewDvcClient() *DvcClient {
|
||||
return &DvcClient{
|
||||
channels: make(map[string]ChannelClient, 100),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DvcClient) LoadAddin(f core.ChannelSender) {
|
||||
|
||||
}
|
||||
|
||||
type DvcHeader struct {
|
||||
cmd uint8
|
||||
sp uint8
|
||||
cbChId uint8
|
||||
}
|
||||
|
||||
func readHeader(r io.Reader) *DvcHeader {
|
||||
value, _ := core.ReadUInt8(r)
|
||||
cmd := (value & 0xf0) >> 4
|
||||
sp := (value & 0x0c) >> 2
|
||||
cbChId := (value & 0x03) >> 0
|
||||
return &DvcHeader{cmd, sp, cbChId}
|
||||
}
|
||||
|
||||
func (h *DvcHeader) serialize(channelId uint32) []byte {
|
||||
b := &bytes.Buffer{}
|
||||
core.WriteUInt8((h.cmd<<4)|(h.sp<<2)|h.cbChId, b)
|
||||
if h.cbChId == 0 {
|
||||
core.WriteUInt8(uint8(channelId), b)
|
||||
} else if h.cbChId == 1 {
|
||||
core.WriteUInt16LE(uint16(channelId), b)
|
||||
} else {
|
||||
core.WriteUInt32LE(channelId, b)
|
||||
}
|
||||
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (c *DvcClient) Send(s []byte) (int, error) {
|
||||
glog.Debug("len:", len(s), "data:", hex.EncodeToString(s))
|
||||
name, _ := c.GetType()
|
||||
return c.w.SendToChannel(name, s)
|
||||
}
|
||||
func (c *DvcClient) Sender(f core.ChannelSender) {
|
||||
c.w = f
|
||||
}
|
||||
func (c *DvcClient) GetType() (string, uint32) {
|
||||
return ChannelName, ChannelOption
|
||||
}
|
||||
|
||||
func (c *DvcClient) Process(s []byte) {
|
||||
glog.Debug("recv:", hex.EncodeToString(s))
|
||||
r := bytes.NewReader(s)
|
||||
hdr := readHeader(r)
|
||||
glog.Infof("dvc: Cmd=0x%x, Sp=%d CbChId=%d all=%d", hdr.cmd, hdr.sp, hdr.cbChId, r.Len())
|
||||
|
||||
b, _ := core.ReadBytes(r.Len(), r)
|
||||
|
||||
switch hdr.cmd {
|
||||
case DYNVC_CAPABILITIES:
|
||||
glog.Info("DYNVC_CAPABILITIES")
|
||||
c.processCapsPdu(hdr, b)
|
||||
case DYNVC_CREATE_REQ:
|
||||
glog.Info("DYNVC_CREATE_REQ")
|
||||
c.processCreateReq(hdr, b)
|
||||
case DYNVC_DATA_FIRST:
|
||||
glog.Info("DYNVC_DATA_FIRST")
|
||||
case DYNVC_DATA:
|
||||
glog.Info("DYNVC_DATA")
|
||||
case DYNVC_CLOSE:
|
||||
glog.Info("DYNVC_CLOSE")
|
||||
default:
|
||||
glog.Errorf("type 0x%x not supported", hdr.cmd)
|
||||
}
|
||||
}
|
||||
func (c *DvcClient) processCreateReq(hdr *DvcHeader, s []byte) {
|
||||
r := bytes.NewReader(s)
|
||||
channelId := readDvcId(r, hdr.cbChId)
|
||||
name, _ := core.ReadBytes(r.Len(), r)
|
||||
channelName := string(name)
|
||||
glog.Infof("Server requests channelId=%d, name=%s", channelId, channelName)
|
||||
|
||||
//response
|
||||
b := &bytes.Buffer{}
|
||||
b.Write(hdr.serialize(channelId))
|
||||
core.WriteUInt32LE(0, b)
|
||||
c.Send(b.Bytes())
|
||||
}
|
||||
|
||||
func readDvcId(r io.Reader, cbLen uint8) (id uint32) {
|
||||
switch cbLen {
|
||||
case 0:
|
||||
i, _ := core.ReadUInt8(r)
|
||||
id = uint32(i)
|
||||
case 1:
|
||||
i, _ := core.ReadUint16LE(r)
|
||||
id = uint32(i)
|
||||
default:
|
||||
id, _ = core.ReadUInt32LE(r)
|
||||
}
|
||||
return
|
||||
}
|
||||
func (c *DvcClient) processCapsPdu(hdr *DvcHeader, s []byte) {
|
||||
r := bytes.NewReader(s)
|
||||
core.ReadUInt8(r)
|
||||
ver, _ := core.ReadUint16LE(r)
|
||||
glog.Infof("Server supports dvc=%d", ver)
|
||||
|
||||
hdr.cmd = DYNVC_CAPABILITIES
|
||||
hdr.cbChId = 0
|
||||
hdr.sp = 0
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
core.WriteUInt16LE(0x0050, b)
|
||||
core.WriteUInt16LE(ver, b)
|
||||
c.Send(b.Bytes())
|
||||
}
|
||||
@@ -0,0 +1,451 @@
|
||||
// rail.go
|
||||
package rail
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/shadow1ng/fscan/mylib/grdp/core"
|
||||
"github.com/shadow1ng/fscan/mylib/grdp/glog"
|
||||
"github.com/shadow1ng/fscan/mylib/grdp/plugin"
|
||||
)
|
||||
|
||||
const (
|
||||
ChannelName = plugin.RAIL_SVC_CHANNEL_NAME
|
||||
ChannelOption = plugin.CHANNEL_OPTION_INITIALIZED | plugin.CHANNEL_OPTION_ENCRYPT_RDP |
|
||||
plugin.CHANNEL_OPTION_COMPRESS_RDP | plugin.CHANNEL_OPTION_SHOW_PROTOCOL
|
||||
)
|
||||
|
||||
const (
|
||||
TS_RAIL_ORDER_EXEC = 0x0001
|
||||
TS_RAIL_ORDER_ACTIVATE = 0x0002
|
||||
TS_RAIL_ORDER_SYSPARAM = 0x0003
|
||||
TS_RAIL_ORDER_SYSCOMMAND = 0x0004
|
||||
TS_RAIL_ORDER_HANDSHAKE = 0x0005
|
||||
TS_RAIL_ORDER_NOTIFY_EVENT = 0x0006
|
||||
TS_RAIL_ORDER_WINDOWMOVE = 0x0008
|
||||
TS_RAIL_ORDER_LOCALMOVESIZE = 0x0009
|
||||
TS_RAIL_ORDER_MINMAXINFO = 0x000A
|
||||
TS_RAIL_ORDER_CLIENTSTATUS = 0x000B
|
||||
TS_RAIL_ORDER_SYSMENU = 0x000C
|
||||
TS_RAIL_ORDER_LANGBARINFO = 0x000D
|
||||
TS_RAIL_ORDER_GET_APPID_REQ = 0x000E
|
||||
TS_RAIL_ORDER_GET_APPID_RESP = 0x000F
|
||||
TS_RAIL_ORDER_TASKBARINFO = 0x0010
|
||||
TS_RAIL_ORDER_LANGUAGEIMEINFO = 0x0011
|
||||
TS_RAIL_ORDER_COMPARTMENTINFO = 0x0012
|
||||
TS_RAIL_ORDER_HANDSHAKE_EX = 0x0013
|
||||
TS_RAIL_ORDER_ZORDER_SYNC = 0x0014
|
||||
TS_RAIL_ORDER_CLOAK = 0x0015
|
||||
TS_RAIL_ORDER_POWER_DISPLAY_REQUEST = 0x0016
|
||||
TS_RAIL_ORDER_SNAP_ARRANGE = 0x0017
|
||||
TS_RAIL_ORDER_GET_APPID_RESP_EX = 0x0018
|
||||
TS_RAIL_ORDER_EXEC_RESULT = 0x0080
|
||||
)
|
||||
|
||||
type RailClient struct {
|
||||
w core.ChannelSender
|
||||
DesktopWidth uint16
|
||||
DesktopHeight uint16
|
||||
RemoteApplicationProgram string
|
||||
ShellWorkingDirectory string
|
||||
RemoteApplicationCmdLine string
|
||||
}
|
||||
|
||||
func NewClient() *RailClient {
|
||||
return &RailClient{
|
||||
DesktopWidth: 800,
|
||||
DesktopHeight: 600,
|
||||
RemoteApplicationProgram: "calc",
|
||||
ShellWorkingDirectory: "/tmp",
|
||||
}
|
||||
}
|
||||
|
||||
type RailPDUHeader struct {
|
||||
OrderType uint16 `struc:"little"`
|
||||
OrderLength uint16 `struc:"little"`
|
||||
}
|
||||
|
||||
func NewRailPDUHeader(mType, ln uint16) *RailPDUHeader {
|
||||
return &RailPDUHeader{
|
||||
OrderType: mType,
|
||||
OrderLength: ln,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *RailPDUHeader) serialize() []byte {
|
||||
b := &bytes.Buffer{}
|
||||
core.WriteUInt16LE(h.OrderType, b)
|
||||
core.WriteUInt16LE(h.OrderLength, b)
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (c *RailClient) sendData(mType uint16, ln int, s []byte) {
|
||||
glog.Debug(ln, ":ln:", len(s), "data:", hex.EncodeToString(s))
|
||||
header := NewRailPDUHeader(mType, uint16(ln))
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
core.WriteBytes(header.serialize(), b)
|
||||
core.WriteBytes(s, b)
|
||||
|
||||
c.Send(b.Bytes())
|
||||
}
|
||||
|
||||
func (c *RailClient) Send(s []byte) (int, error) {
|
||||
glog.Debug("len:", len(s), "data:", hex.EncodeToString(s))
|
||||
name, _ := c.GetType()
|
||||
return c.w.SendToChannel(name, s)
|
||||
}
|
||||
func (c *RailClient) Sender(f core.ChannelSender) {
|
||||
c.w = f
|
||||
}
|
||||
func (c *RailClient) GetType() (string, uint32) {
|
||||
return ChannelName, ChannelOption
|
||||
}
|
||||
|
||||
func (c *RailClient) Process(s []byte) {
|
||||
glog.Debug("recv:", hex.EncodeToString(s))
|
||||
r := bytes.NewReader(s)
|
||||
msgType, _ := core.ReadUint16LE(r)
|
||||
length, _ := core.ReadUint16LE(r)
|
||||
|
||||
glog.Infof("rail: type=0x%x length=%d, all=%d", msgType, length, r.Len())
|
||||
|
||||
b, _ := core.ReadBytes(int(length), r)
|
||||
glog.Info("b:", hex.EncodeToString(b))
|
||||
|
||||
switch msgType {
|
||||
case TS_RAIL_ORDER_HANDSHAKE:
|
||||
glog.Info("TS_RAIL_ORDER_HANDSHAKE")
|
||||
c.processOrderHandshake(b)
|
||||
case TS_RAIL_ORDER_SYSPARAM:
|
||||
glog.Info("TS_RAIL_ORDER_SYSPARAM")
|
||||
c.processOrderSysparam(b)
|
||||
case TS_RAIL_ORDER_EXEC_RESULT:
|
||||
glog.Info("TS_RAIL_ORDER_EXEC_RESULT")
|
||||
c.processExecResult(b)
|
||||
|
||||
default:
|
||||
glog.Errorf("type 0x%x not supported", msgType)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RailClient) processOrderHandshake(b []byte) {
|
||||
r := bytes.NewReader(b)
|
||||
buildNumber, _ := core.ReadUInt32LE(r)
|
||||
glog.Info("buildNumber:", buildNumber)
|
||||
|
||||
//send client info
|
||||
c.sendClientStatus()
|
||||
|
||||
//send client systemparam
|
||||
c.sendClientSystemparam()
|
||||
|
||||
//send client execute
|
||||
c.sendClientExecute()
|
||||
}
|
||||
|
||||
const (
|
||||
TS_RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE = 0x00000001
|
||||
TS_RAIL_CLIENTSTATUS_AUTORECONNECT = 0x00000002
|
||||
TS_RAIL_CLIENTSTATUS_ZORDER_SYNC = 0x00000004
|
||||
TS_RAIL_CLIENTSTATUS_WINDOW_RESIZE_MARGIN_SUPPORTED = 0x00000010
|
||||
TS_RAIL_CLIENTSTATUS_HIGH_DPI_ICONS_SUPPORTED = 0x00000020
|
||||
TS_RAIL_CLIENTSTATUS_APPBAR_REMOTING_SUPPORTED = 0x00000040
|
||||
TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED = 0x00000080
|
||||
TS_RAIL_CLIENTSTATUS_GET_APPID_RESPONSE_EX_SUPPORTED = 0x00000100
|
||||
TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED = 0x00000200
|
||||
)
|
||||
|
||||
func (c *RailClient) sendClientStatus() {
|
||||
glog.Info("Send client Status")
|
||||
var flags uint32 = TS_RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE
|
||||
|
||||
//if (settings->AutoReconnectionEnabled)
|
||||
//clientStatus.flags |= TS_RAIL_CLIENTSTATUS_AUTORECONNECT;
|
||||
|
||||
flags |= TS_RAIL_CLIENTSTATUS_ZORDER_SYNC
|
||||
flags |= TS_RAIL_CLIENTSTATUS_WINDOW_RESIZE_MARGIN_SUPPORTED
|
||||
flags |= TS_RAIL_CLIENTSTATUS_APPBAR_REMOTING_SUPPORTED
|
||||
flags |= TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED
|
||||
flags |= TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
core.WriteUInt32LE(flags, b)
|
||||
|
||||
c.sendData(TS_RAIL_ORDER_CLIENTSTATUS, 4, b.Bytes())
|
||||
}
|
||||
|
||||
const (
|
||||
SPI_SET_SCREEN_SAVE_ACTIVE = 0x00000011
|
||||
SPI_SET_SCREEN_SAVE_SECURE = 0x00000077
|
||||
)
|
||||
const (
|
||||
/*Bit mask values for SPI_ parameters*/
|
||||
SPI_MASK_SET_DRAG_FULL_WINDOWS = 0x00000001
|
||||
SPI_MASK_SET_KEYBOARD_CUES = 0x00000002
|
||||
SPI_MASK_SET_KEYBOARD_PREF = 0x00000004
|
||||
SPI_MASK_SET_MOUSE_BUTTON_SWAP = 0x00000008
|
||||
SPI_MASK_SET_WORK_AREA = 0x00000010
|
||||
SPI_MASK_DISPLAY_CHANGE = 0x00000020
|
||||
SPI_MASK_TASKBAR_POS = 0x00000040
|
||||
SPI_MASK_SET_HIGH_CONTRAST = 0x00000080
|
||||
SPI_MASK_SET_SCREEN_SAVE_ACTIVE = 0x00000100
|
||||
SPI_MASK_SET_SET_SCREEN_SAVE_SECURE = 0x00000200
|
||||
SPI_MASK_SET_CARET_WIDTH = 0x00000400
|
||||
SPI_MASK_SET_STICKY_KEYS = 0x00000800
|
||||
SPI_MASK_SET_TOGGLE_KEYS = 0x00001000
|
||||
SPI_MASK_SET_FILTER_KEYS = 0x00002000
|
||||
)
|
||||
const (
|
||||
SPI_SET_DRAG_FULL_WINDOWS = 0x00000025
|
||||
SPI_SET_KEYBOARD_CUES = 0x0000100B
|
||||
SPI_SET_KEYBOARD_PREF = 0x00000045
|
||||
SPI_SET_MOUSE_BUTTON_SWAP = 0x00000021
|
||||
SPI_SET_WORK_AREA = 0x0000002F
|
||||
SPI_DISPLAY_CHANGE = 0x0000F001
|
||||
SPI_TASKBAR_POS = 0x0000F000
|
||||
SPI_SET_HIGH_CONTRAST = 0x00000043
|
||||
SPI_SETCARETWIDTH = 0x00002007
|
||||
SPI_SETSTICKYKEYS = 0x0000003B
|
||||
SPI_SETTOGGLEKEYS = 0x00000035
|
||||
SPI_SETFILTERKEYS = 0x00000033
|
||||
)
|
||||
|
||||
type TsFilterKeys struct {
|
||||
Flags uint32
|
||||
WaitTime uint32
|
||||
DelayTime uint32
|
||||
RepeatTime uint32
|
||||
BounceTime uint32
|
||||
}
|
||||
type RailHighContrast struct {
|
||||
flags uint32
|
||||
colorSchemeLength uint32
|
||||
colorScheme string
|
||||
}
|
||||
type Rectangle16 struct {
|
||||
left uint16
|
||||
top uint16
|
||||
right uint16
|
||||
bottom uint16
|
||||
}
|
||||
type RailSysparamOrder struct {
|
||||
param uint32
|
||||
params uint32
|
||||
dragFullWindows uint8
|
||||
keyboardCues uint8
|
||||
keyboardPref uint8
|
||||
mouseButtonSwap uint8
|
||||
workArea Rectangle16
|
||||
displayChange Rectangle16
|
||||
taskbarPos Rectangle16
|
||||
highContrast RailHighContrast
|
||||
caretWidth uint32
|
||||
stickyKeys uint32
|
||||
toggleKeys uint32
|
||||
filterKeys TsFilterKeys
|
||||
setScreenSaveActive uint8
|
||||
setScreenSaveSecure uint8
|
||||
}
|
||||
|
||||
func (c *RailClient) sendClientSystemparam() {
|
||||
glog.Info("Send client Systemparam")
|
||||
|
||||
var sp RailSysparamOrder
|
||||
sp.params = 0
|
||||
sp.params |= SPI_MASK_SET_HIGH_CONTRAST
|
||||
sp.highContrast.colorScheme = ""
|
||||
sp.highContrast.colorSchemeLength = 0
|
||||
sp.highContrast.flags = 0x7E
|
||||
sp.params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP
|
||||
sp.mouseButtonSwap = 0
|
||||
sp.params |= SPI_MASK_SET_KEYBOARD_PREF
|
||||
sp.keyboardPref = 0
|
||||
sp.params |= SPI_MASK_SET_DRAG_FULL_WINDOWS
|
||||
sp.dragFullWindows = 0
|
||||
sp.params |= SPI_MASK_SET_KEYBOARD_CUES
|
||||
sp.keyboardCues = 0
|
||||
sp.params |= SPI_MASK_SET_WORK_AREA
|
||||
sp.workArea.left = 0
|
||||
sp.workArea.top = 0
|
||||
sp.workArea.right = c.DesktopWidth
|
||||
sp.workArea.bottom = c.DesktopHeight
|
||||
|
||||
if sp.params&SPI_MASK_SET_HIGH_CONTRAST != 0 {
|
||||
sp.param = SPI_SET_HIGH_CONTRAST
|
||||
c.sendOneClientSysparam(&sp)
|
||||
}
|
||||
|
||||
if sp.params&SPI_MASK_TASKBAR_POS != 0 {
|
||||
sp.param = SPI_TASKBAR_POS
|
||||
c.sendOneClientSysparam(&sp)
|
||||
}
|
||||
|
||||
if sp.params&SPI_MASK_SET_MOUSE_BUTTON_SWAP != 0 {
|
||||
sp.param = SPI_SET_MOUSE_BUTTON_SWAP
|
||||
c.sendOneClientSysparam(&sp)
|
||||
}
|
||||
|
||||
if sp.params&SPI_MASK_SET_KEYBOARD_PREF != 0 {
|
||||
sp.param = SPI_SET_KEYBOARD_PREF
|
||||
c.sendOneClientSysparam(&sp)
|
||||
}
|
||||
|
||||
if sp.params&SPI_MASK_SET_DRAG_FULL_WINDOWS != 0 {
|
||||
sp.param = SPI_SET_DRAG_FULL_WINDOWS
|
||||
c.sendOneClientSysparam(&sp)
|
||||
}
|
||||
|
||||
if sp.params&SPI_MASK_SET_KEYBOARD_CUES != 0 {
|
||||
sp.param = SPI_SET_KEYBOARD_CUES
|
||||
c.sendOneClientSysparam(&sp)
|
||||
}
|
||||
|
||||
if sp.params&SPI_MASK_SET_WORK_AREA != 0 {
|
||||
sp.param = SPI_SET_WORK_AREA
|
||||
glog.Debug("SPI_SET_WORK_AREA")
|
||||
c.sendOneClientSysparam(&sp)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RailClient) sendOneClientSysparam(sp *RailSysparamOrder) {
|
||||
length := 0
|
||||
b := &bytes.Buffer{}
|
||||
core.WriteUInt32LE(sp.param, b)
|
||||
switch sp.param {
|
||||
case SPI_SET_DRAG_FULL_WINDOWS:
|
||||
core.WriteUInt8(sp.dragFullWindows, b)
|
||||
|
||||
case SPI_SET_KEYBOARD_CUES:
|
||||
core.WriteUInt8(sp.keyboardCues, b)
|
||||
|
||||
case SPI_SET_KEYBOARD_PREF:
|
||||
core.WriteUInt8(sp.keyboardPref, b)
|
||||
|
||||
case SPI_SET_MOUSE_BUTTON_SWAP:
|
||||
core.WriteUInt8(sp.mouseButtonSwap, b)
|
||||
|
||||
case SPI_SET_WORK_AREA:
|
||||
core.WriteUInt16LE(sp.workArea.left, b)
|
||||
core.WriteUInt16LE(sp.workArea.top, b)
|
||||
core.WriteUInt16LE(sp.workArea.right, b)
|
||||
core.WriteUInt16LE(sp.workArea.bottom, b)
|
||||
|
||||
case SPI_DISPLAY_CHANGE:
|
||||
core.WriteUInt16LE(sp.displayChange.left, b)
|
||||
core.WriteUInt16LE(sp.displayChange.top, b)
|
||||
core.WriteUInt16LE(sp.displayChange.right, b)
|
||||
core.WriteUInt16LE(sp.displayChange.bottom, b)
|
||||
|
||||
case SPI_TASKBAR_POS:
|
||||
core.WriteUInt16LE(sp.taskbarPos.left, b)
|
||||
core.WriteUInt16LE(sp.taskbarPos.top, b)
|
||||
core.WriteUInt16LE(sp.taskbarPos.right, b)
|
||||
core.WriteUInt16LE(sp.taskbarPos.bottom, b)
|
||||
|
||||
case SPI_SET_HIGH_CONTRAST:
|
||||
core.WriteUInt32LE(sp.highContrast.flags, b)
|
||||
core.WriteUInt32LE(sp.highContrast.colorSchemeLength, b)
|
||||
data := core.UnicodeEncode(sp.highContrast.colorScheme)
|
||||
core.WriteBytes(data, b)
|
||||
|
||||
case SPI_SETFILTERKEYS:
|
||||
core.WriteUInt32LE(sp.filterKeys.Flags, b)
|
||||
core.WriteUInt32LE(sp.filterKeys.WaitTime, b)
|
||||
core.WriteUInt32LE(sp.filterKeys.DelayTime, b)
|
||||
core.WriteUInt32LE(sp.filterKeys.RepeatTime, b)
|
||||
core.WriteUInt32LE(sp.filterKeys.BounceTime, b)
|
||||
|
||||
case SPI_SETSTICKYKEYS:
|
||||
core.WriteUInt32LE(sp.stickyKeys, b)
|
||||
|
||||
case SPI_SETCARETWIDTH:
|
||||
core.WriteUInt32LE(sp.caretWidth, b)
|
||||
|
||||
case SPI_SETTOGGLEKEYS:
|
||||
core.WriteUInt32LE(sp.toggleKeys, b)
|
||||
|
||||
case SPI_MASK_SET_SET_SCREEN_SAVE_SECURE:
|
||||
core.WriteUInt8(sp.setScreenSaveSecure, b)
|
||||
|
||||
case SPI_MASK_SET_SCREEN_SAVE_ACTIVE:
|
||||
core.WriteUInt8(sp.setScreenSaveActive, b)
|
||||
|
||||
default:
|
||||
glog.Error("ERROR_BAD_ARGUMENTS")
|
||||
return
|
||||
}
|
||||
|
||||
c.sendData(TS_RAIL_ORDER_SYSPARAM, length+b.Len(), b.Bytes())
|
||||
}
|
||||
|
||||
type RailExecOrder struct {
|
||||
flags uint16
|
||||
RemoteApplicationProgram string
|
||||
RemoteApplicationWorkingDir string
|
||||
RemoteApplicationArguments string
|
||||
}
|
||||
|
||||
func (c *RailClient) sendClientExecute() {
|
||||
glog.Info("Send Client Execute")
|
||||
var exec RailExecOrder
|
||||
//exec.flags = TS_RAIL_EXEC_FLAG_EXPAND_ARGUMENTS
|
||||
exec.RemoteApplicationProgram = c.RemoteApplicationProgram
|
||||
exec.RemoteApplicationWorkingDir = c.ShellWorkingDirectory
|
||||
exec.RemoteApplicationArguments = c.RemoteApplicationCmdLine
|
||||
|
||||
program := core.UnicodeEncode(exec.RemoteApplicationProgram)
|
||||
workdir := core.UnicodeEncode(exec.RemoteApplicationWorkingDir)
|
||||
arguments := core.UnicodeEncode(exec.RemoteApplicationArguments)
|
||||
|
||||
length := 4
|
||||
b := &bytes.Buffer{}
|
||||
core.WriteUInt16LE(exec.flags, b)
|
||||
core.WriteUInt16LE(uint16(len(program)), b)
|
||||
core.WriteUInt16LE(uint16(len(workdir)), b)
|
||||
core.WriteUInt16LE(uint16(len(arguments)), b)
|
||||
core.WriteBytes(program, b)
|
||||
core.WriteBytes(workdir, b)
|
||||
core.WriteBytes(arguments, b)
|
||||
length += b.Len()
|
||||
|
||||
c.sendData(TS_RAIL_ORDER_EXEC, length, b.Bytes())
|
||||
|
||||
}
|
||||
|
||||
func (c *RailClient) processOrderSysparam(b []byte) {
|
||||
r := bytes.NewReader(b)
|
||||
systemParam, _ := core.ReadUInt32LE(r)
|
||||
body, _ := core.ReadUInt8(r)
|
||||
glog.Infof("systemParam:0x%x, body:%d", systemParam, body)
|
||||
}
|
||||
|
||||
const (
|
||||
//The Client Execute request was successful and the requested application or file has been launched.
|
||||
RAIL_EXEC_S_OK = 0x0000
|
||||
//The Client Execute request could not be satisfied because the server is not monitoring the current input desktop.
|
||||
RAIL_EXEC_E_HOOK_NOT_LOADED = 0x0001
|
||||
//The Execute request could not be satisfied because the request PDU was malformed.
|
||||
RAIL_EXEC_E_DECODE_FAILED = 0x0002
|
||||
//The Client Execute request could not be satisfied because the requested application was blocked by policy from being launched on the server.
|
||||
RAIL_EXEC_E_NOT_IN_ALLOWLIST = 0x0003
|
||||
//The Client Execute request could not be satisfied because the application or file path could not be found.
|
||||
RAIL_EXEC_E_FILE_NOT_FOUND = 0x0005
|
||||
//The Client Execute request could not be satisfied because an unspecified error occurred on the server.
|
||||
RAIL_EXEC_E_FAIL = 0x0006
|
||||
//The Client Execute request could not be satisfied because the remote session is locked.
|
||||
RAIL_EXEC_E_SESSION_LOCKED = 0x0007
|
||||
)
|
||||
|
||||
func (c *RailClient) processExecResult(b []byte) {
|
||||
r := bytes.NewReader(b)
|
||||
flags, _ := core.ReadUint16LE(r)
|
||||
execResult, _ := core.ReadUint16LE(r)
|
||||
rawResult, _ := core.ReadUInt32LE(r)
|
||||
core.ReadUint16LE(r)
|
||||
exeOrFileLength, _ := core.ReadUint16LE(r)
|
||||
exeOrFile, _ := core.ReadBytes(r.Len(), r)
|
||||
glog.Info("flags:", flags, "execResult:", execResult, "rawResult:", rawResult)
|
||||
glog.Info("length:", exeOrFileLength, "file:", core.UnicodeDecode(exeOrFile))
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package rdpgfx
|
||||
|
||||
import (
|
||||
"github.com/shadow1ng/fscan/mylib/grdp/plugin"
|
||||
)
|
||||
|
||||
const (
|
||||
ChannelName = plugin.RDPGFX_DVC_CHANNEL_NAME
|
||||
)
|
||||
Reference in New Issue
Block a user