About a month and a half ago I wrote a post about dumping memory on Mac OS X which was followed by a post introducing intropy, a Python framework I’m developing that enables you to effortlessly analyze software. In this post I am going to demonstrate some of the power of (a very early implementation of) intropy by taking you through a script that writes some bytes to memory in another process then reads them back.
Below is the complete code to spawn a new process, execute a command, write a block of data into the new process, and then read that data back into our process. You’ll notice that compared to my description of how to dump memory on Mac OS X this Python script is a lot less scary. One thing that I really like about intropy is that you don’t need to understand the details of how a call to task_for_pid() or mach_vm_read() works, all you need to do is describe what you want to accomplish and get it done.
1 """
2 Module: mem
3 Author: Dean Pucsek <dean@lightbulbone.com>
4 Date: June 2011
5
6 Copyright (C) 2011 Dean Pucsek. All rights reserved.
7
8 Write a set of bytes to memory then read them back.
9 """
10
11 import idb
12
13 def main():
14 addr = 0x100001000
15 sz = 0x10
16
17 payload = "\x41\x42\x43\x44"
18 payload += "\x45\x46\x47\x48"
19 payload += "\x49\x4a\x4b\x4c"
20 payload += "\x4d\x4e\x4f\x50"
21
22 dbg = idb.idb()
23 ts = dbg.spawn("sleep 90")
24
25 dbg.memwrite(ts, addr, payload)
26
27 buf = dbg.memread(ts, addr, sz)
28
29 for i in range(0,sz):
30 print hex(ord(buf.raw[i])),
31
32 print ' '
33
34 if __name__ == "__main__":
35 main()
While I’m sure you can figure out what each line does, especially if you are familiar with Python, lets step through some of the more interesting bits.
Line 11
This line simply imports the idb module of intropy. Note that as of writing this post I still have yet to publicly release the intropy code base so you’ll have to wait before you can try this out yourself.
Lines 14-20
These lines initialize some of the data we need for the read and write. The variable names and contents should speak for themselves, but if you’r curious the payload is nothing more than the ABC’s!
Line 22
Here we are initializing our dbg variable with a new instance of the idb class. If you’re not familiar with Python classes and instantiation I highly recommend you check out the documentation.
Line 23
Rather than attach ourselves to an existing process we have decided to spawn a new one. The spawn() method takes care of forking, executing, and attaching a new process to our session. It returns an object known as a task_struct in intropy which contains various pieces of information about the process and resources it is associated with. In intropy you should never need to directly access this structure. The reason it is returned is so that other functions can make use of it. In future versions the task_struct will likely not be exposed.
Line 25
Write to memory! Yep, it’s a one liner, were you hoping for more? This line will attempt to copy the payload into the specified location of the spawned process. In order for this to be successful the destination address must be writable.
Line 27
Read sz bytes starting at addr in the spawned process! Aren’t one liners awesome? This call returns a buffer that contains the data read which is implemented using a Python ctypes array (hence the funky printing on lines 29-32). In a future revision of intropy I may have this function return a Python string instead in order to increase the amount of existing code that can be used to analyze the returned data.
That, my friends, is how you write and read memory in intropy. Although this example is quite simple it definitely shows how powerful intropy can be in terms of reduced coding, more descriptive code, and portability.