Last active
April 25, 2024 17:18
-
-
Save stephancasas/41e0ab965f1a63b214e81837b303171c to your computer and use it in GitHub Desktop.
Modern utility functions for Mach task read/write operations.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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, ©_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