Files
Kiran Bandla df3980cb77 Added 1.83
2013-03-25 15:33:17 -04:00

277 lines
11 KiB
Python
Executable File

import socket
import struct
from immlib import *
DESC="""Creates a table that displays packets received on the network."""
#############################################################################
'''
Some defines for re-use.
'''
PACKET_TYPE_SEND = "Send "
PACKET_TYPE_RECV = "Recv "
PACKET_PROTOCOL_UDP = "(UDP)"
PACKET_PROTOCOL_TCP = "(TCP)"
#############################################################################
class simple_hooks(LogBpHook):
#########################################################################
def __init__(self):
LogBpHook.__init__(self)
#########################################################################
def run(self,regs):
imm = Debugger()
(payload_ptr,type,function_name) = imm.getKnowledge("%08x" % regs['EIP'])
# The length is stored as a function return argument, so let's read EAX
length = regs['EAX']
# Because return codes can be -1 (error) we have to test for that.
if length > 1 and length != 0xffffffff:
counter = 0
payload = ""
bin_payload = ""
# Get the raw packet payload and the length of the bytes
raw_payload = imm.readMemory(payload_ptr,length)
pack_len = str(length)+"c"
imm.log("Pack Len: %s " % pack_len)
if raw_payload is not None:
final_payload = struct.unpack(pack_len,raw_payload)
# Iterate through the unpacked string, only outputting printable
# ascii characters, output the standard dots if non-printable
while counter < int(length):
if ord(final_payload[counter]) >= 32 and ord(final_payload[counter]) <= 126:
payload += final_payload[counter]
else:
payload += "."
bin_payload += "%02x" % ord(final_payload[counter])
counter += 1
# Build the list thats table-friendly
log_items = [function_name,type,"%d" % int(length),bin_payload[:512],payload[:512]]
# Get a handle to the window and add the items, along with the related
# address, this is sweet cause you can double-click on a packet and
# see in the disassembly where it was sent/received :)
cap_win = imm.getKnowledge("cap_win")
cap_win.add(regs['EIP'],log_items)
# Drop the entry in the KB, disable the BP, and unHook.
imm.forgetKnowledge("%08x" % regs['EIP'])
imm.disableBreakpoint(regs['EIP'])
self.UnHook()
#############################################################################
class ext_hooks(LogBpHook):
#########################################################################
def __init__(self):
LogBpHook.__init__(self)
#########################################################################
def run(self,regs):
imm = Debugger()
(payload_ptr,recv_ptr,type,function_name) = imm.getKnowledge("%08x" % regs['EIP'])
# This is an [out] pointer that let's us know how much data was
# received on a socket (non-overlapped)
length = imm.readMemory(recv_ptr,4)
length = struct.unpack("l",length)
# Network apps are chatty, we don't want to grab garbage packets
if length[0] > 1:
counter = 0
payload = ""
bin_payload = ""
# Get the raw packet payload and the length of the bytes
raw_payload = imm.readMemory(payload_ptr,int(length[0]))
pack_len = str(int(length[0]))+"c"
if raw_payload is not None:
final_payload = struct.unpack(pack_len,raw_payload)
# Iterate through the unpacked string, only outputting printable
# ascii characters, output the standard dots if non-printable
while counter < int(length[0]):
if ord(final_payload[counter]) >= 32 and ord(final_payload[counter]) <= 126:
payload += final_payload[counter]
else:
payload += "."
bin_payload += "%02x" % ord(final_payload[counter])
counter += 1
# Build the list thats table-friendly
log_items = [function_name,type,"%d" % int(length[0]),bin_payload[:512],payload[:512]]
# Get a handle to the window and add the items, along with the related
# address, this is sweet cause you can double-click on a packet and
# see in the disassembly where it was sent/received :)
cap_win = imm.getKnowledge("cap_win")
cap_win.add(regs['EIP'],log_items)
# Drop the entry in the KB, disable the BP, and unHook.
imm.forgetKnowledge("%08x" % regs['EIP'])
imm.disableBreakpoint(regs['EIP'])
self.UnHook()
#############################################################################
class set_hooks(LogBpHook):
def __init__(self):
LogBpHook.__init__(self)
#########################################################################
def run(self,regs):
'''
This routine is the first one hit, when a socket operation occurs.
'''
imm = Debugger()
# Retrieve the function name
function_name = imm.getKnowledge("%08x" % regs['EIP'])
self.retrieve_packet(imm,function_name,regs)
#########################################################################
def retrieve_packet(self,imm,function_name,regs):
'''
This function determines how to handle the packet data. Some socket
operations require more work (such as WSARecv), and others less (recv).
If necessary this function will register a hook on [ESP], where any
[out] pointers from a function will be set.
'''
# Determine what function we have hooked, based on this, retrieve the packet contents
if function_name == "WSARecv":
type = PACKET_TYPE_RECV+PACKET_PROTOCOL_TCP
extended_hook = True
if function_name == "WSASend":
type=PACKET_TYPE_SEND+PACKET_PROTOCOL_TCP
extended_hook = True
if function_name == "recvfrom":
type=PACKET_TYPE_RECV+PACKET_PROTOCOL_UDP
extended_hook = False
if function_name =="recv":
type=PACKET_TYPE_RECV+PACKET_PROTOCOL_TCP
extended_hook = False
# An extended hook requires a bit more work to pull out the packet info
if extended_hook == True:
# Get the pointer to the payload pointer :(
pbuffer_ptr = imm.readMemory( regs['ESP'] + 8, 4)
pbuffer_ptr = struct.unpack("L", pbuffer_ptr)
#imm.log("Buffer Location: 0x%08x" % pbuffer_ptr[0])
# Get the pointer to the packet payload
payload_ptr = imm.readMemory(pbuffer_ptr[0]+4,4)
payload_ptr = struct.unpack("<L", payload_ptr)
#imm.log("Payload Pointer: %08x" % payload_ptr[0])
# Get the [out] pointer of the received bytes
recv_ptr = imm.readMemory(regs['ESP'] + 0x10, 4)
recv_ptr = struct.unpack("L",recv_ptr)
#imm.log("Receive Pointer: %08x" % recv_ptr[0])
# Figure out [esp]
esp_ptr = imm.readMemory(regs['ESP'],4)
esp_ptr = struct.unpack("<L", esp_ptr)
#imm.log("[ESP] at 0x%08x" % esp_ptr[0])
# Now we hook [esp]
ret_hook = ext_hooks()
ret_hook.add("%08x" % esp_ptr[0],esp_ptr[0])
# Add this ret hook to the knowledgebase
imm.addKnowledge("%08x" % esp_ptr[0],(payload_ptr[0],recv_ptr[0],type,function_name))
else:
# Get the pointer to the buffer
payload_ptr = imm.readMemory(regs['ESP'] + 8, 4)
payload_ptr = struct.unpack("L", payload_ptr)
# Figure out where [ESP] points to
esp_ptr = imm.readMemory(regs['ESP'],4)
esp_ptr = struct.unpack("<L", esp_ptr)
# Add the [ESP] hook for when the function returns
simple_hook = simple_hooks()
simple_hook.add("%08x" % esp_ptr[0],esp_ptr[0])
# Add our pertinent information to the knowledgebase
imm.addKnowledge("%08x" % esp_ptr[0],(payload_ptr[0],type,function_name))
# The main routine that gets run when you type !packets
def main(args):
imm = Debugger()
imm.ignoreSingleStep("CONTINUE")
hooker = set_hooks()
# Create the packet capture window
column_titles = ["Function","Type","Length","Binary","ASCII"]
cap_win = imm.createWindow("Captured Packets", column_titles )
# Add the window to the knowledge base
imm.addKnowledge("cap_win", cap_win,force_add=0x1)
# Find the addresses of the functions we want to hook
# Then register the hooks
ws_wsarecv = imm.getAddress("ws2_32.WSARecv")
ws_wsasend = imm.getAddress("ws2_32.WSASend")
ws_recv = imm.getAddress("ws2_32.recv")
ws_recvfrom = imm.getAddress("ws2_32.recvfrom")
# Set the hooks
hooker.add("WSARecv", ws_wsarecv)
hooker.add("WSASend", ws_wsasend)
hooker.add("recv", ws_recv)
hooker.add("recvfrom", ws_recvfrom)
# Register the hook-address pair with the knowledgebase
imm.addKnowledge("%08x" % ws_wsarecv, "WSARecv")
imm.addKnowledge("%08x" % ws_wsasend, "WSASend")
imm.addKnowledge("%08x" % ws_recv, "recv")
imm.addKnowledge("%08x" % ws_recvfrom, "recvfrom")
return "Network hooks in place."