feat: Add automatic file type detection and enhanced analysis

- Auto-detect XML files for encoding, other files for decoding/analysis
- Enhanced structure analysis for both .NET and VC versions
- Added V2GTP header analysis and EXI structure breakdown
- Added message type prediction based on body choice patterns
- Improved SessionID analysis with ASCII decoding
- Updated usage messages to reflect auto-detection capabilities

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
ChiKyun Kim
2025-09-12 17:32:53 +09:00
parent a3eb5cbf27
commit a5247e0d32
2 changed files with 305 additions and 22 deletions

View File

@@ -122,6 +122,122 @@ const char* get_payload_type_name(uint16_t payload_type) {
}
}
void analyze_v2gtp_header(uint8_t* data, size_t size) {
if (size < 8) return;
printf("\n--- V2G Transfer Protocol Header ---\n");
printf("Version: 0x%02X\n", data[0]);
printf("Inverse Version: 0x%02X\n", data[1]);
uint16_t payload_type = (data[2] << 8) | data[3];
printf("Payload Type: 0x%04X (%s)\n", payload_type, get_payload_type_name(payload_type));
uint32_t payload_length = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];
printf("Payload Length: %u bytes\n", payload_length);
if (8 + payload_length == size) {
printf("✓ V2GTP header is valid (payload length matches)\n");
} else {
printf("⚠ V2GTP header mismatch (expected %u, got %zu)\n", (unsigned)(8 + payload_length), size);
}
// Analyze EXI payload if present
if (size > 8) {
analyze_exi_structure(data, size, 8);
}
}
void analyze_exi_structure(uint8_t* data, size_t size, size_t offset) {
if (offset + 4 > size) return;
printf("\n--- EXI Structure Analysis ---\n");
printf("EXI data starts at offset: %zu\n", offset);
printf("EXI payload size: %zu bytes\n", size - offset);
// EXI Header analysis
if (offset + 4 <= size) {
printf("EXI Magic: 0x%02X (expected 0x80)\n", data[offset]);
printf("Document Choice: 0x%02X\n", data[offset + 1]);
printf("Grammar State: 0x%02X 0x%02X\n", data[offset + 2], data[offset + 3]);
}
// SessionID analysis (if present after EXI header)
if (offset + 12 <= size) {
printf("\n--- SessionID Analysis ---\n");
printf("SessionID bytes: ");
for (size_t i = offset + 4; i < offset + 12 && i < size; i++) {
printf("%02X ", data[i]);
}
printf("\n");
// Try to decode SessionID as ASCII if reasonable
if (is_readable_ascii(data, offset + 4, 8)) {
printf("SessionID (ASCII): \"");
for (size_t i = offset + 4; i < offset + 12 && i < size; i++) {
printf("%c", data[i]);
}
printf("\"\n");
}
}
// Predict message type based on patterns
predict_message_type(data, size, offset);
}
int is_readable_ascii(uint8_t* data, size_t offset, size_t length) {
for (size_t i = 0; i < length && offset + i < length; i++) {
uint8_t b = data[offset + i];
if (b < 32 || b > 126) // Not printable ASCII
return 0;
}
return 1;
}
void predict_message_type(uint8_t* data, size_t size, size_t offset) {
printf("\n--- Message Type Prediction ---\n");
// Look for body choice pattern (around offset 12-16 typically)
for (size_t i = offset + 8; i < offset + 20 && i < size; i++) {
uint8_t b = data[i];
// Body choice is typically encoded in specific patterns
if ((b & 0xF0) == 0xD0) { // Common pattern for body choices
int body_choice = (b >> 1) & 0x1F; // Extract 5-bit choice
printf("Possible Body Choice at offset %zu: %d (%s)\n",
i, body_choice, get_message_type_description(body_choice));
}
}
}
const char* get_message_type_description(int body_choice) {
switch(body_choice) {
case 0: return "SessionSetupReq";
case 1: return "SessionSetupRes";
case 2: return "ServiceDiscoveryReq";
case 3: return "ServiceDiscoveryRes";
case 4: return "ServiceDetailReq";
case 5: return "ServiceDetailRes";
case 6: return "PaymentServiceSelectionReq";
case 7: return "PaymentServiceSelectionRes";
case 8: return "AuthorizationReq";
case 9: return "AuthorizationRes";
case 10: return "ChargeParameterDiscoveryReq";
case 11: return "ChargeParameterDiscoveryRes";
case 12: return "PowerDeliveryReq";
case 13: return "CurrentDemandReq";
case 14: return "CurrentDemandRes";
case 15: return "PowerDeliveryRes";
case 16: return "ChargingStatusReq";
case 17: return "ChargingStatusRes";
case 18: return "SessionStopReq";
case 19: return "SessionStopRes";
default: {
static char unknown_msg[32];
snprintf(unknown_msg, sizeof(unknown_msg), "Unknown (%d)", body_choice);
return unknown_msg;
}
}
}
// Function to analyze complete packet structure
void analyze_data_structure(uint8_t* data, size_t size) {
printf("=== Data Structure Analysis ===\n");
@@ -237,15 +353,23 @@ void analyze_data_structure(uint8_t* data, size_t size) {
}
}
// Look for EXI pattern
for (size_t i = 0; i <= size - 2; i++) {
uint16_t pattern = (data[i] << 8) | data[i + 1];
if (pattern == EXI_START_PATTERN) {
printf("EXI start pattern (0x8098) found at offset: %zu\n", i);
if (i >= offset) {
printf("EXI payload size: %zu bytes\n", size - i);
// Check protocol type and analyze
if (size >= 8 && data[0] == V2G_PROTOCOL_VERSION && data[1] == V2G_INV_PROTOCOL_VERSION) {
printf("Protocol: V2G Transfer Protocol detected\n");
analyze_v2gtp_header(data, size);
} else if (size >= 2 && ((data[0] << 8) | data[1]) == EXI_START_PATTERN) {
printf("Protocol: Direct EXI format\n");
analyze_exi_structure(data, size, 0);
} else {
printf("Protocol: Unknown format - attempting EXI detection\n");
// Look for EXI pattern
for (size_t i = 0; i <= size - 2; i++) {
uint16_t pattern = (data[i] << 8) | data[i + 1];
if (pattern == EXI_START_PATTERN) {
printf("EXI start pattern (0x8098) found at offset: %zu\n", i);
analyze_exi_structure(data, size, i);
break;
}
break;
}
}
printf("\n");
@@ -1453,6 +1577,14 @@ int main(int argc, char *argv[]) {
filename = "-"; // Use "-" to indicate stdin
} else {
filename = argv[arg_index];
// 자동으로 확장자를 감지하여 모드 결정
char* ext = strrchr(filename, '.');
if (ext && _stricmp(ext, ".xml") == 0) {
encode_mode = 1;
printf("Auto-detected XML file: encoding to EXI\n");
} else {
printf("Auto-detected binary file: analyzing structure\n");
}
}
} else if (argc == 3 && strcmp(argv[arg_index], "-decode") == 0) {
xml_mode = 1;
@@ -1462,9 +1594,11 @@ int main(int argc, char *argv[]) {
filename = argv[arg_index + 1];
} else {
printf("Usage: V2GDecoder [-debug] [-decode|-encode] input_file\\n");
printf(" V2GDecoder [-debug] filename (auto-detect by extension)\\n");
printf(" V2GDecoder [-debug] -encode (read XML from stdin)\\n");
printf(" V2GDecoder [-debug] -decode (read hex string from stdin)\\n");
printf("Enhanced EXI viewer with XML conversion capabilities\\n");
printf(" filename Auto-detect: .xml files are encoded, others are decoded/analyzed\\n");
printf(" -debug Enable detailed bit-level encoding/decoding output\\n");
printf(" -decode Convert EXI to Wireshark-style XML format\\n");
printf(" -decode Read hex string from stdin (echo hex | V2GDecoder -decode)\\n");