pelite/
rich_structure.rs

1/*!
2Rich Structure.
3 */
4
5// References:
6//
7// * https://github.com/dishather/richprint
8// * https://ntcore.com/?p=27
9// * https://securelist.com/the-devils-in-the-rich-header/84348/
10// * http://bytepointer.com/articles/the_microsoft_rich_header.htm
11// * http://bytepointer.com/articles/rich_header_lifewire_vxmags_29A-8.009.htm
12// * https://pdfs.semanticscholar.org/44ad/fa896e6598b1723507060126125a0cad39a1.pdf
13
14use std::{fmt, iter, mem, result};
15
16use crate::{Error, Result};
17
18//----------------------------------------------------------------
19
20// The Rich structure:
21// 'DanS' ^ x, x, x, x,
22// compid ^ x, revision ^ x, ...
23// 'Rich', x
24// padding, ...
25
26const DANS_MARKER: u32 = 0x536e6144; // "DanS"
27const RICH_MARKER: u32 = 0x68636952; // "Rich"
28
29/// Rich structure.
30#[derive(Copy, Clone)]
31pub struct RichStructure<'a> {
32	dos_stub: &'a [u32],
33	image: &'a [u32],
34}
35impl<'a> RichStructure<'a> {
36	pub(crate) fn try_from(image: &'a [u32]) -> Result<RichStructure<'a>> {
37		// Read as a slice of dwords up until the PE headers
38		let image = image.get(15)
39			.and_then(|e_lfanew| image.get(..(e_lfanew / 4) as usize))
40			.ok_or(Error::Invalid)?;
41
42		// Skip the padding zeroes
43		let mut end = image.len();
44		loop {
45			if end < 16 {
46				return Err(Error::Invalid);
47			}
48			if image[end - 1] != 0 {
49				break;
50			}
51			end -= 1;
52		}
53		let end = end;
54
55		// Find the Rich marker and the xor key
56		if image[end - 2] != RICH_MARKER {
57			return Err(Error::BadMagic);
58		}
59		let x = image[end - 1];
60		let dx = DANS_MARKER ^ x;
61
62		// Scan to find the header block
63		let mut start = end - 6;
64		loop {
65			if start < 16 {
66				return Err(Error::Invalid);
67			}
68			if image[start] == dx && image[start + 1] == x && image[start + 2] == x && image[start + 3] == x {
69				break;
70			}
71			start -= 2;
72		}
73		let start = start;
74
75		// Everything before is the dos stub
76		let dos_stub = &image[..start];
77		let image = &image[start..end];
78
79		Ok(RichStructure { dos_stub, image })
80	}
81	/// Returns the Rich image without the padding.
82	pub fn image(&self) -> &'a [u32] {
83		self.image
84	}
85	/// Calculate the checksum.
86	///
87	/// The checksum should be equal to the xor key.
88	pub fn checksum(&self) -> u32 {
89		Self::_checksum(self.dos_stub, self.records())
90	}
91	fn _checksum<I>(dos_stub: &[u32], records: I) -> u32 where I: Iterator<Item = RichRecord> {
92		let mut csum = mem::size_of_val(dos_stub) as u32;
93
94		let mut i = 0;
95		for dword in dos_stub {
96			// Zero the e_lfanew field
97			let bytes = if i == 0x3c { [0; 4] }
98			else { unsafe { *(dword as *const _ as *const [u8; 4]) } };
99			// Accumulate
100			csum = u32::wrapping_add(csum, (bytes[0] as u32).rotate_left(i + 0));
101			csum = u32::wrapping_add(csum, (bytes[1] as u32).rotate_left(i + 1));
102			csum = u32::wrapping_add(csum, (bytes[2] as u32).rotate_left(i + 2));
103			csum = u32::wrapping_add(csum, (bytes[3] as u32).rotate_left(i + 3));
104			i += 4;
105		}
106
107		for record in records {
108			let value = (record.product as u32) << 16 | (record.build as u32);
109			csum = u32::wrapping_add(csum, value.rotate_left(record.count));
110		}
111
112		csum
113	}
114	/// Gets the xor key.
115	pub fn xor_key(&self) -> u32 {
116		self.image[1]
117	}
118	/// Gets the records.
119	pub fn records(&self) -> RichIter<'a> {
120		let iter = &self.image[4..self.image.len() - 2];
121		let key = self.xor_key();
122		RichIter { iter, key }
123	}
124	/// Encodes a new set of records.
125	///
126	/// If the destination does not have the right len, returns Err with the right len.
127	/// Call encode again with destination of the returned len, destination is not modified.
128	///
129	/// Returns Ok with the len of the destination when encoding was successful.
130	pub fn encode(&self, records: &[RichRecord], dest: &mut [u32]) -> result::Result<usize, usize> {
131		let xor_key = Self::_checksum(self.dos_stub, records.iter().cloned());
132		let n = records.len();
133		let total_size = ((xor_key / 32) % 3 + n as u32) * 8 + 0x20;
134		let total_len = (total_size / 4) as usize;
135		if dest.len() < n * 2 + 6 {
136			Err(total_len)
137		}
138		else {
139			// Write the header
140			dest[0] = DANS_MARKER ^ xor_key;
141			dest[1] = xor_key;
142			dest[2] = xor_key;
143			dest[3] = xor_key;
144			// Write the records
145			for (i, record) in records.iter().enumerate() {
146				let values = record.encode(xor_key);
147				dest[i * 2 + 4] = values[0];
148				dest[i * 2 + 5] = values[1];
149			}
150			// Write the footer
151			dest[n * 2 + 4] = RICH_MARKER;
152			dest[n * 2 + 5] = xor_key;
153			// Write the padding
154			for i in n * 2 + 6..dest.len() {
155				dest[i] = 0;
156			}
157			Ok(total_len)
158		}
159	}
160}
161impl<'a> fmt::Debug for RichStructure<'a> {
162	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163		f.debug_struct("RichStructure")
164			.field("xor_key", &self.xor_key())
165			.field("checksum", &self.checksum())
166			.field("records", &self.records())
167			.finish()
168	}
169}
170
171//----------------------------------------------------------------
172
173/// Rich record.
174///
175/// Rich records contain a product identifier and its build number.
176/// The count value indicates how many .obj files were linked generated by the product.
177#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
178#[repr(C)]
179pub struct RichRecord {
180	pub build: u16,
181	pub product: u16,
182	pub count: u32,
183}
184impl RichRecord {
185	/// Decodes the record with the given key.
186	pub fn decode(key: u32, values: &[u32; 2]) -> RichRecord {
187		let field = values[0] ^ key;
188		let build = (field & 0xffff) as u16;
189		let product = ((field >> 16) & 0xffff) as u16;
190		let count = values[1] ^ key;
191		RichRecord { build, product, count }
192	}
193	/// Encodes the record with the given key.
194	pub fn encode(&self, key: u32) -> [u32; 2] {
195		let value = (self.product as u32) << 16 | (self.build as u32);
196		[value ^ key, self.count ^ key]
197	}
198}
199
200//----------------------------------------------------------------
201
202/// Defines the kinds of objects.
203///
204/// Rich records can identify the product used and with it the _'language'_ of the objects.
205/// This allows a mapping of products and the kind of _'language'_ it was generated from.
206#[derive(Copy, Clone, Debug, Eq, PartialEq)]
207#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
208pub enum ObjectKind {
209	Unknown,
210	Link,
211	/// Exported symbol.
212	Export,
213	/// Imported symbol.
214	Import,
215	/// Resource object.
216	Resource,
217	/// Assembly object.
218	Assembly,
219	/// C++ object.
220	#[cfg_attr(feature = "serde", serde(rename = "C++"))]
221	CPP,
222	/// C object.
223	C,
224}
225impl From<u16> for ObjectKind {
226	fn from(product: u16) -> ObjectKind {
227		match product {
228			0x00ff          | 0x00c9 | 0x009a          | 0x007c | 0x005e | 0x0045          | 0x0006 => ObjectKind::Resource,
229			0x0100 | 0x00dc | 0x00ca | 0x009b | 0x0092 | 0x007a | 0x005c | 0x003f                   => ObjectKind::Export,
230			0x0101 | 0x00dd | 0x00cb | 0x009c | 0x0093 | 0x007b | 0x005d | 0x0019          | 0x0002 => ObjectKind::Import,
231			0x0102 | 0x00de | 0x00cc | 0x009d | 0x0091 | 0x0078 | 0x005a | 0x003d          | 0x0004 => ObjectKind::Link,
232			0x0103 | 0x00df | 0x00cd | 0x009e | 0x0095 | 0x007d | 0x000f | 0x0040                   => ObjectKind::Assembly,
233			0x0104 | 0x00e0 | 0x00ce | 0x00aa | 0x0083 | 0x006d | 0x005f | 0x001c | 0x000a | 0x0015 => ObjectKind::C,
234			0x0105 | 0x00e1 | 0x00cf | 0x00ab | 0x0084 | 0x006e | 0x0060 | 0x001d | 0x000b | 0x0016 => ObjectKind::CPP,
235
236			0x0001 => ObjectKind::Import,
237			_ => ObjectKind::Unknown,
238		}
239	}
240}
241
242//----------------------------------------------------------------
243
244/// Iterator over the Rich records.
245#[derive(Clone)]
246pub struct RichIter<'a> {
247	iter: &'a [u32],
248	key: u32,
249}
250impl<'a> Iterator for RichIter<'a> {
251	type Item = RichRecord;
252	fn next(&mut self) -> Option<RichRecord> {
253		if self.iter.len() >= 2 {
254			let record = RichRecord::decode(self.key, &[self.iter[0], self.iter[1]]);
255			self.iter = &self.iter[2..];
256			Some(record)
257		}
258		else {
259			None
260		}
261	}
262	fn size_hint(&self) -> (usize, Option<usize>) {
263		let len = self.iter.len() / 2;
264		(len, Some(len))
265	}
266	fn count(self) -> usize {
267		self.size_hint().0
268	}
269	fn nth(&mut self, n: usize) -> Option<RichRecord> {
270		if self.iter.len() >= n * 2 + 2 {
271			let record = RichRecord::decode(self.key, &[self.iter[n * 2], self.iter[n * 2 + 1]]);
272			self.iter = &self.iter[n * 2 + 2..];
273			Some(record)
274		}
275		else {
276			self.iter = &self.iter[..0];
277			None
278		}
279	}
280}
281impl<'a> DoubleEndedIterator for RichIter<'a> {
282	fn next_back(&mut self) -> Option<RichRecord> {
283		let len = self.iter.len();
284		if len >= 2 {
285			let record = RichRecord::decode(self.key, &[self.iter[len - 2], self.iter[len - 1]]);
286			self.iter = &self.iter[..len - 2];
287			Some(record)
288		}
289		else {
290			None
291		}
292	}
293}
294impl<'a> ExactSizeIterator for RichIter<'a> {}
295impl<'a> iter::FusedIterator for RichIter<'a> {}
296impl<'a> fmt::Debug for RichIter<'a> {
297	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
298		f.debug_list().entries(self.clone()).finish()
299	}
300}
301
302//----------------------------------------------------------------
303
304/*
305	"rich_structure": {
306		"xor_key": 129284757318,
307		"checksum": 129284757318,
308		"records": [
309			{
310				"build": 6030,
311				"product": 95,
312				"count": 68,
313			},
314		]
315	},
316*/
317
318#[cfg(feature = "serde")]
319mod serde {
320	use crate::util::serde_helper::*;
321	use super::{RichStructure, RichRecord};
322
323	impl<'a> Serialize for RichStructure<'a> {
324		fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
325			let mut state = serializer.serialize_struct("RichStructure", 3)?;
326			state.serialize_field("xor_key", &self.xor_key())?;
327			state.serialize_field("checksum", &self.checksum())?;
328			state.serialize_field("records", &SerdeIter(self.records()))?;
329			state.end()
330		}
331	}
332	impl Serialize for RichRecord {
333		fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
334			let mut state = serializer.serialize_struct("RichRecrod", 4)?;
335			state.serialize_field("product", &self.product)?;
336			// state.serialize_field("kind", &ObjectKind::from(self.product))?;
337			state.serialize_field("build", &self.build)?;
338			state.serialize_field("count", &self.count)?;
339			state.end()
340		}
341	}
342}