A look at anti-virtualization in malware samples

In previous posts, I described PuppetMaster, a way to dynamically detect and control CPU-based VMM detection methods in malware samples. We ran it on 2 sets of malware samples, and here are the results.

1. 60k samples from a Nepenthes honeypot

  • 62498 samples on the honeypot
  • 59554 of them being executable files
  • 48404 were analysed “correctly”
  • 13409 samples were terminated due to a 2 minutes timeout

The number of samples trying to detect virtualization is surprisingly low:

  • 71 (0.15%) binaries used at least one anti-virtualization technique
  • 65 (0.13%) binaries used the SIDT anti-virtualization technique
  • 0 (0.00%) binaries used the STR anti-virtualization technique
  • 0 (0.00%) binaries used the SLDT anti-virtualization technique
  • 0 (0.00%) binaries used the SGDT anti-virtualization technique
  • 14 (0.03%) binaries used the VMware channel anti-virtualization technique

2. 25k samples from uh… somewhere

These samples were shared by Paul Royal, so thanks Paul :)

  • 25118 samples
  • 23104 of them being executable files
  • 18670 were analysed “correctly”
  • 8298 samples were terminated due to a 2 minutes timeout

Again, the number of samples trying to detect virtualization is very low:

  • 117 (0.63%) binaries used at least one anti-virtualization technique
  • 56 (0.30%) binaries used the SIDT anti-virtualization technique
  • 0 (0.00%) binaries used the STR anti-virtualization technique
  • 2 (0.01%) binaries used the SLDT anti-virtualization technique
  • 6 (0.03%) binaries used the SGDT anti-virtualization technique
  • 58 (0.31%) binaries used the VMware channel anti-virtualization technique

Conclusion

There are a few potential reasons why the numbers are so low:

  1. the samples used other techniques that we do not support (such as detecting the VMware tools, or hardware version)
  2. or the samples we got are really not representative of malware samples in the wild. Indeed, our 60k samples contain mostly Allaple samples.
  3. or anti-virtualization techniques are not that common in actual malware samples…

It would be interesting to run the test on better malware repositories, unfortunately this is not something obvious to get our hands on. So if you have a big malware repo ready to be dissected, and you would like to share them with an academic lab for free, I’d be glad to hear from you: reynaudd at loria dot fr.

Advertisements

Reversing CUDA Software

After my Ruxcon talk on GPGPU malware, some people doubted that malware could use GPUs at all and that even if malware used GPUs, they would just be like normal malware (and since I did not provide any code sample at the conference, I can understand the frustration).

Here is a small code sample to convince the unconvinced: it contains encrypted strings, that are sent on the GPU to be decrypted. And once decrypted, they are executed in a shell.

#include <stdio.h>
#include <cuda.h>
#define MAX_SIZE 255

// caution: kickass encryption ahead
__global__ void decodeOnDevice(char *a) {
  char cap;
  int i = 0;
  while(a[i] && i<MAX_SIZE) {
    cap = a[i] & 32;
    a[i] &= ~cap;
    a[i] = ((a[i] >= 'A') && (a[i] <= 'Z') ? ((a[i] - 'A' + 13) % 26 + 'A') : a[i]) | cap;
    i++;
  }
}

int main(void) {
  char *temp_host;       // pointers to host memory
  char *temp_device;     // pointers to device memory
  char commands[2][MAX_SIZE];
  int i;

  // allocate arrays on host
  temp_host = (char *)malloc(MAX_SIZE);

  // allocate arrays on device
  cudaMalloc((void **) &temp_device, MAX_SIZE);

  // initialize host data
  memset(commands[0], 0, MAX_SIZE);
  memset(commands[1], 0, MAX_SIZE);

  // these are the encoded commands
  memcpy(commands[0], "rpub Jung vf lbhe anzr, unaqfbzr xavtug?", strlen("rpub Jung vf lbhe anzr, unaqfbzr xavtug?"));
  memcpy(commands[1], "rpub - Fve Tnynunq... gur Punfgr.", strlen("rpub - Fve Tnynunq... gur Punfgr."));

  for(i = 0; i<2; i++) {
    memset(temp_host, 0, MAX_SIZE);
    memcpy(temp_host, commands[i], strlen(commands[i]));

    // send data from host to device
    cudaMemcpy(temp_device, temp_host, MAX_SIZE, cudaMemcpyHostToDevice);

    // data copied on device, invoking kernel
    decodeOnDevice <<< 1, 1 >>> (temp_device);

    // retrieve data from device
    cudaMemcpy(temp_host, temp_device, MAX_SIZE, cudaMemcpyDeviceToHost);

    // execute the decoded command
    system(temp_host);
  }
}

New Firefox Malware

Howdy,

Apparently BitDefender stumbled upon a Firefox-only banking malware. It installs itself as a Firefox plugin (= it installs a native binary) and as a javascript file in the Chrome folder (= it modifies the source code of Firefox):

  • %ProgramFiles%\Mozilla Firefox\plugins\npbasic.dll
  • %ProgramFiles%\Mozilla Firefox\chrome\chrome\content\browser.js

If anyone has a sample, I’d like to have a look at it. It’s not technically a Firefox extension, but its payload could also be delivered as an extension (with no native code at all). If anybody wonders why there is not more Firefox crapware, there are two reasons for it:

  • the browser market is still dominated by IE
  • malware authors have not realised how easy it was to write malware for Firefox

Links:

Ruxcon08 Cover Up

Hi folks,

I just come back from Ruxcon08 in Sydney, a really nice security conference with lots of high-level talks, an excellent venue and super-duper ambiance. Thanks to everyone for the positive feedback on my presentation on GPU Powered Malware (slides here).

My personal highlights are:

Silvio Cesare, Security Applications for Emulation. A really good talk dealing in part with automated unpacking, tracing, dynamic taint analysis and symbolic execution. All of which are the next step in malware analysis (me thinks). Silvio also produced a quite amazing memory bug checker for the Linux kernel.

– Nishad Herath, Now you see it, now you don’t! – Obfuscation ’08 style… He introduced the new trends that we see in obfuscation (not malware-specific) like code fragmentation and instruction virtualisation. Too bad he was (intendedly ?) light on details on the use of abstract interpretation and trace analyses. Me wants more !

Though not related with what I do, I also enjoyed Browser Rider by Ben Mossé (you really have to see a Javascript tunnel between a rogue server and a browser in action to get the full flavour) and Intelligent Web Fuzzing by Mr and Mrs Archibald. Instrumenting PHP, MySQL and Bash with all that hooks looks definitely hairy ! Oh yeah and a special mention for Netscreen of the Dead by Graeme Neilson – this guy is getting Zombie-creepiness and gore to the next level.

Well see you next year I guess ;)

Links:

A Quick Survey on Automatic Unpacking Techniques

This is a non-comprehensive list of papers and tools dealing with automated unpacking. Please let me know if I’ve missed another technique or if I misunderstood any of the techniques below.

Ring0/Ring3 components, using manual unpacking and heuristics

OllyBonE:

OllyBonE (Break on Execution) uses a Windows driver to prevent memory pages from being executed, and an OllyDbg plugin communicating with the driver. As such it is not an automatic unpacker and requires manual tagging of the pages in which the unpacked code is expected to be found.

Technology used: Windows driver to prevent memory page execution, debugger plugin

Handles unknown packers: no.

Drawbacks: requires a priori knowledge of the memory location of the unpacked code, vulnerable to anti-debugging techniques, modification of the integrity of the host operating system due to the driver.

Code Available: yes, http://www.joestewart.org/ollybone/.

Original Site

(Updated) Dream of Every Reverser / Generic Unpacker:

It is a Windows driver used to hook ring 3 memory accesses. It is used in a project called Generic Unpacker by the same author to find the original entrypoint. The tool then tries to find all import references, dumps the file and fixes the imports. It is reported to work against UPX, FSG and AsPack, but not against more complex packers.

Technology used: Windows driver to hook userland memory access

Handles unknown packers: no.

Drawbacks: requires a priori knowledge of the memory location of the unpacked code, modification of the integrity of the host operating system due to the driver.

Code Available: yes, http://deroko.phearless.org/GenericUnpacker.rar.

Original Site

(updated) RL!Depacker

No description for this one, however it looks similar to Dream of Every Reverser / Generic Unpacker.

Code Available: yes,  http://ap0x.jezgra.net/RL!dePacker.rar.

Original Site

(updated) QuickUnpack

Again, no real description, but it looks similar to RL!Depacker and DOER / Generic Unpacker. It is a scriptable engine using a debugging API. It is reported to work against 60+ simple packers.

Code Available: yes, http://www.team-x.ru/guru-exe/?path=Tools/Unpackers/QuickUnpack/

Original Site (in Russian)

Universal PE Unpacker:

This is an IDA Pro plugin, using the IDA Pro Debugger interface. It waits for the packer to call GetProcAddress and then activates single-stepping mode until EIP is in a predefined range (an estimate for the OEP). It only works well against UPX, Morphine, Aspack, FSG and MEW (according to the authors of Renovo).

Technology used: Debugging and heuristics.

Handles unknown packers: no, needs an approximation of the OEP and assumes that the unpacker will call GetProcAddress before calling the original code.

Drawbacks: not fully automatic, very vulnerable to debugger detection, does not necessarily work against all packers or self-modifying code.

Code Available: yes, since IDA Pro 4.9

Original Site

Instruction-level analysis, comparison between written addresses and executed addresses

Renovo:

Built on TEMU (BitBlaze), it uses full system emulation to record memory writes (and mark those memory locations as dirty). Each time a new basic block is executed, if it contains a dirty memory location a hidden layer has been found. Cost: 8 times slower than normal execution. It seems to unpack everything correctly except Armadillon and Obsidium (due to incorrect system emulation ?). It seems to only obtain partial results against Themida with the VM option on.

Technology used: Full system emulation.

Handles unknown packers: yes.

Drawbacks: order of magnitude slowdown, detection of the emulation stage

Code Available: I couldn’t find it.

Original Site, Local Copy

Azure:

Paul Royal’s solution, named after BluePill because it is based on KVM, a Linux-based hypervisor. It uses Intel’s VT extension to trace the target process (at the instruction-level), by setting the trap flag and intercepting the resulting exception. The memory writes are then recorded and compared to the address of the current instruction. According to the paper, it handles every packer correctly (including Armadillo, Obsidium and Themida VM).

Technology used: Hardware assisted virtualization and virtual machine introspection.

Handles unknown packers: yes.

Drawbacks: detection of the hypervisor. Slowdown ?

Code Available: yes, http://blackhat.com/presentations/bh-usa-08/Royal/Royal_Extras.zip.

Original Site, Local Copy

Saffron:

Developed by Danny Quist and Valsmith, a first version uses Intel PIN to dynamically instrument the analyzed code. It actually inserts instructions in the code flow, allowing lightweight fine-grained control (no need for emulation or virtualization), but it modifies the integrity of the packer. A second version modifies the page fault handler of Windows and traps when a written memory page is executed. It has mixed results with Molebox, Themida, Obsidium, and doesn’t handle Armadillo correctly (according to Paul Royal).

Technology used: Dynamic instrumentation, Pagefault handling (with a kernel component in the host operating system).

Handles unknown packers: yes.

Drawbacks: modifies the integrity of the code (with DI) and of the host operating system. It must not work in a virtual machine. The dynamic instrumentation is very slow. The memory monitoring of the pagefault handler is coarse-grained (pages are aligned on a 4k boundary), and therefore some memory access can go unnoticed.

Code Available: dynamic instrumentation available, what about the driver ?

Original Site, Local Copy

(updated) OmniUnpack:

Uses a technique similar to the second version of Saffron: a Windows driver to enforce a W^X policy on memory pages.

Technology used: Pagefault handling  and system call tracing (with a kernel component in the host operating system)

Handles unknown packers: yes.

Drawbacks: modifies the integrity of the host operating system. It must not work in a virtual machine. The memory monitoring of the pagefault handler is coarse-grained, leading to spurious unpacking stages.

Code Available: ?

Original SiteLocal Copy

Pandora’s Bochs:

Developed by Lutz Böhne, it is based on Bochs which is used to monitor memory writes and compare them with branch targets. Interestingly, the assumptions about the program are stated explicitly (which is a GOOD thing) : the unpacking does not involve multiple processes, it does not happen in kernel mode, the unpacked code is reached through a branch instruction (not a fall-through edge), etc… Another interesting point in this approach is that it uses no component in the guest OS (as opposed to Renovo for example), all the information is retrieved from outside the matrix (as with Azure).

Technology used: Full system emulation based on Bochs.

Handles unknown packers: yes.

Drawbacks: As stated in the paper the limitations are speed, compatibility (not all packed samples seemed to run under Bochs), detection of OEP and reconstruction of imports sometimes failed.

Code Available: http://damogran.de/blog/archives/21-To-release,-or-not-to-release-….html

Original Site, Local Copy

Other techniques (comparison with static disassembly or disk image)

Secure and Avanced Unpacking by Sebastien Josse:

The idea developed by Sebastien Josse is to use full system emulation (based on QEMU ?) and to compare the basic blocks that are going to be executed by the virtual CPU with the equivalent address in the file image of the executable. If the memory and the disk version differ, it means that the code has been generated on the fly and therefore a hidden layer has been found. Josse then proposes techniques to rebuild a fully functional executable based on the memory dump. This technique seems to work well (but sometimes requires human intervention) against several packers, including Armadillo, ASProtect, PEtite, UPX, yC…

Technology used:Full system emulation, comparison between memory images and disk images.

Handles unknown packers: yes, manual intervention might be required in some cases.

Drawbacks: slowdown due to the full system emulation, full reconstruction of the unpacked program is not always possible.

Code Available: ?

Original Site

PolyUnpack:

The idea behind PolyUnpack is to address the fundamental nature of unpacking, which is runtime code generation. To identifiy code that has been generated at runtime, PolyUnpack uses a conceptually elegant technique: it first statically analyses the program to build a map of statically accessible code, and then traces the execution of the program. The dynamically intercepted instructions are compared with the static disassembly, if they do not appear in the static disassembly then they have been generated at runtime.

Technology used: comparison between static disassembly and dynamic tracing. The dynamic trace is extracted with single-step debugging APIs.

Handles unknown packers: yes.

Drawbacks: vulnerable to debugger detection. Note that this is a limitation of the implementation, not of the concept.

Code Available: http://polyunpack.cc.gt.atl.ga.us/polyunpack.zip (updated 26/06/2009)

Original Site, Local Copy

Malicious Firefox Extensions – continued

I worked with Phil on malicious firefox extensions – very briefly at SSTIC, in details on the lab’s blog, and in an unpublished short paper.

As some people asked, yes the issues have been reported to the Mozilla security team (thanks to JP Gaulier and Tristan Nitot). And the result is a bug report marked as invalid (which is normal, since what we wanted to communicate was not a bug report but rather design issues).

So basically the situation is: ActiveX is bad because there is absolutely no security policy. There is absolutely no security policy for Firefox extensions but it’s cool.

I’m out, I really need a double shot of espresso now.

Dan