forked from osmocom/wireshark
JDWP dissector for TCP transport
Bug: 16479 Change-Id: I2618bb4b664c1dd7b4663c368b6ca99ec0533dd5 Reviewed-on: https://code.wireshark.org/review/36636 Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com> Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
parent
9132feb4a4
commit
3a42f536ed
|
@ -61,6 +61,7 @@ OBSAI UDP-based Communication Protocol (UDPCP)
|
|||
AudioCodes Debug Recording (ACDR)
|
||||
Tunnel Extensible Authentication Protocol (TEAP)
|
||||
USB Printer (USBPRINTER)
|
||||
Java Debug Wire Protocol (JDWP)
|
||||
--
|
||||
|
||||
=== Updated Protocol Support
|
||||
|
|
|
@ -1280,6 +1280,7 @@ set(DISSECTOR_SRC
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/packet-ixiatrailer.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-ixveriwave.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-j1939.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-jdwp.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-jmirror.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-jpeg.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/packet-json.c
|
||||
|
|
|
@ -0,0 +1,730 @@
|
|||
/* packet-jdwp.c
|
||||
* Routines for JDWP (Java Debug Wire Protocol) dissection
|
||||
* Copyright 2020, Eugene Adell <eugene.adell@gmail.com>
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <epan/packet.h>
|
||||
#include <epan/prefs.h>
|
||||
#include <epan/expert.h>
|
||||
#include <epan/to_str.h>
|
||||
#include <epan/conversation.h>
|
||||
#include <epan/wmem/wmem.h>
|
||||
|
||||
#include "packet-tcp.h"
|
||||
|
||||
void proto_register_jdwp(void);
|
||||
void proto_reg_handoff_jdwp(void);
|
||||
|
||||
/* IMPORTANT IMPLEMENTATION NOTES
|
||||
*
|
||||
* You need to be looking at:
|
||||
*
|
||||
* https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/jdwp-spec.html
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#define JDWP_PORT 9009 /* Not IANA registered */
|
||||
#define FRAME_HEADER_LEN 11
|
||||
#define JDWP_MIN_LENGTH 11
|
||||
#define JDWP_HANDSHAKE_LENGTH 14
|
||||
#define JDWP_HANDSHAKE_MSG "JDWP-Handshake"
|
||||
|
||||
#define PACKET_TYPE_COMMAND 0
|
||||
#define PACKET_TYPE_REPLY 128
|
||||
|
||||
#define COMMAND_SET_VIRTUALMACHINE 1
|
||||
#define COMMAND_SET_REFERENCETYPE 2
|
||||
#define COMMAND_SET_CLASSTYPE 3
|
||||
#define COMMAND_SET_ARRAYTYPE 4
|
||||
#define COMMAND_SET_INTERFACETYPE 5
|
||||
#define COMMAND_SET_METHOD 6
|
||||
#define COMMAND_SET_FIELD 8
|
||||
#define COMMAND_SET_OBJECTREFERENCE 9
|
||||
#define COMMAND_SET_STRINGREFERENCE 10
|
||||
#define COMMAND_SET_THREADREFERENCE 11
|
||||
#define COMMAND_SET_THREADGROUPREFERENCE 12
|
||||
#define COMMAND_SET_ARRAYREFERENCE 13
|
||||
#define COMMAND_SET_CLASSLOADERREFERENCE 14
|
||||
#define COMMAND_SET_EVENTREQUEST 15
|
||||
#define COMMAND_SET_STACKFRAME 16
|
||||
#define COMMAND_SET_CLASSOBJECTREFERENCE 17
|
||||
#define COMMAND_SET_EVENT 64
|
||||
|
||||
static int proto_jdwp = -1;
|
||||
|
||||
static int hf_jdwp_type = -1;
|
||||
static int hf_jdwp_length = -1;
|
||||
static int hf_jdwp_id = -1;
|
||||
static int hf_jdwp_flags = -1;
|
||||
static int hf_jdwp_commandset = -1;
|
||||
static int hf_jdwp_commandset_virtualmachine = -1;
|
||||
static int hf_jdwp_commandset_referencetype = -1;
|
||||
static int hf_jdwp_commandset_classtype = -1;
|
||||
static int hf_jdwp_commandset_arraytype = -1;
|
||||
static int hf_jdwp_commandset_interfacetype = -1;
|
||||
static int hf_jdwp_commandset_method = -1;
|
||||
static int hf_jdwp_commandset_field = -1;
|
||||
static int hf_jdwp_commandset_objectreference = -1;
|
||||
static int hf_jdwp_commandset_stringreference = -1;
|
||||
static int hf_jdwp_commandset_threadreference = -1;
|
||||
static int hf_jdwp_commandset_threadgroupreference = -1;
|
||||
static int hf_jdwp_commandset_arrayreference = -1;
|
||||
static int hf_jdwp_commandset_classloaderreference = -1;
|
||||
static int hf_jdwp_commandset_eventrequest = -1;
|
||||
static int hf_jdwp_commandset_stackframe = -1;
|
||||
static int hf_jdwp_commandset_classobjectreference = -1;
|
||||
static int hf_jdwp_commandset_event = -1;
|
||||
static int hf_jdwp_errorcode = -1;
|
||||
static int hf_jdwp_data = -1;
|
||||
|
||||
static gint ett_jdwp = -1;
|
||||
|
||||
static expert_field ei_jdwp_hlen_invalid = EI_INIT;
|
||||
static expert_field ei_jdwp_flags_invalid = EI_INIT;
|
||||
|
||||
// contains the command set names
|
||||
static const value_string commandsetnames[] = {
|
||||
{1, "VirtualMachine"},
|
||||
{2, "ReferenceType"},
|
||||
{3, "ClassType"},
|
||||
{4, "ArrayType"},
|
||||
{5, "InterfaceType"},
|
||||
{6, "Method"},
|
||||
{8, "Field"},
|
||||
{9, "ObjectReference"},
|
||||
{10, "StringReference"},
|
||||
{11, "ThreadReference"},
|
||||
{12, "ThreadGroupReference"},
|
||||
{13, "ArrayReference"},
|
||||
{14, "ClassLoaderReference"},
|
||||
{15, "EventRequest"},
|
||||
{16, "StackFrame"},
|
||||
{17, "ClassObjectReference"},
|
||||
{64, "Event"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type Virtual Machine
|
||||
static const value_string commandset_virtualmachine[] = {
|
||||
{1, "Version"},
|
||||
{2, "ClassesBySignature"},
|
||||
{3, "AllClasses"},
|
||||
{4, "AllThreads"},
|
||||
{5, "TopLevelThreadGroups"},
|
||||
{6, "Dispose"},
|
||||
{7, "IDSizes"},
|
||||
{8, "Suspend"},
|
||||
{9, "Resume"},
|
||||
{10, "Exit"},
|
||||
{11, "CreateString"},
|
||||
{12, "Capabilities"},
|
||||
{13, "ClassPaths"},
|
||||
{14, "DisposeObjects"},
|
||||
{15, "HoldEvents"},
|
||||
{16, "ReleaseEvents"},
|
||||
{17, "CapabilitiesNew"},
|
||||
{18, "RedefineClasses"},
|
||||
{19, "SetDefaultStratum"},
|
||||
{20, "AllClassesWithGeneric"},
|
||||
{21, "InstanceCounts"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type Reference
|
||||
static const value_string commandset_referencetype[] = {
|
||||
{1, "Signature"},
|
||||
{2, "ClassLoader"},
|
||||
{3, "Modifiers"},
|
||||
{4, "Fields"},
|
||||
{5, "Methods"},
|
||||
{6, "GetValues"},
|
||||
{7, "SourceFile"},
|
||||
{8, "NestedTypes"},
|
||||
{9, "Status"},
|
||||
{10, "Interfaces"},
|
||||
{11, "ClassObject"},
|
||||
{12, "SourceDebugExtension"},
|
||||
{13, "SignatureWithGeneric"},
|
||||
{14, "FieldsWithGeneric"},
|
||||
{15, "MethodsWithGeneric"},
|
||||
{16, "Instances"},
|
||||
{17, "ClassFileVersion"},
|
||||
{18, "ConstantPool"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type Class
|
||||
static const value_string commandset_classtype[] = {
|
||||
{1, "Superclass"},
|
||||
{2, "SetValues"},
|
||||
{3, "InvokeMethod"},
|
||||
{4, "NewInstance"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type Array
|
||||
static const value_string commandset_arraytype[] = {
|
||||
{1, "NewInstance"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type Interface
|
||||
static const value_string commandset_interfacetype[] = {
|
||||
{1, "InvokeMethod"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type Method
|
||||
static const value_string commandset_method[] = {
|
||||
{1, "LineTable"},
|
||||
{2, "VariableTable"},
|
||||
{3, "Bytecodes"},
|
||||
{4, "IsObsolete"},
|
||||
{5, "VariableTableWithGeneric"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type Field
|
||||
static const value_string commandset_field[] = {
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type Object Reference
|
||||
static const value_string commandset_objectreference[] = {
|
||||
{1, "ReferenceType"},
|
||||
{2, "GetValues"},
|
||||
{3, "SetValues"},
|
||||
{5, "MonitorInfo"},
|
||||
{6, "InvokeMethod"},
|
||||
{7, "DisableCollection"},
|
||||
{8, "EnableCollection"},
|
||||
{9, "IsCollected"},
|
||||
{10, "ReferringObjects"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type String Reference
|
||||
static const value_string commandset_stringreference[] = {
|
||||
{1, "Value"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type Thread Reference
|
||||
static const value_string commandset_threadreference[] = {
|
||||
{1, "Name"},
|
||||
{2, "Suspend"},
|
||||
{3, "Resume"},
|
||||
{4, "Status"},
|
||||
{5, "ThreadGroup"},
|
||||
{6, "Frames"},
|
||||
{7, "FrameCount"},
|
||||
{8, "OwnedMonitors"},
|
||||
{9, "CurrentContentedMonitor"},
|
||||
{10, "Stop"},
|
||||
{11, "Interrupt"},
|
||||
{12, "SuspendCount"},
|
||||
{13, "OwnedMonitorsStackDepthInfo"},
|
||||
{14, "ForceEearlyReturn"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type ThreadGroup Reference
|
||||
static const value_string commandset_threadgroupreference[] = {
|
||||
{1, "Name"},
|
||||
{2, "Parent"},
|
||||
{3, "Children"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type Array Reference
|
||||
static const value_string commandset_arrayreference[] = {
|
||||
{1, "Length"},
|
||||
{2, "GetValues"},
|
||||
{3, "SetValues"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type ClassLoader Reference
|
||||
static const value_string commandset_classloaderreference[] = {
|
||||
{1, "VisibleClasses"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type EventRequest
|
||||
static const value_string commandset_eventrequest[] = {
|
||||
{1, "Set"},
|
||||
{2, "Clear"},
|
||||
{3, "ClearAllBreakpoints"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type StackFrame
|
||||
static const value_string commandset_stackframe[] = {
|
||||
{1, "GetValues"},
|
||||
{2, "SetValues"},
|
||||
{3, "ThisObject"},
|
||||
{4, "PopFrames"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type ClassObject Reference
|
||||
static const value_string commandset_classobjectreference[] = {
|
||||
{1, "ReflectedType"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
// contains the commands for the command set of type Event
|
||||
static const value_string commandset_event[] = {
|
||||
{100, "Composite"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
/* translates the error code to human readable value
|
||||
* value 0 ("NONE") means SUCCESS, all other values mean FAILURE
|
||||
*/
|
||||
static const value_string error_codes[] = {
|
||||
{0, "NONE"},
|
||||
{10, "INVALID_THREAD"},
|
||||
{11, "INVALID_THREAD_GROUP"},
|
||||
{12, "INVALID_PRIORITY"},
|
||||
{13, "THREAD_NOT_SUSPENDED"},
|
||||
{14, "THREAD_SUSPENDED"},
|
||||
{20, "INVALID_OBJECT"},
|
||||
{21, "INVALID_CLASS"},
|
||||
{22, "CLASS_NOT_PREPARED"},
|
||||
{23, "INVALID_METHODID"},
|
||||
{24, "INVALID_LOCATION"},
|
||||
{25, "INVALID_FIELDID"},
|
||||
{30, "INVALID_FRAMEID"},
|
||||
{31, "NO_MORE_FRAMES"},
|
||||
{32, "OPAQUE_FRAME"},
|
||||
{33, "NOT_CURRENT_FRAME"},
|
||||
{34, "TYPE_MISMATCH"},
|
||||
{35, "INVALID_SLOT"},
|
||||
{40, "DUPLICATE"},
|
||||
{41, "NOT_FOUND"},
|
||||
{50, "INVALID_MONITOR"},
|
||||
{51, "NOT_MONITOR_OWNER"},
|
||||
{52, "INTERRUPT"},
|
||||
{60, "INVALID_CLASS_FORMAT"},
|
||||
{61, "CIRCULAR_CLASS_DEFINITION"},
|
||||
{62, "FAILS_VERIFICATION"},
|
||||
{63, "ADD_METHOD_NOT_IMPLEMENTED"},
|
||||
{64, "SCHEMA_CHANGE_NOT_IMPLEMENTED"},
|
||||
{65, "INVALID_TYPESTATE"},
|
||||
{66, "HIERARCHY_CHANGE_NOT_IMPLEMENTED"},
|
||||
{67, "DELETE_METHOD_NOT_IMPLEMENTED"},
|
||||
{68, "UNSUPPORTED_VERSION"},
|
||||
{69, "NAMES_DONT_MATCH"},
|
||||
{70, "CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED"},
|
||||
{71, "METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED"},
|
||||
{99, "NOT_IMPLEMENTED"},
|
||||
{100, "NULL_POINTER"},
|
||||
{101, "ABSENT_INFORMATION"},
|
||||
{102, "INVALID_EVENT_TYPE"},
|
||||
{103, "ILLEGAL_ARGUMENT"},
|
||||
{110, "OUT_OF_MEMORY"},
|
||||
{111, "ACCESS_DENIED"},
|
||||
{112, "VM_DEAD"},
|
||||
{113, "INTERNAL"},
|
||||
{115, "UNATTACHED_THREAD"},
|
||||
{500, "INVALID_TAG"},
|
||||
{502, "ALREADY_INVOKING"},
|
||||
{503, "INVALID_INDEX"},
|
||||
{504, "INVALID_LENGTH"},
|
||||
{506, "INVALID_STRING"},
|
||||
{507, "INVALID_CLASS_LOADER"},
|
||||
{508, "INVALID_ARRAY"},
|
||||
{509, "TRANSPORT_LOAD"},
|
||||
{510, "TRANSPORT_INIT"},
|
||||
{511, "NATIVE_METHOD"},
|
||||
{512, "INVALID_COUNT"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
/* determine PDU length of protocol JDWP */
|
||||
static guint
|
||||
get_jdwp_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
|
||||
{
|
||||
/* Handshake messages don't contain the length field and
|
||||
* they all are strictly identical in length and content
|
||||
*/
|
||||
if (tvb_reported_length(tvb) == JDWP_HANDSHAKE_LENGTH) {
|
||||
if (tvb_strneql(tvb, offset, JDWP_HANDSHAKE_MSG, JDWP_HANDSHAKE_LENGTH) == 0) {
|
||||
return JDWP_HANDSHAKE_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
/* All other packets are either a Command or a Reply, of different lengths
|
||||
* and this length is indicated on the 4 first bytes
|
||||
*/
|
||||
return (guint)tvb_get_ntohl(tvb, offset);
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_jdwp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
/* packet type can take 3 values (handshake, command, reply) */
|
||||
gint packet_type;
|
||||
|
||||
/* length */
|
||||
gint32 hlen = 0;
|
||||
|
||||
/* flag can take 2 values (0, 128) */
|
||||
guint32 flags;
|
||||
|
||||
/* fields that need to be remembered */
|
||||
guint32 mem_commandset = -1;
|
||||
guint32 mem_errorcode = -1;
|
||||
|
||||
/* Check that there's enough data */
|
||||
if (tvb_reported_length(tvb) < JDWP_MIN_LENGTH)
|
||||
return 0;
|
||||
|
||||
/* Set the Protocol Column */
|
||||
col_set_str(pinfo->cinfo, COL_PROTOCOL, "JDWP");
|
||||
col_clear(pinfo->cinfo, COL_INFO);
|
||||
|
||||
proto_item *ti, *hlen_item, *flags_item;
|
||||
proto_tree *jdwp_tree;
|
||||
|
||||
/* Clear out stuff in the info column */
|
||||
col_clear(pinfo->cinfo,COL_INFO);
|
||||
|
||||
ti = proto_tree_add_item(tree, proto_jdwp, tvb, 0, -1, ENC_NA);
|
||||
jdwp_tree = proto_item_add_subtree(ti, ett_jdwp);
|
||||
|
||||
/* The two first packets are Handshake packets and
|
||||
* their content is always "JDWP-Handshake"
|
||||
* All other packets are either a Command or a Reply
|
||||
*/
|
||||
packet_type = 1;
|
||||
if (tvb_reported_length(tvb) == JDWP_HANDSHAKE_LENGTH) {
|
||||
if (tvb_strneql(tvb, offset, JDWP_HANDSHAKE_MSG, JDWP_HANDSHAKE_LENGTH) == 0) {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "JDWP Handshake");
|
||||
packet_type = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (packet_type == 0) {
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_type, tvb, offset, 14, ENC_ASCII|ENC_NA);
|
||||
return tvb_captured_length(tvb);
|
||||
}
|
||||
|
||||
/* LENGTH
|
||||
*/
|
||||
hlen_item = proto_tree_add_item_ret_uint(jdwp_tree, hf_jdwp_length, tvb, offset, 4, ENC_BIG_ENDIAN, &hlen);
|
||||
offset += 4;
|
||||
|
||||
/* ID
|
||||
*/
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_id, tvb, offset, 4, ENC_BIG_ENDIAN);
|
||||
offset += 4;
|
||||
|
||||
/* FLAGS
|
||||
*/
|
||||
flags_item = proto_tree_add_item_ret_uint(jdwp_tree, hf_jdwp_flags, tvb, offset, 1, ENC_BIG_ENDIAN, &flags);
|
||||
offset += 1;
|
||||
|
||||
/* COMMAND
|
||||
*/
|
||||
switch (flags) {
|
||||
case PACKET_TYPE_COMMAND:
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "Command");
|
||||
proto_tree_add_item_ret_uint(jdwp_tree, hf_jdwp_commandset, tvb, offset, 1, ENC_BIG_ENDIAN, &mem_commandset);
|
||||
offset += 1;
|
||||
|
||||
switch (mem_commandset) {
|
||||
|
||||
case COMMAND_SET_VIRTUALMACHINE:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_virtualmachine, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_REFERENCETYPE:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_referencetype, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_CLASSTYPE:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_classtype, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_ARRAYTYPE:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_arraytype, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_INTERFACETYPE:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_interfacetype, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_METHOD:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_method, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_FIELD:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_field, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_OBJECTREFERENCE:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_objectreference, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_STRINGREFERENCE:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_stringreference, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_THREADREFERENCE:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_threadreference, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_THREADGROUPREFERENCE:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_threadgroupreference, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_ARRAYREFERENCE:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_arrayreference, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_CLASSLOADERREFERENCE:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_classloaderreference, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_EVENTREQUEST:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_eventrequest, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_STACKFRAME:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_stackframe, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_CLASSOBJECTREFERENCE:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_classobjectreference, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
case COMMAND_SET_EVENT:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_event, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_virtualmachine, tvb, offset, 1, ENC_BIG_ENDIAN);
|
||||
offset += 1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* command comes with data when the minimal length is 12 */
|
||||
if (hlen > 11) {
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_data, tvb, offset, hlen - 11, ENC_NA);
|
||||
} else if (hlen < 11) {
|
||||
expert_add_info(pinfo, hlen_item, &ei_jdwp_hlen_invalid);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PACKET_TYPE_REPLY:
|
||||
proto_tree_add_item_ret_uint(jdwp_tree, hf_jdwp_errorcode, tvb, offset, 2, ENC_BIG_ENDIAN, &mem_errorcode);
|
||||
offset += 2;
|
||||
|
||||
if(mem_errorcode == 0) {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "Reply (Success)");
|
||||
} else {
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "Reply (Failure)");
|
||||
}
|
||||
|
||||
/* reply comes with data when the minimal length is 12 */
|
||||
if (hlen > 11) {
|
||||
proto_tree_add_item(jdwp_tree, hf_jdwp_data, tvb, offset, hlen - 11, ENC_NA);
|
||||
} else if (hlen < 11) {
|
||||
expert_add_info(pinfo, hlen_item, &ei_jdwp_hlen_invalid);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
expert_add_info(pinfo, flags_item, &ei_jdwp_flags_invalid);
|
||||
break;
|
||||
}
|
||||
|
||||
return tvb_captured_length(tvb);
|
||||
}
|
||||
|
||||
static int
|
||||
dissect_jdwp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
||||
{
|
||||
tcp_dissect_pdus(tvb, pinfo, tree, TRUE, FRAME_HEADER_LEN,
|
||||
get_jdwp_message_len, dissect_jdwp_message, data);
|
||||
return tvb_captured_length(tvb);
|
||||
}
|
||||
|
||||
void
|
||||
proto_register_jdwp(void)
|
||||
{
|
||||
|
||||
expert_module_t* expert_jdwp;
|
||||
|
||||
static hf_register_info hf[] = {
|
||||
{ &hf_jdwp_type,
|
||||
{ "Packet Type", "jdwp.type", FT_STRING, BASE_NONE, NULL, 0x0, "Type",
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_length,
|
||||
{ "Length", "jdwp.length", FT_UINT32, BASE_DEC, NULL, 0x0, "Data Length",
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_id,
|
||||
{ "id", "jdwp.id", FT_UINT32, BASE_DEC, NULL, 0x0, "unique identifier",
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_flags,
|
||||
{ "flags", "jdwp.flags", FT_UINT8, BASE_HEX, NULL, 0x0, "tag packets as a command or reply",
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset,
|
||||
{ "command set", "jdwp.commandset", FT_UINT8, BASE_DEC, VALS(commandsetnames), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_virtualmachine,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_virtualmachine), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_referencetype,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_referencetype), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_classtype,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_classtype), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_arraytype,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_arraytype), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_interfacetype,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_interfacetype), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_method,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_method), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_field,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_field), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_objectreference,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_objectreference), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_stringreference,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_stringreference), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_threadreference,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_threadreference), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_threadgroupreference,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_threadgroupreference), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_arrayreference,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_arrayreference), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_classloaderreference,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_classloaderreference), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_eventrequest,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_eventrequest), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_stackframe,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_stackframe), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_classobjectreference,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_classobjectreference), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_commandset_event,
|
||||
{ "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_event), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_errorcode,
|
||||
{ "error code", "jdwp.errorcode", FT_UINT8, BASE_DEC, VALS(error_codes), 0x0, NULL,
|
||||
HFILL }
|
||||
},
|
||||
{ &hf_jdwp_data,
|
||||
{ "data", "jdwp.data", FT_BYTES, BASE_NONE, NULL, 0x0, "details of the command or reply",
|
||||
HFILL }
|
||||
}
|
||||
};
|
||||
|
||||
static ei_register_info ei[] = {
|
||||
{ &ei_jdwp_hlen_invalid, { "jdwp.hlen.invalid", PI_MALFORMED, PI_ERROR, "Decode aborted: invalid packet length", EXPFILL }},
|
||||
{ &ei_jdwp_flags_invalid, { "jdwp.flags.invalid", PI_MALFORMED, PI_ERROR, "Decode aborted: invalid flags value", EXPFILL }}
|
||||
};
|
||||
|
||||
static gint *ett[] = {
|
||||
&ett_jdwp
|
||||
};
|
||||
|
||||
proto_jdwp = proto_register_protocol("Java Debug Wire Protocol", "JDWP", "jdwp");
|
||||
proto_register_field_array(proto_jdwp, hf, array_length(hf));
|
||||
proto_register_subtree_array(ett, array_length(ett));
|
||||
expert_jdwp = expert_register_protocol(proto_jdwp);
|
||||
expert_register_field_array(expert_jdwp, ei, array_length(ei));
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
proto_reg_handoff_jdwp(void)
|
||||
{
|
||||
dissector_handle_t jdwp_handle;
|
||||
|
||||
jdwp_handle = create_dissector_handle(dissect_jdwp, proto_jdwp);
|
||||
dissector_add_uint_with_preference("tcp.port", JDWP_PORT, jdwp_handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
* Local variables:
|
||||
* c-basic-offset: 2
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* vi: set shiftwidth=2 tabstop=8 expandtab:
|
||||
* :indentSize=2:tabSize=8:noTabs=true:
|
||||
*/
|
Loading…
Reference in New Issue