Support for reassembly of DCERPC over SMB, from Ronnie Sahlberg.

svn path=/trunk/; revision=4335
This commit is contained in:
Guy Harris 2001-12-05 08:20:30 +00:00
parent faacd2b71c
commit 6b253331f0
5 changed files with 203 additions and 89 deletions

View File

@ -2,7 +2,7 @@
* Routines for DCERPC packet disassembly
* Copyright 2001, Todd Sabin <tas@webspan.net>
*
* $Id: packet-dcerpc.c,v 1.19 2001/11/27 22:37:19 guy Exp $
* $Id: packet-dcerpc.c,v 1.20 2001/12/05 08:20:28 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@ -1582,5 +1582,5 @@ proto_reg_handoff_dcerpc (void)
heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
heur_dissector_add ("smb_transact", dissect_dcerpc_cn_pk, proto_dcerpc);
heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
}

View File

@ -8,7 +8,7 @@ XXX Fixme : shouldnt show [malformed frame] for long packets
* significant rewrite to tvbuffify the dissector, Ronnie Sahlberg and
* Guy Harris 2001
*
* $Id: packet-smb-pipe.c,v 1.58 2001/11/28 11:33:54 guy Exp $
* $Id: packet-smb-pipe.c,v 1.59 2001/12/05 08:20:28 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@ -55,6 +55,7 @@ XXX Fixme : shouldnt show [malformed frame] for long packets
#include "packet-smb-pipe.h"
#include "packet-smb-browse.h"
#include "packet-dcerpc.h"
#include "reassemble.h"
static int proto_smb_pipe = -1;
static int hf_pipe_function = -1;
@ -72,6 +73,7 @@ static int hf_pipe_getinfo_pipe_name = -1;
static int hf_pipe_write_raw_bytes_written = -1;
static gint ett_smb_pipe = -1;
static gint ett_smb_pipe_fragments = -1;
static int proto_smb_lanman = -1;
static int hf_function_code = -1;
@ -2533,7 +2535,7 @@ static heur_dissector_list_t smb_transact_heur_subdissector_list;
static gboolean
dissect_pipe_msrpc(tvbuff_t *d_tvb, packet_info *pinfo, proto_tree *parent_tree,
guint16 fid)
proto_tree *tree, guint32 fid)
{
dcerpc_private_info dcerpc_priv;
smb_info_t *smb_priv = (smb_info_t *)pinfo->private_data;
@ -2544,11 +2546,73 @@ dissect_pipe_msrpc(tvbuff_t *d_tvb, packet_info *pinfo, proto_tree *parent_tree,
pinfo->private_data = &dcerpc_priv;
/* offer desegmentation service to DCERPC */
pinfo->can_desegment=0;
pinfo->desegment_offset = 0;
pinfo->desegment_len = 0;
if(smb_dcerpc_reassembly){
pinfo->can_desegment=2;
}
/* see if this packet is already desegmented */
if(smb_dcerpc_reassembly && pinfo->fd->flags.visited){
fragment_data *fd_head;
tvbuff_t *new_tvb;
fd_head=fragment_get(pinfo, pinfo->fd->num ,
dcerpc_fragment_table);
if(fd_head && fd_head->flags&FD_DEFRAGMENTED){
proto_tree *tr;
proto_item *it;
fragment_data *fd;
new_tvb = tvb_new_real_data(fd_head->data,
fd_head->datalen, fd_head->datalen,
"DCERPC over SMB");
tvb_set_child_real_data_tvbuff(d_tvb, new_tvb);
pinfo->fd->data_src=g_slist_append(pinfo->fd->data_src,
new_tvb);
pinfo->fragmented=FALSE;
d_tvb=new_tvb;
/* list what segments we have */
it = proto_tree_add_text(tree, d_tvb, 0, 0, "Fragments");
tr = proto_item_add_subtree(it, ett_smb_pipe_fragments);
for(fd=fd_head->next;fd;fd=fd->next){
proto_tree_add_text(tr, d_tvb, 0, 0, "Frame:%d Data:%d-%d",
fd->frame, fd->offset, fd->offset+fd->len-1);
}
}
}
result = dissector_try_heuristic(smb_transact_heur_subdissector_list, d_tvb,
pinfo, parent_tree);
pinfo->private_data = smb_priv;
/* check if dissector wanted us to desegment the data */
if(smb_dcerpc_reassembly && !pinfo->fd->flags.visited && pinfo->desegment_len){
fragment_add(d_tvb, 0, pinfo, pinfo->fd->num,
dcerpc_fragment_table,
0, tvb_length(d_tvb), TRUE);
fragment_set_tot_len(pinfo, pinfo->fd->num,
dcerpc_fragment_table,
pinfo->desegment_len+tvb_length(d_tvb));
/* since the other fragments are in normal ReadAndX and WriteAndX calls
we must make sure we can map FID values to this defragmentation
session */
/* first remove any old mappings */
if(g_hash_table_lookup(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid)){
g_hash_table_remove(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid);
}
g_hash_table_insert(smb_priv->ct->dcerpc_fid_to_frame, (void *)fid,
(void *)pinfo->fd->num);
}
/* clear out the variables */
pinfo->can_desegment=0;
pinfo->desegment_offset = 0;
pinfo->desegment_len = 0;
if (!result)
call_dissector(data_handle, d_tvb, pinfo, parent_tree);
@ -2786,7 +2850,7 @@ dissect_pipe_smb(tvbuff_t *sp_tvb, tvbuff_t *s_tvb, tvbuff_t *pd_tvb,
if (d_tvb == NULL)
return FALSE;
return dissect_pipe_msrpc(d_tvb, pinfo, tree,
fid);
pipe_tree, fid);
}
break;
}
@ -2988,6 +3052,7 @@ proto_register_smb_pipe(void)
};
static gint *ett[] = {
&ett_smb_pipe,
&ett_smb_pipe_fragments,
};
proto_smb_pipe = proto_register_protocol(

View File

@ -2,7 +2,7 @@
* Routines for smb packet dissection
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
*
* $Id: packet-smb.c,v 1.178 2001/12/05 00:49:31 guy Exp $
* $Id: packet-smb.c,v 1.179 2001/12/05 08:20:28 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@ -666,18 +666,24 @@ static const gchar *get_unicode_or_ascii_string(tvbuff_t *tvb,
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
These are needed by the reassembly of SMB Transaction payload
These are needed by the reassembly of SMB Transaction payload and DCERPC over SMB
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
/* Reassembly of SMB Transaction calls */
static gboolean smb_trans_reassembly = FALSE;
gboolean smb_dcerpc_reassembly = FALSE;
static GHashTable *smb_trans_fragment_table = NULL;
GHashTable *dcerpc_fragment_table = NULL;
static void
smb_trans_reassembly_init(void)
{
fragment_table_init(&smb_trans_fragment_table);
}
static void
smb_dcerpc_reassembly_init(void)
{
fragment_table_init(&dcerpc_fragment_table);
}
static fragment_data *
@ -802,10 +808,6 @@ static int smb_transact2_info_init_count = 200;
static GMemChunk *smb_transact_info_chunk = NULL;
static int smb_transact_info_init_count = 200;
typedef struct conv_tables {
GHashTable *unmatched;
GHashTable *matched;
} conv_tables_t;
static GMemChunk *conv_tables_chunk = NULL;
static int conv_tables_count = 10;
@ -4597,8 +4599,8 @@ static int
dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, proto_tree *smb_tree)
{
guint8 wc, cmd=0xff;
guint16 andxoffset=0, bc, datalen=0;
smb_info_t *si;
guint16 andxoffset=0, bc, datalen=0, dataoffset=0;
smb_info_t *si = (smb_info_t *)pinfo->private_data;
WORD_COUNT;
@ -4621,7 +4623,6 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
offset += 2;
/* If we have seen the request, then print which FID this refers to */
si = (smb_info_t *)pinfo->private_data;
/* first check if we have seen the request */
if(si->sip != NULL && si->sip->frame_req>0){
add_fid(tvb, pinfo, tree, 0, 0, (int)si->sip->extra_info);
@ -4645,7 +4646,8 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
offset += 2;
/* data offset */
proto_tree_add_item(tree, hf_smb_data_offset, tvb, offset, 2, TRUE);
dataoffset=tvb_get_letohs(tvb, offset);
proto_tree_add_uint(tree, hf_smb_data_offset, tvb, offset, 2, dataoffset);
offset += 2;
/* 10 reserved bytes */
@ -4655,6 +4657,43 @@ dissect_read_andx_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
BYTE_COUNT;
/* is this part of DCERPC over SMB reassembly?*/
if(smb_dcerpc_reassembly && !pinfo->fd->flags.visited && (bc<=tvb_length_remaining(tvb, offset)) ){
guint32 frame;
frame=(guint32)g_hash_table_lookup(si->ct->dcerpc_fid_to_frame,
si->sip->extra_info);
if(frame){
fragment_data *fd_head;
/* first fragment is always from a SMB Trans command and
offset 0 of the following read/write SMB commands start
BEYOND the first Trans SMB payload. Look for offset
in first read fragment */
fd_head=fragment_get(pinfo, frame, dcerpc_fragment_table);
if(fd_head){
/* skip to last fragment and add this data there*/
while(fd_head->next){
fd_head=fd_head->next;
}
/* if dataoffset was not specified in the SMB command
then we try to guess it as good as we can
*/
if(dataoffset==0){
dataoffset=offset+bc-datalen;
}
fd_head=fragment_add(tvb, dataoffset, pinfo,
frame, dcerpc_fragment_table,
fd_head->offset+fd_head->len,
datalen, TRUE);
/* we completed reassembly, abort searching for more
fragments*/
if(fd_head){
g_hash_table_remove(si->ct->dcerpc_fid_to_frame,
si->sip->extra_info);
}
}
}
}
/* file data */
offset = dissect_file_data(tvb, pinfo, tree, offset, bc, datalen);
bc = 0;
@ -12745,6 +12784,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
guint8 errclass = 0;
guint16 errcode = 0;
guint16 uid, pid, tid;
conversation_t *conversation;
top_tree=parent_tree;
@ -12798,6 +12838,29 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
proto_tree_add_text(htree, tvb, offset, 4, "Server Component: SMB");
offset += 4; /* Skip the marker */
/* find which conversation we are part of and get the tables for that
conversation*/
conversation = find_conversation(&pinfo->src, &pinfo->dst,
pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
if(conversation){
si.ct=conversation_get_proto_data(conversation, proto_smb);
} else {
/* OK this is a new conversation, we must create it
and attach appropriate data (matched and unmatched
table for this conversation)
*/
conversation = conversation_new(&pinfo->src, &pinfo->dst,
pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
si.ct = g_mem_chunk_alloc(conv_tables_chunk);
si.ct->matched= g_hash_table_new(smb_saved_info_hash_matched,
smb_saved_info_equal_matched);
si.ct->unmatched= g_hash_table_new(smb_saved_info_hash_matched,
smb_saved_info_equal_matched);
si.ct->dcerpc_fid_to_frame=g_hash_table_new(
smb_saved_info_hash_matched,
smb_saved_info_equal_matched);
conversation_add_proto_data(conversation, proto_smb, si.ct);
}
if( (si.request)
&& (si.mid==0)
@ -12829,18 +12892,9 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
requests smb_saved_info_t but we dont touch it or change anything
in it.
*/
conversation_t *conversation;
conv_tables_t *ct;
si.unidir = TRUE; /*we dont expect an answer to this one*/
/* find which conversation we are part of and get the tables for that
conversation*/
conversation = find_conversation(&pinfo->src, &pinfo->dst,
pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
if(conversation){
ct=conversation_get_proto_data(conversation, proto_smb);
if(!pinfo->fd->flags.visited){
/* try to find which original call we match and if we
find it add us to the matched table. Dont touch
@ -12853,15 +12907,15 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
last seen MID matching ours is the right one.
This can fail but is better than nothing
*/
sip=g_hash_table_lookup(ct->unmatched, (void *)si.mid);
sip=g_hash_table_lookup(si.ct->unmatched, (void *)si.mid);
if(sip!=NULL){
g_hash_table_insert(ct->matched, (void *)pinfo->fd->num, sip);
g_hash_table_insert(si.ct->matched, (void *)pinfo->fd->num, sip);
}
} else {
/* we have seen this packet before; check the
matching table
*/
sip=g_hash_table_lookup(ct->matched, (void *)pinfo->fd->num);
sip=g_hash_table_lookup(si.ct->matched, (void *)pinfo->fd->num);
if(sip==NULL){
/*
We didn't find it.
@ -12871,7 +12925,6 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
*/
}
}
}
if(sip && sip->frame_req){
@ -12902,38 +12955,13 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
}
}
} else { /* normal bidirectional request or response */
conversation_t *conversation;
conv_tables_t *ct;
si.unidir = FALSE;
/* first we try to find which conversation this packet is
part of
*/
conversation = find_conversation(&pinfo->src, &pinfo->dst,
pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
if(conversation==NULL){
/* OK this is a new conversation, we must create it
and attach appropriate data (matched and unmatched
table for this conversation)
*/
conversation = conversation_new(&pinfo->src, &pinfo->dst,
pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
ct = g_mem_chunk_alloc(conv_tables_chunk);
ct->matched= g_hash_table_new(smb_saved_info_hash_matched,
smb_saved_info_equal_matched);
ct->unmatched= g_hash_table_new(smb_saved_info_hash_matched,
smb_saved_info_equal_matched);
conversation_add_proto_data(conversation, proto_smb, ct);
} else {
/* this is an old conversation, just get the tables */
ct=conversation_get_proto_data(conversation, proto_smb);
}
if(!pinfo->fd->flags.visited){
/* first see if we find an unmatched smb "equal" to
the current one
*/
sip=g_hash_table_lookup(ct->unmatched, (void *)si.mid);
sip=g_hash_table_lookup(si.ct->unmatched, (void *)si.mid);
if(sip!=NULL){
if(si.request){
/* ok, we are processing an SMB
@ -12950,7 +12978,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
request and concentrate on the
present one instead.
*/
g_hash_table_remove(ct->unmatched, (void *)si.mid);
g_hash_table_remove(si.ct->unmatched, (void *)si.mid);
} else {
/* we have found a response to some request we have seen earlier.
What we do now depends on whether this is the first response
@ -12959,13 +12987,13 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
if(sip->frame_res==0){
/* ok it is the first response we have seen to this packet */
sip->frame_res = pinfo->fd->num;
g_hash_table_insert(ct->matched, (void *)sip->frame_req, sip);
g_hash_table_insert(ct->matched, (void *)sip->frame_res, sip);
g_hash_table_insert(si.ct->matched, (void *)sip->frame_req, sip);
g_hash_table_insert(si.ct->matched, (void *)sip->frame_res, sip);
} else {
/* we have already seen another response to this one, but
register it anyway so we see which request it matches
*/
g_hash_table_insert(ct->matched, (void *)pinfo->fd->num, sip);
g_hash_table_insert(si.ct->matched, (void *)pinfo->fd->num, sip);
}
}
}
@ -12974,7 +13002,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
sip->frame_req = pinfo->fd->num;
sip->frame_res = 0;
sip->extra_info = NULL;
g_hash_table_insert(ct->unmatched, (void *)si.mid, sip);
g_hash_table_insert(si.ct->unmatched, (void *)si.mid, sip);
}
} else {
/* we have seen this packet before; check the
@ -12985,7 +13013,7 @@ dissect_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
we've seen this packet before, we've already
saved the information.
*/
sip=g_hash_table_lookup(ct->matched, (void *)pinfo->fd->num);
sip=g_hash_table_lookup(si.ct->matched, (void *)pinfo->fd->num);
}
}
@ -14911,7 +14939,12 @@ proto_register_smb(void)
"Reassemble SMB Transaction payload",
"Whether the dissector should do reassembly the payload of SMB Transaction commands spanning multiple SMB PDUs",
&smb_trans_reassembly);
prefs_register_bool_preference(smb_module, "smb.dcerpc.reassembly",
"Reassemble DCERPC over SMB",
"Whether the dissector should do reassembly of DCERPC over SMB commands",
&smb_dcerpc_reassembly);
register_init_routine(smb_trans_reassembly_init);
register_init_routine(smb_dcerpc_reassembly_init);
}
void

View File

@ -1,7 +1,7 @@
/* packet-tcp.c
* Routines for TCP packet disassembly
*
* $Id: packet-tcp.c,v 1.120 2001/12/03 08:47:27 guy Exp $
* $Id: packet-tcp.c,v 1.121 2001/12/05 08:20:30 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@ -539,6 +539,9 @@ desegment_tcp(tvbuff_t *tvb, packet_info *pinfo, int offset,
*/
call_dissector(data_handle,tvb_new_subset(tvb, deseg_offset,-1,tvb_reported_length_remaining(tvb,deseg_offset)), pinfo, tree);
}
pinfo->can_desegment=0;
pinfo->desegment_offset = 0;
pinfo->desegment_len = 0;
}

15
smb.h
View File

@ -2,7 +2,7 @@
* Defines for smb packet dissection
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
*
* $Id: smb.h,v 1.28 2001/12/05 00:49:32 guy Exp $
* $Id: smb.h,v 1.29 2001/12/05 08:20:30 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@ -242,6 +242,15 @@ typedef struct {
#define TRANSACTION_PIPE 0
#define TRANSACTION_MAILSLOT 1
/* this is the structure which is associated with each conversation */
typedef struct conv_tables {
/* these two tables are used to match requests with responses */
GHashTable *unmatched;
GHashTable *matched;
/* this tables is used by DCERPC over SMB reassembly*/
GHashTable *dcerpc_fid_to_frame;
} conv_tables_t;
typedef struct smb_info {
int cmd, mid;
gboolean unicode; /* Are strings in this SMB Unicode? */
@ -250,6 +259,7 @@ typedef struct smb_info {
int info_level;
int info_count;
smb_saved_info_t *sip; /* smb_saved_info_t, if any, for this */
conv_tables_t *ct;
} smb_info_t;
/*
@ -270,4 +280,7 @@ extern void add_fid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
extern int dissect_ipc_state(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *parent_tree, int offset, gboolean setstate);
extern gboolean smb_dcerpc_reassembly;
extern GHashTable *dcerpc_fragment_table;
#endif