Ethereal-dev: Re: [Ethereal-dev] packet-smb.c:11327 - si->info_level = t2i->info_level

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Gilbert Ramirez <gram@xxxxxxxxxxxxxxx>
Date: Thu, 21 Feb 2002 10:20:46 -0600
On Wed, 20 Feb 2002 16:02:40 Gilbert Ramirez wrote:
> 
> Using gdb on the core file, one could actually extract the current
> packet from the core file. I'm working on a script to do that.
> Instead of using 'expect' to interact with gdb, I intend to call
> gdb a few times, each time passing it a --command switch, giving it
> a file of commands to run. I should be able to get the packet and save
> it either as a text file for text2pcap to convert, or as a libpcap file.
> 
> --gilbert
> 

I just now checked in my first attempt at a script to do exactly
this. It's tools/pkt-from-core.py. It's a python script that
takes a core file and tries to extract the packet that was being
dissected. It looks for a call to epan_dissect_run() in the backtrace,
and if it finds that, uses gdb to query the variables. It then
writes a hex dump of the packet to a temporary file, and calls
text2pcap to create a libpcap file.

You invoke it like you do gdb, with the name of the executable file
and a core file. Additionally, -w is used to give the name of the
capture file that you wish to create.

pkt-from-core.py -w capture_file executable-file (core-file or process-id)

	Given an executable file and a core file, this tool
	uses gdb to retrieve the packet that was being dissected
	at the time ethereal/tethereal stopped running. The packet
	is saved in the capture_file specified by the -w option.

Marcin, do you want to see if it works on your system? The script
is attached to this e-mail.

--gilbert
#!/bin/sh
echo MANGLED_ON_PURPOSE.306090
exit
#!/usr/bin/env python
"""
Retrieve a packet from a ethereal/tethereal core file
and save it in a packet-capture file.
"""

import getopt
import os
import re
import sys
import tempfile
	
exec_file = None
core_file = None
output_file = None

class BackTrace:
	re_frame = re.compile(r"^#(?P<num>\d+) ")
	re_func1 = re.compile(r"^#\d+\s+(?P<func>\w+) \(")
	re_func2 = re.compile(r"^#\d+\s+0x[A-Fa-f\d]+ in (?P<func>\w+) \(")

	def __init__(self, lines):

		# In order; each item is the function name.
		self.frames = []
		found_non_bt_frame = 0
		frame_will_be = 0

		for line in lines:
			m = self.re_frame.search(line)
			if m:
				# Skip the first frame that gdb shows,
				# which is not part of the backtrace.
				if not found_non_bt_frame:
					found_non_bt_frame = 1
					continue

				# Get the frame number and make sure it's
				# what we expect it should be.
				frame_num = int(m.group("num"))
				if frame_num != frame_will_be:
					sys.exit("Found frame %d instead of %d" % \
						(frame_num, frame_will_be))

				# Find the function name. XXX - need to handle '???'
				n = self.re_func1.search(line)
				if not n:
					n = self.re_func2.search(line)

				if n:
					func = n.group("func")
				else:
					sys.exit("Function name not found in %s" % (line,))

				# Save the info
				self.frames.append(func)
				frame_will_be += 1

	def Frames(self):
		return self.frames
			

	def HasFunction(self, func):
		return func in self.frames

	def Frame(self, func):
		return self.frames.index(func)


# Some values from wiretap; wiretap should be a shared
# libray and a Python module should be created for it so
# this program could just write a libpcap file directly.
WTAP_ENCAP_PER_PACKET                 = -1
WTAP_ENCAP_UNKNOWN                    = 0
WTAP_ENCAP_ETHERNET                   = 1
WTAP_ENCAP_TOKEN_RING                 = 2
WTAP_ENCAP_SLIP                       = 3
WTAP_ENCAP_PPP                        = 4
WTAP_ENCAP_FDDI                       = 5
WTAP_ENCAP_FDDI_BITSWAPPED            = 6
WTAP_ENCAP_RAW_IP                     = 7
WTAP_ENCAP_ARCNET                     = 8
WTAP_ENCAP_ATM_RFC1483                = 9
WTAP_ENCAP_LINUX_ATM_CLIP             = 10
WTAP_ENCAP_LAPB                       = 11
WTAP_ENCAP_ATM_SNIFFER                = 12
WTAP_ENCAP_NULL                       = 13
WTAP_ENCAP_ASCEND                     = 14
WTAP_ENCAP_LAPD                       = 15
WTAP_ENCAP_V120                       = 16
WTAP_ENCAP_PPP_WITH_PHDR              = 17
WTAP_ENCAP_IEEE_802_11                = 18
WTAP_ENCAP_SLL                        = 19
WTAP_ENCAP_FRELAY                     = 20
WTAP_ENCAP_CHDLC                      = 21
WTAP_ENCAP_CISCO_IOS                  = 22
WTAP_ENCAP_LOCALTALK                  = 23
WTAP_ENCAP_PRISM_HEADER               = 24
WTAP_ENCAP_PFLOG                      = 25
WTAP_ENCAP_AIROPEEK                   = 26
WTAP_ENCAP_HHDLC                      = 27
# last WTAP_ENCAP_ value + 1
WTAP_NUM_ENCAP_TYPES                  = 28

wtap_to_pcap_map = {
	WTAP_ENCAP_NULL			: 0,
	WTAP_ENCAP_ETHERNET		: 1,
	WTAP_ENCAP_TOKEN_RING		: 6,
	WTAP_ENCAP_ARCNET		: 7,
	WTAP_ENCAP_SLIP			: 8,
	WTAP_ENCAP_PPP			: 9,
	WTAP_ENCAP_FDDI_BITSWAPPED	: 10,
	WTAP_ENCAP_FDDI			: 10,
	WTAP_ENCAP_ATM_RFC1483		: 11,
	WTAP_ENCAP_RAW_IP		: 12,
	WTAP_ENCAP_LINUX_ATM_CLIP	: 16, # or 18, or 19...
	WTAP_ENCAP_CHDLC		: 104,
	WTAP_ENCAP_IEEE_802_11		: 105,
	WTAP_ENCAP_SLL			: 113,
	WTAP_ENCAP_LOCALTALK		: 114,
	WTAP_ENCAP_PFLOG		: 117,
	WTAP_ENCAP_CISCO_IOS		: 118,
	WTAP_ENCAP_PRISM_HEADER		: 119,
	WTAP_ENCAP_HHDLC		: 121,
}


wtap_name = {
	WTAP_ENCAP_UNKNOWN                    : "Unknown",
	WTAP_ENCAP_ETHERNET                   : "Ethernet",
	WTAP_ENCAP_TOKEN_RING                 : "Token-Ring",
	WTAP_ENCAP_SLIP                       : "SLIP",
	WTAP_ENCAP_PPP                        : "PPP",
	WTAP_ENCAP_FDDI                       : "FDDI",
	WTAP_ENCAP_FDDI_BITSWAPPED            : "FDDI (Bitswapped)",
	WTAP_ENCAP_RAW_IP                     : "Raw IP",
	WTAP_ENCAP_ARCNET                     : "ARCNET",
	WTAP_ENCAP_ATM_RFC1483                : "ATM RFC1483",
	WTAP_ENCAP_LINUX_ATM_CLIP             : "Linux ATM CLIP",
	WTAP_ENCAP_LAPB                       : "LAPB",
	WTAP_ENCAP_ATM_SNIFFER                : "ATM Sniffer",
	WTAP_ENCAP_NULL                       : "Null",
	WTAP_ENCAP_ASCEND                     : "Ascend",
	WTAP_ENCAP_LAPD                       : "LAPD",
	WTAP_ENCAP_V120                       : "V.120",
	WTAP_ENCAP_PPP_WITH_PHDR              : "PPP (with PHDR)",
	WTAP_ENCAP_IEEE_802_11                : "IEEE 802.11",
	WTAP_ENCAP_SLL                        : "SLL",
	WTAP_ENCAP_FRELAY                     : "Frame Relay",
	WTAP_ENCAP_CHDLC                      : "Cisco HDLC",
	WTAP_ENCAP_CISCO_IOS                  : "Cisco IOS",
	WTAP_ENCAP_LOCALTALK                  : "LocalTalk",
	WTAP_ENCAP_PRISM_HEADER               : "Prism Header",
	WTAP_ENCAP_PFLOG                      : "PFLog",
	WTAP_ENCAP_AIROPEEK                   : "AiroPeek",
	WTAP_ENCAP_HHDLC                      : "HHDLC",
}

def wtap_to_pcap(wtap):
	if not wtap_to_pcap_map.has_key(wtap):
		sys.exit("Don't know how to convert wiretap encoding %d to libpcap." % \
			(wtap))

	return wtap_to_pcap_map[wtap]


def run_gdb(*commands):
	if len(commands) == 0:
		return []

	# Create a temporary file
	fname = tempfile.mktemp()
	try:
		fh = open(fname, "w")
	except IOError, err:
		sys.exit("Cannot open %s for writing: %s" % (fname, err))

	# Put the commands in it
	for cmd in commands:
		fh.write(cmd)
		fh.write("\n")

	fh.write("quit\n")
	try:
		fh.close()
	except IOError, err:
		try:
			os.unlink(fname)
		except:
			pass
		sys.exit("Cannot close %s: %s" % (fname, err))


	# Run gdb
	cmd = "gdb --nw --quiet --command=%s %s %s" % (fname, exec_file, core_file)
#	print "Command is %s" % (cmd,)
	try:
		pipe = os.popen(cmd)
	except OSError, err:
		try:
			os.unlink(fname)
		except:
			pass
		sys.exit("Cannot run gdb: %s" % (err,))

	# Get gdb's output
	result = pipe.readlines()
	error = pipe.close()
	if error != None:
		try:
			os.unlink(fname)
		except:
			pass
		sys.exit("gdb returned an exit value of %s" % (error,))


	# Remove the temp file and return the results
	try:
		os.unlink(fname)
	except:
		pass
	return result

def get_value_from_frame(frame_num, variable, fmt=""):
	cmds = []
	if frame_num > 0:
		cmds.append("up %d" % (frame_num,))

	cmds.append("print %s %s" % (fmt, variable))
	lines = apply(run_gdb, cmds)

	LOOKING_FOR_START = 0
	READING_VALUE = 1
	state = LOOKING_FOR_START
	result = ""
	for line in lines:
		if line[-1] == "\n":
			line = line[0:-1]
		if line[-1] == "\r":
			line = line[0:-1]

		if state == LOOKING_FOR_START:
			if len(line) < 4:
				continue
			else:
				if line[0:4] == "$1 =":
					result = line[4:]
					state = READING_VALUE

		elif state == READING_VALUE:
			result += line

	return result

def get_int_from_frame(frame_num, variable):
	text = get_value_from_frame(frame_num, variable)
	try:
		integer = int(text)
	except ValueError:
		sys.exit("Could not convert '%s' to integer." % (text,))
	return integer


def get_byte_array_from_frame(frame_num, variable, length):
	var = "{char}%s@%d" % (variable, length)
	text = get_value_from_frame(frame_num, var, "/u")
	
	# Remove curly braces
	i = text.find("{")
	if i == -1:
		sys.exit("Left curly brace not found in '%s'" % (text,))
	text = text[i+1:]

	i = text.find("}")
	if i == -1:
		sys.exit("Right curly brace not found in '%s'" % (text,))
	text = text[:i]

	# Split the string until many little strings, each representing a byte
	# in decimal
	values_as_text = text.split(',')

	# And get the numeric values
	return map(int, values_as_text)

def make_cap_file(pkt_data, lnk_t):

	pcap_lnk_t = wtap_to_pcap(lnk_t)

	# Create a temporary file
	fname = tempfile.mktemp()
	try:
		fh = open(fname, "w")
	except IOError, err:
		sys.exit("Cannot open %s for writing: %s" % (fname, err))

	print "Packet Data:"

	# Put the hex dump in it
	offset = 0
	BYTES_IN_ROW = 16
	for byte in pkt_data:
		if (offset % BYTES_IN_ROW) == 0:
			print >> fh, "\n%08X  " % (offset,),
			print "\n%08X  " % (offset,),

		print >> fh, "%02X " % (byte,),
		print "%02X " % (byte,),
		offset += 1

	print >> fh, "\n"
	print "\n"

	try:
		fh.close()
	except IOError, err:
		try:
			os.unlink(fname)
		except:
			pass
		sys.exit("Cannot close %s: %s" % (fname, err))


	# Run text2pcap
	cmd = "text2pcap -q -l %s %s %s" % (pcap_lnk_t, fname, output_file)
#	print "Command is %s" % (cmd,)
	try:
		retval = os.system(cmd)
	except OSError, err:
		try:
			os.unlink(fname)
		except:
			pass
		sys.exit("Cannot run text2pcap: %s" % (err,))

	# Remove the temp file
	try:
		os.unlink(fname)
	except:
		pass

	if retval == 0:
		print "%s created with %d bytes in packet, and %s encoding." % \
			(output_file, len(pkt_data), wtap_name[lnk_t])
	else:
		sys.exit("text2pcap did not run succesfully.")


def run():

	# Get the back trace
	bt_text = run_gdb("bt")
	bt = BackTrace(bt_text)
	if not bt.HasFunction("epan_dissect_run"):
		print "epan_dissect_run() not found in backtrace."
		print "A packet cannot be pulled from this core."
		sys.exit(1)

	# Figure out where the call to epan_dissect_run is.
	frame_num = bt.Frame("epan_dissect_run")

	# Get the capture length
	cap_len = get_int_from_frame(frame_num, "fd->cap_len")

	# Get the encoding type
	lnk_t = get_int_from_frame(frame_num, "fd->lnk_t")

	# Get the packet data
	pkt_data = get_byte_array_from_frame(frame_num, "data", cap_len)

#	print "Length=%d" % (cap_len,)
#	print "Encoding=%d" % (lnk_t,)
#	print "Data (%d bytes) = %s" % (len(pkt_data), pkt_data)
	make_cap_file(pkt_data, lnk_t)
	

def usage():
	print "pkt-from-core.py -w capture_file executable-file (core-file or process-id)"
	print ""
	print "\tGiven an executable file and a core file, this tool"
	print "\tuses gdb to retrieve the packet that was being dissected"
	print "\tat the time ethereal/tethereal stopped running. The packet"
	print "\tis saved in the capture_file specified by the -w option."
	sys.exit(1)

def main():
	global exec_file
	global core_file
	global output_file

	optstring = "w:"
	try:
		opts, args = getopt.getopt(sys.argv[1:], optstring)
	except getopt.error:
		usage()

	for opt, arg in opts:
		if opt == "-w":
			output_file = arg
		else:
			assert 0

	if output_file == None:
		usage()

	if len(args) != 2:
		usage()

	exec_file = args[0]
	core_file = args[1]

	run()

if __name__ == '__main__':
	main()
This message has been 'sanitized'.  This means that potentially
dangerous content has been rewritten or removed.  The following
log describes which actions were taken.

Sanitizer (start="1014308447"):
  Part (pos="1565"):
    SanitizeFile (filename="unnamed.txt", mimetype="text/plain"):
      Match (rule="2"):
        Enforced policy: accept

  Part (pos="3164"):
    SanitizeFile (filename="pkt-from-core.py", mimetype="text/script"):
      Match (rule="default"):
        Enforced policy: accept

    Defanged UNIX shell script(s).

  Total modifications so far: 1


Anomy 0.0.0 : Sanitizer.pm
$Id: Sanitizer.pm,v 1.32 2001/10/11 19:27:15 bre Exp $