public IPSession() { events = new List<TCPEvent>(); streamIn = new PacketStream(); streamOut = new PacketStream(); nodes = new List<TransactionNode>(); }
private TransactionNode ExtractTNSData(PacketStream stream, StreamDirection direction) { TransactionNode node; OracleTransactionType type; List<PacketSlice> slices = new List<PacketSlice>(); Int16 pLen = 0; int packetType; try { pLen = stream.PeekInt16(); stream.ReadBytes(2, slices); stream.ReadBytes(2); //skip checksum packetType = stream.ReadByte(); type = (OracleTransactionType)packetType; stream.ReadByte(); //skip the reserved byte } catch (Exception e) { logger.AddMessage(e.Message); return null; } switch (type) { case OracleTransactionType.CONNECT: try { node = new TransactionNode("Connect"); node.AddField("Packet Size", pLen, "Packet Size", slices); Int16 headerChecksum = stream.ReadInt16(); Int16 version = stream.PeekInt16(); stream.ReadBytes(2, slices); node.AddField("Version", version, "Version", slices); Int16 compatVersion = stream.PeekInt16(); stream.ReadBytes(2, slices); node.AddField("Version (compatible)", compatVersion, "Compatible Version", slices); Int16 serviceOptions = stream.ReadInt16(); Int16 sessionDataUnitSize = stream.ReadInt16(); Int16 maxTxDataUnitSize = stream.ReadInt16(); Int16 NTProtCharacteristics = stream.ReadInt16(); Int16 lineTurnValue = stream.ReadInt16(); Int16 valueOfOneInHW = stream.ReadInt16(); Int16 ctDataLen = stream.PeekInt16(); stream.ReadBytes(2, slices); node.AddField("Data Length", ctDataLen, "The length of the connect datastring.", slices); Int16 ctDataOffset = stream.ReadInt16(); Int16 maxRecCtData = stream.ReadInt16(); Int16 ctFlagsA = stream.ReadInt16(); Int16 ctFlagsB = stream.ReadInt16(); Int32 traceItemA = stream.ReadInt32(); Int32 traceItemB = stream.ReadInt32(); Int64 traceID = stream.ReadInt64(); stream.ReadInt64(); byte[] ctData = stream.PeekBytes(ctDataLen); string connectData = StaticUtils.DecodeASCII(ctData); stream.ReadBytes(ctDataLen, slices); node.AddField("Connect data", connectData, "Connect data", slices); try { Match match = Regex.Match(connectData, "\\(PROTOCOL=(?<proto>\\w{2,})\\)\\(HOST=(?<host>[.\\w]{7,})\\)\\(PORT=(?<port>\\d{2,})\\)\\).*SERVICE_NAME=(?<sid>[.\\w]{1,})\\)"); string proto = match.Groups["proto"].Value; string host = match.Groups["host"].Value; string newPort = match.Groups["port"].Value; string sid = match.Groups["sid"].Value; TransactionNode cInfoNode = new TransactionNode("Connection Info"); cInfoNode.AddField("Protocol", proto, "Protocol", slices); cInfoNode.AddField("Host", host, "Server being connected to", slices); cInfoNode.AddField("Port", newPort, "Port", slices); cInfoNode.AddField("Service", sid, "Service", slices); node.AddChild(cInfoNode); } catch (ArgumentException) { } return node; } catch (Exception e) { logger.AddMessage(e.Message); return null; } case OracleTransactionType.ACCEPT: node = new TransactionNode("Accept"); node.AddField("Packet Size", pLen, "Packet Size", slices); try { Int16 headerChecksum = stream.ReadInt16(); Int16 version = stream.PeekInt16(); stream.ReadBytes(2, slices); node.AddField("Version", version, "Version", slices); Int16 serviceOptions = stream.ReadInt16(); Int16 sessionDataUnitSize = stream.PeekInt16(); stream.ReadBytes(2, slices); node.AddField("Session Data Unit Size", sessionDataUnitSize, "Session Data Unit Size", slices); Int16 maxTxDataUnitSize = stream.PeekInt16(); stream.ReadBytes(2, slices); node.AddField("Max Tx Unit Size", maxTxDataUnitSize, "Maximum Transmission Data Unit Size", slices); Int16 valueOfOneInHW = stream.ReadInt16(); Int16 acceptDataLength = stream.ReadInt16(); Int16 dataOffset = stream.ReadInt16(); int connectFlagsA = stream.ReadByte(); int connectFlagsB = stream.ReadByte(); stream.ReadBytes(pLen - 24); //read out empty bytes } catch (Exception e) { logger.AddMessage(e.Message); return null; } return node; case OracleTransactionType.REDIRECT: node = new TransactionNode("Redirect"); node.AddField("Packet Size", pLen, "Packet Size", slices); try { Int16 headerChecksum = stream.ReadInt16(); Int16 redirLen = stream.PeekInt16(); stream.ReadBytes(2, slices); node.AddField("Redirection Data Length", redirLen, "Length of the redirection data string", slices); byte[] redirData = stream.PeekBytes(redirLen); string sRedir = StaticUtils.DecodeASCII(redirData); stream.ReadBytes(redirLen, slices); node.AddField("Redirection Data", sRedir, "Redirection data", slices); //get the redirected port string newPort = null; string proto = null; string host = null; try { Match match = Regex.Match(sRedir, "\\(PROTOCOL=(?<proto>\\w{2,})\\)\\(HOST=(?<host>[.\\w]{7,})\\)\\(PORT=(?<port>\\d{2,})\\)\\)"); proto = match.Groups["proto"].Value; host = match.Groups["host"].Value; newPort = match.Groups["port"].Value; } catch (ArgumentException) { // Syntax error in the regular expression } if(!newPort.Equals("")) redirPort = Int32.Parse(newPort); TransactionNode redirInfo = new TransactionNode("Redirection Info"); redirInfo.AddField("Protocol", proto, "Protocol used", slices); redirInfo.AddField("Host", host, "Host", slices); redirInfo.AddField("Port", newPort, "Port", slices); node.AddChild(redirInfo); } catch (Exception e) { logger.AddMessage(e.Message); return null; } return node; case OracleTransactionType.DATA: string label; if (direction == StreamDirection.IN) label = "Response"; else label = "Request"; node = new TransactionNode("Data - "+label ); node.AddField("Packet Size", pLen, "Packet Size", slices); try { Int16 headerChecksum = stream.ReadInt16(); Int16 dataFlags = stream.ReadInt16(); int payLoadLength = pLen - 10; byte[] payLoad = stream.PeekBytes(payLoadLength); string sPayload = StaticUtils.DecodeASCII(payLoad); stream.ReadBytes(payLoadLength, slices); node.AddField("Data", sPayload, "Data", slices); } catch (Exception e) { logger.AddMessage(e.Message); return null; } return node; default: logger.AddMessage(String.Format("Packet dissection not implemented [TransactionType={0}]", type)); return null; } }
static void Main(string[] args) { PacketStream stream = new PacketStream(); IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Parse("169.254.2.2"), 27516); IPEndPoint remoteEndpoint = new IPEndPoint(IPAddress.Parse("169.254.2.1"), 1056); int n = 1; IPPacket p = new IPPacket(n++, 1, PacketDirection.PACKET_DIRECTION_OUTGOING, localEndpoint, remoteEndpoint, NewArrayIncremental(6, 10)); stream.AppendPacket(p); p = new IPPacket(n++, 1, PacketDirection.PACKET_DIRECTION_OUTGOING, localEndpoint, remoteEndpoint, NewArrayIncremental(3, 35)); stream.AppendPacket(p); p = new IPPacket(n++, 1, PacketDirection.PACKET_DIRECTION_OUTGOING, localEndpoint, remoteEndpoint, NewArrayIncremental(1, 60)); stream.AppendPacket(p); p = new IPPacket(n++, 1, PacketDirection.PACKET_DIRECTION_OUTGOING, localEndpoint, remoteEndpoint, NewArrayIncremental(1, 200)); stream.AppendPacket(p); p = new IPPacket(n++, 1, PacketDirection.PACKET_DIRECTION_OUTGOING, localEndpoint, remoteEndpoint, NewArrayIncremental(3, 210)); stream.AppendPacket(p); p = new IPPacket(n++, 1, PacketDirection.PACKET_DIRECTION_OUTGOING, localEndpoint, remoteEndpoint, NewArrayIncremental(1, 70)); stream.AppendPacket(p); p = new IPPacket(n++, 1, PacketDirection.PACKET_DIRECTION_OUTGOING, localEndpoint, remoteEndpoint, NewArrayIncremental(1, 80)); stream.AppendPacket(p); Debug.Assert(stream.Position == 0, "Position != 0"); Debug.Assert(stream.Length == 16, "Length != 16"); byte[] buf = new byte[stream.Length]; Debug.Assert(stream.Read(buf, 0, 16) == 16, "Read() != 16"); byte[] expectedBytes = new byte[] { 10, 11, 12, 13, 14, 15, 35, 36, 37, 60, 200, 210, 211, 212, 70, 80 }; Debug.Assert(CompareByteArrays(buf, expectedBytes), "Content after first read is not as expected"); Debug.Assert(stream.Position == 16, "Position != 16"); Debug.Assert(stream.Read(buf, 0, 10) == 0, "Read at offset 16 doesn't return 0"); stream.Seek(-1, SeekOrigin.Current); Debug.Assert(stream.Read(buf, 2, 100) == 1, "Read at offset 15 doesn't return 1"); Debug.Assert(buf[2] == 80, "Byte at offset 15 isn't 80"); stream.Seek(-16, SeekOrigin.Current); Debug.Assert(stream.Position == 0, "Position != 0 after reverse seek"); stream.Position = 9; Debug.Assert(stream.Read(buf, 1, 1) == 1, "Read at Position=9 didn't yield 1 byte"); Debug.Assert(buf[1] == 60, "buf[1] != 60"); stream.Position = 13; Debug.Assert(stream.Read(buf, 5, 4) == 3, "Read at Position=13 didn't yield 3 bytes"); Debug.Assert(buf[5] == 212, "buf[5] != 212"); Debug.Assert(buf[6] == 70, "buf[5] != 70"); Debug.Assert(buf[7] == 80, "buf[5] != 80"); System.Console.WriteLine("All tests passed"); System.Console.ReadKey(); }
protected void ReadNextP2PMessageChunk(PacketStream stream, TransactionNode parentNode) { TransactionNode p2pNode = new TransactionNode(parentNode, "MSNP2PMessageChunk"); // Headers TransactionNode p2pHeaders = new TransactionNode(p2pNode, "Headers"); List<PacketSlice> slices = new List<PacketSlice>(); UInt32 sessionID = stream.ReadU32LE(slices); p2pHeaders.AddField("SessionID", sessionID, "Session ID.", slices); UInt32 messageID = stream.ReadU32LE(slices); p2pHeaders.AddField("MessageID", messageID, "Message ID.", slices); UInt64 dataOffset = stream.ReadU64LE(slices); p2pHeaders.AddField("DataOffset", dataOffset, "Data offset.", slices); UInt64 dataSize = stream.ReadU64LE(slices); p2pHeaders.AddField("DataSize", dataSize, "Data size.", slices); UInt32 chunkSize = stream.ReadU32LE(slices); p2pHeaders.AddField("ChunkSize", chunkSize, "Chunk size.", slices); UInt32 flags = stream.ReadU32LE(slices); p2pHeaders.AddField("Flags", flags, StaticUtils.FormatFlags(flags), "Flags.", slices); UInt32 ackedMsgID = stream.ReadU32LE(slices); p2pHeaders.AddField("AckedMsgID", ackedMsgID, "MessageID of the message to be acknowledged.", slices); UInt32 prevAckedMsgID = stream.ReadU32LE(slices); p2pHeaders.AddField("PrevAckedMsgID", prevAckedMsgID, "AckedMsgID of the last chunk to ack.", slices); UInt64 ackedDataSize = stream.ReadU64LE(slices); p2pHeaders.AddField("AckedDataSize", ackedDataSize, "Acknowledged data size.", slices); // Body TransactionNode p2pContent = null; if (chunkSize > 0) { p2pContent = new TransactionNode(p2pNode, "Content"); byte[] bytes = stream.ReadBytes((int)chunkSize, slices); if (sessionID != 0) { p2pContent.AddField("Raw", bytes, StaticUtils.FormatByteArray(bytes), "Raw content.", slices); } else { p2pContent.AddTextField("MSNSLP", bytes, StaticUtils.DecodeUTF8(bytes), "MSNSLP data.", slices); } } }
protected void SBParseMSG(PacketStream stream, TransactionNode payloadNode, int payloadLength) { List<PacketSlice> slices = new List<PacketSlice>(2); string content = stream.PeekStringUTF8(payloadLength); TransactionNode headersNode = new TransactionNode(payloadNode, "Headers"); int pos = content.IndexOf("\r\n\r\n"); string headers = content.Substring(0, pos); string[] lines = headers.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); foreach (string line in lines) { stream.ReadBytes(StaticUtils.GetUTF8ByteCount(line), slices); string[] tokens = line.Split(new char[] { ':' }, 2); tokens[1] = tokens[1].TrimStart(new char[] { ' ' }); headersNode.AddField(tokens[0], tokens[1], "Message header field.", slices); // Skip CRLF stream.ReadBytes(2); } // Skip extra CRLF stream.ReadBytes(2); int bodyLength = payloadLength - StaticUtils.GetUTF8ByteCount(headers) - 4; if (bodyLength > 0) { TransactionNode bodyNode = new TransactionNode(payloadNode, "Body"); string contentType = (string)headersNode.Fields["Content-Type"]; contentType = contentType.Split(new char[] { ';' }, 2)[0]; if (contentType == "application/x-msnmsgrp2p") { ReadNextP2PMessageChunk(stream, bodyNode); UInt32 appID = stream.ReadU32BE(slices); bodyNode.AddField("AppID", appID, "Application ID.", slices); } else if (contentType == "text/x-msmsgsinvite") { string bodyStr = stream.ReadStringUTF8(bodyLength, slices); bodyNode.AddTextField("Body", bodyStr, "Invite body.", slices); } else { string bodyStr = stream.ReadStringUTF8(bodyLength, slices); bodyNode.AddField("Body", bodyStr, "Body.", slices); } } }
private TransactionNode ReadNextP2PDirectMessage(PacketStream stream, string name) { TransactionNode msgNode = new TransactionNode(name); msgNode.Description = msgNode.Name; List<PacketSlice> slices = new List<PacketSlice>(1); uint len = stream.ReadU32LE(slices); msgNode.AddField("MSNP2PLength", len, "P2P message chunk length.", slices); ReadNextP2PMessageChunk(stream, msgNode); return msgNode; }
private void ReadAllP2PDirectMessages(IPSession session, PacketStream stream) { while (stream.GetBytesAvailable() > 0) { try { TransactionNode node = ReadNextP2PDirectMessage(stream, "MSNP2PDirectMessage"); session.AddNode(node); } catch (EndOfStreamException e) { logger.AddMessage(String.Format("MSNP2PDirect: EOS at {0} ({1})", stream.Position, e)); break; } } }
private void SwitchToResponseAndParseResult(TransactionNode resp, List<PacketSlice> slices, out UInt32 retVal, out UInt32 lastError, bool formatRetVal) { stream = session.GetNextStreamDirection(); UInt32 msgLen = stream.ReadU32LE(slices); resp.AddField("MessageLength", Convert.ToString(msgLen), "Length of the RAPI response.", slices); lastError = stream.ReadU32LE(slices); resp.AddField("LastError", String.Format("0x{0:x8}", lastError), "Last error on the CE device.", slices); retVal = stream.ReadU32LE(slices); resp.AddField("ReturnValue", (formatRetVal) ? StaticUtils.FormatRetVal(retVal) : StaticUtils.FormatValue(retVal), "Return value.", slices); }
private void HandleRapiSession() { List<PacketSlice> slices = new List<PacketSlice>(); TransactionNode node, req, resp; string str; UInt32 val, retVal, lastError; while (stream.GetBytesAvailable() > 0) { UInt32 msgLen, msgType; List<PacketSlice> msgLenSlices = new List<PacketSlice>(1); List<PacketSlice> msgTypeSlices = new List<PacketSlice>(1); // Message length msgLen = stream.ReadU32LE(msgLenSlices); if (msgLen == 5) { node = new TransactionNode("RAPINotification"); node.Description = node.Name; node.AddField("MessageType", "RAPI_NOTIFICATION", "Message type.", msgLenSlices); val = stream.ReadU32LE(slices); node.AddField("NotificationType", (val == 4) ? "REQUEST_NEW_CONNECTION" : StaticUtils.FormatFlags(val), "Notification type.", slices); val = stream.ReadU32LE(slices); node.AddField("Argument", val, "Argument.", slices); session.AddNode(node); if (stream.GetBytesAvailable() < 4) break; else continue; } else if (msgLen == 1) { node = new TransactionNode("RAPIKeepalive"); node.Description = node.Name; req = new TransactionNode(node, "Request"); req.AddField("MessageType", "RAPI_PING", "Message type.", msgLenSlices); stream = session.GetNextStreamDirection(); if (stream.GetBytesAvailable() < 4) break; stream.ReadU32LE(slices); resp = new TransactionNode(node, "Response"); resp.AddField("MessageType", "RAPI_PONG", "Message type.", slices); session.AddNode(node); stream = session.GetNextStreamDirection(); if (stream.GetBytesAvailable() < 4) break; else continue; } // Message type msgType = stream.ReadU32LE(msgTypeSlices); if (msgType >= rapiCallNames.Length) { logger.AddMessage("Unknown call name: {0:x8}", msgType); return; } string name = rapiCallNames[msgType]; RAPICallNode call = new RAPICallNode(name); call.Description = call.Name; req = call.Request; resp = call.Response; req.AddField("MessageLength", msgLen, "Length of the RAPI request.", msgLenSlices); req.AddField("MessageType", String.Format("{0} (0x{1:x2})", name, msgType), "Type of the RAPI request.", msgTypeSlices); if (name == "CeRegOpenKeyEx") { val = stream.ReadU32LE(slices); req.AddField("hKey", StaticUtils.FormatRegKey(val), "Handle to a currently open key or one of the following predefined reserved handle values:\n" + "HKEY_CLASSES_ROOT\nHKEY_CURRENT_USER\nHKEY_LOCAL_MACHINE\nHKEY_USERS", slices); str = stream.ReadRAPIString(slices); req.AddField("szSubKey", str, "A null-terminated string containing the name of the subkey to open.", slices); req.Summary = String.Format("{0}, \"{1}\"", StaticUtils.FormatRegKey(val, true), str); SwitchToResponseAndParseResult(resp, slices, out retVal, out lastError); val = stream.ReadU32LE(slices); string result = String.Format("0x{0:x8}", val); resp.AddField("hkResult", result, "Handle to the opened key.", slices); if (retVal == Constants.ERROR_SUCCESS) resp.Summary = String.Format("{0}, {1}", StaticUtils.FormatRetVal(retVal, true), result); else resp.Summary = StaticUtils.FormatRetVal(retVal, true); } else if (name == "CeRegCreateKeyEx") { val = stream.ReadU32LE(slices); req.AddField("hKey", StaticUtils.FormatRegKey(val), "Handle to a currently open key or one of the following predefined reserved handle values:\n" + "HKEY_CLASSES_ROOT\nHKEY_CURRENT_USER\nHKEY_LOCAL_MACHINE\nHKEY_USERS", slices); string szSubKey = stream.ReadRAPIString(slices); req.AddField("szSubKey", (szSubKey != null) ? szSubKey : "(null)", "A null-terminated string specifying the name of a subkey that this function opens or creates. " + "The subkey specified must be a subkey of the key identified by the hKey parameter. This subkey " + "must not begin with the backslash character (\\). If the parameter is NULL, then RegCreateKeyEx " + "behaves like RegOpenKey, where it opens the key specified by hKey.", slices); string szClass = stream.ReadRAPIString(slices); req.AddField("szClass", (szClass != null) ? szClass : "(null)", "A null-terminated string that specifies the class (object type) of this key. This parameter is " + "ignored if the key already exists.", slices); req.Summary = String.Format("{0}, {1}, {2}", StaticUtils.FormatRegKey(val, true), StaticUtils.FormatStringArgument(szSubKey), StaticUtils.FormatStringArgument(szClass)); SwitchToResponseAndParseResult(resp, slices, out retVal, out lastError); string result = String.Format("0x{0:x8}", stream.ReadU32LE(slices)); resp.AddField("hkResult", result, "Handle to the opened key.", slices); UInt32 disposition = stream.ReadU32LE(slices); resp.AddField("dwDisposition", StaticUtils.FormatRegDisposition(disposition), "Receives one of REG_CREATED_NEW_KEY and REG_OPENED_EXISTING_KEY.", slices); if (retVal == Constants.ERROR_SUCCESS) resp.Summary = String.Format("{0}, {1}, {2}", StaticUtils.FormatRetVal(retVal, true), result, StaticUtils.FormatRegDisposition(disposition, true)); else resp.Summary = StaticUtils.FormatRetVal(retVal, true); } else if (name == "CeRegCloseKey") { val = stream.ReadU32LE(slices); req.AddField("hKey", StaticUtils.FormatRegKey(val), "Handle to the open key to close.", slices); req.Summary = StaticUtils.FormatRegKey(val, true); SwitchToResponseAndParseResult(resp, slices, out retVal, out lastError); resp.Summary = StaticUtils.FormatRetVal(retVal, true); } else if (name == "CeRegQueryValueEx") { val = stream.ReadU32LE(slices); req.AddField("hKey", StaticUtils.FormatRegKey(val), "Handle to a currently open key or any of the following predefined reserved handle values:\n" + "HKEY_CLASSES_ROOT\nHKEY_CURRENT_USER\nHKEY_LOCAL_MACHINE\nHKEY_USERS", slices); string szValueName = stream.ReadRAPIString(slices); req.AddField("szValueName", szValueName, "A string containing the name of the value to query.", slices); UInt32 cbData = stream.ReadU32LE(slices); req.AddField("cbData", cbData, "A variable that specifies the maximum number of bytes to return.", slices); req.Summary = String.Format("{0}, {1}, {2}", StaticUtils.FormatRegKey(val, true), StaticUtils.FormatStringArgument(szValueName), cbData); SwitchToResponseAndParseResult(resp, slices, out retVal, out lastError); UInt32 dwType = stream.ReadU32LE(slices); resp.AddField("dwType", StaticUtils.FormatRegType(dwType), "The type of data associated with the specified value.", slices); cbData = stream.ReadU32LE(slices); resp.AddField("cbData", Convert.ToString(cbData), "The size of the data returned.", slices); str = ReadAndFormatDataForRegType(dwType, cbData, slices); if (str == null) str = "NULL"; resp.AddField("Data", str, "The data returned.", slices); resp.Summary = StaticUtils.FormatRetVal(retVal, true); } else if (name == "CeRegSetValueEx") { UInt32 key = stream.ReadU32LE(slices); req.AddField("hKey", StaticUtils.FormatRegKey(key), "Handle to a currently open key or any of the following predefined reserved handle values:\n" + "HKEY_CLASSES_ROOT\nHKEY_CURRENT_USER\nHKEY_LOCAL_MACHINE\nHKEY_USERS", slices); string szValueName = stream.ReadRAPIString(slices); req.AddField("szValueName", szValueName, "String containing the name of the value to set. If a value with this name is not already " + "present in the key, the function adds it to the key. If this parameter is NULL or an empty " + "string, the function sets the type and data for the key's unnamed value. Registry keys do " + "not have default values, but they can have one unnamed value, which can be of any type.", slices); UInt32 dwType = stream.ReadU32LE(slices); req.AddField("dwType", StaticUtils.FormatRegType(dwType), "Type of information to be stored as the value's data.", slices); UInt32 cbData = stream.ReadU32LE(slices); req.AddField("cbData", Convert.ToString(cbData), "Specifies the size, in bytes, of the information passed in the the Data field.", slices); str = ReadAndFormatDataForRegType(dwType, cbData, slices); if (str == null) str = "NULL"; req.AddField("Data", str, "Buffer containing the data to be stored with the specified value name.", slices); string dataSummary; if (dwType == Constants.REG_DWORD || dwType == Constants.REG_DWORD_BIG_ENDIAN) { dataSummary = str; } else dataSummary = String.Format("[{0} bytes]", cbData); req.Summary = String.Format("{0}, {1}, {2}, {3}", StaticUtils.FormatRegKey(key), StaticUtils.FormatStringArgument(szValueName), StaticUtils.FormatRegType(dwType), dataSummary); SwitchToResponseAndParseResult(resp, slices, out retVal, out lastError); resp.Summary = StaticUtils.FormatRetVal(retVal, true); } else if (name == "CeProcessConfig") { str = stream.ReadRAPIString(slices); req.AddXMLField("szRequest", str, "Config request.", slices); UInt32 flags = stream.ReadU32LE(slices); req.AddField("dwFlags", StaticUtils.FormatFlags(flags), "Flags.", slices); req.Summary = String.Format("[{0} bytes], 0x{1:x8}", str.Length, flags); SwitchToResponseAndParseResult(resp, slices, out retVal, out lastError); str = stream.ReadRAPIString(slices); resp.AddXMLField("szResponse", str, "Config response.", slices); if (retVal == Constants.ERROR_SUCCESS) resp.Summary = String.Format("{0}, [{1} bytes]", StaticUtils.FormatRetVal(retVal, true), (str != null) ? str.Length : 0); else resp.Summary = StaticUtils.FormatRetVal(retVal, true); } else if (name == "CeGetDesktopDeviceCaps") { string caps = FormatDeviceCaps(stream.ReadU32LE(slices)); req.AddField("nIndex", caps, "The item to return.", slices); req.Summary = caps; SwitchToResponseAndParseResult(resp, slices, out retVal, out lastError, false); resp.Summary = StaticUtils.FormatValue(retVal); } else if (name == "CeSyncStart") { string xml = stream.ReadRAPIString(slices); req.AddXMLField("szXML", (xml != null) ? xml : "(null)", "Optional message.", slices); if (xml != null) req.Summary = String.Format("[{0} bytes]", xml.Length); else req.Summary = "NULL"; SwitchToResponseAndParseResult(resp, slices, out retVal, out lastError); resp.Summary = StaticUtils.FormatRetVal(retVal, true); } else if (name == "CeSyncResume" || name == "CeSyncPause") { req.Summary = ""; SwitchToResponseAndParseResult(resp, slices, out retVal, out lastError, false); resp.Summary = StaticUtils.FormatRetVal(retVal, true); } else if (name == "CeStartReplication") { req.Summary = ""; SwitchToResponseAndParseResult(resp, slices, out retVal, out lastError, false); resp.Summary = StaticUtils.FormatBool(retVal); } else if (name == "CeGetFileAttributes") { string fileName = stream.ReadRAPIString(slices); req.AddXMLField("szFileName", fileName, "Name of a file or directory.", slices); req.Summary = String.Format("\"{0}\"", fileName); SwitchToResponseAndParseResult(resp, slices, out retVal, out lastError, false); resp.Summary = StaticUtils.FormatValue(retVal); } else { if (msgLen > 4) { byte[] bytes = stream.ReadBytes((int)msgLen - 4, slices); req.AddField("UnparsedData", StaticUtils.FormatByteArray(bytes), "Unparsed data.", slices); } req.Summary = "[not yet parsed]"; SwitchToResponseAndParseResult(resp, slices, out retVal, out lastError, false); resp.Summary = "[not yet parsed]"; } session.AddNode(call); stream = session.GetNextStreamDirection(); if (stream.GetBytesAvailable() == 0) break; } }
private void HandleRapiHandshake() { RAPIConnectionState state = RAPIConnectionState.HANDSHAKE; List<PacketSlice> slices = new List<PacketSlice>(); TransactionNode parentNode, node; string str; UInt32 val; // Read and verify the initial request UInt32 initialRequest = stream.ReadU32LE(slices); if (initialRequest != NOTIFY_INITIAL_HANDSHAKE && initialRequest != NOTIFY_CONNECTION_READY) { logger.AddMessage("RAPI protocol error, unknown initial request {0}", initialRequest); return; } node = new TransactionNode((initialRequest == 0) ? "RAPIInitialHandshake" : "RAPIConnectionStart"); node.Description = node.Name; node.AddField("InitialRequest", (initialRequest == NOTIFY_INITIAL_HANDSHAKE) ? "NOTIFY_INITIAL_HANDSHAKE" : "NOTIFY_CONNECTION_READY", "Initial request.", slices); // Now it's our turn stream = session.GetNextStreamDirection(); if (initialRequest == NOTIFY_INITIAL_HANDSHAKE) { UInt32 firstPing = stream.ReadU32LE(slices); node.AddField("FirstPing", firstPing, "First ping, should be 3.", slices); // And the first pong stream = session.GetNextStreamDirection(); UInt32 firstPong = stream.ReadU32LE(slices); node.AddField("FirstPong", firstPong, "First pong, should be 4 for older WM5, 6 for newer versions.", slices); if (firstPong == 6) { // Now we're supposed to send 4 DWORDs stream = session.GetNextStreamDirection(); UInt32 secondPing = stream.ReadU32LE(slices); node.AddField("SecondPingValue1", secondPing, "Second ping value #1, should be 7.", slices); secondPing = stream.ReadU32LE(slices); node.AddField("SecondPingValue2", secondPing, "Second ping value #2, should be 8.", slices); secondPing = stream.ReadU32LE(slices); node.AddField("SecondPingValue3", secondPing, "Second ping value #3, should be 4.", slices); secondPing = stream.ReadU32LE(slices); node.AddField("SecondPingValue4", secondPing, "Second ping value #4, should be 1.", slices); // And the device should reply stream = session.GetNextStreamDirection(); UInt32 secondPong = stream.ReadU32LE(slices); node.AddField("SecondPong", secondPong, "Second pong, should be 4.", slices); } // Got it session.AddNode(node); parentNode = new TransactionNode("RAPIDeviceInfo"); parentNode.Description = parentNode.Name; UInt32 deviceInfoLen = stream.ReadU32LE(slices); UInt32 remainingDevInfoLen = deviceInfoLen; parentNode.AddField("Length", deviceInfoLen, "Device info length.", slices); if (deviceInfoLen > MAX_DEVICE_INFO_LENGTH) { logger.AddMessage("RAPI protocol error, length of the device info package should be below {0}, was {1}", MAX_DEVICE_INFO_LENGTH, deviceInfoLen); return; } node = new TransactionNode(parentNode, "DeviceInfo"); Guid guid = new Guid(stream.ReadBytes(16, slices)); str = String.Format("{{0}}", guid.ToString()); node.AddField("DeviceGUID", str, "Device GUID.", slices); remainingDevInfoLen -= 16; val = stream.ReadU32LE(slices); node.AddField("OsVersionMajor", val, "OS version, major.", slices); remainingDevInfoLen -= 4; val = stream.ReadU32LE(slices); node.AddField("OsVersionMinor", val, "OS version, minor.", slices); remainingDevInfoLen -= 4; val = stream.ReadU32LE(slices); node.AddField("DeviceNameLength", val, "Device name length (in characters, not bytes).", slices); remainingDevInfoLen -= 4; // calculate the string size in unicode, with terminating NUL word val = (val + 1) * 2; str = stream.ReadCStringUnicode((int)val, slices); node.AddField("DeviceName", str, "Device name.", slices); remainingDevInfoLen -= val; val = stream.ReadU32LE(slices); node.AddField("DeviceVersion", StaticUtils.FormatFlags(val), "Device version.", slices); remainingDevInfoLen -= 4; val = stream.ReadU32LE(slices); node.AddField("DeviceProcessorType", StaticUtils.FormatFlags(val), "Device processor type.", slices); remainingDevInfoLen -= 4; val = stream.ReadU32LE(slices); node.AddField("Unknown1", StaticUtils.FormatFlags(val), "Counter or a flag? ANDed with 0xFFFFFFFE in the code (should take a closer look at this).", slices); remainingDevInfoLen -= 4; val = stream.ReadU32LE(slices); node.AddField("CurrentPartnerId", StaticUtils.FormatFlags(val), "Current partner id.", slices); remainingDevInfoLen -= 4; val = stream.ReadU32LE(slices); node.AddField("DeviceId", StaticUtils.FormatFlags(val), "Current device id. Lives in HKCU\\Software\\Microsoft\\Windows CE Services\\Partners\\<DeviceIdentifier>.", slices); remainingDevInfoLen -= 4; /* dw = stream.ReadU32LE(slices); node.AddField("PlatformNameLength", dw, "Platform name length.", slices); remainingDevInfoLen -= 4;*/ // Don't swallow the 4 last remainingDevInfoLen -= 4; byte[] bytes = stream.ReadBytes((int)remainingDevInfoLen, slices); node.AddField("UnknownData1", StaticUtils.FormatByteArray(bytes), "Unknown device info data.", slices); val = stream.ReadU32LE(slices); node.AddField("PasswordMask", StaticUtils.FormatFlags(val), "Password mask. Non-zero if a password is set.", slices); remainingDevInfoLen -= 4; state = (val != 0) ? RAPIConnectionState.AUTH : RAPIConnectionState.SESSION; // Now it's our turn stream = session.GetNextStreamDirection(); node = parentNode; } else { state = RAPIConnectionState.SESSION; } // Add the last node for each case session.AddNode(node); while (state == RAPIConnectionState.AUTH) { parentNode = new TransactionNode("RAPIAuthAttempt"); parentNode.Description = parentNode.Name; node = new TransactionNode(parentNode, "Request"); val = stream.ReadU16LE(slices); node.AddField("Length", val, "Authentication data length.", slices); byte[] bytes = stream.ReadBytes((int)val, slices); node.AddField("Data", StaticUtils.FormatByteArray(bytes), "Authentication data.", slices); stream = session.GetNextStreamDirection(); node = new TransactionNode(parentNode, "Response"); val = stream.ReadU16LE(slices); node.AddField("Success", (val != 0) ? "TRUE" : "FALSE", "Whether the authentication attempt was successful.", slices); session.AddNode(parentNode); stream = session.GetNextStreamDirection(); if (val != 0) state = RAPIConnectionState.SESSION; } }
public override bool HandleSession(IPSession session) { if (session.LocalEndpoint == null || session.LocalEndpoint.Port != 990) return false; this.session = session; stream = session.GetNextStreamDirection(); // The device should send the first DWORD of the handshake if (stream.CurPacket.Direction == PacketDirection.PACKET_DIRECTION_INCOMING) { HandleRapiHandshake(); } if (stream.GetBytesAvailable() >= 4) HandleRapiSession(); return true; }
protected void AddBodyNode(PacketStream stream, TransactionNode transactionNode, string contentType, string contentEncoding, int bodyLen) { List<PacketSlice> slices = new List<PacketSlice>(1); TransactionNode bodyNode = new TransactionNode("Body"); byte[] body = stream.ReadBytes(bodyLen, slices); if (contentType == "text/html" || contentType == "text/xml") { int realBodyLen = body.Length; if (body[realBodyLen - 1] == '\0') realBodyLen--; Decoder dec; if (contentEncoding == "utf-8") { dec = Encoding.UTF8.GetDecoder(); } else { dec = Encoding.ASCII.GetDecoder(); } char[] bodyChars = new char[dec.GetCharCount(body, 0, realBodyLen)]; dec.GetChars(body, 0, realBodyLen, bodyChars, 0); string bodyStr = new string(bodyChars); if (contentType == "text/xml") bodyNode.AddXMLField("XML", bodyStr, "Body XML data.", slices); else bodyNode.AddTextField("HTML", bodyStr, "Body HTML data.", slices); } else if (contentType == "application/vnd.ms-sync.wbxml") { string xml = WBXML.ConvertToXML(body); bodyNode.AddXMLField("WBXML", xml, "Body WBXML data.", slices); } else { bodyNode.AddField("Raw", body, StaticUtils.FormatByteArray(body), "Raw body data.", slices); } transactionNode.AddChild(bodyNode); }
private TransactionNode ExtractHttpData(PacketStream stream, HTTPTransactionType type, string nodeName) { if (nodeName == null) { nodeName = (type == HTTPTransactionType.REQUEST) ? "Request" : "Response"; } TransactionNode node = new TransactionNode(nodeName); List<PacketSlice> slices = new List<PacketSlice>(); string line = stream.PeekLineUTF8(); int fieldCount = (type == HTTPTransactionType.REQUEST) ? 3 : 2; string[] tokens = line.Split(new char[] { ' ' }, fieldCount); if (tokens.Length < fieldCount) throw new ProtocolError(); if (type == HTTPTransactionType.REQUEST) { stream.ReadBytes(StaticUtils.GetUTF8ByteCount(tokens[0]), slices); node.AddField("Verb", tokens[0], "Request verb.", slices); stream.ReadByte(); stream.ReadBytes(StaticUtils.GetUTF8ByteCount(tokens[1]), slices); node.AddField("Argument", tokens[1], "Request argument.", slices); stream.ReadByte(); stream.ReadBytes(StaticUtils.GetUTF8ByteCount(tokens[2]), slices); node.AddField("Protocol", tokens[2], "Protocol identifier.", slices); // Set a description node.Description = String.Format("{0} {1}", tokens[0], tokens[1]); if (node.Description.Length > MAX_DESCRIPTION_LENGTH) { node.Description = node.Description.Substring(0, MAX_DESCRIPTION_LENGTH - ellipsis.Length); node.Description += ellipsis; } } else { stream.ReadBytes(StaticUtils.GetUTF8ByteCount(tokens[0]), slices); node.AddField("Protocol", tokens[0], "Protocol identifier.", slices); if (tokens.Length > 1) { stream.ReadByte(); stream.ReadBytes(StaticUtils.GetUTF8ByteCount(tokens[1]), slices); node.AddField("Result", tokens[1], "Result.", slices); } // Set a description string result = tokens[1]; if (result.Length > MAX_DESCRIPTION_LENGTH) { result = result.Substring(0, MAX_DESCRIPTION_LENGTH - ellipsis.Length) + ellipsis; } node.Description = result; } stream.ReadBytes(2); TransactionNode headersNode = new TransactionNode("Headers"); Dictionary<string, string> headerFields = new Dictionary<string, string>(); do { line = stream.PeekLineUTF8(); if (line.Length > 0) { tokens = line.Split(new char[] { ':' }, 2); if (tokens.Length < 2) throw new ProtocolError(); string key = tokens[0]; string value = tokens[1].TrimStart(); stream.ReadBytes(StaticUtils.GetUTF8ByteCount(line), slices); headersNode.AddField(key, value, "Header field.", slices); headerFields[key.ToLower()] = value; } stream.ReadBytes(2); } while (line != ""); if (headersNode.Fields.Count > 0) { node.AddChild(headersNode); } int contentLen = -1; if (headerFields.ContainsKey("content-length")) contentLen = Convert.ToInt32(headerFields["content-length"]); else if (headerFields.ContainsKey("contentlength")) contentLen = Convert.ToInt32(headerFields["contentlength"]); if (contentLen != -1) { string contentType = null, contentEncoding = null; if (headerFields.ContainsKey("content-type")) contentType = headerFields["content-type"]; else if (headerFields.ContainsKey("contenttype")) contentType = headerFields["contenttype"]; if (contentType != null) { contentType = contentType.ToLower(); tokens = contentType.Split(new char[] { ';' }); contentType = tokens[0].Trim(); if (tokens.Length > 1) { string[] encTokens = tokens[1].Split(new char[] { '=' }, 2); if (encTokens[0].Trim() == "charset" && encTokens.Length > 1) { contentEncoding = encTokens[1]; } } } string str = stream.PeekStringASCII(5); if (str == "<?xml") { contentType = "text/xml"; contentEncoding = "utf-8"; // FIXME } if (contentLen > 0) { AddBodyNode(stream, node, contentType, contentEncoding, contentLen); } } return node; }
private TransactionNode ExtractHttpData(PacketStream stream, HTTPTransactionType type) { return ExtractHttpData(stream, type, null); }