threatflux_binary_analysis/formats/
java.rs1use 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
14pub 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
148pub 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}