diff options
author | Marc-André Moreau <marcandre.moreau@gmail.com> | 2011-03-13 04:48:13 +0300 |
---|---|---|
committer | Marc-André Moreau <marcandre.moreau@gmail.com> | 2011-03-13 04:48:13 +0300 |
commit | 63bc595c94521369b6996717ff03fa49f232d9c8 (patch) | |
tree | bba4fcc719fc55319fafb141b2be6dfd4b422958 |
-rw-r--r-- | packet-rdp.c | 725 | ||||
-rw-r--r-- | packet-rdp.h | 34 | ||||
-rw-r--r-- | readme.txt | 52 |
3 files changed, 811 insertions, 0 deletions
diff --git a/packet-rdp.c b/packet-rdp.c new file mode 100644 index 0000000..3789b7c --- /dev/null +++ b/packet-rdp.c @@ -0,0 +1,725 @@ +/* packet-rdp.c + * Routines for Remote Desktop Protocol dissection + * Copyright 2010, Marc-Andre Moreau <marcandre.moreau@gmail.com> + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glib.h> +#include <epan/packet.h> +#include <epan/prefs.h> +#include "packet-rdp.h" + +gint bytes = 0; +gint offset = 0; +gint rdp_offset = 0; +gint tpkt_offset = 0; +gint x224_offset = 0; +gint mcs_offset = 0; +gint ts_security_header_offset = 0; +gint ts_share_control_header_offset = 0; +gint ts_share_data_header_offset = 0; +gint ts_confirm_active_pdu_offset = 0; +gint ts_caps_set_offset = 0; + +int proto_rdp = -1; +static int hf_rdp_rdp = -1; +static int hf_rdp_tpkt = -1; +static int hf_rdp_x224 = -1; +static int hf_rdp_mcs = -1; +static int hf_ts_security_header = -1; +static int hf_ts_share_control_header = -1; +static int hf_ts_share_data_header = -1; + +static int hf_ts_confirm_active_pdu = -1; +static int hf_ts_confirm_active_pdu_shareid = -1; +static int hf_ts_confirm_active_pdu_originatorid = -1; +static int hf_ts_confirm_active_pdu_length_source_descriptor = -1; +static int hf_ts_confirm_active_pdu_length_combined_capabilities = -1; +static int hf_ts_confirm_active_pdu_source_descriptor = -1; +static int hf_ts_confirm_active_pdu_number_capabilities = -1; +static int hf_ts_confirm_active_pdu_pad2octets = -1; + +static int hf_ts_capability_sets = -1; + +static int hf_ts_caps_set = -1; +static int hf_ts_caps_set_capability_set_type = -1; +static int hf_ts_caps_set_length_capability = -1; +static int hf_ts_caps_set_capability_data = -1; + +static gint ett_rdp = -1; +static gint ett_ts_confirm_active_pdu = -1; +static gint ett_ts_capability_sets = -1; +static gint ett_ts_caps_set = -1; + +#define SEC_EXCHANGE_PKT 0x0001 +#define SEC_ENCRYPT 0x0008 +#define SEC_RESET_SEQNO 0x0010 +#define SEC_IGNORE_SEQNO 0x0020 +#define SEC_INFO_PKT 0x0040 +#define SEC_LICENSE_PKT 0x0080 +#define SEC_LICENSE_ENCRYPT_CS 0x0200 +#define SEC_LICENSE_ENCRYPT_SC 0x0200 +#define SEC_REDIRECTION_PKT 0x0400 +#define SEC_SECURE_CHECKSUM 0x0800 +#define SEC_FLAGSHI_VALID 0x8000 + +#define PDUTYPE_DEMAND_ACTIVE_PDU 0x1 +#define PDUTYPE_CONFIRM_ACTIVE_PDU 0x3 +#define PDUTYPE_DEACTIVATE_ALL_PDU 0x6 +#define PDUTYPE_DATA_PDU 0x7 +#define PDUTYPE_SERVER_REDIR_PKT 0xA + +#define PDUTYPE2_UPDATE 2 +#define PDUTYPE2_CONTROL 20 +#define PDUTYPE2_POINTER 27 +#define PDUTYPE2_INPUT 28 +#define PDUTYPE2_SYNCHRONIZE 31 +#define PDUTYPE2_REFRESH_RECT 33 +#define PDUTYPE2_PLAY_SOUND 34 +#define PDUTYPE2_SUPPRESS_OUTPUT 35 +#define PDUTYPE2_SHUTDOWN_REQUEST 36 +#define PDUTYPE2_SHUTDOWN_DENIED 37 +#define PDUTYPE2_SAVE_SESSION_INFO 38 +#define PDUTYPE2_FONTLIST 39 +#define PDUTYPE2_FONTMAP 40 +#define PDUTYPE2_SET_KEYBOARD_INDICATORS 41 +#define PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST 43 +#define PDUTYPE2_BITMAPCACHE_ERROR_PDU 44 +#define PDUTYPE2_SET_KEYBOARD_IME_STATUS 45 +#define PDUTYPE2_OFFSCRCACHE_ERROR_PDU 46 +#define PDUTYPE2_SET_ERROR_INFO_PDU 47 +#define PDUTYPE2_DRAWNINEGRID_ERROR_PDU 48 +#define PDUTYPE2_DRAWGDIPLUS_ERROR_PDU 49 +#define PDUTYPE2_ARC_STATUS_PDU 50 +#define PDUTYPE2_STATUS_INFO_PDU 54 +#define PDUTYPE2_MONITOR_LAYOUT_PDU 55 + +#define CAPSET_TYPE_GENERAL 0x0001 +#define CAPSET_TYPE_BITMAP 0x0002 +#define CAPSET_TYPE_ORDER 0x0003 +#define CAPSET_TYPE_BITMAPCACHE 0x0004 +#define CAPSET_TYPE_CONTROL 0x0005 +#define CAPSET_TYPE_ACTIVATION 0x0007 +#define CAPSET_TYPE_POINTER 0x0008 +#define CAPSET_TYPE_SHARE 0x0009 +#define CAPSET_TYPE_COLORCACHE 0x000A +#define CAPSET_TYPE_SOUND 0x000C +#define CAPSET_TYPE_INPUT 0x000D +#define CAPSET_TYPE_FONT 0x000E +#define CAPSET_TYPE_BRUSH 0x000F +#define CAPSET_TYPE_GLYPHCACHE 0x0010 +#define CAPSET_TYPE_OFFSCREENCACHE 0x0011 +#define CAPSET_TYPE_BITMAPCACHE_HOSTSUPPORT 0x0012 +#define CAPSET_TYPE_BITMAPCACHE_REV2 0x0013 +#define CAPSET_TYPE_VIRTUALCHANNEL 0x0014 +#define CAPSET_TYPE_DRAWNINEGRIDCACHE 0x0015 +#define CAPSET_TYPE_DRAWGDIPLUS 0x0016 +#define CAPSET_TYPE_RAIL 0x0017 +#define CAPSET_TYPE_WINDOW 0x0018 +#define CAPSET_TYPE_COMPDESK 0x0019 +#define CAPSET_TYPE_MULTIFRAGMENTUPDATE 0x001A +#define CAPSET_TYPE_LARGE_POINTER 0x001B +#define CAPSET_TYPE_SURFACE_COMMANDS 0x001C +#define CAPSET_TYPE_BITMAP_CODECS 0x001D + +#define MCS_ERECT_DOMAIN_REQUEST 0x01 +#define MCS_DISCONNECT_PROVIDER_ULTIMATUM 0x08 +#define MCS_ATTACH_USER_REQUEST 0x0A +#define MCS_ATTACH_USER_CONFIRM 0x0B +#define MCS_CHANNEL_JOIN_REQUEST 0x0E +#define MCS_CHANNEL_JOIN_CONFIRM 0x0F +#define MCS_SEND_DATA_REQUEST 0x19 +#define MCS_SEND_DATA_INDICATION 0x1A +#define MCS_CONNECT_INITIAL 0x65 +#define MCS_CONNECT_RESPONSE 0x66 + +#define X224_CONNECTION_REQUEST 0xE +#define X224_CONNECTION_CONFIRM 0xD +#define X224_DISCONNECT_REQUEST 0x8 +#define X224_DISCONNECT_CONFIRM 0xC +#define X224_DATA 0xF + +static const value_string capability_set_types[] = { + { CAPSET_TYPE_GENERAL, "General" }, + { CAPSET_TYPE_BITMAP, "Bitmap" }, + { CAPSET_TYPE_ORDER, "Order" }, + { CAPSET_TYPE_BITMAPCACHE, "Bitmap Cache Revision 1" }, + { CAPSET_TYPE_CONTROL, "Control" }, + { CAPSET_TYPE_ACTIVATION, "Window Activation" }, + { CAPSET_TYPE_POINTER, "Pointer" }, + { CAPSET_TYPE_SHARE, "Share" }, + { CAPSET_TYPE_COLORCACHE, "Color Table Cache" }, + { CAPSET_TYPE_SOUND, "Sound" }, + { CAPSET_TYPE_INPUT, "Input" }, + { CAPSET_TYPE_FONT, "Font" }, + { CAPSET_TYPE_BRUSH, "Brush" }, + { CAPSET_TYPE_GLYPHCACHE, "Glyph" }, + { CAPSET_TYPE_OFFSCREENCACHE, "Offscreen" }, + { CAPSET_TYPE_BITMAPCACHE_HOSTSUPPORT, "Bitmap Cache Host Support" }, + { CAPSET_TYPE_BITMAPCACHE_REV2, "Bitmap Cache Revison 2" }, + { CAPSET_TYPE_VIRTUALCHANNEL, "Virtual Channel" }, + { CAPSET_TYPE_DRAWNINEGRIDCACHE, "DrawNineGrid Cache" }, + { CAPSET_TYPE_DRAWGDIPLUS, "Draw GDI+ Cache" }, + { CAPSET_TYPE_RAIL, "Remote Programs" }, + { CAPSET_TYPE_WINDOW, "Window List" }, + { CAPSET_TYPE_COMPDESK, "Desktop Composition Extension" }, + { CAPSET_TYPE_MULTIFRAGMENTUPDATE, "Multifragment Update" }, + { CAPSET_TYPE_LARGE_POINTER, "Large Pointer" }, + { CAPSET_TYPE_SURFACE_COMMANDS, "Surface Commands" }, + { CAPSET_TYPE_BITMAP_CODECS, "Bitmap Codecs" }, + { 0x0, NULL } +}; + +static const value_string pdu_types[] = { + { PDUTYPE_DEMAND_ACTIVE_PDU, "Demand Active" }, + { PDUTYPE_CONFIRM_ACTIVE_PDU, "Confirm Active" }, + { PDUTYPE_DEACTIVATE_ALL_PDU, "Deactivate All" }, + { PDUTYPE_DATA_PDU, "Data" }, + { PDUTYPE_SERVER_REDIR_PKT, "Server Redirection Packet" }, + { 0x0, NULL } +}; + +static const value_string pdu2_types[] = { + { PDUTYPE2_UPDATE, "Update" }, + { PDUTYPE2_CONTROL, "Control" }, + { PDUTYPE2_POINTER, "Pointer" }, + { PDUTYPE2_INPUT, "Input" }, + { PDUTYPE2_SYNCHRONIZE, "Synchronize" }, + { PDUTYPE2_REFRESH_RECT, "Refresh Rect" }, + { PDUTYPE2_PLAY_SOUND, "Play Sound" }, + { PDUTYPE2_SUPPRESS_OUTPUT, "Suppress Output" }, + { PDUTYPE2_SHUTDOWN_REQUEST, "Shutdown Request" }, + { PDUTYPE2_SHUTDOWN_DENIED, "Shutdown Denied" }, + { PDUTYPE2_SAVE_SESSION_INFO, "Save Session Info" }, + { PDUTYPE2_FONTLIST, "Font List" }, + { PDUTYPE2_FONTMAP, "Font Map" }, + { PDUTYPE2_SET_KEYBOARD_INDICATORS, "Set Keyboard Indicator" }, + { PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST, "Bitmap Cache Persistent List" }, + { PDUTYPE2_BITMAPCACHE_ERROR_PDU, "Bitmap Cache Error" }, + { PDUTYPE2_SET_KEYBOARD_IME_STATUS, "Set Keyboard IME Status" }, + { PDUTYPE2_OFFSCRCACHE_ERROR_PDU, "Offscreen Cache Error" }, + { PDUTYPE2_SET_ERROR_INFO_PDU, "Set Error Info" }, + { PDUTYPE2_DRAWNINEGRID_ERROR_PDU, "Draw Nine Grid Error" }, + { PDUTYPE2_DRAWGDIPLUS_ERROR_PDU, "Draw GDI+ Error" }, + { PDUTYPE2_ARC_STATUS_PDU, "Arc Status" }, + { PDUTYPE2_STATUS_INFO_PDU, "Status Info" }, + { PDUTYPE2_MONITOR_LAYOUT_PDU, "Monitor Layout" }, + { 0x0, NULL } +}; + +static const value_string t125_mcs_tpdu_types[] = { + { MCS_ERECT_DOMAIN_REQUEST, "Erect Domain Request" }, + { MCS_DISCONNECT_PROVIDER_ULTIMATUM, "Disconnect Provider Ultimatum" }, + { MCS_ATTACH_USER_REQUEST, "Attach User Request" }, + { MCS_ATTACH_USER_CONFIRM, "Attach User Confirm" }, + { MCS_CHANNEL_JOIN_REQUEST, "Channel Join Request" }, + { MCS_CHANNEL_JOIN_CONFIRM, "Channel Join Confirm" }, + { MCS_SEND_DATA_REQUEST, "Send Data Request" }, + { MCS_SEND_DATA_INDICATION, "Send Data Indication" }, + { MCS_CONNECT_INITIAL, "Connect Initial" }, + { MCS_CONNECT_RESPONSE, "Connect Response" }, + { 0x0, NULL } +}; + +static const value_string x224_tpdu_types[] = { + { X224_CONNECTION_REQUEST, "Connection Request" }, + { X224_CONNECTION_CONFIRM, "Connection Confirm" }, + { X224_DISCONNECT_REQUEST, "Disconnect Request" }, + { X224_DISCONNECT_CONFIRM, "Disconnect Confirm" }, + { X224_DATA, "Data" }, + { 0x0, NULL } +}; + +void proto_reg_handoff_rdp(void); +void dissect_ts_caps_set(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree); +void dissect_ts_confirm_active_pdu(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree); +void dissect_ts_info_packet(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree); +void dissect_ts_share_control_header(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree); +void dissect_ts_share_data_header(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree); +void dissect_ts_security_header(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree); + +void +dissect_ts_caps_set(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree) +{ + guint16 capabilitySetType; + guint16 lengthCapability; + + if (tree) + { + proto_item *ti; + proto_tree *ts_caps_set_tree; + + ts_caps_set_offset = offset; + capabilitySetType = tvb_get_letohs(tvb, offset); + lengthCapability = tvb_get_letohs(tvb, offset + 2); + + ti = proto_tree_add_item(tree, hf_ts_caps_set, tvb, ts_caps_set_offset, lengthCapability, TRUE); + ts_caps_set_tree = proto_item_add_subtree(ti, ett_ts_caps_set); + + proto_item_set_text(ti, "%s Capability Set", val_to_str(capabilitySetType, capability_set_types, "Unknown %d Capability Set")); + proto_item_append_text(ti, ", Length = %d", lengthCapability - 4); + + proto_tree_add_item(ts_caps_set_tree, hf_ts_caps_set_capability_set_type, tvb, offset, 2, TRUE); + proto_tree_add_item(ts_caps_set_tree, hf_ts_caps_set_length_capability, tvb, offset + 2, 2, TRUE); + proto_tree_add_item(ts_caps_set_tree, hf_ts_caps_set_capability_data, tvb, offset + 4, lengthCapability - 4, TRUE); + offset += lengthCapability; + } +} + +void +dissect_ts_confirm_active_pdu(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree) +{ + guint32 shareId; + guint16 originatorId; + guint16 lengthSourceDescriptor; + guint16 lengthCombinedCapabilities; + guint16 numberCapabilities; + + if (tree) + { + int i; + proto_item *ti; + proto_tree *ts_confirm_active_pdu_tree; + proto_tree *ts_capability_sets_tree; + + ts_confirm_active_pdu_offset = offset; + shareId = tvb_get_letohl(tvb, offset); + originatorId = tvb_get_letohs(tvb, offset + 4); + lengthSourceDescriptor = tvb_get_letohs(tvb, offset + 6); + lengthCombinedCapabilities = tvb_get_letohs(tvb, offset + 8); + numberCapabilities = tvb_get_letohs(tvb, offset + 10 + lengthSourceDescriptor); + + ti = proto_tree_add_item(tree, hf_ts_confirm_active_pdu, tvb, ts_confirm_active_pdu_offset, -1, TRUE); + ts_confirm_active_pdu_tree = proto_item_add_subtree(ti, ett_ts_confirm_active_pdu); + + proto_tree_add_item(ts_confirm_active_pdu_tree, hf_ts_confirm_active_pdu_shareid, tvb, offset, 4, TRUE); + proto_tree_add_item(ts_confirm_active_pdu_tree, hf_ts_confirm_active_pdu_originatorid, tvb, offset + 4, 2, TRUE); + proto_tree_add_item(ts_confirm_active_pdu_tree, hf_ts_confirm_active_pdu_length_source_descriptor, tvb, offset + 6, 2, TRUE); + proto_tree_add_item(ts_confirm_active_pdu_tree, hf_ts_confirm_active_pdu_length_combined_capabilities, tvb, offset + 8, 2, TRUE); + proto_tree_add_item(ts_confirm_active_pdu_tree, hf_ts_confirm_active_pdu_source_descriptor, tvb, offset + 10, lengthSourceDescriptor, TRUE); + offset += (10 + lengthSourceDescriptor); + + proto_tree_add_item(ts_confirm_active_pdu_tree, hf_ts_confirm_active_pdu_number_capabilities, tvb, offset, 2, TRUE); + proto_tree_add_item(ts_confirm_active_pdu_tree, hf_ts_confirm_active_pdu_pad2octets, tvb, offset + 2, 2, TRUE); + offset += 4; + + ti = proto_tree_add_item(ts_confirm_active_pdu_tree, hf_ts_capability_sets, tvb, offset, lengthCombinedCapabilities - 4, TRUE); + ts_capability_sets_tree = proto_item_add_subtree(ti, ett_ts_capability_sets); + + for (i = 0; i < numberCapabilities; i++) + dissect_ts_caps_set(tvb, pinfo, ts_capability_sets_tree); + } +} + +void +dissect_ts_info_packet(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree) +{ + guint32 codePage; + guint32 flags; + guint16 cbDomain; + guint16 cbUserName; + guint16 cbPassword; + guint16 cbAlternateShell; + guint16 cbWorkingDir; + + if (tree) + { + codePage = tvb_get_letohl(tvb, offset); + flags = tvb_get_letohl(tvb, offset + 4); + cbDomain = tvb_get_letohs(tvb, offset + 6); + cbUserName = tvb_get_letohs(tvb, offset + 8); + cbPassword = tvb_get_letohs(tvb, offset + 10); + cbAlternateShell = tvb_get_letohs(tvb, offset + 12); + cbWorkingDir = tvb_get_letohs(tvb, offset + 14); + } +} + +void +dissect_ts_share_data_header(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree) +{ + guint32 shareId; + guint8 streamId; + guint16 uncompressedLength; + guint8 pduType2; + + if (tree) + { + bytes = tvb_length_remaining(tvb, 0); + + if (bytes >= 4) + { + proto_item *ti; + ts_share_control_header_offset = offset; + shareId = tvb_get_letohl(tvb, offset); + streamId = tvb_get_guint8(tvb, offset + 5); + uncompressedLength = tvb_get_letohs(tvb, offset + 6); + pduType2 = tvb_get_guint8(tvb, offset + 8); + offset += 9; + + ti = proto_tree_add_item(tree, hf_ts_share_data_header, tvb, ts_share_data_header_offset, offset - ts_share_data_header_offset, FALSE); + proto_item_set_text(ti, "TS_SHARE_DATA_HEADER: %s", val_to_str(pduType2, pdu2_types, "Unknown %d")); + + col_clear(pinfo->cinfo, COL_INFO); + col_add_fstr(pinfo->cinfo, COL_INFO, "%s PDU", val_to_str(pduType2, pdu2_types, "Data %d PDU")); + } + } +} + +void +dissect_ts_share_control_header(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree) +{ + guint16 pduType; + guint16 PDUSource; + guint16 totalLength; + + if (tree) + { + bytes = tvb_length_remaining(tvb, 0); + totalLength = tvb_get_letohs(tvb, offset); + + if (bytes >= 4) + { + proto_item *ti; + ts_share_control_header_offset = offset; + pduType = tvb_get_letohs(tvb, offset + 2) & 0xF; + PDUSource = tvb_get_letohs(tvb, offset + 4); + + if (totalLength == 128) + return; + + offset += 6; + ti = proto_tree_add_item(tree, hf_ts_share_control_header, tvb, ts_share_control_header_offset, offset - ts_share_control_header_offset, FALSE); + proto_item_set_text(ti, "TS_SHARE_CONTROL_HEADER: %s", val_to_str(pduType, pdu_types, "Unknown %d")); + + switch (pduType) + { + case PDUTYPE_DEMAND_ACTIVE_PDU: + col_set_str(pinfo->cinfo, COL_INFO, "Demand Active PDU"); + break; + + case PDUTYPE_CONFIRM_ACTIVE_PDU: + col_set_str(pinfo->cinfo, COL_INFO, "Confirm Active PDU"); + dissect_ts_confirm_active_pdu(tvb, pinfo, tree); + break; + + case PDUTYPE_DATA_PDU: + dissect_ts_share_data_header(tvb, pinfo, tree); + break; + } + } + } +} + +void +dissect_ts_security_header(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree) +{ + guint16 flags; + guint16 flagsHi; + + if (tree) + { + bytes = tvb_length_remaining(tvb, 0); + + if (bytes >= 4) + { + proto_item *ti; + ts_security_header_offset = offset; + flags = tvb_get_letohs(tvb, offset); + flagsHi = tvb_get_letohs(tvb, offset + 2); + offset += 4; + + ti = proto_tree_add_item(tree, hf_ts_security_header, tvb, ts_security_header_offset, offset - ts_security_header_offset, FALSE); + proto_item_set_text(ti, "TS_SECURITY_HEADER, Flags = 0x%04X", flags); + + if (flags & SEC_INFO_PKT) + { + dissect_ts_info_packet(tvb, pinfo, tree); + col_clear(pinfo->cinfo, COL_INFO); + col_add_str(pinfo->cinfo, COL_INFO, "Client Info PDU"); + } + } + } +} + +static void +dissect_mcs(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree) +{ + guint8 type; + guint8 byte; + guint8 flags; + guint16 initiator; + guint16 channelId; + guint16 length; + guint16 real_length; + + if (tree) + { + bytes = tvb_length_remaining(tvb, 0); + + if (bytes > 0) + { + proto_item *ti; + type = tvb_get_bits8(tvb, offset * 8, 6); + mcs_offset = offset++; + + /* Connect Initial and Connect Response */ + if (type == 31) + type = tvb_get_guint8(tvb, offset++); + + col_clear(pinfo->cinfo, COL_INFO); + col_add_fstr(pinfo->cinfo, COL_INFO, "MCS %s PDU", val_to_str(type, t125_mcs_tpdu_types, "Unknown %d")); + + switch (type) + { + case MCS_SEND_DATA_INDICATION: + case MCS_SEND_DATA_REQUEST: + initiator = tvb_get_ntohs(tvb, offset + 2); + channelId = tvb_get_ntohs(tvb, offset + 4); + offset += 4; + flags = tvb_get_guint8(tvb, offset++); + + byte = tvb_get_guint8(tvb, offset++); + length = (guint16) byte; + + if (byte & 0x80) + { + length &= ~0x80; + length <<= 8; + byte = tvb_get_guint8(tvb, offset++); + length += (guint16) byte; + } + + ti = proto_tree_add_item(tree, hf_rdp_mcs, tvb, mcs_offset, offset - mcs_offset, FALSE); + proto_item_set_text(ti, "T.125 MCS %s PDU, Length = %d", val_to_str(type, t125_mcs_tpdu_types, "Unknown %d"), length); + + real_length = tvb_length(tvb) - rdp_offset; + if ((offset - rdp_offset) + length != real_length) + proto_item_append_text(ti, " [Length Mismatch: %d]", real_length); + + dissect_ts_share_control_header(tvb, pinfo, tree); + break; + + default: + ti = proto_tree_add_item(tree, hf_rdp_mcs, tvb, mcs_offset, -1, FALSE); + proto_item_set_text(ti, "T.125 MCS %s PDU", val_to_str(type, t125_mcs_tpdu_types, "Unknown %d")); + break; + } + } + } +} + +static void +dissect_x224(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree) +{ + guint8 type; + guint8 length; + + if (tree) + { + bytes = tvb_length_remaining(tvb, 0); + + if (bytes > 0) + { + proto_item *ti; + x224_offset = offset; + length = tvb_get_guint8(tvb, offset); + type = tvb_get_bits8(tvb, (offset + 1) * 8, 4); + + if (length > 1) + { + ti = proto_tree_add_item(tree, hf_rdp_x224, tvb, offset, length + 1, FALSE); + proto_item_set_text(ti, "X.224 %s TPDU", val_to_str(type, x224_tpdu_types, "Unknown %d")); + offset += (length + 1); + dissect_mcs(tvb, pinfo, tree); + } + } + } +} + +static void +dissect_tpkt(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree) +{ + guint8 version; + guint16 length; + + if (tree) + { + bytes = tvb_length_remaining(tvb, 0); + + if (bytes >= 4) + { + proto_item *ti; + version = tvb_get_guint8(tvb, offset); + length = tvb_get_ntohs(tvb, offset + 2); + + if (version == 3) + { + tpkt_offset = offset; + ti = proto_tree_add_item(tree, hf_rdp_tpkt, tvb, 0, 4, FALSE); + proto_item_set_text(ti, "TPKT Header, Length = %d", length); + offset += 4; + dissect_x224(tvb, pinfo, tree); + } + } + } +} + +static void +dissect_rdp(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree) +{ + if (tree) + { + offset = 0; + bytes = tvb_length_remaining(tvb, 0); + + if (bytes > 0) + { + proto_item *ti; + proto_tree *rdp_tree; + + rdp_offset = offset; + ti = proto_tree_add_item(tree, proto_rdp, tvb, 0, -1, FALSE); + rdp_tree = proto_item_add_subtree(ti, ett_rdp); + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "RDP"); + + dissect_tpkt(tvb, pinfo, rdp_tree); + } + } +} + +void +proto_register_ts_caps_set(void) +{ + static hf_register_info hf[] = + { + { &hf_ts_caps_set_capability_set_type, + { "capabilitySetType", "rdp.capset_type", FT_UINT16, BASE_DEC, VALS(capability_set_types), 0x0, NULL, HFILL } }, + { &hf_ts_caps_set_length_capability, + { "lengthCapability", "rdp.capset_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_ts_caps_set_capability_data, + { "capabilityData", "rdp.capset_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } } + }; + + static gint *ett[] = { + &ett_ts_caps_set + }; + + proto_register_field_array(proto_rdp, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); +} + +void +proto_register_ts_capability_sets(void) +{ + static hf_register_info hf[] = + { + { &hf_ts_caps_set, + { "capabilitySet", "rdp.capset", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } } + }; + + static gint *ett[] = { + &ett_ts_capability_sets + }; + + proto_register_field_array(proto_rdp, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); +} + +void +proto_register_ts_confirm_active_pdu(void) +{ + static hf_register_info hf[] = + { + { &hf_ts_confirm_active_pdu_shareid, + { "shareId", "rdp.shareid", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, + { &hf_ts_confirm_active_pdu_originatorid, + { "originatorId", "rdp.originatorid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, + { &hf_ts_confirm_active_pdu_length_source_descriptor, + { "lengthSourceDescriptor", "rdp.len_src_desc", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_ts_confirm_active_pdu_length_combined_capabilities, + { "lengthCombinedCapabilities", "rdp.caplen", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_ts_confirm_active_pdu_source_descriptor, + { "sourceDescriptor", "rdp.src_desc", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_ts_confirm_active_pdu_number_capabilities, + { "numberCapabilities", "rdp.capnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_ts_confirm_active_pdu_pad2octets, + { "pad2Octets", "rdp.pad2octets", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_ts_capability_sets, + { "capabilitySets", "rdp.capsets", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } } + }; + + static gint *ett[] = { + &ett_ts_confirm_active_pdu + }; + + proto_register_field_array(proto_rdp, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); +} + +void +proto_register_rdp(void) +{ + module_t *module_rdp; + + static hf_register_info hf[] = + { + { &hf_rdp_rdp, + { "rdp", "rdp", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_rdp_tpkt, + { "TPKT Header", "rdp.tpkt", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_rdp_x224, + { "X.224 Header", "rdp.x224", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_rdp_mcs, + { "MCS Header", "rdp.mcs", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_ts_security_header, + { "TS_SECURITY_HEADER", "rdp.sec", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_ts_share_control_header, + { "TS_SHARE_CONTROL_HEADER", "rdp.share_ctrl", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_ts_share_data_header, + { "TS_SHARE_DATA_HEADER", "rdp.share_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, + { &hf_ts_confirm_active_pdu, + { "Confirm Active PDU", "rdp.confirm_active", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } } + }; + + static gint *ett[] = { + &ett_rdp + }; + + proto_rdp = proto_register_protocol("Remote Desktop Protocol", "RDP", "rdp"); + register_dissector("rdp", dissect_rdp, proto_rdp); + + proto_register_field_array(proto_rdp, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + module_rdp = prefs_register_protocol( proto_rdp, proto_reg_handoff_rdp); +} + +void +proto_reg_handoff_rdp(void) +{ + +} + diff --git a/packet-rdp.h b/packet-rdp.h new file mode 100644 index 0000000..7853f35 --- /dev/null +++ b/packet-rdp.h @@ -0,0 +1,34 @@ +/* packet-rdp.c + * Routines for Remote Desktop Protocol dissection + * Copyright 2010, Marc-Andre Moreau <marcandre.moreau@gmail.com> + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PACKET_RDP_H__ +#define __PACKET_RDP_H__ + +/* "proto_rdp" is exported from libwireshark.dll. + * Thus we need a special declaration. + */ +WS_VAR_IMPORT int proto_rdp; + +#endif /* __PACKET_RDP_H__ */ diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..3924e62 --- /dev/null +++ b/readme.txt @@ -0,0 +1,52 @@ +RDP Wireshark Dissector + +In order to use this wireshark dissector for the RDP protocol, you will need to compile wireshark from the development sources. + +There are two ways to add a dissector to wireshark: plug-in or built-in. Even though you could probably make the current dissector +a plug-in, I do not encourage to do it this way, as there is a major drawback: wireshark plug-ins aren't loaded in wireshark when +it is ran as root, for obvious security reasons. As you need to be root in order to capture packets, you won't be able to capture +and dissect the RDP protocol at the same time if you compile the dissector as a plug-in. Therefore, here are the instructions on how +to add this RDP dissector as built-in to wireshark, so you can use it while running wireshark as root. + +Go to http://www.wireshark.org/develop.html and follow the instructions to get the latest wireshark development sources: +svn co http://anonsvn.wireshark.org/wireshark/trunk/ wireshark + +Once you have the sources, instead a couple of development packages that you'll probably need, such as gtk-dev. Make sure that you have +SSL development libraries (GnuTLS, OpenSSL) installed, as wireshark will built without the SSL dissector if they aren't present when +running the configure script. As we are dependent on the SSL dissector for the RDP dissector, the SSL development libraries are mandatory. + +Copy packet-rdp.c and packet-rdp.h to wireshark/epan/dissectors/ and add new entries in wireshark/epan/dissectors/Makefile.common: + +Add this line right over the "packet-rdt.c" line (they're in alphabetical order): + packet-rdp.c \ + +Similarly add this line right over the "packet-rdt.h" line: + packet-rdp.h \ + +Now in the root of the wireshark folder, run autogen.sh if you haven't already, and run (or re-run) the configure script. +The configure script must be ran after Makefile.common has been modified, otherwise the new dissector won't get built. + +When this is done and you've solved all dependencies the configure script may complain about, simply "make". +It takes a while the first time, but after that you're done :) + +To test it out once it is built, use one of the sample packet captures that I've prepared: +http://www.awakecoding.com/downloads/rdp_sample_packet_capture.zip +http://www.awakecoding.com/downloads/rdp_sample_packet_capture_tls_without_nla.zip + +Both archives contain a packet capture with a readme and the private key required to decrypt the TLS packets. +The dissector does not work with the RDP "legacy" encryption, only with RDP over TLS. + +If you want to use the dissector to analyze your own packets, you will need to configure your server to use a self-signed certificate +with an exportable private key. The amount of effort required to do so varies a lot between versions of Windows Server. Some easy versions +are Windows Server 2003 SP1: http://thelazyadmin.com/blogs/thelazyadmin/archive/2007/01/26/Configure-RDP-over-SSL-with-SelfSSL.aspx +Otherwise you should give Windows Server 2008 _R2_ a try, and I really insist on the "R2" here. Windows Server 2008 (not R2) can create +a self-signed certificate for you, but it will mark the key as non-exportable by default, and there's no way around it. You can try +generating your own self-signed certificate to try to import it, but good luck on finding the almost non-existing information on the subject. +Windows Server 2008 R2 changed the default behavior to give you the option of NOT marking the private key as non-exportable. Once you get +a self-signed certificate with an exportable private key configured with your RDP server, it should be quite easy to figure out how to extract +the private key and convert it from pfx to pem format (OpenSSL can do it, just google it there are tons of websites that explain how). + +Obviously the dissector is still in an early development stage and I put efforts on the packets that I need to take a closer look at. It is +still very useful and will probably save you a lot of time. + + |