Thursday, 10 November 2011

Reducing detection rate on novirusthanks.com..

Your keylogger is being detected based on heuristics, meaning that even though there is no specific antivirus signature for it (as it has not been seen in the wild yet) it can still be generically detected as malware due to its behavior and/or information found in the PE file itself.

I'd suggest following these guidelines to reduce the detection rate:

1) Dynamically load APIs wherever possible.
When you statically link functions from the Windows library, as you've done here, it builds an import table in the structure of your portable executable file that displays which functions are being imported and what their addresses are. Antimalware programs scan these tables and look for imported APIs that are likely to be used for viral purposes. Let's see what you're importing here;

Code:
GetModuleFileName
RegOpenKey
RegSetValue
CopyFile
SetFileAttributes

It doesn't take an amazing antivirus to recognize the installation pattern that most malware follows: Drop a file, create a regkey, hide traces of your own existence, connect to c&c. Thus statically linking these APIs will raise a red flag because it's obvious that they are about to be used for those exact purposes.

I would suggest looking at the winapi functions LoadLibrary and GetProcAddress--that's the starting point for dynamically loading APIs. There are much better and more advanced ways to dynamically load procedures which people have thought up over the years, but you have to begin somewhere, and even something simplistic like LL-GPA is better than static imports.

2) All static strings/information should be encrypted and briefly decrypted at runtime as they are needed.
This applies to every constant piece of info in the source, whether it's the regkey path, a domain name, a port, an email address...whatever. It should all have a layer of encryption on it. For stuff like regkey names it doesn't matter so much what encryption is used or how strong--the point is just to make the plaintext invisible to automated scanning. For sensitive information like domains, a good encryption algorithm (RC4/5 are common) with a strong key should be used. Then when you need the strings, briefly decrypt them in memory.

3) Junk code can help but can also be a red flag if used too heavily.
Junk code (like random if-else statements that you mentioned) can sometimes decrease the detection rate, but when it's overused antivirus folks can create a detection signature based on the static junk code, and it will become a basis for detection on its own. Other commonly used examples of junk code include jumps to random functions, random loops, sleep statements, etc. Some people also statically link APIs that aren't commonly used in malware, as the inclusion of these "clean" APIs can sometimes lead an antivirus to falsely mark the malware as a legitimate application; this could be considered a form of junk code.

4) Stay away from wrapper/convenience functions.
An example of a convenience function in your code would be CopyFile--it's a function written to shorten (i.e. make more convenient) the fairly common and tedious process of manually copying a file using CreateFile/ReadFile/WriteFile. It leaves a gigantic fingerprint that's going to be heavily detected, and, in addition, you can't really control/modify its behavior in the way that you could if you wrote your own function for copying files. Find out how the convenience function works, then make your own. For example, in this case you could use CreateFile/Read/WriteFile (or NtCreateFile/NtWriteFile/NtReadFile), and that would be a better alternative to taking the easy way out with CopyFile. The second most common example of a convenience function, that I can think of, would probably be URLDownloadToFile. It's used to simplify the slightly more complicated and undoubtedly dull task of manually creating a file on disk and mapping a stream of data from the internet into that file. It's convenient, but it's also heavily detected and doesn't allow you to account for errors/exceptions your own way should the function fail on some internal level.

That's about all I can think of at the moment. I'm sure there's more that I'm not remembering.

0 comments:

Post a Comment