threatflux_binary_analysis/formats/
java.rs

1//! Java class and JAR file parser
2
3use crate::{
4    types::{
5        Architecture, BinaryFormat as Format, BinaryMetadata, Endianness, Export, Import, Section,
6        SectionPermissions, SectionType, SecurityFeatures, Symbol, SymbolBinding, SymbolType,
7        SymbolVisibility,
8    },
9    BinaryError, BinaryFormatParser, BinaryFormatTrait, Result,
10};
11
12type ParseResult = Result<Box<dyn BinaryFormatTrait>>;
13
14/// Java binary format parser (class files and JAR archives)
15pub struct JavaParser;
16
17impl JavaParser {
18    fn parse_class(data: &[u8]) -> ParseResult {
19        if data.len() < 4 || &data[0..4] != b"\xca\xfe\xba\xbe" {
20            return Err(BinaryError::invalid_data("Invalid Java class magic"));
21        }
22
23        let minor = if data.len() >= 6 {
24            u16::from_be_bytes([data[4], data[5]])
25        } else {
26            0
27        };
28        let major = if data.len() >= 8 {
29            u16::from_be_bytes([data[6], data[7]])
30        } else {
31            0
32        };
33
34        let metadata = BinaryMetadata {
35            size: data.len(),
36            format: Format::Java,
37            architecture: Architecture::Jvm,
38            entry_point: None,
39            base_address: None,
40            timestamp: None,
41            compiler_info: Some(format!("Java class version {}.{}", major, minor)),
42            endian: Endianness::Big,
43            security_features: SecurityFeatures::default(),
44        };
45
46        let sections = vec![Section {
47            name: "class".to_string(),
48            address: 0,
49            size: data.len() as u64,
50            offset: 0,
51            permissions: SectionPermissions {
52                read: true,
53                write: false,
54                execute: false,
55            },
56            section_type: SectionType::Data,
57            data: None,
58        }];
59
60        Ok(Box::new(JavaBinary {
61            metadata,
62            sections,
63            symbols: Vec::new(),
64            imports: Vec::new(),
65            exports: Vec::new(),
66        }))
67    }
68
69    fn parse_jar(data: &[u8]) -> ParseResult {
70        use std::io::Cursor;
71        use zip::ZipArchive;
72
73        let reader = Cursor::new(data);
74        let mut archive =
75            ZipArchive::new(reader).map_err(|e| BinaryError::parse(format!("Zip error: {e}")))?;
76        let mut symbols = Vec::new();
77
78        for i in 0..archive.len() {
79            let file = archive
80                .by_index(i)
81                .map_err(|e| BinaryError::parse(format!("Zip entry error: {e}")))?;
82            if file.name().ends_with(".class") {
83                symbols.push(Symbol {
84                    name: file.name().to_string(),
85                    demangled_name: None,
86                    address: 0,
87                    size: file.size(),
88                    symbol_type: SymbolType::Object,
89                    binding: SymbolBinding::Global,
90                    visibility: SymbolVisibility::Default,
91                    section_index: None,
92                });
93            }
94        }
95
96        let metadata = BinaryMetadata {
97            size: data.len(),
98            format: Format::Java,
99            architecture: Architecture::Jvm,
100            entry_point: None,
101            base_address: None,
102            timestamp: None,
103            compiler_info: Some("Java archive".to_string()),
104            endian: Endianness::Big,
105            security_features: SecurityFeatures::default(),
106        };
107
108        let sections = vec![Section {
109            name: "jar".to_string(),
110            address: 0,
111            size: data.len() as u64,
112            offset: 0,
113            permissions: SectionPermissions {
114                read: true,
115                write: false,
116                execute: false,
117            },
118            section_type: SectionType::Data,
119            data: None,
120        }];
121
122        Ok(Box::new(JavaBinary {
123            metadata,
124            sections,
125            symbols,
126            imports: Vec::new(),
127            exports: Vec::new(),
128        }))
129    }
130}
131
132impl BinaryFormatParser for JavaParser {
133    fn parse(data: &[u8]) -> Result<Box<dyn BinaryFormatTrait>> {
134        if data.starts_with(b"\xca\xfe\xba\xbe") {
135            Self::parse_class(data)
136        } else if data.starts_with(b"PK\x03\x04") {
137            Self::parse_jar(data)
138        } else {
139            Err(BinaryError::invalid_data("Unknown Java binary format"))
140        }
141    }
142
143    fn can_parse(data: &[u8]) -> bool {
144        data.starts_with(b"\xca\xfe\xba\xbe") || data.starts_with(b"PK\x03\x04")
145    }
146}
147
148/// Java binary representation
149pub struct JavaBinary {
150    metadata: BinaryMetadata,
151    sections: Vec<Section>,
152    symbols: Vec<Symbol>,
153    imports: Vec<Import>,
154    exports: Vec<Export>,
155}
156
157impl BinaryFormatTrait for JavaBinary {
158    fn format_type(&self) -> Format {
159        Format::Java
160    }
161
162    fn architecture(&self) -> Architecture {
163        Architecture::Jvm
164    }
165
166    fn entry_point(&self) -> Option<u64> {
167        None
168    }
169
170    fn sections(&self) -> &[Section] {
171        &self.sections
172    }
173
174    fn symbols(&self) -> &[Symbol] {
175        &self.symbols
176    }
177
178    fn imports(&self) -> &[Import] {
179        &self.imports
180    }
181
182    fn exports(&self) -> &[Export] {
183        &self.exports
184    }
185
186    fn metadata(&self) -> &BinaryMetadata {
187        &self.metadata
188    }
189}