Windows Exploit Development – Part 3: Changing Offsets and Rebased Modules

Written on:December 29, 2013
Add One


In Part 2 we constructed a basic stack based overflow exploit for ASX To MP3 Converter. As I indicated in that post, the exploit itself is far from perfect. Successful EIP overwrite is influenced by the file path of the m3u file. In addition, although application modules are preferred when selecting jump/call addresses, the application DLL we used was rebased, meaning the address to our CALL EBX instruction is subject to change and is therefore unreliable. In this installment we’ll take a closer look at these issues and some ways we can improve our original exploit to make it more reliable. 

Changing EIP Offsets

One of the things I highlighted in Part 2 was that the exploit for ASX To MP3 Converter only worked if the m3u file was run from the root of the C:\ directory because the offset to EIP overwrite was dependent upon the file path. If you want to verify, try moving the m3u file from C:\ to your desktop and retry the exploit in the debugger. Refer to the below screenshot — you should see the same access violation and a similar entry on the stack.  


As you can see, instead of being overwritten with our CALL EBX instruction, EIP is now being overwritten by the preceding “junk” portion of our payload made up of all A’s (\x41). Since the longer file path was incorporated into the payload, it has pushed everything to the right and changed our offset to EIP. For a proof-of-concept exploit this may not be a big deal (since we were able to get it to work from at least one location). However, if you are performing a penetration test or application security assessment and need to assign a risk rating to a given vulnerability, it is often influenced by the likelihood the exploit could be realized. Obviously, an exploit that can only be triggered from one location on a file system has a lower likelihood of being realized than one that can be exploited from multiple locations. To address this issue, we can modify the exploit to include multiple potential offsets, thereby increasing its likelihood of execution.  

If you recall, our completed exploit buffer looked like this:


The offset to EIP (when the m3u file was located at the root of C:\) was 26,121 bytes. As we proved by moving our m3u file to the Desktop, a longer file path causes the EIP overwrite to move to the left into the Junk portion of the buffer (all A’s), thereby decreasing the size of the offset. The good thing is if the file path is the only influence over the offset, we should be able to predict exactly where the new offset will be given a particular path. Let’s pick a different save location for the m3u file to prove this theory. The full path to the m3u file located on my Desktop is below (with the difference from the previous path highlighted in red):

C:\Documents and Settings\Administrator\Desktop\asx2mp3.m3u. 

This new path is 45 characters longer, which means we should adjust our EIP offset by -45, giving us a new offset of 26,076. Let’s update our exploit code and see if this works (change only the offset to the exploit you built in part 2 to follow along).

Rebased Application Modules

Running the exploit with the updated offset on my rebooted Windows machine produces the following result:


EIP has clearly been overwritten with my chosen CALL EBX address (0x01C27228 from MSA2Mcodec00.dll) but the program doesn’t seem to recognize it as a valid address. I’ve run into another problem here because in my previous exploit code, I used an address from a “rebased” application module (DLL). Without going into too much detail about rebasing, understand that every module has a designated base address at which it is supposed to load (and compilers often have a default address that they assign to all modules). If there is an address conflict at load time, the OS must rebase one of the modules (very costly from a performance perspective). Alternatively, an application developer may rebase a module ahead of time in an attempt to avoid such conflicts. In our case, if MSA2Mcodec00.dll is rebased, the address space changes and as a result, our CALL EBX address changes. Unfortunately, this impacts the reliability of successful exploit even more so than our EIP offset problem. Here we have two choices — 1) see if we can find another application module that doesn’t implement rebasing (preferred) or 2) use an OS module. Remember from part 2, the drawback of using an OS DLL (vs an application DLL) is that it reduces the likelihood the exploit will work across different versions of Windows. That being said, an exploit that works on every Windows XP machine is better than an exploit that only works on one machine! We can use the mona plugin to examine the loaded modules more closely and see which ones implement rebasing by running the following command:

Below is a screenshot of the beginning of the resulting find.txt file. It shows all of the modules in which the instruction “call ebx” was found as well as the attributes associated with each of those modules including whether they implement rebasing (note the “rebase” column). Don’t worry about the other columns just yet. I’ve highlighted the rebase attribute value for all of the application modules. 


Notice there are two with a value of “False” in that column (highlighted in orange). Unfortunately, all of the “call ebx” addresses in both of these modules contain null bytes, which as you recall from part 2, poses its own set of problems. It looks like we have no choice but to use a system module. I would choose from one of the larger dlls such as shell32, user32, kernel32, or ntdll as they may be less likely to change between OS service packs. Scroll farther down in the find.txt file to see the actual “call ebx” addresses found. I’ll choose the first shell32 address listed (0x7c9f38f6).


Now, I’ll update the exploit script with the new CALL EBX address from SHELL32 (note the already-updated EIP offset), create the m3u file, and run it from the Desktop. 




Updating The Exploit to Support Multiple Offsets

Ok, so we’ve overcome our address rebasing issue by choosing an OS module and verified that the offset can be predicted from the length of the resulting path size of the m3u exploit file. The next step is to incorporate multiple offsets into our exploit code to increase the likelihood of it being successfully executed from different locations. We could accomplish this by simply comprising the junk portion of our buffer of a pattern of repeating offsets (instead of using A’s, use EIP + EIP + EIP, etc). While this increases the likelihood of successful exploit, it is rather haphazard since common storage locations (Desktop, My Documents, etc) may or may not align with that pattern. Instead we could generate a list of likely save locations and place the offset a bit more strategically in our buffer. We could do this manually, by counting the length of each potential file path and creating an offset for each location as follows:


This would technically get the job done and at the end we’d be left with a buffer that looks like the following:


Of course that’s not very efficient coding and makes adding and removing paths cumbersome so let’s harness the power of scripting to make it a bit easier to manage. 

First, we’ll create an array of likely paths. I’ve created one with a few possible paths, though there are more:


I also included the manually calculated offsets (as comments) for illustrative purposes, though by scripting the offset creation we won’t need to actually do this for each file path. Next, we create a loop and dynamically build the junk + eip portion of our buffer using the contents of our array.


As you can see above, we just loop through the array and use the length of each file path (minus the shared ‘C:\’) to strategically place our offsets.  

Our final exploit looks like this:

If you want to visualize how the buffer looks, open the resulting m3u file in a text editor and you should see the offsets as follows:


Even this updated exploit is not perfect due to our use of an OS DLL for EIP overwrite and the limited number of exploit trigger locations, but it’s certainly an improvement over our original version from Part 2

I should mention that in addition to changing offsets influenced by file paths, it is not entirely uncommon to come across an exploit that has multiple offsets determined by the way it is launched. Take for example this recently-posted exploit for RealPlayer which incorporates two offsets/EIP overwrites — one for when the exploit .rmp file is launched directly and one for when it is opened from within the application. If the exploit code itself looks slightly different, it’s because it is an SEH-based buffer overflow, a topic we will get to in a few more posts. For now, if you do choose to try the exploit on a test machine you may need to make a few adjustments, depending on your OS. If you’re running Windows XP SP3 you might need to adjust the $junk2 offset by one to 10515 and depending on which version of RealPlayer you have, you may need to switch SEH values. 

While these were just a couple of examples of locally-executed exploits with changing/multiple offsets they should provide some insight into how this issue can present itself when creating exploits and how you might go about addressing it.


Over the last two posts we’ve constructed a very basic stack-based buffer overflow exploit and overcome some minor complications stemming from changing EIP offsets influenced by the exploit file path and changing module addressing caused by a rebased application DLL. In the next post, we’ll look at how to use jump code for situations in which you cannot use a simple CALL/JMP instruction to reach your shellcode. 

Related Posts:

One Comment add one

  1. fellow says:

    Thanks Mike, It is a very great tutorial,But I have a doubt the first 26121 bytes of the m3u file in part 2 we were filling it with A(x41), so how could the variation in path create the trouble. you mentioned
    “Since the longer file path was incorporated into the payload”, so I have these few questions.

    1. where this path is bieng incorporated?
    2. Is it being incorporated before EIP and after junk? If yes then how?
    3. if No then why are we decreasing the size of junk?
    4. Or the path is on the stack before our 50000 bytes m3u file and make it shift to the left/right.

    please explain this part.

Leave a Comment

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