Skip to main content

How to Get Libraries to Load in Fixed Addresses

Problem

I was using DynamoRIO to do instruction tracing to troubleshoot the runtime execution stability of my program and a DLL it was loading and realised that I could not easily diff the files as the addresses were always different.

Figure 1. Sample DynamoRIO trace

The output shown in Figure 1 illustrates a trace. My program starts to execute at line 83. The address — 0x20XXXX would be where my program was being loaded in. On modern Windows systems, this would be different whenever my program ran due to ASLR.

Disabling ASLR

The quick fix to this would have been: “use Windows 7 duh”. However, I didn’t think it was a future proof solution and just merely postponed the inevitable, so I decided to see if I could do that on a fully patched Windows 10.

The first recourse was to use Google: “Windows 10 disable alsr”. Sadly though, none of it worked. (Sadly, the “MoveImages” registry key only seems to work on Windows 7.) I tried turning off Exploit Guard, but to no avail too.

Luckily, disabling ASLR on my program was easy since I had the source.

Figure 2. These flags would tell Windows to always load my program at 0x200000

Disabling ASLR on my program was simple enough as I had the source. Once I recompiled my program with the linker options like in Figure 2, PE viewers such as CFF Explorer would report my program with the following attributes:

Figure 3. A program with ASLR disabled would not have a relocation section, hence the IMAGE_FILE_RELOCS_STRIPPED (Or, “relocation info stripped from file”) flag set
Figure 4. The DLLCharacteristics of the file would always specify that the IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE (or “DLL can move”) flag is cleared

Lastly, a file without ASLR support would not have a relocation table.

Figure 5. No .reloc!

That’s all simple and good. Nothing much to say about here. But what about the DLL that my program was loading? My program was loading a closed source DLL, so recompiling it was out of the question.

Luckily (we’re so in luck today!), CFF Explorer can edit PE files (which includes DLLs), so I set the IMAGE_FILE_RELOCS_STRIPPED flag and cleared the IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag. According to specs shown in Figure 6, this should cause my DLL to be loaded at its ImageBase (0x40000). I had previously set my program to load at 0x20000 so it should not clash. Furthermore, the specs also state that I will get an error if the program cannot load the DLL at the image base. Sounds great!

Figure 6. Setting this flag should work!

However…

Figure 7. Nani?! Why is my DLL not being loaded at the right address?

For whatever reason, 0x400000 was reserved, and the loader, instead of throwing an error, loaded my DLL at any location of its choosing. This was surprising since the specs said that it would throw an error. However, this seems to be expected behaviour as the DLL has a .reloc section in the header, so the loader would ignore the flag and just load it.

Figure 8. Yeah it says no ASLR but it still loads it wherever it wants

This means that I would need to remove the .reloc section and also, since 0x400000 is reserved, I should just modify the DLL to load at another address instead. This operation is called rebasing. I could have also just modified it in CFF Explorer (or any other PE editor, but I would have to edit a few other fields), so I looked around for the lazy way and it turns out that Visual Studio has just the right tools for rebasing a DLL!

Figure 9. Helpful terminal shortcuts installed by VS

When Visual Studio is installed, it creates 2 shortcuts to launch command prompts that have specific paths set up. These prompts allow users to use the VS environment for compiling and also to access any executables in VS’s path. In this case, the 32 bit and 64 bit choice is irrelevant and we just launch either of them and run editbin.

Figure 10. Editbin’s ancestor used to be rebase.exe
Figure 11. Using editbin is reasonably painless. I didn’t need to set dynamicbase:no as I had already done so using CFF Explorer

The command shown in Figure 11 would have rebased our DLL from the default 0x400000 to 0x1f0000. Time to check it in CFF Explorer!

Figure 12. Rebase success!

Running my program now should cause the library to be loaded at 0x1F00000. However, at this point I decided to delete the .reloc reference too, so that if there are address collisions, the program will bail, instead of happily loading in some random address, leaving me to do troubleshooting in the future.

Using CFF Explorer, I went to the Data Directories section and removed the reference to the Relocation Directory RVA and set the size to 0.

Figure 13. Modify the Relocation Directory RVA and Size to 0

I decided not to delete the actual .reloc section in section headers for now in case I ever wanted to go back (unlikely!) but that can be easily done with CFF Explorer too.

Figure 14. Yay now my DLL loads consistently at the specified address

The End?

This concludes my short article. I decided to write one since I didn’t really find such information in 1 spot and also there was quite a bit of outdated stuff floating around. Hope this will be useful to the wandering souls who somehow land on this article!

Now back to improving the runtime execution stability of my program…



Comments

Popular posts from this blog

CVE-2020-16602 - Remote File Execution on Razer Chroma SDK Server (<= v3.12.17)

Introduction This writeup is about a remote file execution vulnerability I found on the Razer Chroma SDK Server that comes with Razer Synapse. It chains several issues to enable me to remotely execute a file on the user’s system. This issue is still present in the latest version which is 3.12.17. Issue 1 The Chroma Server listens binds on all network interfaces and listens on port 54236. The server also does a hostname check to make sure that it is being accessed as https://chromasdk.io/ instead of an IP address. External clients can modify their hosts file to alias an IP address to chromasdk.io in order to access a remote Chroma Server. Issue 2 When the server receives a call to register an app (via a REST call), it will create a folder in C:\ProgramData\Razer Chroma SDK\Apps\<appname> and write 3 files, ChromaAppInfo.xml, appname.exe and a DLL. When these files are created, they are only modifiable by admin. The server will then execute the appname.exe file. However, the C:\Pr