Linux memory manipulation using .NET Core 2

Recently, I wanted to port my .NET Framework Windows application to Linux. Obviously, since .NET Core 2 is there, I decided to use it instead of Mono. It wasn’t that much of pain until I had to re-implement a class to manipulate the memory of a remote process. I did a quick research and at first it looked pretty complicated. Apparently, most of the guides I found on the internet were implementing memory manipulation using ptrace. Luckily, since Linux 3.2 we can use process_vm_readv and process_vm_writev.

Implementation

Referring to the man page, you can see that first of all we have to implement the iovec struct.

struct iovec {
  void  *iov_base;    /* Starting address */
  size_t iov_len;     /* Number of bytes to transfer */
};

The first field is a pointer. As a replacement for size_t, I’ll be using int because that’s what Unsafe.SizeOf<T>() returns. Here’s the final C# implementation:

[StructLayout(LayoutKind.Sequential)]
unsafe struct iovec
{
  public void* iov_base;
  public int iov_len;
}

Let’s implement process_vm_readv now. The man page shows the following method signature:

ssize_t process_vm_readv(pid_t pid,
                        const struct iovec *local_iov,
                        unsigned long liovcnt,
                        const struct iovec *remote_iov,
                        unsigned long riovcnt,
                        unsigned long flags);

pid is the Process ID accessible from the Id property of the System.Diagnostics.Process class. Next parameter is a pointer to the local iovec struct that will be holding the result of the operation. liovcnt is the count of local structs. This parameter is useful when we want to perform multiple memory operations, but my implementation doesn’t do that. The following param is again a pointer to the iovec struct, but this time it’s the remote one that holds information about the memory fragment we’re trying to read. riovcnt is the remote equivalent to liovcnt. According to the man page, the flags argument is currently unused and does nothing. process_vm_readv on success returns the number of bytes read.

Here’s the C# Pinvoke implementation:

[DllImport("libc")]
private static extern unsafe int process_vm_readv(int pid,
    iovec* local_iov,
    ulong liovcnt,
    iovec* remote_iov,
    ulong riovcnt,
    ulong flags);

process_vm_writev has exactly the same signature as process_vm_readv. The big difference lies in what these two calls do. process_vm_readv transfers the data from remote_iov to local_iov while process_vm_writev does the opposite.

[DllImport("libc")]
private static extern unsafe int process_vm_readv(int pid,
    iovec* local_iov,
    ulong liovcnt,
    iovec* remote_iov,
    ulong riovcnt,
    ulong flags);

Usage

Now as we got the API ready, let’s create some methods to access it.

Read:

public unsafe bool Read<T>(IntPtr address, out T value) where T : unmanaged
{
  var size = Unsafe.SizeOf<T>();
  var ptr = stackalloc byte[size];

  var localIo = new iovec
  {
    iov_base = ptr,
    iov_len = size
  };

  var remoteIo = new iovec
  {
    iov_base = address.ToPointer(),
    iov_len = size
  };
                
  var res = process_vm_readv(_process.Id, &localIo, 1, &remoteIo, 1, 0);

  value = *(T*)ptr;

  return res != -1;
}

Write:

public unsafe bool Write<T>(T value, IntPtr address) where T : unmanaged
{
  var ptr = &value;
  var size = Unsafe.SizeOf<T>();

  var localIo = new iovec
  {
    iov_base = ptr,
    iov_len = size
  };

  var remoteIo = new iovec
  {
    iov_base = address.ToPointer(),
    iov_len = size
  };

  var res = process_vm_writev(_process.Id, &localIo, 1, &remoteIo, 1, 0);

  return res != -1;
}

Make sure to enable unsafe code for these examples to work.

Reversing Flash Applications

Learn the basics of ActionScript Byte Code.

Flash is dying and close to its final death. Remember back when every browser game was made using that technology? These years are gone. However, Flash is still a fairly interesting technology. Let’s dig deeper into ActionScript, which is the programming language used to create Flash applications.

Getting started

To start you’ll need:
1. Basic understanding of object-oriented programming concepts (variables, methods, classes).
2. A Flash decompiler. In this tutorial I’ll be using JPEXS (requires Java).
3. A flash application to reverse. I’ll be using a sample application I made for this post.

My JPEXS settings. The theme I’m using is called Graphite. You can change your theme in Advanced Settings.

Let’s go!

Open the .swf file in JPEXS. You can do that by dragging and dropping it into the window. If you want to proceed with other Flash file than I linked above, there’s an option to dump the .swf straight from the memory of a process (Windows only).

You should see something like this.

Expand the scripts folder and open the main class (which usually is simply called Main). You’ll see two windows appear on the right side. First one is called ActionScript Source. It’s used to display source code generated by the decompiler. Actual instructions for the ActionScript Virtual Machine (AVM) are located in the second window called P-code source. What the decompiler really displays are simplified byte-code instructions. If you click on an instruction, JPEXS will display a short documentation describing what it does.

P-Code source window showing the P-code for function Main.

Play a little with the ActionScript editor (but don’t edit anything yet). As you may have noticed, the contents of P-code editor change as you navigate through the ActionScript code. That’s because it displays P-Code of the currently selected ActionScript code block.

Header

Click on the function Main inside the ActionScript source window. Now take a look at the P-Code editor.

method
name null
returns null

This is part stores basic data about the current code block. Since it’s the main function, name is null. The method doesn’t have a return type, so returns equals null as well.

Body

Now let’s have a quick look at the body section.

body
maxstack 3
localcount 2
initscopedepth 9
maxscopedepth 10

maxstack indicates how big the stack can get during the execution. Take a look at the ActionScript code. This line explains why the value equals to 3:

_loc1_.text = "Missing element in our set is: " + this.doTheMaths() + "!";

As you can see, we’re pushing 3 elements onto the stack and then we set the text property of _loc1_. At the end of the call our stack looks like:
1. “Missing element in our set is: “
2. this.doTheMaths()
3. “!”

localcount is the count of local variables used in the code block + 1. In our case, we see only one local (_loc1_), so the value is 2. If there was another local, localcount would be 3.

initscopedepth defines the minimum scope that may be accessed within the method.

maxscopedepth defines the maximum scope that may be accessed within the method. Usually its value equals to initscopedepth + 1.

The actual code

Let’s talk about what the method does.

code
getlocal_0
pushscope
getlocal_0
constructsuper 0
findpropstrict Qname(PackageNamespace("flash.text"),"TextField")
constructprop Qname(PackageNamespace("flash.text"),"TextField") 0
coerce Qname(PackageNamespace("flash.text"),"TextField")
setlocal_1
getlocal_1
pushstring "Missing element in our set is: "
getlocal_0
callproperty Qname(PrivateNamespace(null),"doTheMaths") 0
add
pushstring "!"
add
setproperty Qname(PackageNamespace(""),"text")
findpropstrict Qname(PackageNamespace(""),"addChild")
getlocal_1
callpropvoid Qname(PackageNamespace(""),"addChild") 1
returnvoid

Let’s disassemble it part by part.

getlocal_0
pushscope

This pushes our local_0 (which is a reference to this) onto the scope task and makes it available for name lookup. Basically, makes this available for us to use.

getlocal_0
constructsuper 0

It’s basically the super() call with zero arguments.

findpropstrict Qname(PackageNamespace("flash.text"),"TextField")
constructprop Qname(PackageNamespace("flash.text"),"TextField") 0
coerce Qname(PackageNamespace("flash.text"),"TextField")
setlocal_1

That looks like a complicated operation. In reality it’s pretty simple. First line looks up the property (class) called TextField inside the flash.text namespace.

Then, TextField is being constructed with 0 arguments (thus the line ends with a zero).

The coerce instruction converts the value into a different data type. In our case it just sets the type of the previously constructed property to TextField. Don’t ask me why this is needed.

Finally, setlocal_1 sets the value of local 1.

Translated to ActionScript 3 the operation we covered looks like:

var _loc1_:TextField = new TextField();

Let’s move one line below. We’re going to talk about:

_loc1_.text = "Missing element in our set is: " + this.doTheMaths() + "!";

Which P-Code equivalent is:

getlocal_1
pushstring "Missing element in our set is: "
getlocal_0
callproperty Qname(PrivateNamespace(null),"doTheMaths") 0
add
pushstring "!"
add
setproperty Qname(PackageNamespace(""),"text")

getlocal_1 indicates we’ll be using the local 1 (in our case it’s the variable holding a TextField instance).

getlocal_0 can be translated to this.

callproperty calls the property of previously pushed onto the stack object. Again, we know it’s simply this. As you can see, when calling a method that belongs to its parent class, Qname gets a PrivateNamespace with a null value. Again, a zero ends the line because we aren’t passing any arguments.

The next operation looks a little confusing at first. To make it simpler, think of the stack. How does it look like at this point of execution? We pushed a string “Missing element in our set is: “, then we called this.doTheMaths(). Here we go. add simply adds two stack values. Logically, this should be written as val1, add, val2. But at the point of executing add, the computer wouldn’t know what val2 is.

Next two lines simply add the asterisk to the final string.

Look at the first line again. We told the computer we’d be using local_1. The last operation the computer assigns the constructed value to the text property of local_1 (our TextField instance).

Last line of the Main method is pretty simple. The P-Code:

findpropstrict Qname(PackageNamespace(""),"addChild")
getlocal_1
callpropvoid Qname(PackageNamespace(""),"addChild") 1

simply finds the addChild method and calls it with one argument which is our local_1.

That’s all for today.

Thanks for reading! Hope you learned something. Let me know if you’d like to see a continuation of this tutorial in which I’d show some real life examples covering obfuscated and protected applications.