diff --git a/20-vmreadv/poke.c b/20-vmreadv/poke.c
index 9883a04..126a1fd 100644
--- a/20-vmreadv/poke.c
+++ b/20-vmreadv/poke.c
@@ -13,8 +13,22 @@
// Read memory from pid's memory, starting at ptr and len bytes.
// Returns an heap-allocated buffer
void *peek(pid_t pid, const void *ptr, size_t len) {
- // FIXME: process_vm_readv(2)
- return NULL;
+ struct iovec local[1];
+ struct iovec remote[1];
+
+ void * buffer = malloc(len);
+ if (!buffer) die("malloc");
+
+ remote[0].iov_base = (void*)ptr;
+ remote[0].iov_len = len;
+ local[0].iov_base = buffer;
+ local[0].iov_len = len;
+
+ ssize_t nread = process_vm_readv(pid, local, 1, remote, 1, 0);
+ if (nread != len)
+ die("process_vm_readv");
+
+ return buffer;
}
// Copy memory from this process to the remote process (pid).
@@ -22,7 +36,17 @@ void *peek(pid_t pid, const void *ptr, size_t len) {
// Local Address: buffer
// Length: len
void poke(pid_t pid, void *ptr, void *buffer, size_t len) {
- // FIXME: process_vm_writev(2)
+ struct iovec local[1];
+ struct iovec remote[1];
+
+ remote[0].iov_base = ptr;
+ remote[0].iov_len = len;
+ local[0].iov_base = buffer;
+ local[0].iov_len = len;
+
+ ssize_t nread = process_vm_writev(pid, local, 1, remote, 1, 0);
+ if (nread != len)
+ die("process_vm_readv");
}
int main(int argc, char* argv[]) {
@@ -35,17 +59,39 @@ int main(int argc, char* argv[]) {
int n = sscanf(argv[2], "0x%p", &ptr);
if (n != 1) die("sscanf");
- // FIXME: Read the PyObject obj in remote process (pid, ptr)
- // FIXME: Extract the type name (Py_TYPE(obj)->tp_name
- // FIXME: If "float" PyFloatObject: square ob_fvalue
- // FIXME: If "int" PyLongObject: set the lowest 2 bytes to 0xabba
-
- // Example output of make run (two invocations of poke):
- // pointers ['0x7f6050b5da90', '0x7f60507cd410', '0x7f60507cd410']
- // objects ['0xdeadbeef', 23.0, 23.0]
- // PyObject @ 0x7f6050b5da90: refcount=3, type=int
- // PyLongObject: ob_digit[0] = 0x1eadbeef
- // PyObject @ 0x7f60507cd410: refcount=4, type=float
- // PyFloatObject: ob_fval=23.000000
- // object ['0xdeadabba', 529.0, 529.0]
+ // We get the object, which contains a pointer to its type object
+ PyObject *obj = peek(pid, ptr, sizeof(PyObject));
+ // Get the type object
+ PyTypeObject *type = peek(pid, Py_TYPE(obj), sizeof(PyTypeObject));
+ // Get (parts of) the type name
+ char *typename = peek(pid, type->tp_name, 16);
+ typename[15] = 0; // Make sure we have an zero terminated string
+
+ // Some debug output
+ printf(" PyObject @ %p: refcount=%ld, type=%s\n", ptr, Py_REFCNT(obj), typename);
+
+ if (strcmp(typename, "float") == 0) {
+ // If we have a float, we peek the object again with the correct size
+ PyFloatObject *D = peek(pid, ptr, sizeof(PyFloatObject));
+
+ // Print the floating point value
+ printf(" PyFloatObject: ob_fval=%f\n", D->ob_fval);
+
+ // Square the value
+ D->ob_fval *= D->ob_fval;
+
+ // Write the object back to python memory
+ poke(pid, ptr, D, sizeof(PyFloatObject));
+ }
+
+ if (strcmp(typename, "int") == 0) {
+ // Same procedure for PyLongObject. Noteworthy here is, that
+ // Python supports arbitrary large integers. However, we only
+ // manipulate the lower 16 bits here.
+ PyLongObject *L = peek(pid, ptr, sizeof(PyLongObject));
+ printf(" PyLongObject: ob_digit[0] = 0x%x\n", L->ob_digit[0]);
+ L->ob_digit[0] &= ~0xffff;
+ L->ob_digit[0] |= 0xabba;
+ poke(pid, ptr, L, sizeof(PyLongObject));
+ }
}