|
| 1 | +#include <Python.h> |
| 2 | +#include <sys/types.h> |
| 3 | +#include <mach/mach_init.h> |
| 4 | +#include <mach/mach_traps.h> |
| 5 | +#include <mach/mach_types.h> |
| 6 | +#include <mach/mach_vm.h> |
| 7 | + |
| 8 | +static PyObject *MachError; |
| 9 | + |
| 10 | +static PyObject *mach_error(kern_return_t ret) { |
| 11 | + return PyErr_Format(MachError, "kernel return code %d", (int)ret); |
| 12 | +} |
| 13 | + |
| 14 | +static PyObject *pymach_task_self(PyObject *self, PyObject *args) { |
| 15 | + return Py_BuildValue("i", mach_task_self()); |
| 16 | +} |
| 17 | + |
| 18 | +static PyObject *pymach_task_for_pid(PyObject *self, PyObject *args) { |
| 19 | + int pid; |
| 20 | + task_t task; |
| 21 | + kern_return_t ret; |
| 22 | + if (!PyArg_ParseTuple(args, "i", &pid)) return NULL; |
| 23 | + ret = task_for_pid(mach_task_self(), pid, &task); |
| 24 | + if (ret) return mach_error(ret); |
| 25 | + return Py_BuildValue("i", task); |
| 26 | +} |
| 27 | + |
| 28 | +static PyObject *pymach_vm_protect(PyObject *self, PyObject *args) { |
| 29 | + task_t task; |
| 30 | + mach_vm_address_t address; |
| 31 | + mach_vm_size_t size; |
| 32 | + int prot; |
| 33 | + kern_return_t ret; |
| 34 | + if (!PyArg_ParseTuple(args, "iKLi", &task, &address, &size, |
| 35 | + &prot)) return NULL; |
| 36 | + ret = mach_vm_protect(task, address, size, 0, prot); |
| 37 | + if (ret) return mach_error(ret); |
| 38 | + Py_RETURN_NONE; |
| 39 | +} |
| 40 | + |
| 41 | +static PyObject *pymach_vm_read(PyObject *self, PyObject *args) { |
| 42 | + task_t task; |
| 43 | + mach_vm_address_t address; |
| 44 | + mach_vm_size_t size; |
| 45 | + vm_offset_t data; |
| 46 | + mach_msg_type_number_t dataCnt; |
| 47 | + kern_return_t ret; |
| 48 | + if (!PyArg_ParseTuple(args, "iKL", &task, &address, &size)) return NULL; |
| 49 | + ret = mach_vm_read(task, address, size, &data, &dataCnt); |
| 50 | + if (ret) return mach_error(ret); |
| 51 | + PyObject *val = Py_BuildValue("s#", data, dataCnt); |
| 52 | + mach_vm_deallocate(mach_task_self(), data, dataCnt); |
| 53 | + return val; |
| 54 | +} |
| 55 | + |
| 56 | +static PyObject *pymach_vm_write(PyObject *self, PyObject *args) { |
| 57 | + task_t task; |
| 58 | + mach_vm_address_t address; |
| 59 | + char *buf; |
| 60 | + int len; |
| 61 | + kern_return_t ret; |
| 62 | + if (!PyArg_ParseTuple(args, "iKt#", &task, &address, |
| 63 | + &buf, &len)) return NULL; |
| 64 | + ret = mach_vm_write(task, address, (vm_offset_t)buf, len); |
| 65 | + if (ret) return mach_error(ret); |
| 66 | + Py_RETURN_NONE; |
| 67 | +} |
| 68 | + |
| 69 | +static PyMethodDef MachMethods[] = { |
| 70 | + {"task_self", pymach_task_self, METH_VARARGS, |
| 71 | + "Get a Mach port for the current task"}, |
| 72 | + {"task_for_pid", pymach_task_for_pid, METH_VARARGS, |
| 73 | + "Get a Mach port for the task corresponding to a pid"}, |
| 74 | + {"vm_protect", pymach_vm_protect, METH_VARARGS, |
| 75 | + "Change memory protection in another task"}, |
| 76 | + {"vm_read", pymach_vm_read, METH_VARARGS, |
| 77 | + "Read memory from another task"}, |
| 78 | + {"vm_write", pymach_vm_write, METH_VARARGS, |
| 79 | + "Write memory to another task"}, |
| 80 | + {NULL, NULL, 0, NULL} |
| 81 | +}; |
| 82 | + |
| 83 | +PyMODINIT_FUNC initmach(void) { |
| 84 | + PyObject *m = Py_InitModule("mach", MachMethods); |
| 85 | + if (!m) return; |
| 86 | + MachError = PyErr_NewException("mach.MachError", NULL, NULL); |
| 87 | + Py_INCREF(MachError); |
| 88 | + PyModule_AddObject(m, "MachError", MachError); |
| 89 | + PyModule_AddObject(m, "VM_PROT_NONE", PyInt_FromLong(VM_PROT_NONE)); |
| 90 | + PyModule_AddObject(m, "VM_PROT_READ", PyInt_FromLong(VM_PROT_READ)); |
| 91 | + PyModule_AddObject(m, "VM_PROT_WRITE", PyInt_FromLong(VM_PROT_WRITE)); |
| 92 | + PyModule_AddObject(m, "VM_PROT_EXECUTE", PyInt_FromLong(VM_PROT_EXECUTE)); |
| 93 | + PyModule_AddObject(m, "VM_PROT_DEFAULT", PyInt_FromLong(VM_PROT_DEFAULT)); |
| 94 | + PyModule_AddObject(m, "VM_PROT_ALL", PyInt_FromLong(VM_PROT_ALL)); |
| 95 | +} |
0 commit comments