Payloads Module

std::string intToHex(uint64_t value)

Converts a 64-bit unsigned integer to its hexadecimal string representation.

Parameters:

value – The 64-bit unsigned integer to convert.

Returns:

A std::string containing the “0x” prefixed hexadecimal representation of the value (uppercase).

struct PayloadData
#include <PayloadBuilder.h>

Helper struct to encapsulate payload data for the builder.

This struct groups a Payload object, associated registers, and an optional offset for the next RIP (Instruction Pointer).

Note

The registers member is stored by value, meaning a copy is made.

Public Functions

inline PayloadData(Payload &payload_ref, const std::vector<Register> &regs = {}, std::optional<size_t> rip_ptr_offset = std::nullopt)

Constructs a PayloadData instance.

Parameters:
  • payload_ref – Reference to the Payload.

  • regs – Optional vector of Registers pointing to this buffer when RIP control is triggered (defaults to empty).

  • rip_ptr_offset – Optional offset of a field containing a function pointer which if overwritten can lead to RIP control. If nullopt, then this payload does not contain such a field.

Public Members

Payload &payload

Reference to the Payload object.

const std::vector<Register> registers

Registers pointing to this buffer when RIP control is triggered.

const std::optional<size_t> rip_ptr_offset

Optional offset of a field containing a function pointer which if overwritten can lead to RIP control. If nullopt, then this payload does not contain such a field.

struct RopAction
#include <RopChain.h>

Represents a single ROP (Return-Oriented Programming) action.

A RopAction is a sequence of 64-bit values that form part of a ROP chain. These values can represent addresses, immediate data, or arguments for gadgets.

Public Members

std::vector<uint64_t> values

The sequence of 64-bit values comprising this ROP action.

class Payload
#include <Payload.h>

Manages a dynamic, contiguous block of memory, tracking used sections.

This class provides functionalities to allocate, reserve, release, and write data to a buffer. It maintains a separate tracking mechanism to mark which bytes in the buffer are considered “used” or “reserved”. It also offers methods to find empty contiguous blocks for new data.

Public Functions

Payload(int size)

Constructs a new Payload object with a specified size.

Initializes the internal data buffer and a corresponding used_bytes tracking vector, marking all bytes as free initially.

Parameters:

size – The total size in bytes for the payload buffer.

Payload(const Payload &other)

Copy constructor for the Payload class.

Creates a new Payload object by deep-copying the data, used bytes map, and used size from another Payload instance.

Parameters:

other – The Payload object to copy from.

size_t Size()

Returns the total size of the internal data buffer.

Returns:

The total size of the buffer in bytes.

std::vector<uint8_t> &GetData()

Gets a reference to the raw internal data vector.

Warning

Modifying this vector directly can lead to inconsistencies with used_bytes_.

Returns:

A reference to the underlying std::vector<uint8_t> data buffer.

std::vector<uint8_t> GetUsedData() const

Returns a copy of the data that is currently marked as “used”.

Returns:

A new std::vector<uint8_t> containing the data from the beginning of the buffer up to used_size_.

bool CheckFree(uint64_t offset, uint64_t len, bool throws = false)

Checks if a specified range of bytes is free (not marked as used).

Parameters:
  • offset – The starting offset in the buffer to check.

  • len – The length of the contiguous block to check.

  • throws – If true, an ExpKitError is thrown if the range is not free or out of bounds. If false, it simply returns false.

Throws:

ExpKitError – if throws is true and the range is out of bounds or occupied.

Returns:

true if the entire range is free and within bounds, false otherwise.

uint8_t *Reserve(uint64_t offset, uint64_t len)

Reserves a contiguous block of memory and marks it as used.

This method checks if the specified range is free. If so, it marks the bytes as used and returns a pointer to the beginning of the reserved block within the internal data buffer. It updates used_size_ if the new reservation extends beyond the previously used area.

Parameters:
  • offset – The starting offset in the buffer to reserve.

  • len – The length of the contiguous block to reserve.

Throws:

ExpKitError – if the range is not free or out of bounds.

Returns:

A uint8_t* pointer to the reserved memory location within the buffer.

void Release(uint64_t offset, uint64_t len)

Releases a previously reserved block of memory.

Marks the specified range of bytes as free. If the released block was at the end of the used_size_ area, used_size_ is adjusted downwards.

Parameters:
  • offset – The starting offset of the block to release.

  • len – The length of the block to release.

uint64_t *ReserveU64(uint64_t offset)

Reserves space for a uint64_t at a given offset.

Warning

This function assumes the underlying buffer’s memory address will not change during its lifetime, which is generally true for std::vector unless it’s resized.

Parameters:

offset – The starting offset for the uint64_t.

Throws:

ExpKitError – if the space is not free or out of bounds.

Returns:

A uint64_t* pointer to the reserved memory location.

uint32_t *ReserveU32(uint64_t offset)

Reserves space for a uint32_t at a given offset.

Warning

This function assumes the underlying buffer’s memory address will not change during its lifetime, which is generally true for std::vector unless it’s resized.

Parameters:

offset – The starting offset for the uint32_t.

Throws:

ExpKitError – if the space is not free or out of bounds.

Returns:

A uint32_t* pointer to the reserved memory location.

void Set(uint64_t offset, void *src, size_t len)

Sets a block of bytes in the payload.

Reserves the specified range and then copies data from src into it.

Parameters:
  • offset – The starting offset in the payload.

  • src – A pointer to the source data to copy.

  • len – The number of bytes to copy.

Throws:

ExpKitError – if the space is not free or out of bounds.

void Set(uint64_t offset, const std::vector<uint8_t> &bytes)

Sets a block of bytes from a std::vector in the payload.

Reserves the necessary space and then copies the bytes from the provided vector.

Parameters:
  • offset – The starting offset in the payload.

  • bytes – The std::vector containing the data to copy.

Throws:

ExpKitError – if the space is not free or out of bounds.

void SetU32(uint64_t offset, uint32_t value)

Sets a 32-bit unsigned integer value at a specific offset.

Reserves space for a uint32_t and writes the value.

Parameters:
  • offset – The starting offset in the payload.

  • value – The uint32_t value to set.

Throws:

ExpKitError – if the space is not free or out of bounds.

void SetU64(uint64_t offset, uint64_t value)

Sets a 64-bit unsigned integer value at a specific offset.

Reserves space for a uint64_t and writes the value.

Parameters:
  • offset – The starting offset in the payload.

  • value – The uint64_t value to set.

Throws:

ExpKitError – if the space is not free or out of bounds.

std::optional<uint64_t> FindEmpty(uint64_t len, uint64_t alignment = 1, uint64_t min_offset = 0)

Finds the first contiguous block of empty (unused) bytes of a given length.

Searches for a free block starting from min_offset, respecting optional alignment. The algorithm is O(n) where n is the size of the buffer.

Parameters:
  • len – The desired length of the empty block.

  • alignment – The required alignment for the found offset (default is 1).

  • min_offset – The minimum offset to start searching from (default is 0).

Returns:

An std::optional containing the found offset if a suitable block is found, or std::nullopt otherwise.

Payload Snapshot()

Creates a snapshot of the current payload state.

Returns a new Payload object that is a deep copy of the current instance’s data, used bytes, and used size. This can be used for rollback purposes.

Returns:

A new Payload object representing the current state.

void Restore(const Payload &snapshot)

Restores the payload state from a given snapshot.

Replaces the current instance’s data, used bytes map, and used size with those from the provided snapshot.

Parameters:

snapshot – The Payload object to restore from.

class PayloadBuilder
#include <PayloadBuilder.h>

A class designed to construct and optimize exploit payloads.

This builder manages multiple payload components, ROP (Return-Oriented Programming) chains, and stack pivots to create a cohesive and functional exploit payload. It attempts to find suitable stack pivots and apply ROP actions efficiently.

The implementation tracks StackShiftingInfo for every RopAction. If two actions can be stored adjacently, the StackShiftingInfo between them will represent an empty shift.

Public Functions

inline PayloadBuilder(const Pivots &pivots, uint64_t kaslr_base)

Constructs a PayloadBuilder instance.

Parameters:
  • pivots – Available stack pivot gadgets.

  • kaslr_base – The Kernel Address Space Layout Randomization base address.

void AddPayload(Payload &payload, const std::vector<Register> &registers = {}, std::optional<size_t> rip_ptr_offset = std::nullopt)

Adds a new payload component to the builder.

Parameters:
  • payload – A reference to the Payload object to add.

  • registers – Optional vector of Registers pointing to this buffer when RIP control is triggered (defaults to empty).

  • rip_ptr_offset – Optional offset of a field containing a function pointer which if overwritten can lead to RIP control. If nullopt, then this payload does not contain such a field.

void AddPayload(Payload &payload, std::optional<Register> reg = std::nullopt, std::optional<size_t> rip_ptr_offset = std::nullopt)

Adds a new payload component with an optional single register.

Parameters:
  • payload – A reference to the Payload object to add.

  • reg – Optional register pointing to this buffer when RIP control is triggered (defaults to nullopt - so no register points to this buffer).

  • rip_ptr_offset – Optional offset of a field containing a function pointer which if overwritten can lead to RIP control. If nullopt, then this payload does not contain such a field.

void AddRopChain(const RopChain &rop_chain)

Appends a ROP chain to the builder’s sequence of ROP actions.

Parameters:

rop_chain – The RopChain object to add.

void SetRopShift(const uint64_t shift_value)

Uses stack shift gadgets to shift the stack by at least shift_value.

This method is useful for moving the rop chain towards the end of the buffer. This can prevent function calls from clobbering data before the buffer.

Parameters:

shift_value – Shifts the stack by at least shift_value.

bool Build(bool need_pivot = true)

Attempts to build the final payload.

This method tries to find a suitable stack pivot, applies it to the payload, and then attempts to integrate all ROP actions, performing stack shifts as necessary.

Parameters:

need_pivot – If true, the builder will explicitly look for a pivot (defaults to true).

Throws:

ExpKitError – if multiple RIP offsets are found when need_pivot is true.

Returns:

true if a successful payload is built, false otherwise.

void PrintDebugInfo() const

Prints debug information about the built payload, if successful.

This includes details about the chosen stack pivot, stack shifts, and ROP chain layout.

StackPivot GetStackPivot()

Returns the chosen stack pivot.

This function may be called after Build() to get the stack pivot gadget that was chosen.

class RopChain
#include <RopChain.h>

Manages an ordered sequence of ROP actions to form a ROP chain.

The RopChain class allows for the construction of complex ROP chains by adding individual ROP actions or raw 64-bit values. It handles KASLR (Kernel Address Space Layout Randomization) offsets and argument substitution for actions defined by a Target.

Public Functions

RopChain(Target &target, uint64_t kaslr_base)

Constructs a new RopChain.

Parameters:
  • target – A reference to the Target object which provides definitions for ROP actions.

  • kaslr_base – The base address for KASLR, used to adjust symbol addresses.

void AddRopAction(RopActionId id, std::vector<uint64_t> arguments = {})

Adds a predefined ROP action to the chain.

This method retrieves the sequence of ROP items for a given action ID from the associated Target and constructs a RopAction, substituting arguments and applying KASLR offsets where necessary.

Parameters:
  • id – The ID of the ROP action to add.

  • arguments – A vector of 64-bit arguments to substitute into the action. The index of an argument in this vector corresponds to its item.value when item.type == RopItemType::ARGUMENT.

Throws:

ExpKitError – If an unexpected RopAction item type is encountered or if there are not enough arguments provided for an action.

void Add(uint64_t item, bool offset = false)

Adds a raw 64-bit item directly to the ROP chain as a single-value action.

This is useful for adding arbitrary values (e.g., stack pivots, return addresses, or immediate values) that are not part of a predefined RopAction.

Parameters:
  • item – The 64-bit value to add.

  • offset – If true, the kaslr_base_ will be added to the item. Defaults to false.

std::vector<uint8_t> GetData() const

Retrieves the entire ROP chain as a vector of bytes.

The 64-bit items in the chain are converted to a contiguous byte array. This is useful for writing the ROP chain directly to memory or a file.

Returns:

A std::vector<uint8_t> representing the ROP chain in byte format.

std::vector<uint64_t> GetDataWords() const

Retrieves the entire ROP chain as a vector of 64-bit words.

This method collects all individual 64-bit values from the sequence of RopActions into a single flat vector.

Returns:

A std::vector<uint64_t> representing the ROP chain as 64-bit words.

uint64_t GetByteSize() const

Calculates the total size of the ROP chain in bytes.

Returns:

The total size of the ROP chain in bytes.

std::vector<RopAction> GetActions() const

Retrieves the list of individual RopAction objects that compose this chain.

Returns:

A std::vector<RopAction> containing all added ROP actions.

Public Members

uint64_t kaslr_base_

The KASLR base address used for symbol offsetting.

std::vector<RopAction> actions_

Stores the ordered sequence of ROP actions.