Skip to content

Instantly share code, notes, and snippets.

@stephancasas
Last active April 25, 2024 17:18
Show Gist options
  • Save stephancasas/41e0ab965f1a63b214e81837b303171c to your computer and use it in GitHub Desktop.
Save stephancasas/41e0ab965f1a63b214e81837b303171c to your computer and use it in GitHub Desktop.
Modern utility functions for Mach task read/write operations.
//
// MachVMReadWrite.swift
//
// Created by Stephan Casas on 4/25/24.
//
import Foundation;
/// Starting at the given address, read the byte values into the given buffer.
/// - Parameters:
/// - address: The address at which to begin reading values.
/// - buffer: The buffer into which read values will be read.
/// - taskPort: The task port with which to perform the read operation.
/// - Returns: A value of `true` should return when the read operation is successful.
@discardableResult
func vm_read_values(startingAt address: Int, into buffer: inout [UInt8], from taskPort: mach_port_t = mach_task_self_) -> Bool {
var read_mem = vm_offset_t();
var copy_len = mach_msg_type_number_t();
guard mach_vm_read(
taskPort,
.init(bitPattern: .init(address)),
.init(buffer.count),
&read_mem, &copy_len
) == KERN_SUCCESS else {
return false;
}
var _buffer = buffer;
_buffer.withUnsafeMutableBytes({
let _ = memcpy($0.baseAddress, .init(bitPattern: read_mem), buffer.count);
});
buffer = _buffer;
mach_vm_deallocate(
mach_task_self_,
mach_vm_address_t(read_mem),
mach_vm_size_t(copy_len));
return true;
}
/// Starting at the address of the given pointer, read the byte values into the given buffer.
/// - Parameters:
/// - pointer: The location in memory at which to begin reading values.
/// - buffer: The buffer into which read values will be read.
/// - taskPort: The task port with which to perform the read operation.
/// - Returns: A value of `true` should return when the read operation is successful.
@discardableResult
func vm_read_values(startingAt pointer: UnsafeRawPointer, into buffer: inout [UInt8], from taskPort: mach_port_t = mach_task_self_) -> Bool {
vm_read_values(startingAt: .init(bitPattern: pointer), into: &buffer, from: taskPort)
}
/// Read the byte value stored at the given address into the given `inout` value.
/// - Parameters:
/// - address: The address from which to read.
/// - value: The value into which the read value will be copied.
/// - taskPort: The task port with which to perform the read operation.
/// - Returns: A value of `true` should return when the read operation is successful.
@discardableResult
func vm_read_value(at address: Int, into value: inout UInt8, from taskPort: mach_port_t = mach_task_self_) -> Bool {
var buffer = [UInt8](repeating: 0, count: 1);
let result = vm_read_values(startingAt: address, into: &buffer, from: taskPort);
value = buffer[0];
return result;
}
/// Read the byte value stored at the given address into the given `inout` value.
/// - Parameters:
/// - pointer: The location in memory from which to read.
/// - value: The value into which the read value will be copied.
/// - taskPort: The task port with which to perform the read operation.
/// - Returns: A value of `true` should return when the read operation is successful.
@discardableResult
func vm_read_value(at pointer: UnsafeRawPointer, into value: inout UInt8, from taskPort: mach_port_t = mach_task_self_) -> Bool {
vm_read_value(at: .init(bitPattern: pointer), into: &value, from: taskPort)
}
/// Write the given value to the given address in the memory of the given task port.
/// - Parameters:
/// - value: The value to write.
/// - address: The memory address at which to write `value`.
/// - taskPort: The task port with which to perform the write operation.
/// - Returns: A value of `true` should return when the write operation is successful.
@discardableResult
func vm_write_value(_ value: UInt8, at address: Int, of taskPort: mach_port_t = mach_task_self_) -> Bool {
// Set address protection to read/write.
guard mach_vm_protect(
taskPort,
.init(bitPattern: .init(address)),
1, 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE
) == KERN_SUCCESS else {
return false;
}
// Perform write operation.
guard withUnsafePointer(to: value, {
mach_vm_write(taskPort, .init(bitPattern: .init(address)), .init(bitPattern: $0), 1)
}) == KERN_SUCCESS else {
return false;
}
// Restore address protection to read-only.
guard mach_vm_protect(
taskPort,
.init(bitPattern: .init(address)),
1, 0, VM_PROT_READ | VM_PROT_EXECUTE
) == KERN_SUCCESS else {
return false;
}
return true;
}
/// Write the given value to the pointer-given location in the memory of the given task port.
/// - Parameters:
/// - value: The value to write.
/// - pointer: The location in memory at which to write `value`.
/// - taskPort: The task port with which to perform the write operation.
/// - Returns: A value of `true` should return when the write operation is successful.
@discardableResult
func vm_write_value(_ value: UInt8, at pointer: UnsafeRawPointer, of taskPort: mach_port_t = mach_task_self_) -> Bool {
vm_write_value(value, at: .init(bitPattern: pointer), of: taskPort)
}
/// Starting at the given address, write the given buffer into the memory of the given task port.
/// - Parameters:
/// - values: The buffer of values to write.
/// - address: The memory address at which to begin writing.
/// - taskPort: The task port with which to perform the write operation.
/// - Returns: A value of `true` should return when the write operation is successful.
@discardableResult
func vm_write_values(_ values: [UInt8], startingAt address: Int, of taskPort: mach_port_t = mach_task_self_) -> Bool {
var address = address;
for value in values {
if !vm_write_value(value, at: address, of: taskPort) {
return false;
}
address += 1;
}
return true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment