Playing in the Windows API with Python

I have been meaning to make a post like this forever as I feel it is imperative that you learn how to interact with the Windows API to get past the typical “Metasploit Pentester” plateau and take your knowledge and understanding to the next level.    Not only is it important to augment your understanding of what is happening under the hood, but also to give you a little more imagination and to expand the boundaries of your toolmaking ventures!

Also, I want to point out that this is not meant to be either an exhaustive or an advanced walkthrough, it is only meant to get people started and providing them the tools to get started with interaction with the Windows API. So without further ado…

First thing you need to know, is that we will be using the amazing “ctypes” module within python to do all of our interactions, so be sure to start all of your code off with this:

This will not only import all of the stuff we need to do our coding, but will make it where we don’t have to prepend “ctypes.” to everything we use within the ctypes modules. We will be starting out with a simple example and moving to some more complicated ones, building on what we have learned so far.

CopyFile (ansi: CopyFileA) is what we will be starting with. Here is what the CopyFile() function from Kernel32.dll looks like.

Before we move any further, it is worthwhile to note that while the documentation on MSDN’s website calls the function CopyFile, in Python you have to specify CopyFileA or CopyFileW which take either Ansi or Unicode strings, respectively. If you are developing in (for example) C++ with Visual Studio you’ll have a macro defined that will check if you have your project defined as using unicode or not, so you can simply call CopyFile() and your project will call either CopyFileA or CopyFileW, depending on that setting. We do not have that macro set up in Python — So, first we need to instantiate the CopyFileA function and assign it to a child, which is done in the following fashion:

This assigns our “child” CopyFile all of the attributes of the CopyFileA function. All we need to do now is supply valid arguments, so lets check what is required from the MSDN website:

CopyFile Parameters

So per the documentation, all we need to do is provide a source file, destination file, and whether or not we want the function to fail if the destination file exists. Our final code looks like this:

After running the code, we get a new calc file on our desktop! This was a very simple example however, lets look at how to make some more complicated calls.

We will be attempting to do DLL Injection via Python. After poking around you will see that there is plenty of research people have done online, and you can get there by googling a little. The process we will be using to inject our dll will go in the following way:

  1. OpenProcess() – Returns the handle for the process we want to inject into, which is needed for subsequent calls
  2. GetModuleHandle() – Returns the handle for the kernel32.dll
  3. GetProcAddress() – Returns the address of the LoadLibraryA() function within kernel32.dll
  4. VirtualAllocEx() – Allocate memory space to inject our DLL path into
  5. WriteProcessMemory() – Write our DLL path to the newly allocated memory region
  6. CreateRemoteThread() – Execute our newly injected DLL in memory

One thing to note, we will be doing DLL Injection via the LoadLibraryA() function, which means that our DLL will be registered with the targeted process. This means it is easily caught by AV, but as this is a basic tutorial, lets start small! If you want to be stealthy, you should use Reflective DLL Injection.

I’ve found in my endeavors that after calling any Win32 APIs you should call Kernel32::GetLastError(), as it will tell you the response code of the last API you called. Also, if you call two APIs and the first fails but the second is successful, and you call GetLastError() only at the end, you will only show a Success code as the location in memory where the code is stored is overwritten by the second call. Therefore in the following code you’ll notice that I created a GetReturnCode() function to automate this after every call to the Win32 API. Also, you’ll notice that the datatypes for Win32 API programming are somewhat different. They look somewhat daunting at first, but they make sense after you read about them and you can do so here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx.

Finally, in the ctypes modules, if you wish to pass an address of a variable (any Win32 Datatypes that require a pointer… ie lpThreadId, in CreateRemoteThread()) should be passed with the byref() function from ctypes. This will pass the address of the variable instead of the value of the variable.

In my test, I created a DLL with msfvenom:

Next I brought up task manager and checked the pid of a 32 bit process, ran my code and…

Success!

SUCCESS!

This article has primarily been created to show that interacting with the Win32 API is not that hard, even for novice programmers. With a little google-fu, you can put all the pieces together to make low-level, powerful programs. The code to make this possible is as follows:

Thanks for reading!

2 thoughts on “Playing in the Windows API with Python

Leave a Reply

Your email address will not be published. Required fields are marked *