From f57066460f7c914b07a612d037eb5e57f617d5b2 Mon Sep 17 00:00:00 2001 From: Mosder Date: Mon, 6 Jul 2026 10:06:10 +0200 Subject: feat: added basic structures for fight results parsing and base functionallity of finding only the necessary data. Still need to do tcp stream reassembly and the actual parsing of the data. --- analyzer/analyzer.c | 16 +++---- analyzer/parser/fight_results.c | 18 +++++++ analyzer/parser/fight_results.h | 102 ++++++++++++++++++++++++++++++++++++++++ analyzer/parser/parser.c | 15 ++++++ analyzer/parser/parser.h | 21 +++++++++ analyzer/utils/pcap.c | 5 +- analyzer/utils/pcap.h | 3 +- 7 files changed, 168 insertions(+), 12 deletions(-) create mode 100644 analyzer/parser/fight_results.c create mode 100644 analyzer/parser/fight_results.h create mode 100644 analyzer/parser/parser.c create mode 100644 analyzer/parser/parser.h (limited to 'analyzer') diff --git a/analyzer/analyzer.c b/analyzer/analyzer.c index 7790f41..acbd5de 100644 --- a/analyzer/analyzer.c +++ b/analyzer/analyzer.c @@ -1,7 +1,6 @@ #include "analyzer.h" -#include - +#include "parser/parser.h" #include "utils/pcap.h" void analyze_file(char *path) { @@ -22,14 +21,11 @@ void analyze_file(char *path) { // read packets from the file while (pcap_next_ex(handle, &packet_data, &packet) == 1) { int payload_len; - payload = get_payload_from_packet(packet, packet_data, &payload_len); - if (payload_len > 0) { - printf("\n----------------\n"); - printf("Payload length: %d\n", payload_len); - printf("Payload:\n"); - fflush(stdout); - write(STDOUT_FILENO, payload, payload_len); - } + uint32_t tcp_seq; + payload = get_payload_from_packet(packet, packet_data, &payload_len, &tcp_seq); + // TODO: Stream reassembly using TCP sequence number + int parsed_len; + parse_stream((char *)payload, payload_len, &parsed_len); } pcap_close(handle); diff --git a/analyzer/parser/fight_results.c b/analyzer/parser/fight_results.c new file mode 100644 index 0000000..c6ad7cc --- /dev/null +++ b/analyzer/parser/fight_results.c @@ -0,0 +1,18 @@ +#include "fight_results.h" + +#include +#include + +char *find_fight_results(char *stream, int stream_len, int *length) { + char *start = memmem(stream, stream_len, FIGHT_RESULTS_START, strlen(FIGHT_RESULTS_START)); + char *end = memmem(stream, stream_len, FIGHT_RESULTS_END, strlen(FIGHT_RESULTS_END)); + *length = start != NULL && end != NULL ? end - start + strlen(FIGHT_RESULTS_END) : -1; + return start; +} + +FightResults parse_fight_results(char *data, int length) { + // TODO: actually parse that data + printf("len=%d\n%.*s\n----------------\n", length, length, data); + FightResults tmp; + return tmp; +} diff --git a/analyzer/parser/fight_results.h b/analyzer/parser/fight_results.h new file mode 100644 index 0000000..270aba8 --- /dev/null +++ b/analyzer/parser/fight_results.h @@ -0,0 +1,102 @@ +// parser/fight_results.h +// utilities for parsing the fight results data + +// Payload structure: +// FIGHT_RESULTS_START EntityResults (SEPARATOR_ENTITY EntityResults)* FIGHT_RESULTS_END +// +// EntityResults structure: +// field (SEPARATOR_RESULT field)* +// fields are defined in order in the EntityResults struct + +#define FIGHT_RESULTS_START "3;19;" +#define FIGHT_RESULTS_END "[--];" +#define SEPARATOR_ENTITY "[--]" +#define SEPARATOR_RESULT "&" + +typedef struct { + int team; // friend or enemy + char *name; + int exp; + float field4; + int gold; + float field6; + char *field7; + char *gear; // rares, sets, syngs, orbs + int field9; + char *items; // regular items + int field11; + int field12; + float field13; + float field14; // some multiplier most likely exp/gold/psycho/something else idk + float field15; + int level; + double field17; + float field18; + int field19; + int field20; + float field21; + float field22; + int field23; + int field24; + int psycho; + char *drifs; + int splinters; + int field28; + char *field29; + int field30; + int field31; // possibly information who is the player - 1 for current player, 0 for others (need to double check) + int field32; + int field33; + char *field34; + char *saturation; +} EntityResults; + +// values of field "team" +#define TEAM_FRIEND 1 +#define TEAM_ENEMY 2 + +// fight results data for friendly +typedef struct { + char *name; + int exp; + int gold; + char *gear; + char *items; + int level; + int psycho; + char *drifs; + int splinters; + char *saturation_type; + int saturation; +} FriendlyResults; + +// fight results data for enemy +typedef struct { + char *name; + int level; +} EnemyResults; + +// entire fight resutls +typedef struct { + int num_friendly; + FriendlyResults *friendly_results; + int num_enemy; + EnemyResults *enemy_results; +} FightResults; + +// find the first fight results data in stream +// params: +// - stream - stream to find the fight results in +// - stream_len - length of the stream +// - length - length of the fight results data or -1 if there's no end yet +// returns: +// pointer to the beggining of fight results data or NULL if there's none +extern char *find_fight_results(char *stream, int stream_len, int *length); + +// parse given fight results +// params: +// - data - fight results data to parse +// - length - length of fight results data +// returns: +// FightResults struct containing parsed data +extern FightResults parse_fight_results(char *data, int length); diff --git a/analyzer/parser/parser.c b/analyzer/parser/parser.c new file mode 100644 index 0000000..b551d8e --- /dev/null +++ b/analyzer/parser/parser.c @@ -0,0 +1,15 @@ +#include "parser.h" + +#include + +ParsedData *parse_stream(char *stream, int stream_len, int *parsed_len) { + // TODO: Need to do parsing of the entire thing (loop) and return all of the parsed data + if (stream_len > 0) { + int length; + char *start = find_fight_results(stream, stream_len, &length); + if (start != NULL) { + parse_fight_results(start, length); + } + } + return NULL; +} diff --git a/analyzer/parser/parser.h b/analyzer/parser/parser.h new file mode 100644 index 0000000..18b4b83 --- /dev/null +++ b/analyzer/parser/parser.h @@ -0,0 +1,21 @@ +// parser/parser.h +// main parser file + +#include "fight_results.h" + +// "generic" type for parsed data +typedef struct { + enum { FIGHT_RESULTS } data_type; + union { + FightResults fight_results; + } data; +} ParsedData; + +// parse a stream of TCP data +// params: +// - stream - the stream to parse +// - stream_len - length of the stream to parse +// - parsed_len - pointer to inform how much of the stream was parsed (not all if e.g. start of data is there, but the end isn't yet) +// returns: +// pointer to the array of parsed data +extern ParsedData *parse_stream(char *stream, int stream_len, int *parsed_len); diff --git a/analyzer/utils/pcap.c b/analyzer/utils/pcap.c index cdefba7..5e9b611 100644 --- a/analyzer/utils/pcap.c +++ b/analyzer/utils/pcap.c @@ -4,7 +4,7 @@ #include #include -const unsigned char *get_payload_from_packet(const unsigned char *packet, const struct pcap_pkthdr *packet_data, int *payload_len) { +const unsigned char *get_payload_from_packet(const unsigned char *packet, const struct pcap_pkthdr *packet_data, int *payload_len, uint32_t *tcp_seq) { // get Ethernet header const struct ether_header *eth_header = (const struct ether_header *)packet; int eth_header_len = sizeof(struct ether_header); @@ -29,6 +29,9 @@ const unsigned char *get_payload_from_packet(const unsigned char *packet, const const struct tcphdr *tcp_header = (const struct tcphdr *)(packet + eth_header_len + ip_header_len); int tcp_header_len = tcp_header->th_off * 4; + // get TCP sequence number + *tcp_seq = ntohl(tcp_header->seq); + // get payload int total_header_len = eth_header_len + ip_header_len + tcp_header_len; *payload_len = packet_data->caplen - total_header_len; diff --git a/analyzer/utils/pcap.h b/analyzer/utils/pcap.h index d31b961..16da7cd 100644 --- a/analyzer/utils/pcap.h +++ b/analyzer/utils/pcap.h @@ -8,6 +8,7 @@ // - packet - captured packet // - packet_data - metadata about packet // - payload_len - pointer to save the payload length to or -1 if not a correct packet +// - tcp_seq - pointer to save the TCP sequence number // returns: // pointer to the payload or NULL if not a correct packet -extern const unsigned char *get_payload_from_packet(const unsigned char *packet, const struct pcap_pkthdr *packet_data, int *payload_len); +extern const unsigned char *get_payload_from_packet(const unsigned char *packet, const struct pcap_pkthdr *packet_data, int *payload_len, uint32_t *tcp_seq); -- cgit v1.2.3