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,47 +12892,37 @@ 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
anything else since we dont want this one to mess
up the request/response matching. We still consider
the initial call the real request and this is only
some sort of continuation.
*/
/* we only check the unmatched table and assume that the
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);
if(sip!=NULL){
g_hash_table_insert(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);
if(sip==NULL){
/*
We didn't find it.
Too bad, unfortunately there is not really much we can
do now since this means that we never saw the initial
request.
*/
}
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
anything else since we dont want this one to mess
up the request/response matching. We still consider
the initial call the real request and this is only
some sort of continuation.
*/
/* we only check the unmatched table and assume that the
last seen MID matching ours is the right one.
This can fail but is better than nothing
*/
sip=g_hash_table_lookup(si.ct->unmatched, (void *)si.mid);
if(sip!=NULL){
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(si.ct->matched, (void *)pinfo->fd->num);
if(sip==NULL){
/*
We didn't find it.
Too bad, unfortunately there is not really much we can
do now since this means that we never saw the initial
request.
*/
}
}
@ -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