shellcoder/lib.rs
1//! Shellcoder is a thin library for writing shellcode payloads.
2
3#![cfg_attr(not(feature = "std"), no_std)]
4
5use core::borrow::Borrow;
6use core::fmt;
7use core::result::Result as CoreResult;
8#[cfg(feature = "std")]
9use std::io as std_io;
10
11#[allow(unused_imports)]
12use prelude::*;
13
14/// A specialized [`core::result::Result`] type for this crate.
15pub type Result<T> = CoreResult<T, Error>;
16
17#[cfg(feature = "std")]
18pub mod alloc;
19pub mod error;
20#[cfg(feature = "std")]
21pub mod io;
22pub mod ops;
23mod prelude;
24pub mod r#static;
25
26/// Generic interface for operations.
27///
28/// This trait describes a generic interface for operations.
29/// An operation is a function that outputs some data for building a payload.
30///
31/// Popular operations are implemented in this crates, such as [`ops::Fill`],
32/// [`ops::WriteInteger`] or [`ops::WriteBuffer`].
33pub trait Op: fmt::Debug {
34 #[cfg(feature = "std")]
35 /// Writes the operation to the stream.
36 ///
37 /// # Errors
38 ///
39 /// [`error::Error::Io`]: an I/O error occurred.
40 ///
41 /// # Examples
42 ///
43 /// Writes an operation to a [`File`](std::fs::File).
44 ///
45 /// ```rust
46 /// use std::fs::File;
47 ///
48 /// use shellcoder::ops::Advance;
49 /// # use shellcoder::Result;
50 /// use shellcoder::Op as _;
51 ///
52 /// # pub fn main() -> Result<()> {
53 /// let mut file = File::options()
54 /// .write(true)
55 /// .truncate(true)
56 /// .create(true)
57 /// .open("op.bin")?;
58 ///
59 /// Advance::new(42)
60 /// .write_to_io(&mut file)?;
61 /// # Ok(())
62 /// }
63 /// ```
64 ///
65 /// Writes an operation to a vector.
66 ///
67 /// ```rust
68 /// use shellcoder::ops::Fill;
69 /// # use shellcoder::Result;
70 /// use shellcoder::Op as _;
71 ///
72 /// # pub fn main() -> Result<()> {
73 /// let mut buffer = vec![];
74 /// Fill::new(42, b'A')
75 /// .write_to_io(&mut buffer)?;
76 /// # Ok(())
77 /// }
78 /// ```
79 ///
80 ///
81 fn write_to_io(&self, stream: &mut dyn std_io::Write) -> Result<usize>;
82
83 /// Writes the operation to a buffer.
84 ///
85 /// # Errors
86 ///
87 /// [`error::Error::OutputBufferTooSmall`]: the provided output buffer is too small
88 /// to contain the result of the operation.
89 ///
90 /// # Examples
91 ///
92 /// Writes an operation to a buffer.
93 ///
94 /// ```rust
95 /// use shellcoder::ops::Fill;
96 /// # use shellcoder::Result;
97 /// use shellcoder::Op as _;
98 ///
99 /// # pub fn main() -> Result<()> {
100 /// let mut buffer = [0u8; 10];
101 /// Fill::new(10, b'A')
102 /// .write_to(&mut buffer)?;
103 /// assert_eq!(&buffer, b"AAAAAAAAAA");
104 /// # Ok(())
105 /// # }
106 /// ```
107 ///
108 /// Writes to a buffer that is too small to contain the output of the
109 /// operation.
110 ///
111 /// ```rust
112 /// use shellcoder::ops::WriteInteger;
113 /// # use shellcoder::Result;
114 /// # use shellcoder::error::Error;
115 /// use shellcoder::Op as _;
116 ///
117 /// # pub fn main() -> Result<()> {
118 /// let mut buffer = [0u8; 3];
119 /// let error = WriteInteger::new_be(0xdeadbeefu32)
120 /// .write_to(&mut buffer)
121 /// .unwrap_err();
122 /// assert!(matches!(error, Error::OutputBufferTooSmall(4)));
123 /// # Ok(())
124 /// # }
125 /// ```
126 fn write_to(&self, out: impl AsMut<[u8]>) -> Result<usize>;
127}
128
129/// Generic interface for shellcoders.
130///
131/// This is the generic interface for writing shellcodes.
132///
133/// # Examples
134///
135/// Writes a simple shellcode that exposes two addresses 8 bytes apart:
136///
137/// ```ignore
138/// use shellcoder::{Op as _, Shellcoder as _};
139/// # #[cfg(feature = "std")]
140/// use shellcoder::alloc::Shellcoder;
141///
142/// use shellcoder::ops;
143///
144/// # use shellcoder::Result;
145/// # #[cfg(feature = "std")]
146/// # pub fn main() -> Result<()> {
147/// let mut shellcoder = Shellcoder::new();
148/// let shellcode = shellcoder
149/// .int_le(0x100000fbau64)?
150/// .advance(8)?
151/// .int_le(0x10000fcdeu64)?
152/// .as_bytes();
153/// assert_eq!(shellcode, &[
154/// 0xba, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
155/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156/// 0xde, 0xfc, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]);
157/// # Ok(())
158/// # }
159/// ```
160///
161/// Writes a shellcode that copies another buffer, with doing no dynamic
162/// allocation.
163///
164/// ```ignore
165/// use shellcoder::{Op as _, Shellcoder as _};
166/// # #[cfg(feature = "std")]
167/// use shellcoder::r#static::Shellcoder;
168///
169/// use shellcoder::ops;
170///
171/// fn get_buffer() -> &'static [u8] {
172/// b"pwnd"
173/// }
174///
175/// # use shellcoder::Result;
176/// # #[cfg(feature = "std")]
177/// # pub fn main() -> Result<()> {
178/// let some_payload: &[u8] = get_buffer();
179///
180/// let mut scratch_buffer = [0u8; 42];
181///
182/// let shellcode = Shellcoder::new(&mut scratch_buffer)
183/// .push_buffer(some_payload)?
184/// .get();
185/// assert_eq!(&shellcode[..4], b"pwnd");
186/// # Ok(())
187/// # }
188/// ```
189pub trait Shellcoder: fmt::Debug {
190 /// Pushes an operation, and returns the number of bytes that have been
191 /// written.
192 ///
193 /// # Errors
194 ///
195 /// - [`error::Error::OutputBufferTooSmall`]: the provided output buffer is too small
196 /// to contain the result of the operation.
197 /// - [`Error:Io`]: an I/O error occurred.
198 fn add<O>(&mut self, op: impl Borrow<O>) -> Result<&mut Self>
199 where
200 O: Op;
201
202 /// Advances the cursor by n bytes, filling gaps with zeroes.
203 ///
204 /// # Errors
205 ///
206 /// - [`error::Error::OutputBufferTooSmall`]: the provided output buffer is too small
207 /// to contain the result of the operation.
208 /// - [`Error:Io`]: an I/O error occurred.
209 #[inline]
210 fn advance(&mut self, n: usize) -> Result<&mut Self> {
211 self.add(ops::Advance::new(n))
212 }
213
214 /// Fills with a certain number of bytes.
215 ///
216 /// # Errors
217 ///
218 /// - [`error::Error::OutputBufferTooSmall`]: the provided output buffer is too small
219 /// to contain the result of the operation.
220 /// - [`Error:Io`]: an I/O error occurred.
221 #[inline]
222 fn fill(&mut self, len: usize, chr: u8) -> Result<&mut Self> {
223 self.add(ops::Fill::new(len, chr))
224 }
225
226 /// Pushes an integer in big endian.
227 ///
228 /// # Errors
229 ///
230 /// - [`error::Error::OutputBufferTooSmall`]: the provided output buffer is too small
231 /// to contain the result of the operation.
232 /// - [`Error:Io`]: an I/O error occurred.
233 #[inline]
234 fn int_be<I>(&mut self, i: I) -> Result<&mut Self>
235 where
236 I: ops::EncodableInteger,
237 {
238 self.add(ops::WriteInteger::<I>::new_be(i))
239 }
240
241 /// Pushes an integer in little endian.
242 ///
243 /// # Errors
244 ///
245 /// - [`error::Error::OutputBufferTooSmall`]: the provided output buffer is too small
246 /// to contain the result of the operation.
247 /// - [`Error:Io`]: an I/O error occurred.
248 #[inline]
249 fn int_le<I>(&mut self, i: I) -> Result<&mut Self>
250 where
251 I: ops::EncodableInteger,
252 {
253 self.add(ops::WriteInteger::<I>::new_le(i))
254 }
255
256 /// Pushes a buffer.
257 ///
258 /// # Errors
259 ///
260 /// - [`error::Error::OutputBufferTooSmall`]: the provided output buffer is too small
261 /// to contain the result of the operation.
262 /// - [`error::Error:Io`]: an I/O error occurred.
263 #[inline]
264 fn push_buffer(&mut self, buffer: impl AsRef<[u8]>) -> Result<&mut Self> {
265 self.add(ops::WriteBuffer::new(&buffer))
266 }
267}