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}