githubEdit

API Hashing

Introduction

As we all know that the IAT of a binary gives a vague idea of what the file is capable of. And a simple way to avoid this is by using a technique like API Hashing / String Hashing. +1 since they also can't use strings to take a peek at us.

Analyzing Mapping Injection

I'll start with running strings on the Mapping Injection implementation which can be found herearrow-up-right.

> strings MappingInjection.exe
......
Stack around _alloca corrupted
RegOpenKeyExW
RegQueryValueExW
RegCloseKey
PDBOpenValidate5
RSDS
CloseHandle
GetLastError
WaitForSingleObject
Sleep
GetCurrentProcess
GetCurrentProcessId
CreateThread
CreateRemoteThread
OpenProcess
CreateFileMappingW
MapViewOfFile
UnmapViewOfFile
KERNEL32.dll
MapViewOfFileNuma2
api-ms-win-core-memory-l1-1-5.dll
memcpy
__C_specific_handler
......
wcscpy_s
ucrtbased.dll
GetCurrentThreadId
IsDebuggerPresent
RaiseException
MultiByteToWideChar
WideCharToMultiByte
...

We can see a lot of stuff here, keeping aside the variables/print messages/etc, we also see a list of Windows API being used here like the MapViewOfFile (You might see some extra APIs at the bottom but that's because CRT included them). A better way would be to look at it using something like PE bear and we see a list of APIs being used.

But what if we want them to suffer more, then we can just use API hashing instead and avoid the string MapViewOfFile to display anywhere in the code, so that it looks a little less suspiciuos.

Simple Explanation

What we are going to do is basically Hash required functions in Kernel32.dll or any other module according to our needs, and then note their hash, then in our Malware, when we want to get the base address of that function, instead of matching the string, we will match with the hash value of the modules and get the ones that match with it.

Some of the common hashing techniques include

  • djb2

  • CRC32

  • FNV-1a

  • SuperFastHash

  • LoseLose

  • Murmur

and many more, the source code of which could be found herearrow-up-right, we can even develop our own custom hashing technique. There's also this githubarrow-up-right which does the job of printing the hashes in a few different format.

Generating Hashes

I'll go with the LoseLose (LoseLose is weak and susceptible to hash collision, I found it the hard way) MurMur Implementation and generate the hashes for necessary winapi for running Mapping Injection. Here's the C code to get the necessary hashes

Running the code will give me this

API Hashing

Okay so we have the necessary hashes, now we need a way to get our necessary function by it's hash value, I've written a small code which is pretty similar to the GetProcAddress instead that it calculates the hash for all of the exports and returns the VA for the export having the same hash value.

Then I'll check the value for a single API to make sure we are getting the correct API, and then perform the Injection.

I can see that both the hash value matches and looking at x64dbg, I can confirm it is for the MapViewOfFile API.

Now I just need to get all the functions and the rest of the process is similar to that of Mapping Injection. Here I'll just perform the Remote Mapping Injection instead of both Local & Remote.

Only a slight change would be while calling the MapViewOfFileNuma2 function, looking at the MSDN for MapViewOfFile2, Microsoft recommends calling the numa2 with the final parameter being set to NUMA_NO_PREFERRED_NODE. The full source can be found at the end of the page.

After everything has been done, I'll check the pe binary again in PE-bear and this time, we don't see any of the Mapping related APIs which we used.

Again, the extra APIs are due to CRT adding some of their own, if we configure it to be build for a Release, then we see that some of the API have been removed lowering the count, although to completely eliminate them, we would have to remove CRT (as shown here).

Pitfall

So Initially I thought of using the LoseLoseA for hashing, but the program wasn't working and after some debugging, I realized that this function is susceptible to hash collision. Both the MapViewOfFileNuma2 and the GetPackageContext function have the same hash value of 0x6B1, and since the GetPackageContext function appears first, I was getting the VA for that. Fortunately, I debugged it well to point out the mistake early.

If you are trying to use a hashing function, or creating your own, then make sure it is a strong hash and isn't susceptible to something like hash collision.

Source Code

This can also be found on my github herearrow-up-right.

Conclusion

That's it for now, I know I have gone hiatus for a while, but now I'll be more active and keep posting. I'll also write a Rust implementation soon soon.

References

Last updated