Skip to content

gmh5225/ExportHider

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 

Repository files navigation

image image

ExportHider

ExportHider generates a C++ DLL template which contains a code stub that allows you to hide Exported Functions from the Export Directory of the DLL on the filesystem. After putting the function definitions and compiling the file, you won't see the hidden export functions through PE File Viewers like PEBear or CFF Explorer. However, since the code stub in the template recreates the Export Directory during runtime, legitimate GetProcAddress calls would still work. It might be useful for DLL Sideloading or DLL stagers.

How It Works?

Normally, when you want to define an Exported Function in the DLL files (in C or C++), you simply put a __declspec(dllexport) keyword before the function name, or create a .def file. After the compilation, the compiler creates a specific table called Export Directory for holding the information related to Exported Functions. The structure of the Export Directory can be seen below:

When a process wants to use a function from a DLL file, Windows Loader simply parses this structure and imports the requested functions by using the AddressOfFunctions, AddressOfNames, AddressOfNameOrdinals arrays.

The specific routine for importing a function is explained by ferreirasc's blog post in detail, but shortly for a function imported by name, the Loader iterates the AddressOfNames array (values of this array are just RVA values) and searches the given name. Once, the loader has a match in the “i” position, it will refer to the ith index of AddressOfNameOrdinals array and get the ordinal associated with this function. Having the ordinal, the loader will refer to AddressOfFunctions on the ordinal value position to finally get the RVA associated with the imported function.

The crucial point here is that all these search and access operations by the Windows Loader are done after the DLL is mapped to the process address space. During DLL mapping (or calling LoadLibrary function), the whole DLL file including its PE Headers is written to the memory, and the Loader parses the headers in the memory to reach the Export Directory. This means that if the DLL itself is able to overwrite its PE headers in the memory to change the Export Directory Address (simply the 0th index of the DataDirectory) after attaching to the process, the loader can look for functions to import in an arbitrary Export Directory rather than in the Export Directory added by the compiler.

Command Line Parameters


   __                       _          _     _
  /__\_  ___ __   ___  _ __| |_  /\  /(_) __| | ___ _ __
 /_\ \ \/ / '_ \ / _ \| '__| __|/ /_/ / |/ _` |/ _ \ '__|
//__  >  <| |_) | (_) | |  | |_/ __  /| | (_| |  __/ |
\__/ /_/\_\ .__/ \___/|_|   \__\/ /_/ |_|\__,_|\___|_|
          |_|
                     by @R0h1rr1m

Usage of C:\Users\Public\DLLDemo\ExportHider.exe:

    -h | --help                                 Show the help message.
    -i | --input <Input Path>                   Input path for the list of function names to be hidden. (Mandatory)
    -o | --output <Output Path>                 Output path for the DLL template. (Mandatory)
    -n | --name <DLL Name>                      Name of the DLL for the Export Directory. (Mandatory)
    -c | --count <Number of Other Functions>    Number of other exported functions that won't be hidden.

Regarding the -i | --input <Input Path> parameter, you need to specify a path for the input file that stores the function names to be hidden line by line. The content of an example input file would be:

TestFunction1
TestFunction2
TestFunction3

Regarding the -c | --count parameter, if you don't want to hide all your exported functions (i.e. there are some functions exported with __declspec(dllexport) or .def file, and they appear in the Export Directory of the DLL file in the filesystem via PE File Viewers), just specify how many there are by using this parameter because the tool needs this information when making memory calculations.

Quick Demo Video

Workarounds

If you want to play with the technique, there are two interesting points that I encountered during the development of the project. You might need to know them before changing the project:

  • Windows Loader uses a Binary Search-like algorithm to find the exported function if you call the GetProcAddress function with a name. Because of that, the names of all exported functions including the hidden ones need to be sorted in the AddressOfNames array. Otherwise, the GetProcAddress function returns NULL. Therefore, I used the Bubble Sort algorithm to sort the members of this array.
  • As I said above, the AddressOfNames array, AddressOfFunctions array, DataDirectory array, and some other fields require values in Relative Virtual Addresses (RVAs). In addition to that, they hold these RVA values in DWORD-sized fields. When you allocate a memory region for a new arbitrary export directory by using Dynamic Memory Allocation Functions like VirtualAlloc or HeapAlloc, given addresses will be far from the DLL mapped region and RVA values don't fit into the DWORD-sized fields and you encounter with integer overflow. That's why I used global variables with the byte array type in the DLL template for memory requirements.

References

About

ExportHider: Generating Export Table during Runtime to Hide the Exported Functions from the DLL File.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • C++ 99.3%
  • C 0.7%