1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
#include "execmem.h"
#include "darwin/manual-syscall.h"
#include "substitute.h"
#include <mach/mach.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <errno.h>
#include <stdio.h>
int execmem_write(void *dest, const void *src, size_t len) {
/* Use vm_region to determine the original protection, so we can mprotect
* it back afterwards. (Note: PROT_* are equal to VM_PROT_*.) */
vm_address_t region = (vm_address_t) dest;
vm_size_t region_len = 0;
struct vm_region_submap_short_info_64 info;
mach_msg_type_number_t info_count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
natural_t max_depth = 99999;
kern_return_t kr = vm_region_recurse_64(mach_task_self(), ®ion, ®ion_len,
&max_depth,
(vm_region_recurse_info_t) &info,
&info_count);
if (kr) {
/* Weird; this probably means the region doesn't exist, but we should
* have already read from the memory in order to generate the patch. */
errno = 0;
return SUBSTITUTE_ERR_VM;
}
uintptr_t lopage = (uintptr_t) dest & ~PAGE_MASK;
uintptr_t hipage = ((uintptr_t) dest + len + PAGE_MASK) & ~PAGE_MASK;
/* We do the syscall manually just in case the user is trying to write to
* the mprotect syscall stub itself, or one of the functions it calls.
* (Obviously, it will still break if the user targets some libsubstitute
* function within the same page as this one, though.) */
int ret = manual_syscall(SYS_mprotect, lopage, hipage - lopage,
PROT_READ | PROT_WRITE, 0, 0);
if (ret) {
errno = ret;
return SUBSTITUTE_ERR_VM;
}
/* volatile to avoid compiler transformation to call to memcpy */
volatile uint8_t *d8 = dest;
const uint8_t *s8 = src;
while (len--)
*d8++ = *s8++;
int oldprot = info.protection & (PROT_READ | PROT_WRITE | PROT_EXEC);
ret = manual_syscall(SYS_mprotect, lopage, hipage - lopage,
oldprot, 0, 0);
if (ret) {
errno = ret;
return SUBSTITUTE_ERR_VM;
}
return SUBSTITUTE_OK;
}
|