While working on building a couple new simulation modules for ATTACKIFY, we came across an interesting feature within
rundll32.exe. When creating some test DLL files we created exported functions with the following names:
So at this point our DLL has two exported functions named
MyFunctionA (this was originally just testing). The first function,
MyFunction could contain potentially malicious code, however in this case it only displays a message box to indicate where you are in the execution.
So let’s run the new DLL with
rundll32.exe and execute the exported function by name,
MyFunction, and see what happens.
Well that’s is interesting
rundll32.exe is executing the function
MyFunctionA instead of the specified
MyFunction as seen in the command line. As mentioned before we were testing something else when we came across this problem and couldn not figure out why
rundll32.exe was not running the function we specified as it seemed to run just fine with other tools that are not
rundll32.exe. So inorder to successfully execute the function we want, we can use something that is not
rundll32.exe like a custom tool or PowerShell.
Our snippet for PowerShell can be something as simple as:
Running the above PowerShell script successfully executes our function specified in the DLL as compared to
What can we do with this?
Not all that much, however, something attackers/malware writers/red teamers could use this technique to potentially hide their malicious functionality from some basic analysis for a moment or two longer. An attacker can create 3 exported functions with the same name but ending two harmless functions with the the W or A suffix.
FuncA() could contain non-malicious code and
Func() would contain the malicious functionality
The idea would be that if the suspicious DLL is manually analysed using
rundll32.exe the observed function will run the non-malicious functionality because of the strange behaviour, thus protecting the malicious code from being run and easily analysed. Obviously this not fool proof, but if only basic analysis is performed, this would easily circumvent the malicious code from being observed or detected as one of the harmless functions would run not the malicious one via
Why does rundll32.exe do that?
There is not a lot of information or research on this particular behaviour that we could find before writing this up. We do however suspect that it has to do with Microsoft Windows wide/Unicode and ANSI character compatibility support. So it seems like default behaviour is for
rundll32.exe to fist check for wide/ANSI character supported functions before defaulting to the command-line specified function.
We found this mini write up on rundll32: https://www.hexacorn.com/blog/2019/09/28/rundll32-api-calling/
Then we also found a similar example of our finding here: https://github.com/gtworek/PSBits/tree/master/NoRunDll
Rundll32 and Ordinal Values
It is possible to force
rundll32.exe to still run the specific function, just not by the exported function name. To do this one can use the ordinal value and tell
rundll32.exe to execute the function at position #1, #2, #3 etc. So we can load the DLL up in a DLL Export View that will list all the available function names and the ordinal value for each function (you could also just brute-force the values starting from 1):
rundll32.exe <dllFile>, #1
As you can see the function in question has an ordinal value of 1, we can now simply instruct
rundll32.exe to execute the correct exported function without getting tricked up by the naming obscurity issue:
I guess the lessons here include:
- Know your tools and what they are doing, what they are not doing and the tools limitations - Make sure you thouroughly perform analysis and dont rely on basic testing - Dig a little deeper and use the right tools
We have already implemented a module to simulate the behaviour for you. The module will drop a DLL file to the endpoint, run the exported function that will spawn calc.exe and then when run with
rundll32.exe will prompt the user to try harder! We also leave a copy of the artefact for you to manually play with.