Sunday, September 7, 2014

Astute Explorer (GCHQ Challenge 5 - 10)

Continuation for

On line 26 the function fails if exactly BLOCK_SIZE is not read, this means if there is data available but less than BLOCK_SIZE is present, or the read fails, the function will return NULL. On failure the function does not free szBuffer so there's a pretty serious memory leak.

If the read operation fails, the function should free(szBuf) before returning null, it should also be worth considering handling the event that the read function returns less than BLOCK_SIZE.

I have a hard time understanding the point of this function (it reads the data to a local buffer, which is then disregarded on return), but I'm sure making the function useful is not part of the assignment. The problem exists on line 1009; assuming GetFromInput can read more than 1 byte at a time, it can still exceed MAX_RECEIVE. For example: if MAX_RECEIVE is 10 and GetFromInput reads 20 bytes, siBytesReceived is going to be 20, the loop will exit but the data will have already been written and siBytesRecieved will already have exeeded the limit. There's also the problem that if GetFromInput can fail or return less than MAX_RECEIVE, the loop has no way of checking this and will continue looping (possibly infinitely).

The best idea would be to implement a parameter in GetFromInput that allows the user to specify the maximum amount of data to read in a single call. The function can then calculate how much data is left before MAX_RECEIVE is hit and specify a limit to prevent more than that from being read.

I wasn't able to find any vulnerabilities here, unless the user supplies invalid pointers to the function (it should be their job to check they're valid, not the functions). On line 45 the loop will decrement len until it's 0 then exit, as a result it will always return 0.

Make a copy of len and then decrement the copy.

If the aim of this code was to use obscure nested if/else statements to make code auditing almost impossible, then the programmer (who probably works on the security team at oracle) did a great job. I'm really not sure what's going on with the code or what err is and where it's set. Assuming err is an actual variable and not pseudo-code a runtime library function like malloc wouldn't set it; if malloc returns NULL the application is going to try and use that null pointer. There's also the issue of the use-after-free on line 52: On error ptr is freed and abrt is set, which means logError will always be passed ptr after it has been freed.

Stop hiring college kids.

This piece of code should be instantly recognizable as the apple SSL bug from February (it was all over the news and security sites for months). The extra goto fail; on line 408 means the application will always skip to the cleanup code without setting err, as a result the client doesn't verify that server owns the private key matching the certificate, which opens the client up to MITM attacks.

Remove the extra goto fail;


Although the challenges are fun, they are really poorly made. Most of the code is taken from various websites and no context is give, leaving the player making massive assumptions about how the code works. I can't think of a real world scenario where you would have to find vulnerabilities in tiny snippet of code without knowing what they do or how the application uses them. Almost all of the vulnerabilities in this article could be non existent if the application performs check prior to calling the snippets, or if assumptions made about the imaginary functions they call are wrong.

Astute Explorer (GCHQ Challenge 1 - 5)

GCHQ has been having trouble finding experienced hackers and programmers to work for them, so they've put out a lot of, admittedly fun, challenges. The idea is that people who do well in the online challenges are selected to do face to face challenges, the top few people from the face to face challenge go through to the masterclass, then the top people from the masterclass will be vetted for a job, finally if you pass the vetting process you get to waste your skill earning 35k/year playing cyber warrior for some NSA wannabes. As you can see, it's better to just use the online challenges to kill some time (You can't even apply for GCHQ unless you're a UK citizen).

Sadly I missed the first challenge, but managed to get into "Astute Explorer" just in time (It's finished now so I'm posting my answers). The challenge is an imaginary company is under cyber attack and want you to help secure their software, they have even been kind enough to provided you with random snippets of C code (without any context). Your job is to provide the line number of the vulnerability, explain why it's a vulnerability, and how to patch it. So let's take a look (my area of expertise is malware, so sorry if I end up getting stuff wrong).

I'm not sure there's an exact line number, but the vulnerability here is pretty obvious. strcpy and strcat don't do any checks to make sure the target buffer is large enough to fit the string, so by providing a username/password that exceeds the size of szTotalString, you can cause a buffer overflow.

A lot of people would use functions like strlcpy/StringCchCopy, which copy as much data into the buffer as it can fit then null terminates it. In my opinion this is stupid because the code would still try to check the username and password despite the fact not all of it was copied, I'd personally do strlen on the username and password, then fail if it exceeds the maximum length.

This is a fun one, you can chain multiple vulnerabilities in the code to cause a heap overflow. The height and width are user specified, so the first thought would be to specify a height and width so large that it causes an integer overflow when calculating the size on line 94, resulting in the allocated buffer being too small to accommodate board_squared_t. If you look at line 91 it makes sure that the height and width don't exceed a certain size, Foiled! Or not? The mistake here is that height and width are signed integers and if you listened in maths: multiplying 2 negative values gives a positive result. We can bypass the maximum size check by specifying large negative values instead, which will then become positive and still cause our integer overflow.

Pretty simple, just declare height and width as unsigned integers instead of signed.

I literally have no idea what's going on here. Why is iSize being multiplied by the size of int (4)? What is szBuffer? What does the number is %d = %d mean? If someone handed me this code I'd assume they got their degree in a cereal box and send them back to work at geek squad. Assuming pszArguments[2] is a string and pszArguments[1] is the length of the string, the memcpy operation on line 556 is going to copy 4x more bytes that the length of the string and probably crash. It should also be noted that iArguments isn't checked, so if the user doesn't specify enough arguments, the application is going to crash.

Stop doing drugs at work.

On line 84 szError is passed as the format argument to printf. Because printf will interpret any format specifiers in the format argument this is unsafe (format strings exploit). If the error string were to contain "%d%d%d" the next 12 bytes of memory on the stack would be output to the user, it's also possible to use the %n specifier to write arbitrary data to an arbitrary location.

printf("%s", szError);

I wasn't able to find any major vulnerabilities here. The code leaks memory because _strdup allocates a buffer, which is never freed. There's also an off-by-one error on line 352: the code checks if the filename is larger than or equal to 3, however the extensions in the szOkExt array include the dot (4 bytes), if the user specified a 3 byte filename the code would try to compare 4 bytes and possibly (but unlikely) crash the application.

Check if cFileName is bigger than 3 and free szLCase before return.


I'm clearly not a hacker.
Other 5 answers coming tomorrow. 

Monday, June 16, 2014

Usermode System Call hooking - Betabot Style

This is literally the most requested article ever, I've had loads of people messaging me about this (after the Betabot malware made it famous). I had initially decided not to do an article about it, because it was fairly undocumented and writing an article may have led to more people using it; However, yesterday someone linked me to a few blogs posting their implementations of the hook code (without explanation), so I've finally decided to go over it seeming as the code is already available.

Win32/64 System Calls

System call is a term used to describe functions that do not execute code in usermode, instead they transfer execution to the kernel where the actual work is done. A good example of these is the native API (Ex: NtCreateFile\ZwCreateFile). None of the functions beginning with Nt or Zw actually do their work in usermode, they simply call into the kernel and allow the kernel mode function with the same name to do their work (ntdll!NtCreateFile calls ntoskrnl!NtCreateFile).

Before entering the kernel, all native functions execute some common code, this is known as KiFastSystemCall on 32-bit windows and WOW32Reserved under WOW64 (32-bit process on 64-bit windows).

Native function call path in user mode under windows 32-bit

Native function call path in user mode under WOW64

As is evident in both examples: Nt* functions make a call via a 32-bit pointer to KiFastSystemCall (x86) or X86SwitchTo64BitMode (WOW64). Theoretically we could just replace the pointer at SharedUserData!SystemCallStub and WOW32Reserved with a pointer to our code; However, in practice this doesn't work.

SharedUserData is a shared page mapped into every process by the kernel, thus it's only writable from kernel mode. On the other hand WOW32Reserved is writable from user mode, but it exists inside the thread environment block (TEB), so in order to hook it we'd have to modify the TEB for every running thread.

KiFastSystemCall Hook

Because SharedUserData is non-writable, the only other place we can target is KiFastSystemCall which is 5 byte (enough space for a 32-bit jump). Sadly that actually turned out not to be the case because the last byte, 0xC3 (retn), is needed by KiFastSystemCallRet and cannot be modified, which leaves only 4 writable bytes. 

The sysenter instruction is supported by all modern CPUs and is the fastest way to enter the kernel. On ancient CPUs (before sysenter was invented) an interrupt was used (int 0x2E), for compatibility it was kept in all subsequent versions of windows.

The now obsolete KiIntSystemCall

Here you can see, KiIntSystemCall has a glorious 7 writable bytes (enough space for a 32-bit jump and some) it's also within short jump range of KiFastSystemCall. As you've probably guessed by now, we can do a 2 byte short jump from KiFastSystemCall to KiIntSystemCall and then a 32-bit jump from within KiIntSystemCall to our hook procedure.

Now, what if something calls KiIntSystemCall? Well, it's unlikely but we can handle that too: The rule for the direction flag on windows is that it should always be cleared after a call (that is, a function should never assume it to still be set after making a call). We could use the first byte of KiIntSystemCall for STD (set direction flag), then use the first byte of KiFastSystemCall for CLD (clear direction flag) followed by a jump to KiIntSystemCall+1, that way our hook procedure can use the direction flag to see which calls came from which function.

WOW32Reserved Hook

This is a lot simpler, either we can keep track of every thread and hook WOW32Reserved in each thread's environment block (i think this is what betabot does), or we simply overwrite X86SwitchTo64BitMode which is 7 bytes, writable from user mode, and pointed to by the WOW32Reserve field of every thread's environment block.


Most people who write hooks are used to redirecting one function to another; however, because both of these hooks are placed on common code: every single native function will call the hook procedure. Obviously we're going to need a way to tell NtCreateFile calls from NtCreateProcess and so on, or the process is just going to crash and burn.

If we dissemble the first 5 bytes of any native function it will always be "mov eax, XX", this value is the ordinal of the function within the System Service Dispatch Table (SSDT). Once the call enters the kernel, a function will use this number to identify which entry in the SSDT to call, then call it (meaning each function has a unique number). When our hook in called, the SSDT ordinal will still be in the eax register, all we need to do is gather the SSDT ordinals for all the functions we need (by disassembling the first 5 bytes), then we can compare the number in eax with the ordinal for the function we wish to intercept calls for: if it's equal we process the call, if not we just call the original code.

Comparing the function ordinal with the one we want to hook could be messy, especially if we're hooking multiple functions.

cmp eax, [ntcreatefile_ordinal]
je ntcreatefile_hook
cmp eax, [ntcreateprocess_ordinal]
je ntcreateprocess_hook
jmp original_code

This code is going to get very long and inefficient the more functions are hooked (because every kernel call is passing through this code, the system could slow down), but there's a better way.

We can build an array of DWORDs in memory (assuming we just want to hook NtCreateFile & NtCreateProcess, let's say the NtCreateFile ordinal is 0x02 and NtCreateProcess ordinal is 0x04), the array would look like this:
my_array+0x00 = (DWORD)NULL
my_array+0x04 = (DWORD)NULL
my_array+0x08 = (DWORD)ntcreatefile_hook_address
my_array+0x0C = (DWORD)NULL
my_array+0x10 = (DWORD)ntcreateprocess_hook_address

Then we could do something as simple as:
lea ecx, [my_array]
lea edx, [4*eax+ecx] ;edx will be &my_array[eax]
cmp [edx], 0
je original_code
call [edx] ;call the address pointed to by edx

This is pretty much what the kernel code for calling the SSDT function by its ordinal would do.

Calling Original Code

As with regular hooking, we just need to store the original code before we hook it. The only difference here is as well as pushing the parameters and calling the original code, the function's ordinal will need to be moved into the eax register.


Feel free to ask any questions in the comments or on our forum, hopefully this post has covered everything already.

Thursday, June 5, 2014

Hacking Soraya Panel - Free Bot? Free Bots!

Some security agencies have been raving about a revolutionary new bot that combines point-of-sales card grabbing (ram scraping) with form grabbing. The bot is actually not very interesting and pretty simple, but the panel is a great deal of fun (thanks to xylitol for getting me interested).

By default the panel shows the last 25 connected bots on the index page, not very interesting or helpful feature, but it opens up a whole world of possibilities. To understand what is possible, we need to take a look at the code responsible for adding new bots the the database.

From this code we can gather enough information to "impersonate" a bot. The HTTP method is POST, 'mode' must be '1', 'uid' must be a unique number, 'compname' must be a hex encoded string and so must 'osname'. The only difficult part is the fact the panel requires the bot to use a specific user-agent; however, we can find this by reversing a sample of the bot.

Here I've put together some code to add fake bots to the pane, thus add entries to the "last 25 connections".

Now, what if we decided to be a bit naughty? Let's try and submit HTML code as the bot's computer name. I'm sure this won't work because nobody is that bad at security, right? RIGHT??

Let's see the result...

Oh dear...

We'll, cool. We can submit HTML / JavaScript but what use can that be? Well we could mess with the botmaster by using javascript to redirect him to, replacing the entire page with rick roll, or modify the statistics. But could we hijack all his bot? Turns out the answer is yes!

A quick look at the command page allows us to throw together some code using "XMLHttpRequest()", when executed it will result in an update command being issued to the bot. All we need to do is provide our exe path in urlencoded format.

We could pay for hosting to host our script, only a small price to pay for a lot of free bots. Or, we could just use pastebin... All we need to do now is submit javascript to the panel which will run the code from pastebin.

Once we run it, when the botmaster logs in he will see this on the statistics page (minus the red block over the ip of course)...

The result of him viewing the page will be this....

So looks like revolutionary new malware "Soraya" is a little less than revolutionary when it comes to web security. Anyone with a sample of the bot binary can mess with the botmaster or potentially hijack the entire botnet.

Web Security - As easy as 1, 2, 3.

Tuesday, May 27, 2014

A few Reason for Maximum Password Length

A lot of people have recently been wondering the reason behind maximum password lengths, after it was revealed that eBay limited passwords to 20 characters. Many people see this as a security flaw (and in some cases it is), but often there are reasons behind it. I should also mention that I'm not speaking for eBay or any other site, I'm only highlighting some reasons for password limits.

Hashing Algorithms
Take MD5 for example, a few years ago MD5 was one of the most popular hashing algorithms for websites; However, it has quickly gone from a fairly secure algorithm to a big security no-no in the space of a few years. With large companies running huge distributed networks with custom software, it's usually easier said than done to upgrade the system to use a newer hashing algorithm (It can take months and and even years to modify all the code required across all the different systems). With that in mind, I'll explain the problem using MD5 and a hypothetical company still using such algorithm due to a lengthy upgrade process.

MD5 hashes are 16 bytes (32 hexadecimal chars which are half a byte each) in length and each byte contains 8 bits that can each be zero or one. That is (2^8)^16 or 2 ^ 128 combinations, in decimal: 340,282,366,900,000,000,000,000,000,000,000,000,000.

Now let's take our theoretical site which has a 20 char password limit. Assuming the password can contain alphanumeric characters, is case sensitive, and allows the use of standard symbols: that's 94 combinations for each character (94 ^ 20) which in decimal is 2,901,062,400,000,000,000,000,016,168,360,584,816,944.

What have we noticed already? 94 ^ 20 is far bigger number than 2 ^ 128. Sparing you any more big numbers, a 19 char pass (94 ^ 19) is significantly smaller than 2 ^ 128, so 20 chars is the shortest length of password that still (theoretically) produces more combinations than an MD5 hash can.

Because the MD5 algorithm takes input of any length, but all hashes are fixed at 16 bytes, multiple passwords can hash to the same value (see: hash collisions, collision attack). That is, your password could be the entire works of shakespear but a hacker bruteforcing the hash could theoretically find a match that is less than 20 characters (making allowing any more, a waste of resources).

Disclaimer: I use the word "theoretically" because MD5 does not generate hashes in a linear fashion, it is totally possible that multiple 20 char or less passwords could hash to the same value, but no 20 char or less password could hash to a given value; However, allowing more than 20 chars in this case would only slightly improve security as beyond this number collisions are a certainty.

Software Optimization
Let's say our software is written in C and has to hash passwords of variable length, how do we know the length of the password? Well, in C the end of a string is specified by the presence of the byte 0x00 (null byte), to get the length of the string; an application would count each byte of the string until it finds the null byte (slllllooooowwww). To speed up things we could limit passwords to a certain length, then just pad all passwords less than that length with a predefined byte. As a result we only have to handle a buffer of fixed length and not have to worry about working out the length of someones novel of a password.

If the software was storing plain-text passwords in a database (terrible idea), a length limit would also be a must, because: for reasons I'm not going to explain, databases can be handled easier and with greater speed if all fields in each row are of fixed length (in a theoretical high speed database, if one person had a 64 char password, every other user in the database should have a 64 char password field to make each row of equal length, which would result in am unnecessarily huge database).

The Ape Condition Problem
Let's say you put 4 apes in a metal cage and hang a banana on a string from the roof. Every time an ape pulls on the banana: it triggers a mechanism that electrifies the cage, shocking ALL the apes. Eventually the apes learn that touching the banana results in them all getting electrocuted. You then take one of the apes away and replace it with a new one, as soon as the new ape reaches for the banana, the other 4 apes beat the sh*t out of him. Quickly the new ape learns that touching the banana results in a beat down from the other apes. If slowly over time you keep swapping the apes out until none of the apes were there in the beginning: you now have a bunch of apes beating the sh*t out of any ape who touches the banana, and not one of them knows why.

The programming community sometimes works in a similar way. In the past due to software and hardware limitations there were many reasons to limit passwords and little reason to have long passwords (poor cracking hardware meant even short password cracking was near impossible). Over time these reasons become invalid, but some programming continue to implement such limits, their reason? Other people do it (or some 1990s forum thread tells them they'd be an idiot not to).

Alternate Security Means
A simple problem with people typing long passwords: It's likely they make a mistake while typing it. Think about credit card pin numbers, A 4 digit pin which you're hardly going to mistype. If everyone is limited to a 4 digit pin, the chances of mistyping or forgetting it are slim, which allows the system to implement harsh security measures such as locking your account after 3 failed attempts.

I should point out that such means of security only apply to systems where password hash databases are unlikely to be leaked, or the cracked database won't result in mass compromise of accounts.

Thursday, May 15, 2014

FBI Cybercrime Crackdown - Blackshades

It would seem the FBI is cracking down on cybercrime (well script-kiddies at least), with a bunch of international raids carried out in the past few days and more said to come. As of today it seems that the raids are only targeting users of "blackshades" a popular remote administration tool.

Blackshades is a remote administration tool (RAT) used for remotely accessing and controlling computers over the internet. Although RATs have many legal uses and are sold by software companies, they can also be used for malicious purposes such as data theft, spying and distributed denial of service attacks. Due to the fact that most legitimate RATs require a user to go through the standard installation process, hackers write their own versions that can invisibly infect a computer by running a single executable, this is what blackshades does.

In almost all international law, there is a grey area between what constitutes a legal RAT and an illegal one, as there is no black and white definition that separates software from malware. The authors of blackshades used the gray area to sell their malware for many years, with absolutely no legal implications. When it comes to the actual use of remote administration tools, the law is pretty clear cut: If you have permission from the owner of the computer, it's legal; if you don't it's not. Although the sales team were only marketing their product on hacking forums full of criminals, it had little legal implications for them and they made a lot of money. Blackshades was structured a lot like a regular company in the way they had a website, were registered as an LLC, accepted payments with paypal through a payment gateway, and kept detailed transaction logs; Most of this leading customers to believe that because the software was "legal", what they were doing with it was also legal, as a result most customers were paying for the software with their personal accounts, not making any effort to cover their tracks, and even posting threads about how many people they had infected online.

Threads with users bragging about how many computers
they had infected are not uncommon.

On Tuesday 13th May 2014 the FBI appears to have begun executing international raids with the help of local law enforcement. Although there appears to have been no arrests as of yet, many users of blackshades have reported police or federal officers entering their homes and confiscating any computer equipment. It is widely believe the FBI came into possession of the transaction log kept by the blackshades staff, which contained personal information of customers such as: names, addresses, and IPs. The raids coincide with a statement released by the FBI at the "Reuters Cybersecurity Summit", where they stated they would be taking "a much more offensive approach to cybercrime".

Rickey Gevers also has some interesting information on the raids:

Update 19th Nay 2014:
The FBI has released an official statement here, confirming that it was them orchestrating the international raids against blackshades users. The statement also confirms what many suspected for a while now, that Alex Yucel AKA marjinz, the creator of blackshades, had been arrested in Moldova (now waiting extradition to the US).

Also interesting is that they mention "operation card shop" as what put them onto the scent of blackshades. For those who don't know: Operation card shop was an FBI string operation that involved undercover agents running a carding forum for about 2 years. During the sting operation, "omniscient", the owner of hackforums, urged members to register on the carding forum and even gave the owner a  free upgraded account, it was later revealed that the same FBI agent had tried to buy hackforums a few months earlier. a member of the blackshades team, xviceral, fell victim to this trap after he accidentally gave away a free copy of blackshades (complete with free bots) to an undercover FBI agent, in return for vouching for his product.

You can see a copy of the indictments below:,%20Hogue%20Information%2013%20Cr.%2012.pdf,%20Yucel%20Indictment%20S1%2013%20Cr%20%20834_Redacted.pdf

Now for the bit I'm sure everyone is waiting for.

Tuesday, May 6, 2014

Rovnix new "evolution"

Rovnix is an advanced VBR (Volume Boot Record) rootkit best known for being the bootkit component of Carberp. The kit operates in kernel mode, uses a custom TCP/IP stack to bypass firewalls, and stores components on a virtual filesystem outside of the partition. Yesterday Microsoft posted an update explaining a new "evolution" to rovnix that had been found.


The so-called Evolution

I'm Melting
The first thing i noticed was the file "melts" (delete's itself once run (well, tries to)), this is done by a lot of malware to prevent future forensics, but how this sample does it is a little less than elegant. 

So advanced

The bot drops a non-hidden batch file to the location it's run from (in my case the desktop), the batch file just uses the "DEL" command on an infinite loop, which uses all of the CPU, until the file is deleted. On my test system, the batch file actually fails because the executable locks the file, meaning it can only be deleted once the executable stops (the system reboots), when the system reboots windows stops the batch file before the executable, thus it's never deleted. 

Initial Infection
After executing the packed binary it unpacks itself and continues running, the above batch file is deployed to delete the dropper after run. For stealth reasons, the kit sits idle for an undefined amount of time (I'm yet to find out how this is done), then the system is automatically rebooted. NtShutdownSystem is hooked to receive notifications of shutdowns / reboots, so rebooting the computer will result in intimidate infection and save you a wait. Amusingly the packed dropper doesn't exit until reboot and the delay is long enough to attach a debugger, dump the unpacked code from memory, then move it to another computer.

The entire kit is packed inside the dropper, about 13 files total (32-bit and 64-bit) and during the reboot delay everything exists in one continuous block of memory and once dumped; the components can be split up by byte signature "0x4D 0x5A 0x90" (DOS header).

The first thing i noticed after infection is that the first 16 sectors of the disk are blank (where the VBR should be located). To anyone familiar with rovnix this is a common sign of infection, as it uses the kernel driver to hide infected sectors (which is probably just as suspicious as showing them).


The kit appears to run ok on Windows XP 32-bit, but on Windows 7 64-bit it causes the PC to BSOD about every 20 minutes (Sometimes the system can even get stuck in an infinite BSOD loop).

Anti Reversing
I can't tell if I'm going crazy or the anti reversing protection is what I think it is. The driver appears to check for a wide variety of reversing tools (vbox, vmaware, wireshark, ollydbg, ida, lordpe, etc), then disregards the results and exits the thread. My tests appear to confirm this as I've infected a VM with multiple blacklisted tools running and the malware still continues the infection. 

The return value will be non-zero if any blacklisted tools are found

Disregard everything?
I've checked through the ASM multiple time, but can't seem to find anything that would result in the bot being any wiser about the environment after the execution of this thread.

Virtual File System
Remember the old rovnix filesystem? It used raw disk access to store components outside of the filesystem in non-allocated disk space, making it near impossible for the AV to find or remove? Well that has been "upgraded". The virtual filesystem is now stored inside a file in "C:\system32\", free for the AV to delete at any point (Coder couldn't figure how to access virtual filesystem from usermode?). The file-name ends in ".bin" and is a 64-bit hex value generated using the time stamp counter ("rdtsc" instruction), all files are encrypted with RC6.

Example File-name Generation

Because the file system is now vulnerable due to it being saved as a standard windows file, the coders have added a high level (and fairly useless) kernel mode rootkit to the driver. The rootkit places SSDT hooks on the following functions:
  • NtQueryDirectoryFile - Hides the file.
  • NtCreateFile - Prevents file from being opened by all except bot.
  • NtOpenFile - Same as above.
  • NtClose - No idea.
  • NtSetInformationFile - Prevents rename / delete.
  • NtDeleteFile - Prevents delete.
  • NtQueryInformationFile - Hides the file.
Additionally the rootkit also hooks some registry functions to hide keys, I can't see any sane reason why.

Each hook entry is an array of 16 bytes (4 double words)

Although this won't protect against antiviruses, it may stop usermode malware and beginner security researchers from tampering with the filesystem.

Usermode Component
This entire bootkit + kernel mode rootkit all serves to protect a small trojan which appears to run as a service and do nothing other than log keys and ammyy id's to a command and control server. The MD5 has is: 5e5f3ced234c6f7c91457a875cf4a570.

This isn't the work of common scriptkiddies, it's likely the coder has a moderate knowledge of kernel mode programming; however, the code is not experience with malware (using SSDT hooks and filters in a bootkit, having to move the virtual filesystem into a real file to access it from usermode, using batch file to delete melt exe). This clearly isn't an "evolution" of rovnix as Microsoft claim, it's just some random coders trying to make the bootkit compatible with their bot.

Thanks to Poopsmith for bringing the sample to my attention and Xylitol for retrieving it for me.

Finally, something to reverse.