Визуализация сообщений модема Sierra MC7710 для программы WireShark
КУРСОВАЯ РАБОТА
Визуализация сообщений модема Sierra
MC7710 для программы WireShark
МОСКВА 2013
ОГЛАВЛЕНИЕ
ВВЕДЕНИЕ
ГЛАВА 1. Методы разработки и
подключения программно подключаемых модулей сетевого анализатора wireshark
.1 Графический интерфейс
программного продукта WireShark
.2 Правила разработки
программно подключаемых модулей WireShark
.3 Правила использования
программно подключаемых модулей WireShark
Выводы по главе 1
ГЛАВА 2. Программное
обеспечение визуализации сообщений модема sierra mc7710
.1 Интерфейс программного
модуля СПО QXDM Professional
.2 Программное обеспечение,
реализующее визуализацию сообщений модема Sierra MC7710
.3 Программное обеспечение,
реализующее визуализацию сообщений модема Sierra MC7710 для программы WireShark
.4 Тестирование разработанной
программы isfreader
Выводы по главе 2
Заключение
ЛИТЕРАТУРА
Приложение 1
ВВЕДЕНИЕ
Цель настоящей работы - исследование возможности создания программно
подключаемого модуля для программы WireShark, реализующего визуализацию
сообщений модема Sierra MC7710
Задачами данной курсовой работы являются:
- практическое освоение правил разработки и подключения
программных модулей WireShark;
- изучение интерфейса программного модуля СПО QXDM
Professional;
- разработка программы, реализующего визуализацию сообщений
модема Sierra MC7710, включая отображение специальной информации, полученной
после обработки сообщений программным модулем СПО QXDM Professional;
- исследование возможности интеграции разработанной программы в
виде программного модуля WireShark.
Курсовая работа состоит из двух глав. В первой главе рассмотрены принципы
разработки и использования программно подключаемых модулей WireShark на примере
тестовой программы.
Во второй главе описана разработка программы с возможностью отображения
сообщений модема Sierra MC7710 в шестнадцатеричном формате и специальной
информации, полученной после обработки сообщений программным модулем СПО QXDM
Professional. Так же описано исследование возможности интеграции разработанной
программы в качестве программно подключаемого модуля WireShark.
ГЛАВА 1. Методы разработки и подключения программно подключаемых модулей
сетевого анализатора wireshark
1.1 Графический интерфейс программного продукта WireShark
Программный продукт Wireshark представляет собой анализатор сетевых
протоколов с графическим интерфейсом. Программа позволяет просматривать и
анализировать пакеты, полученные из сетевого интерфейса или ранее собранного
файла.
Для начала сборки перехваченных программой пакетов сообщений по сети,
необходимо выбрать пункт главного меню Capture>Interfaces или кнопку на
верхней панели инструментов List the available capture interfaces - после этого
на экране появится следующее диалоговое окно:
<#"650906.files/image002.gif"> <#"650906.files/image003.gif"> <#"650906.files/image004.gif"> <#"650906.files/image005.gif">
Рис. 1.5. График сбора пакетов
1.2 Правила разработки программно подключаемых модулей WireShark
В качестве примера программно подключаемого модуля для программного
продукта WireShark приведен пример диссектора для протокола foo.
Структура пакета протокола foo:
- 1 байт - версия протокола;
- 1 байт - тип пакета;
- 1 байт - всевозможные флаги;
- 1 байт - булева переменная;
- 4 байт - длина полезной нагрузки;
- От 0 до 200 байт - полезная нагрузка.
Рассмотрим реализацию диссектора на языке C++. Все диссекторы сетевого
анализатора WireShark используют стандартные заголовочные файлы, такие как
config.h, glib.h, и packet.h.
Листинг
1.1
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <epan/packet.h>
#define FOO_PORT 35000
//Номер UDP порта, на котором предполагаем будет находится FOO
траффик.int proto_foo = -1;
/* При регистрации протокола переменная затрется идентификатором
протокола. */proto_register_foo(void)
{_foo = proto_register_protocol (
"FOO Protocol", /* полное имя */
"FOO", /* короткое имя */
"foo" /* аббревиатура */
);
}
Функция proto_register_protocol() регистрирует протокол и выдает его
уникальный идентификатор. Функции передается три разных имени протокола,
которые будут отображены в различных частях программы. (К примеру, имена «FOO
Protocol» и «FOO» используются в настройках программного продукта Wireshark, а
аббревиатура «foo» используется в поле фильтра.)
Функция create_dissector_handle() будет вызываться в случае необходимости
расшифровать пойманный foo-пакет.
Листинг
1.2
proto_reg_handoff_foo(void)
{dissector_handle_t foo_handle;_handle =
create_dissector_handle(dissect_foo, proto_foo);_add_uint("udp.port",
FOO_PORT, foo_handle);
}
В данной части кода регистрируется обработчик-диссектор, который
выполняет работу по разложению протокола по составу и привязываем его к
протоколу proto_foo. Затем нужно связать обработчик с UDP портом, на котором
будет ходить трафик. Таким образом, сетевой анализатор Wireshark вызовет
соответствующую функцию, когда на заданном порту (35000) появится какая-либо
активность. Есть соглашение, согласно которому фукнции proto_register_foo() и
proto_reg_handoff_foo() необходио написать в конце нашего исходного файла.
Листинг
1.3
void dissect_foo(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree)
{_set_str(pinfo->cinfo, COL_PROTOCOL,
"FOO");_clear(pinfo->cinfo, COL_INFO);
}
Функция dissect_foo() будет вызываться для детальной работы над пакетом,
который ей передан. Данные пакета хранятся в специальном буфере - tvb. В pinfo
находится общая информация о протоколе. А в переменной tree происходят основные
изменения, когда определяется конечный вид протокола на выходе. Данного кода
достаточно, чтобы программный продукт WireShark подхватил программно
подключаемый модуль.
Программно подключаемый модуль пока что не несет функциональной нагрузки,
поэтому его необходимо дополнить. Для начала нужно создать ветку на дереве
(tree), в которую будут помещены результаты декодирования. Диссектор вызывается
в двух различных случаях: в одном случае, когда необходимо получить сводную
информацию о пакете, и в другом случае, когда нужно вывести детальную
информацию о том же пакете. Если указатель на tree равен NULL, значит нужна
только сводная информация. Иначе - нужно заполнить tree детальной информацией,
которая будет выведена пользователю. С учетом этого диссектор приобретает вид:
Листинг 1.4
static void dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{_set_str(pinfo->cinfo, COL_PROTOCOL,
"FOO");_clear(pinfo->cinfo, COL_INFO);(tree)
{_item *ti = NULL;= proto_tree_add_item(tree, proto_foo, tvb,
0, -1, FALSE);
}
}
В данном случае добавлена ветка в дерево (tree) вызовом
proto_tree_add_item(). Эта ветка будет содержать все детали о foo протоколе.
Так же необходимо пометить область данных в пакете, которую использует
протокол. В данном случае - это вся область за границей данных UDP пакета.
Параметры функции proto_tree_add_item():
- tree - все дерево информации о пакете;
- proto_foo - идентификатор протокола;
- tvb - блок данных (данные, переданные протоколом);
- 0 - начиная с какой позиции данные в блоке tvb являются
данными foo протокола;
- -1 - количество байт, занимаемое протоколом («-1» означает
«до конца блока данных»);
- FALSE - указывается порядок байт (TRUE - если байты
расположены в сетевом порядке).
После этих изменений программный продукт Wireshark начнет определять, где
начинается и кончается область протокола и помечает ее как «FOO Protocol».
Следующим шагом будет добавление деталей. Для этого шага потребуется
создание нескольких массивов и дополнительных вызовов функций, которые помогут
при расшифровке. Изменения коснутся тела функции proto_register_foo(),
показанной ранее. Нужно добавить два статических массива в начало
proto_register_foo(). Затем необходимо зарегистрировать массивы после вызова
функции proto_register_protocol().
Листинг
1.5
proto_register_foo(void)
{hf_register_info hf[] = {
{ &hf_foo_hdr_version,
{ "FOO Header Version",
"foo.hdr.version",_UINT8, BASE_DEC,, 0x0,, HFILL }
},
{ &hf_foo_hdr_type,
{ "FOO Header Type",
"foo.hdr.type",_UINT8, BASE_DEC,, 0x0,, HFILL }
}
};gint *ett[] = { &ett_foo };_foo =
proto_register_protocol (
"FOO Protocol",
"FOO",
"foo" );_register_field_array(proto_foo, hf,
array_length(hf));_register_subtree_array(ett, array_length(ett));
}
Для детализации отображения протокола потребуется:
Листинг
1.6
(tree)
{_item *ti = NULL;_tree *foo_tree = NULL;=
proto_tree_add_item(tree, proto_foo, tvb, 0, -1, FALSE);_tree = proto_item_add_subtree(ti,
ett_foo);_tree_add_item(foo_tree, hf_foo_hdr_version, tvb, 0, 1,
FALSE);_tree_add_item(foo_tree, hf_foo_hdr_type, tvb, 1, 1, FALSE);
}
На данный момент будут распознаны лишь первые 2 байта foo протокола,
которые отвечают за версию протокола и тип пакета. Вызов функции
proto_item_add_subtree() добавит ветвь (foo_tree) с деталями о foo протоколе в
дерево (tree) информации обо всем пришедшем пакете. В foo_tree будет детально
описан наш протокол.
Переменной ett_foo контролируется «развертка» дерева информации о
протоколе в выводе программы Wireshark.
Функция proto_tree_add_item() на этот раз использует переменную
hf_foo_hdr_version для вывода значения в нужном формате. hdr_version - 1 байт
из tvb, начиная с позиции 0. hdr_type - 1 байт из tvb, начиная с позиции 1.
Рассмотрим объявление hf_foo_hdr_version в статическом массиве, здесь
находится детально описанное поле:
- hf_foo_hdr_version - индекс ветки;
- FOO Header Version - именование поля;
- foo.hdr.version - это строчка, используемая для фильтрации
пакетов (такой вид строчки будет в поле фильтра);
- FT_UNIT8 - указывает на тип и размер элемента, который
считывается из блока данных tvb. В данном случае указывает, что поле «версия
протокола» занимает 1 байт типа unsigned integer. (Другие возможные типы можно
найти в файле wireshark/epan/ftypes/ftypes.h);
- BASE_DEC - для числовых типов указывает, в какой системе
выводить числа. (Также может быть BASE_HEX или BASE_OCT. Для нечисловых типов
используем BASE_NONE).
Необходимо объявить еще несколько переменных и детализировать вывод.
Листинг
1.7
...int hf_foo_hdr_flags = -1;int hf_foo_hdr_bool = -1;int
hf_foo_pl_len = -1;int hf_foo_payload = -1;
...proto_register_foo(void)
{
{ &hf_foo_hdr_flags,
{ "FOO Header Flags",
"foo.hdr.flags",_UINT8, BASE_HEX,, 0x0,, HFILL }
},
{ &hf_foo_hdr_bool,
{ "FOO Header Boolean",
"foo.hdr.bool",_BOOLEAN, BASE_NONE,, 0x0,, HFILL
}
},
{ &hf_foo_pl_len,
{ "FOO Payload Length",
"foo.pl_len",_UINT8, BASE_DEC,, 0x0,, HFILL
}
},
{ &hf_foo_payload,
{ "FOO Payload", "foo.payload",_STRING,
BASE_NONE,, 0x0,, HFILL
}
}
}
void dissect_foo(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree)
{
...(tree)
{offset = 0;_item *ti = NULL;_tree *foo_tree = NULL;=
proto_tree_add_item(tree, proto_foo, tvb, 0, -1, FALSE);_tree =
proto_item_add_subtree(ti, ett_foo);_tree_add_item(foo_tree,
hf_foo_hdr_version, tvb, offset, 1, FALSE); offset +=
1;_tree_add_item(foo_tree, hf_foo_hdr_type, tvb, offset, 1, FALSE); offset +=
1;_tree_add_item(foo_tree, hf_foo_hdr_flags, tvb, offset, 1, FALSE); offset +=
1;_tree_add_item(foo_tree, hf_foo_hdr_bool, tvb, offset, 1, FALSE); offset +=
1;_tree_add_item(foo_tree, hf_foo_pl_len, tvb, offset, 4, TRUE); offset +=
4;_tree_add_item(foo_tree, hf_foo_payload, tvb, offset, -1, FALSE);
}
}
Таким образом, расшифрованы все биты протокола. Теперь сетевой анализатор
Wireshark имеет достаточно хорошее представление о протоколе. Но необходимо
описать обработку поля flags, которое нужно раскладывать побитно вручную. А
также, в случае, если версия протокола неизвестна, можно ли доверять выводу.
Диссектор будет генерировать исключение, если пакет придет без поля payload и с
нулевым значением pl_len.
Далее нужно определить обработку именования версии и типа пришедшего
пакета, что позволит гораздо быстрее воспринимать информацию при просмотре
пакета. Для этого нужны два массива.
Листинг
1.8
const value_string packetversions[] = {
{ 1, "Version 1" },
{ 0, NULL }
};const value_string packettypes[] = {
{ 1, "Ping request" },
{ 2, "Ping acknowledgment" },
{ 3, "Print payload" },
{ 0, NULL }
};
Зависимость в массивах - «значение, имя значения». Таким образом, при
просмотре пакета можно видеть не голый номер типа пакета, а сразу описание
типа. Для доступа к этим массивам будут задействованы VALS-макросы, которые
предоставляются самим программным продуктом Wireshark.
Листинг
1.9
{ &hf_foo_hdr_version,
{ "FOO Header Version",
"foo.hdr.version",_UINT8, BASE_DEC,(packetversions), 0x0,, HFILL }
},
{ &hf_foo_hdr_type,
{
"FOO Header Type", "foo.hdr.type",_UINT8,
BASE_DEC,(packettypes), 0x0,, HFILL
}
}
Теперь необходимо осуществить корректную обработку флагов поступившего
пакета.
Листинг
1.10
#define FOO_FIRST_FLAG 0x01
#define FOO_SECOND_FLAG 0x02
#define FOO_ONEMORE_FLAG 0x04int hf_foo_flags_first = -1;int
hf_foo_flags_second = -1;int hf_foo_flags_onemore = -1;proto_register_foo(void)
{
...
{ &hf_foo_flags_first,
{ "FOO first flag",
"foo.hdr.flags.first",_BOOLEAN, FT_INT8,, FOO_FIRST_FLAG,, HFILL }
},
{ &hf_foo_flags_second,
{ "FOO second flag",
"foo.hdr.flags.second",_BOOLEAN, FT_INT8,, FOO_SECOND_FLAG,, HFILL }
},
{ &hf_foo_flags_onemore,
{ "FOO onemore flag",
"foo.hdr.flags.onemore",_BOOLEAN, FT_INT8,, FOO_ONEMORE_FLAG,, HFILL
}
}
...
}
void dissect_foo(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree) {
..._tree_add_item(foo_tree, hf_foo_hdr_flags, tvb, offset, 1,
FALSE);_tree_add_item(foo_tree, hf_foo_flags_first, tvb, offset, 1,
FALSE);_tree_add_item(foo_tree, hf_foo_flags_second, tvb, offset, 1,
FALSE);_tree_add_item(foo_tree, hf_foo_flags_onemore, tvb, offset, 1, FALSE);
offset += 1;
}
Так как флаг - это один бит информации со значениями «1» или «0», то
используется тип FT_BOOLEAN. Также задана маска для каждого флага шестым
параметром (FOO_FIRST_FLAG, FOO_SECOND_FLAG, FOO_ONEMORE_FLAG), чтобы
определить, какой бит из байта интерпретировать.
.3. Правила использования программно подключаемых модулей WireShark
Перед тем как начать писать программно подключаемый модуль, необходимо
произвести настройку среды разработки программно подключаемого модуля.
Установка дополнительных программных компонентов.
1. Установка программного продукта Visual C++.
2. Установка ПО Platform SDK Server 2003 R2.
3. Установка
ПО Cygwin. Cygwin - UNIX-подобная
<#"650906.files/image006.gif">
Рис. 2.1. Интерфейс СПО QXDM Professional
СПО QXDM Professional позволяет сохранять сообщения, полученные от
устройства в отдельный файл, с которым в дальнейшем можно работать при помощи
специальных СОМ интерфейсов, предоставляемых СПО QXDM Professional.
Рис. 2.2. Рабочая область СПО QXDM Professional
Сообщение полученное от устройства разбивается на составляющие: Type - тип сообщения, Name - имя
сообщения, Timestamp - временная метка пришедшего
сообщения, Summary - содержание сообщения.
Так же СПО QXDM Professional предоставляет возможность просмотреть
полученное сообщение в шестнадцатеричном формате.
Рис. 2.3. Сообщение в шестнадцатеричном формате
СПО QXDM Professional предоставляет COM интерфейсы для работы с файлами,
хранящие элементы (item). COM-интерфейсы грубо можно разделить на пять модулей.
Модуль QXDM - автоматизация QXDM COM-интерфейса, который существовал и
поставляется в QXDM до версии 03.05.50. Предполагается, что поддержка некоторых
из интерфейсов будет осуществляться в течение долгого времени.
Модуль Client - предоставляет средства для объединения QXDM элементов
(данные, полученные от устройства и внутренние данные, обработанные QXDM) в
специальные структуры, также обеспечивает прямой доступ к QXDM элементам.
Модуль Client Config - предоставляет средства для настройки элементов
конкретных типов, т.е. клиент определяет форму представления элементов.
Модуль Item - интерфейс к конкретному объекту, управляемый QXDM.
Модуль Field - предоставляет доступ к базе данных QXDM, анализирует поля
определенного элемента.
Таблица 2.1
COM
интерфейс программы QXDM Professional
№ пп.
|
Название
|
Типы аргументов
|
Описание
|
1
|
2
|
3
|
4
|
1.
|
LoadItemStore()
|
BSTR
|
Позволяет загрузить
хранилище элементов, находящихся в файле с расширением isf
|
2.
|
GetItemCount()
|
ULONG
|
Получает количество
элементов в файле
|
3.
|
GetItem()
|
ULONG
|
Получает текущий элемент
|
4.
|
GetItemTimestampText()
|
VARIANT_BOOL
|
Получает временную метку
текущего элемента
|
5.
|
GetItemTypeText()
|
|
Функция позволяет получить
тип элемента.
|
6.
|
GetItemKeyText ()
|
|
Функция позволяет извлечь
ключ элемента.
|
7.
|
GetItemName ()
|
|
Функция позволяет получить
имя элемента. Функция не имеет аргументов и возвращает значение BSTR
|
8.
|
GetItemNameSummary()
|
|
Функция позволяет извлечь
краткое описание элемента. Функция не принимает аргументов и возвращает
значение BSTR.
|
9.
|
GetItemParsedText ()
|
|
Функция позволяет извлечь
обработанный текст элемента. Функция не принимает аргументов и возвращает
значение BSTR
|
10.
|
GetItemBuffer ()
|
VARIANT_BOOL
|
Функция позволяет получить
буфер текущего элемента.
|
.2 Программное обеспечение, реализующее визуализацию сообщений модема Sierra MC7710
СПО QXDM сообщения модема Sierra MC7710 сохраняет в
файл с расширением .isf. Для обработки файла СПО QXDM предоставляется COM
интерфейс реализованный в виде библиотеки CoreAutomation.dll.
Программа isfreader представленная в приложении 1 позволяет обрабатывать
файлы с расширением isf и извлекать сообщения полученные от модема Sierra MC7710.
Программа isfreader загружает файл с сообщениями с помощью функции
LoadItemStore(). Затем в цикле программа получает описатель элемента
содержащего сообщение и дополнительную информацию с помощью функции GetItem().
Из описателя элемента извлекаются поля сообщения посредством методов
GetItemTypeText() - тип элемента, GetItemKeyText() - ключ элемента,
GetItemName() - имя элемента, GetItemSummary() - содержание элемента.
Извлеченные данные передаются элементу tableview, который формирует
представление элементов в форме таблицы.2.3 Программное обеспечение,
реализующее визуализацию сообщений модема Sierra MC7710 для программы WireShark
Программное средство WireShark позволяет визуализировать данные,
полученные не только с сетевого устройства, но и данные содержащиеся в
локальных файлах. В связи с этим обработка данных в первом и во втором случаях
отличается. В первом случае при поступлении данных из сети программа WireShark
вызывает соответствующий диссектор. Вызванный диссектор осуществляет обработку
и визуализацию полученных данных. Во втором случае для открытия файлов
существует специальная библиотека Wiretap, на данный момент библиотека
поддерживает большое количество форматов и постоянно пополняется.
Сообщения модема Sierra MC7710 после обработки СПО QXDM Professional
можно сохранить в файл с расширением isf(item store file).Данный формат файла ПО WireShark не поддерживается.
Для добавления возможности работать с новыми форматами файлов возможны 2
способа [4].
. Добавить поддержку формата файла в библиотеку Wiretap.
. Разработать внешний конвертор, преобразующий isf файл в
поддерживаемый формат ПО WireShark.
Чтобы добавить поддержку нового формата файла в библиотеку нужно описать
процедуру открытия, которая проверяет магическое число файла и определяет
начало пакета, а также описать процедуру чтения, которая будет выделять пакеты
из файла и снабжать их заголовками. В данном случае отдельным пакет будет
служить отдельное сообщение обработанное СПО QXDM. Чтобы иметь возможность проверять
магическое число файла или иным образом проверять формат файла должна быть
известна структура файла. Для выделения пакетов из файла должен быть известен
размер сообщения, а так же для выделения полей сообщения должно быть известно
их смещение относительно начала сообщения. В связи с этим должна быть известна
структура файла. Так как структура файла isf является закрытой [5] произвести чтение файла
стандартными средствами нет возможности, потому что для добавления возможности
обработки нового формата файла нужно знание о реализации файла [4].
Для реализации внешнего конвертора (пункт 2) необходимо использовать
библиотеку CoreAutomation.dll с помощью которой можно будет извлечь необходимые
поля из файла, затем извлеченную информацию снабдить заголовком и отправить на
заданный порт по протоколу udp или tcp.
Сообщение модема Sierra MC7710 после обработки СПО QXDM Professional
имеет следующие поля (назначение которых описано в п.2.1).
Type
|
Key
|
Item Name
|
Summary
|
Рис. 5. Сообщение модема Sierra MC7710 после обработки СПО QXDM
Каждое сообщение, извлеченное из файла, необходимо снабдить заголовком со
следующими полями.
Размер поля Type
|
Размер поля Key
|
Размер поля Item Name
|
Размер поля Summary
|
Рис. 6. Заголовок сообщения модема Sierra MC7710
Поля псевдозаголовка позволят вычислить необходимое смещение в пакете для
диссектора.
Соответственно, предварительно должен быть разработан диссектор способный
обрабатывать пакеты, полученные от конвертора.
Рис. 7. Работа конвертора для isf файла
.4 Тестирование разработанной программы isfreader
Для тестирования программы isfreader будет использован файл
«10-23.16-25.isf», который содержит сообщения модема Sierra MC7710. В результате тестирования должны быть получены такие же
данные, как и после обработки СПО QXDM.
Рис. 2.2. Результат работы программы QXDM Professional
Рис. 2.3. Результат работы программы isfreader
Данные полученные в результате работы программы QXDM Professional и
данные полученные в результате работы программы isfreader совпадают.
Выводы по
главе 2
Во второй главе был изучен интерфейс СПО QXDM Professional и COM интерфейсы которые с ним поставляются, что позволило
разработать программу isfreader способную обрабатывать файлы, полученные в результате работы СПО QXDM
Professional, а также стало известно что
невозможно реализовать интеграцию разработанного ПО в качестве программно
подключаемого модуля WireShark, потому что реализация файла isf является закрытой. Библиотека CoreAutomation.dll позволяет извлечь
сообщения из isf файл без знания структуры файла, но передать эти сообщения на
обработку соответствующему диссектору с помощью библиотеки wiretap нет
возможности. Для реализации этой возможности необходимо, чтобы в библиотеке
wiretap была возможность ручного формирования пакета.
Заключение
В ходе выполнения курсовой работы были решены следующие задачи:
- освоены правила разработки и подключения программных модулей
WireShark;
- изучен интерфейс программного модуля СПО QXDM Professional;
- разработана программа, реализующая визуализацию сообщений
модема Sierra MC7710, включая отображение специальной информации, полученной
после обработки сообщений программным модулем СПО QXDM Professional;
- исследована возможность интеграции разработанной программы в
виде программного модуля WireShark.
В результате исследования было выяснено, что не существует возможности
интеграции разработанного ПО в качестве программно подключаемого модуля ПО
WireShark, реализующего визуализацию сообщений модема Sierra MC7710. Чтобы
реализовать данный функционал в ПО WireShark необходимо добавить поддержку
работы с isf файлом, в котором содержатся сообщения модема. Для реализации
данной возможности должна быть известна структура файла, а именно должно быть
известно магическое число файла (если оно присутствует в нем), смещение в
файле, с которого начинаются сообщения модема и размер полей сообщения, чтобы
иметь возможность выделить нужное поле сообщения. Данных проблем можно
избежать, если в библиотеке wiretap будет возможность формировать поля пакета
самостоятельно.
ЛИТЕРАТУРА
1. Пользовательская
документация
//<http://www.wireshark.org/docs/wsug_html_chunked/ChapterUsing.html>.
2. Creating
Your Own Custom Wireshark Dissector
//<http://www.codeproject.com/Articles/19426/Creating-Your-Own-Custom-Wireshark-Dissector>
3. Пишем
плагин-диссектор для Wireshark
//<http://habrahabr.ru/post/121990/#anch04//>.
4. Packet
Input //<http://wiki.wireshark.org/Development/PacketInput>
. Interface
Control Documents
//<http://www.qualcomm.com/solutions/testing/interface-control-documents>
Приложение 1.
Листинг программы isfreader
Листинг П1.1
/**********************************************************************
*Файл qt.ui *
*Предназначен для описания объектов классов отвечающих за
визуализацию* *информации. *
*Автор : Филатов А. В., 2013 г. *
**********************************************************************/
#ifndef UI_QT_H
#define UI_QT_H
#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QHeaderView>
#include <QtGui/QMainWindow>
#include <QtGui/QMenuBar>
#include <QtGui/QStatusBar>
#include <QtGui/QTableView>
#include <QtGui/QToolBar>
#include
<QtGui/QWidget>_BEGIN_NAMESPACEUi_qtClass
{:*centralWidget; *tableView;//Создание
объекта класса предназначенного для формирования таблицы
QMenuBar
*menuBar;*mainToolBar;*statusBar;setupUi(QMainWindow *qtClass)
{(qtClass->objectName().isEmpty())>setObjectName(QString::fromUtf8("qtClass"));>resize(1355,
738);= new
QWidget(qtClass);>setObjectName(QString::fromUtf8("centralWidget"));=
new
QTableView(centralWidget);>setObjectName(QString::fromUtf8("tableView"));>setGeometry(QRect(0,
0, 1351, 681));>setCentralWidget(centralWidget);= new
QMenuBar(qtClass);>setObjectName(QString::fromUtf8("menuBar"));>setGeometry(QRect(0,
0, 1355, 21));>setMenuBar(menuBar);= new
QToolBar(qtClass);>setObjectName(QString::fromUtf8("mainToolBar"));>addToolBar(Qt::TopToolBarArea,
mainToolBar);= new
QStatusBar(qtClass);>setObjectName(QString::fromUtf8("statusBar"));>setStatusBar(statusBar);(qtClass);::connectSlotsByName(qtClass);
} // setupUiretranslateUi(QMainWindow *qtClass)
{>setWindowTitle(QApplication::translate("qtClass",
"qt", 0, QApplication::UnicodeUTF8));
#ifndef
QT_NO_TOOLTIP>setToolTip(QApplication::translate("qtClass",
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\"
\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta
name=\"qrichtext\" content=\"1\" /><style
type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body
style=\" font-family:'Segoe UI'; font-size:9pt; font-weight:400;
font-style:normal;\">\n"
"<p style=\"-qt-paragraph-type:empty;
margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;
-qt-block-indent:0; text-indent:0px;\"><br
/></p></body></html>", 0,
QApplication::UnicodeUTF8));
#endif // QT_NO_TOOLTIP
} // retranslateUi
};Ui {qtClass: public Ui_qtClass {};
} // namespace Ui_END_NAMESPACE
#endif // UI_QT_H
Листинг П1.2
/*************************************************************************Файл
qt.cpp *
*Работа с isf
файлом, извлечение из него сообщений и вывод полей *
*сообщений в виде таблицы с помощью класса QTable. Описание работы меню,* *в частности
открытие файла. *
*Автор : Филатов А. В., 2013 г. *
************************************************************************/
#include "qt.h"
//Подключение библиотеки предоставляемой СПО QXDM
Professional
#import "C:\\Program Files (x86)\\Qualcomm\\QXDM\\Bin\\CoreAutomation.dll"::qt(QWidget
*parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{.setupUi(this);
//Инициализация СОМ объекта
HRESULT hr = CoInitialize( 0 );
//Создание действий= new
QAction(tr("&Open"), this);= new QAction(tr("E&xit"),
this);(openAction, SIGNAL(triggered()), this, SLOT(open()));(exitAction,
SIGNAL(triggered()), qApp, SLOT(quit()));=
menuBar()->addMenu(tr("&File"));>addAction(openAction);>addSeparator();>addAction(exitAction);
}
/*************************************************************************Метод класса:
*
*Open *
*Описание: *
*Открытие нового файла. Вывод информации в виде таблицы. *
*Параметры: *
*Нет *
*Нет *
************************************************************************/
void qt::open()
{
//запрос у пользователя имени файла
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open File"), "",("Item store file
(*.isf)"));(fileName != "")
{::IItemStoreFilesPtr pISF(
__uuidof( DMCoreAutomation::ItemStoreFiles ) );hISF =
pISF->LoadItemStore( fileName.toLocal8Bit().data() );itemCount =
pISF->GetItemCount( hISF );*model = new
QStandardItemModel(itemCount,5,this);
//Формирование столбцов
Type>setHorizontalHeaderItem(0, new
QStandardItem(QString("Type")));//Формирование столбца
Type>setHorizontalHeaderItem(1, new
QStandardItem(QString("Key")));>setHorizontalHeaderItem(2, new
QStandardItem(QString("Item Name")));>setHorizontalHeaderItem(3,
new QStandardItem(QString("Summary")));>setHorizontalHeaderItem(4,
new QStandardItem(QString("Hex"))); raw_buffer;//Переменная,которая
будет хранить шестнадцетеричный формат сообщения
//Заполнение таблицы(ULONG i = 0; i < itemCount;
i++)
{
//Получение элемента(извлечение
сообщения)::IColorItemPtr pItem = pISF->GetItem( hISF, i );
//Извлечение полей сообщения
_bstr_t tsTxt = pItem->GetItemTimestampText(
VARIANT_TRUE, VARIANT_TRUE );
_bstr_t itTxt = pItem->GetItemTypeText();
_bstr_t ikTxt = pItem->GetItemKeyText();
_bstr_t inTxt = pItem->GetItemName();
_bstr_t isTxt = pItem->GetItemSummary();
//Запись шестнадцетиричного значения сообщения_buffer
= pItem->GetItemBufferText(VARIANT_TRUE);
//Преобразование из BSTR в WString::wstring
intermediateString(raw_buffer, SysStringLen(raw_buffer));finalString = QString::fromStdWString(intermediateString);
//Запись полученых полей сообщения в таблицу
QStandardItem *firstColumn = new
QStandardItem(QString(itTxt));*secondColumn = new
QStandardItem(QString(ikTxt));*thirdColumn = new
QStandardItem(QString(inTxt));*foursColumn = new
QStandardItem(QString(isTxt));*fivesColumn = new
QStandardItem(QString(finalString));>setItem(i,0,firstColumn);>setItem(i,1,secondColumn);>setItem(i,2,thirdColumn);>setItem(i,3,foursColumn);>setItem(i,4,fivesColumn);.tableView->setModel(model);
}
//Закрытие файла>CloseItemStore( hISF );
}
}qt::quit()
{
}::~qt()
{
}
Листинг П1.3
/*************************************************************************Файл
qt.h *
*Создание класса приложения.Описание меню File. *
* Автор : Филатов А. В., 2013 г. *
************************************************************************/
#ifndef QT_H
#define QT_H
#include <QtGui/QMainWindow>
#include "ui_qt.h"
#include <QStandardItemModel>
#include <QTextEdit>
#include <QFileDialog>
#include <QMessageBox>
#include <QTextStream>qt : public QMainWindow
{_OBJECT:(QWidget *parent = 0, Qt::WFlags flags = 0);
~qt();:::qtClass ui;
//Создание действий
QAction *exitAction;//Действие
для закрытия приложения
QAction *openAction;//Действие
для открытия файла
QMenu *fileMenu;
//Объявление слотов,которые будут открывать и завершать
программу
private slots:open();//Слот для открытия файла quit();//Слот для закрытия приложения
};
#endif // QT_H
Листинг П1.4
/*************************************************************************Файл
main.cpp. *
*Отображение основного окна приложения. *
* Автор : Филатов А. В., 2013 г. *
************************************************************************/
#include "qt.h"
#include <QtGui/QApplication>main(int argc, char
*argv[])
{a(argc, argv);w;.show();a.exec();
}
Листинг плагина
WireShark
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <epan/packet.h>
#define FOO_PORT 35000
/* Номер UDP порта, на котором мы предполагаем будет
находится FOO траффик. */int proto_foo = -1;
/* При регистрации протокола переменная затрется
идентификатором протокола. */gint ett_foo = -1;int type = -1;//Байт отвечающий за длинну поля typeint key = -1;int iname = -1;int summary = -1;sT = 0;//длинна поля
type, полученная из пакетаsK = 0;sN = 0;sS = 0;proto_register_foo(void)
{hf_register_info hf[] = {
{ &type,
{ "Type", "foo.hdr.type",//Тип элемента_STRING,
BASE_NONE,, 0x0,, HFILL }
},
{ &key,
{ "Key", "foo.hdr.key",//Ключ элемента_STRING,
BASE_NONE,, 0x0,, HFILL }
},
{ &iname,
{ "Item name", "foo.hdr.itemname",//Имя элемента_STRING,
BASE_NONE,, 0x0,, HFILL }
},
{ &summary,
{ "Summary", "foo.hdr.summary",//Содержание элемента_STRING, BASE_NONE,, 0x0,, HFILL }
}
};gint *ett[] = { &ett_foo };_foo =
proto_register_protocol (
"FOO Protocol", /* полное имя */
"FOO", /* короткое имя */
"foo" /* аббревиатура */
);_register_field_array(proto_foo, hf,
array_length(hf));_register_subtree_array(ett, array_length(ett));
}void dissect_foo(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree)
{_set_str(pinfo->cinfo, COL_PROTOCOL,
"FOO");_clear(pinfo->cinfo, COL_INFO);(tree) {_item *ti =
NULL;_tree *foo_tree = NULL;= proto_tree_add_item(tree, proto_foo, tvb, 0, -1,
FALSE);_tree = proto_item_add_subtree(ti, ett_foo);
sT = tvb_get_guint8(tvb, 0);//Извлекаем из пакета длину поля
type
sK = tvb_get_guint8(tvb, 1);= tvb_get_guint8(tvb, 2);=
tvb_get_guint8(tvb, 3);_tree_add_item(foo_tree, type, tvb, 4, sT,
FALSE);_tree_add_item(foo_tree, key, tvb, sT + 4, sK,FALSE);_tree_add_item(foo_tree,
iname, tvb, sT + 4 + sK, sN, FALSE);_tree_add_item(foo_tree, summary, tvb, sT +
4 + sK + sN, sS, FALSE);
}
}proto_reg_handoff_foo(void)
{dissector_handle_t foo_handle;_handle =
create_dissector_handle(dissect_foo, proto_foo);_add_uint("udp.port",
FOO_PORT, foo_handle);
}
Листинг программы отправляющий пакеты по придуманному протоколу
«FOO».Предварительно установить адаптер замыкания на себя
// SocketClient.cpp : Defines the entry point for the
console application.
//
#include "stdafx.h"
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <iostream>namespace std;
#import "C:\\Program Files
(x86)\\Qualcomm\\QXDM\\Bin\\CoreAutomation.dll"
#define DEFAULT_PORT 35000//Порт FOOmain(int argc, char **argv)
{<< "File name-> ";fname[256];>> fname;<< endl;
// Initialize COM libraryhr = CoInitialize( 0
);(FAILED( hr ))
{
_tprintf_s( _T("Error: Failed to initialize COM
library\n") );-1;
}
// Initialize QXDM interface::IItemStoreFilesPtr pISF(
__uuidof( DMCoreAutomation::ItemStoreFiles ) );(pISF
== 0)
{
_tprintf_s( _T("Error: Failed to initialize ISF
interface\n") );-1;
}
// Load ISF filehISF = pISF->LoadItemStore( fname
);(hISF == 0xFFFFFFFF)
{
_tprintf_s( _T("Error: Failed to load input ISF:
%s\n"), fname );-1;
}Buffer[8192];*server_name=
"192.168.43.23";server_addr[20];short port = DEFAULT_PORT;retval,
loopflag=0;int addr;socket_type = SOCK_DGRAM;sockaddr_in server;hostent
*hp;wsaData;conn_socket;foobuf[210];itemCount = pISF->GetItemCount( hISF
);((retval = WSAStartup(0x202,&wsaData)) != 0) {//инициализация библиотеки Winsock(stderr,"WSAStartup failed with error
%d\n",retval);();-1;
}(isalpha(server_name[0]))
{ /* server address is a name */=
gethostbyname(server_name);
}
{ /* Convert nnn.nnn address to a usable one */=
inet_addr(server_name);= gethostbyaddr((char *)&addr,4,AF_INET);
}(hp == NULL )
{(stderr,"Client: Cannot resolve address [%s]:
Error %d\n",_name,WSAGetLastError());();(1);
}
//
// Copy the resolved information into the sockaddr_in
structure
//(&server,0,sizeof(server));(&(server.sin_addr),hp->h_addr,hp->h_length);.sin_family
= hp->h_addrtype;.sin_port = htons(port);_socket =
socket(AF_INET,socket_type,0); /* Open a socket */(conn_socket <0 )
{(stderr,"Client: Error Opening socket: Error %d\n",());();-1;
}<< "Start" << endl <<
"-----------------------------------------------------"<<endl;(connect(conn_socket,(struct
sockaddr*)&server,sizeof(server))//Соединение
== SOCKET_ERROR)
{("cls");(stderr,"connect() failed: %d\n",WSAGetLastError());();();-1;
}received = 0;//Полученние данные
int sent = 0;//Отправленные данные
//Заполнение таблицы
for (ULONG i = 0; i < itemCount; i++)
{
//Получение элемента(извлечение сообщения)::IColorItemPtr pItem =
pISF->GetItem( hISF, i );
//Извлечение полей сообщения
_bstr_t itTxt = pItem->GetItemTypeText();
_bstr_t ikTxt = pItem->GetItemKeyText();
_bstr_t inTxt = pItem->GetItemName();
_bstr_t isTxt =
pItem->GetItemSummary();type[30];name[256];key[30];sum[256];_s(type,(char *)
itTxt);_s(key,(char *) ikTxt);_s(name,(char *) inTxt);_s(sum,(char *)
isTxt);<< "Type->" << type <<endl;<<
"Key->" << key <<endl;<< "Item
name->" << name <<endl;<< "Summary->"
<< sum <<endl;<<
"-----------------------------------------------------"<<endl;s;res;=
strlen(type);//size type+= strlen(key);//size key+= strlen(name);//size name+=
strlen(sum);//size
sum.assign(type,strlen(type));+=s;.assign(key,strlen(key));+=
s;.assign(name,strlen(name));+= s;.assign(sum,strlen(sum));
res += s;//строка,которая будет передана
//содержание пакета: (длина поля тип,длинна поля ключ,
//длина поля имя элемента,длина поля содержание элемента,
//сами
type,key,item name,summary,=
send(conn_socket,res.c_str(),strlen(res.c_str()),0);(retval == SOCKET_ERROR)
{("cls");(stderr,"send() failed: error %d\n",WSAGetLastError());();();-1;
}+= retval;("Sent %d bytes to server. Received %d
bytes from server\r\n", sent, received);= "";=
"";(2000);
}
//Закрытие файла>CloseItemStore( hISF );
closesocket(conn_socket);();
}