I developed a custom wireshark dissector plugin on linux debian on wireshark 4.2.5 (also working on 4.2.6) which is working completely fine. However, when I try to use the source code from this plugin and do a custom build on Windows 11 wireshark 4.3.0 (following the documentation instructions to build from VS Code), I get the following error:
The file exists at the above file path, so I'm not sure why it can't load it. For reference, I changed the top-level CMakeLists.txt and custom_plugins.txt files in accordance with the README.plugins. I also changed plugins.wxi, adding my custom plugin after the comments. Any help would be greatly appreciated!
/* packet-wibotic.c
*
* Routines for WiBotic protocol packet dissection
* By Tong Lin <[email protected]>
*
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <[email protected]>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
*
*/
#ifdef __linux__
#define _GNU_SOURCE
#include <dlfcn.h>
#elif _WIN32
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#endif
#include "config.h"
#include <epan packet.h="">
#include <epan tvbuff-int.h="">
#define PY_SSIZE_T_CLEAN
#include <python.h>
void proto_register_wibotic(void);
void proto_reg_handoff_wibotic(void);
#define WIBOTIC_WEBSOCKET_PORT 80
static int proto_wibotic;
static dissector_handle_t wibotic_handle;
proto_item* pi;
static int ett_wibotic = -1;
static int ett_adc = -1;
static int ett_adc_field = -1;
static int hf_packet_type = -1;
static int hf_device_id = -1;
static int hf_adc_data = -1;
static int hf_sub_adc_data = -1;
static int hf_adc_id = -1;
static int hf_adc_value = -1;
static int hf_param_id = -1;
static int hf_value = -1;
static int hf_status = -1;
static int hf_location = -1;
static int hf_data = -1;
static int hf_devices = -1;
static int hf_level = -1;
static int hf_code = -1;
static int hf_message = -1;
static int hf_ext_param_id = -1;
static int hf_rssi = -1;
static int hf_mac_address = -1;
static int hf_completion = -1;
static int hf_state = -1;
static int hf_dest_id = -1;
static int hf_topic = -1;
typedef struct {
char* field_name;
int* field_var;
} hf_field;
hf_field hf_fields[] = {
{"packet", &hf_packet_type},
{"device", &hf_device_id},
{"values", &hf_adc_data},
{"param", &hf_param_id},
{"value", &hf_value},
{"status", &hf_status},
{"location", &hf_location},
{"data", &hf_data},
{"devices", &hf_devices},
{"level", &hf_level},
{"code", &hf_code},
{"message", &hf_message},
{"ext_id", &hf_ext_param_id},
{"rssi", &hf_rssi},
{"mac", &hf_mac_address},
{"completion", &hf_completion},
{"state", &hf_state},
{"dest", &hf_dest_id},
{"topic", &hf_topic}
};
int lookup_correct_field(char* field_name) {
for (int i = 0; i < (int) array_length(hf_fields); i++) {
if (strcmp(hf_fields[i].field_name, field_name) == 0) {
return *hf_fields[i].field_var;
}
}
return 0;
}
void add_items_to_tree(proto_tree* tree, char** hf_field_list, tvbuff_t *tvb, char* struct_format, long encoding, char** attribute_names) {
guint offset = 1;
for (int i = 0; i < (int) strlen(struct_format); i++) {
switch(struct_format[i]) {
case 'B':
pi = proto_tree_add_item(tree, lookup_correct_field(hf_field_list[i]), tvb, offset, 1, encoding);
offset++;
break;
case 'H':
pi = proto_tree_add_item(tree, lookup_correct_field(hf_field_list[i]), tvb, offset, 2, encoding);
offset+=2;
break;
case 'L':
pi = proto_tree_add_item(tree, lookup_correct_field(hf_field_list[i]), tvb, offset, 4, encoding);
offset+=4;
break;
default: //assuming 1 char number
int num = struct_format[i] - '0';
pi = proto_tree_add_item(tree, lookup_correct_field(hf_field_list[i]), tvb, offset, num, encoding);
offset+=2;
break;
}
proto_item_append_text(pi, " %s", attribute_names[i]);
}
if (tvb_captured_length(tvb) > offset) {
if (tvb_get_guint8(tvb, 0) == 0x82) { //hardcoded id to explicitly check for ADC update
proto_item *adc = proto_tree_add_item(tree, hf_adc_data, tvb, offset, -1, encoding);
proto_tree *adc_tree = proto_item_add_subtree(adc, ett_adc);
int num_values = (tvb_captured_length(tvb) - 2)/6;
for (int i = 0; i < 2*num_values; i+=2) {
proto_item *adc_val = proto_tree_add_item(adc_tree, hf_sub_adc_data, tvb, offset, 6, encoding);
proto_item_append_text(adc_val, " %s", attribute_names[i + strlen(struct_format)]);
proto_tree *adc_subtree = proto_item_add_subtree(adc_val, ett_adc_field);
pi = proto_tree_add_item(adc_subtree, hf_adc_id, tvb, offset, 2, encoding);
offset+=2;
pi = proto_tree_add_item(adc_subtree, hf_adc_value, tvb, offset, 4, encoding);
proto_item_append_text(pi, " %s", attribute_names[i + strlen(struct_format) + 1]);
offset+=4;
}
} else {
proto_tree_add_item(tree, hf_data, tvb, offset, -1, encoding);
}
}
}
static int
dissect_wibotic(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data _U_)
{
col_set_str(pinfo->cinfo, COL_PROTOCOL, "WiBotic"); //set protocol column to recognize Wibotic
col_clear(pinfo->cinfo,COL_INFO);
proto_item* ti = proto_tree_add_item(tree, proto_wibotic, tvb, 0, -1, ENC_NA);
proto_tree *wibotic_tree = proto_item_add_subtree(ti, ett_wibotic);
//load in the file with the python methods
PyObject* pName = PyUnicode_DecodeFSDefault("tvbparser");
PyObject* pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
PyObject* pFuncPacketType = PyObject_GetAttrString(pModule, "get_packet_type");
if (pFuncPacketType && PyCallable_Check(pFuncPacketType)) {
PyObject* pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, PyBytes_FromStringAndSize(tvb->real_data, tvb_captured_length(tvb)));
PyObject* pValue = PyObject_CallObject(pFuncPacketType, pArgs);
if (pValue == NULL) {
Py_DECREF(pFuncPacketType);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call #1 failed\n");
return 1;
}
Py_DECREF(pFuncPacketType);
//add type of update to column list
PyObject* pPacketType = PyUnicode_AsUTF8String(pValue);
char* packetType = strdup(PyBytes_AsString(pPacketType));
col_add_fstr(pinfo->cinfo, COL_INFO, "Type %s", packetType);
Py_DECREF(pValue);
Py_DECREF(pPacketType);
//add list of values to prototree
//get endianness
PyObject* pFuncEndian = PyObject_GetAttrString(pModule, "get_packet_endianness");
if (pFuncEndian && PyCallable_Check(pFuncEndian)) {
PyObject* pValue2 = PyObject_CallObject(pFuncEndian, pArgs);
long endianness = PyLong_AsLong(pValue2);
if (pValue2 == NULL || endianness == 1) {
Py_DECREF(pFuncEndian);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call #2 failed\n");
return 1;
}
Py_DECREF(pFuncEndian);
Py_DECREF(pValue2);
//get struct format, array of string names of fields and parse
PyObject* pFuncStructFormat = PyObject_GetAttrString(pModule, "get_struct_format");
if (pFuncStructFormat && PyCallable_Check(pFuncStructFormat)) {
PyObject* pValue3 = PyObject_CallObject(pFuncStructFormat, pArgs);
if (pValue3 == NULL) {
Py_DECREF(pFuncStructFormat);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call #3 failed\n");
return 1;
}
Py_DECREF(pFuncStructFormat);
//get struct_format
PyObject* pStructFormat = PyUnicode_AsUTF8String(pValue3);
char* structFormat = strdup(PyBytes_AsString(pStructFormat));
Py_DECREF(pValue3);
Py_DECREF(pStructFormat);
PyObject* pFuncFieldList = PyObject_GetAttrString(pModule, "get_packet_field_list");
if (pFuncFieldList && PyCallable_Check(pFuncFieldList)) {
PyObject* pValue4 = PyObject_CallObject(pFuncFieldList, pArgs);
if (pValue4 == NULL) {
Py_DECREF(pFuncFieldList);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call #4 failed\n");
return 1;
}
Py_DECREF(pFuncFieldList);
//parse fields list
int listSize = PyList_Size(pValue4);
if (listSize != -1) {
char** hf_field_names = (char**) malloc(listSize * sizeof(char*));
if (hf_field_names == NULL) {
fprintf(stderr, "hf_field_names malloc failed");
return 1;
}
for (int i = 0; i < listSize; i++) {
PyObject* pItem = PyList_GetItem(pValue4, i);
PyObject* pFieldName = PyUnicode_AsUTF8String(pItem);
char* fieldName = strdup(PyBytes_AsString(pFieldName));
hf_field_names[i] = fieldName;
}
PyObject* pFuncAttributes = PyObject_GetAttrString(pModule, "get_attributes_list");
if (pFuncAttributes && PyCallable_Check(pFuncAttributes)) {
PyObject* pValue5 = PyObject_CallObject(pFuncAttributes, pArgs);
if (pValue5 == NULL) {
Py_DECREF(pFuncAttributes);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call #5 failed\n");
return 1;
}
Py_DECREF(pFuncAttributes);
int listSize2 = PyList_Size(pValue5);
if (listSize2 != -1) {
char** attribute_names = (char**) malloc(listSize2 * sizeof(char*));
if (attribute_names == NULL) {
fprintf(stderr, "attribute_names malloc failed");
return 1;
}
for (int i = 0; i < listSize2; i++) {
PyObject* pItem2 = PyList_GetItem(pValue5, i);
PyObject* pAttributeName = PyUnicode_AsUTF8String(pItem2);
char* attributeName = strdup(PyBytes_AsString(pAttributeName));
attribute_names[i] = attributeName;
}
//adds packet type to UI
pi = proto_tree_add_item(wibotic_tree, hf_packet_type, tvb, 0, 1, endianness);
proto_item_append_text(pi, " %s", packetType);
//ignores first 2 characters of the struct format (endianness and packet)
add_items_to_tree(wibotic_tree, hf_field_names, tvb, structFormat + 2, endianness, attribute_names);
free(hf_field_names);
free(attribute_names);
Py_DECREF(pValue4);
Py_DECREF(pArgs);
Py_DECREF(pModule);
}
} else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"get_struct_format\"\n");
}
} else {
fprintf(stderr, "Cannot find list of header field values\n");
}
} else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"get_struct_format\"\n");
}
} else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"get_struct_format\"\n");
}
} else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"get_packet_endianness\"\n");
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"get_packet_type\"\n");
}
} else {
PyErr_Print();
printf("Failed to load tvb-parser");
}
return tvb_captured_length(tvb);
}
void
proto_register_wibotic(void)
{
static hf_register_info hf[] = { //add all fields...
{&hf_packet_type,
{ "Packet Type", "wibotic.packettype",
FT_UINT8, BASE_HEX,
NULL, 0x0,
NULL, HFILL}
},
{ &hf_device_id,
{ "Device ID", "wibotic.deviceid",
FT_UINT8, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_adc_data,
{ "ADC Data", "wibotic.adcdata",
FT_NONE, BASE_NONE,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_sub_adc_data,
{ "ADC Data Field", "wibotic.adcdatafield",
FT_NONE, BASE_NONE,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_adc_id,
{ "ADC Field ID", "wibotic.adcid",
FT_UINT16, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_adc_value,
{ "ADC Field Value", "wibotic.adcvalue",
FT_NONE, BASE_NONE,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_param_id,
{ "Parameter ID", "wibotic.parameterid",
FT_UINT32, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_value,
{ "Value", "wibotic.value",
FT_UINT32, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_status,
{ "Status", "wibotic.status",
FT_UINT8, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_location,
{ "Location", "wibotic.location",
FT_UINT8, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_data,
{ "Data", "wibotic.data",
FT_NONE, BASE_NONE,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_devices,
{ "Connected Devices", "wibotic.devices",
FT_UINT16, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_level,
{ "Severity Level", "wibotic.level",
FT_UINT8, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_code,
{ "Code", "wibotic.code",
FT_STRING, BASE_NONE,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_message,
{ "Message", "wibotic.message",
FT_NONE, BASE_NONE,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_ext_param_id,
{ "Ext Param ID", "wibotic.extparamid",
FT_UINT16, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_rssi,
{ "RSSI", "wibotic.rssi",
FT_UINT8, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_mac_address,
{ "MAC", "wibotic.MAC",
FT_UINT48, BASE_HEX,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_completion,
{ "Completion", "wibotic.completion",
FT_UINT8, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_state,
{ "State", "wibotic.state",
FT_UINT8, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_dest_id,
{ "Destination ID", "wibotic.dest",
FT_UINT8, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
},
{ &hf_topic,
{ "Topic ID", "wibotic.topicid",
FT_UINT8, BASE_DEC,
NULL, 0x0,
NULL, HFILL }
}
};
static int *ett[] = {
&ett_wibotic,
&ett_adc,
&ett_adc_field
};
proto_wibotic = proto_register_protocol (
"WiBotic Protocol ", /* name */
"WiBotic", /* short name */
"wibotic" /* filter_name */
);
proto_register_field_array(proto_wibotic, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
register_postdissector(wibotic_handle);
}
void
proto_reg_handoff_wibotic(void)
{
wibotic_handle = create_dissector_handle(dissect_wibotic, proto_wibotic);
dissector_add_string("ws.protocol", "wibotic", wibotic_handle);
Py_Initialize();
char filePath[100];
#ifdef _WIN32
GetFullPathNameA("tvbparser.py", sizeof(filePath), filePath, NULL);
#elif __linux__
Dl_info info;
dladdr((void*) proto_reg_handoff_wibotic, &info);
strcpy(filePath, info.dli_fname);
int len = strlen(filePath);
filePath[len-10] = '\0';
strncat(filePath, "python-scripts", 23);
#endif
char cmd[300];
snprintf(cmd, sizeof(cmd), "import sys\nsys.path.append(\"%s\")", filePath);
PyRun_SimpleString(cmd);
}