Wednesday, August 03, 2005

Process monitoring and malware analysis

As part of looking into ways of improving malware analysis, I got to thinking about some things. For instance, some malware may maintain encrypted strings (ie, passwords or URLs) which it then decrypts in memory, and deletes once the string has been used. Some data used by the malware process may be transient in memory. So what do you do?

Well, I had a thought...what if you could run a process for a specified period of time, dump the contents of memory (and maybe run some other tools), then resume the process for a short period of time? Using Perl, we can do this! Here's the code:


#! c:\perl\bin\perl.exe
# strap.pl
# use to launch an application (malware) and then at predefined
# intervals, suspend() the process, perform some actions (ie, dump
# contents of memory, run external programs like listdlls.exe, etc.)
# then resume the application
use strict;
use Win32::Process;

So, we're using the Win32::Process module. Now, let's set up our variables. For testing purposes, I used AIM...

my $proc;
my $app = "c:\\program files\\aim\\aim.exe";
my $args = "";
my $dir = ".";
my $exit_code;

Now, let's go ahead and create our process...

if (Win32::Process::Create($proc,$app,$args,0,NORMAL_PRIORITY_CLASS,$dir)) {
print "Process created.\n";
# Get PID
my $pid = $proc->GetProcessID();
print "Process $pid created.\n";

Now that we've created our process, let's let it run for a bit (in this case, 3 seconds), then suspend the process. What we're doing, for testing purposes is running this loop only 10 times. This can be expanded (and the Wait() time changed, as well), or an entirely different loop structure can be used.

foreach (1..10) {
$proc->Wait(3000);
$proc->Suspend();
print "Process suspended.\n";

Now that the process has been suspended, we can go ahead and do things like dump process memory (with pmdump.exe), or run tools like handle.exe, listdlls.exe, etc.

sleep(3);

Once we're done, go ahead and resume the process...

$proc->Resume();
print "Process resumed.\n";
}
}

Now, just a little error checking...

else {
print "Process creation failed: ".Win32::FormatMessage Win32::GetLastError()."\n";
exit(1);
}

So, once this script has completed, you can conduct your analysis. For memory dumps, run strings.exe against the files, or use scripts to extract email or IP addresses, etc.

Addedum: In responding to some comments this morning, I thought that something I said should be included in the text of the post itself.

What I've presented above is not meant to replace anything. Rather, it's a tool...nothing more. Like any tool, it's effectiveness depends upon how you use it. One possible scenario for the use of this tool would be where an administrator or analyst has an unknown bit of software (we won't call it malware yet b/c we don't know). When looking at the program with a hex editor (part of performing static analysis), the analyst may believe that the program is encrypted or obfuscated in some manner. Now, most admins/analysts don't have tools like IDAPro at their disposal, and don't have the necessary skill sets to use things like debuggers and disassemblers. So, moving on to dynamic analysis, they want to run the program on a "sacrificial lamb" system to see what it does. Loading up monitoring tools, the analyst may want to run the application in a more controlled fashion, dumping memory contents along the way.

The above script will let you do that. Admittedly, the script itself is raw, and in it's early stages...but the basic idea is there. The great thing about scripts like this is that they can be easily expanded. For example, let's say we replace sleep(3) the necessary command to run pmdump.exe. When the above script ends, you'll have a directory with a bunch of memory dump files. Well, at that point, the script can then:
  1. Hash each of the files (using Jesse's tools)
  2. Run strings.exe against each file
  3. Grep() through each file looking for email or IP addresses, keywords, etc.
  4. Run 'diff' between all of the files to see what changed between snapshots
  5. Save the results to a flat file, a spreadsheet, or a database for analysis

To me, it's all kinda cool! Something like this would have been kind of interesting when I was using netcat to demonstrate Locard's Exchange Principle.

10 comments:

Anonymous said...

Neat idea! Can the program check to see if it's running under such an environment? For example, that it's being "debugged"? That it's parent is not Explorer.exe? Can it ignore the suspend request?

Anonymous said...

Also, what about a MiniDump of the process?

H. Carvey said...

Jesse,

Can the program check to see if it's running under such an environment? For example, that it's being "debugged"?

I don't know if malware is checking for that sort of thing. In the code, I'm not attaching to the process in debug mode, so I'm not really sure that such a thing would show up.

That it's parent is not Explorer.exe?

I was using 'tlist -c' in my testing last night...maybe I should move on to 'tlist -t'.

Have you seen any malware apps that check to see if their parent process is Explorer.exe?

Can it ignore the suspend request?

Perhaps. We'll have to see. I've only worked with 'normal', 'well-behaved' applications as I'm developing this idea...as of last night. ;-)

Also, what about a MiniDump of the process?

That's the beauty of this whole thing...you can do what you want while the process is suspended. In my code, I simply have the script sleep() for three seconds. However, the Wait() function has a granularity of milliseconds. So a script like this provides the analyst with a level of control that they wouldn't get by running the MS debugging tools manually.

Is this a be-all and end-all? No. It's not meant to replace anything, but rather meant to give folks another option. Not all of us own IDAPro, and not all of us can or want to use debuggers and disassemblers. This is simply something that they can do, and it's automated.

Looking at the code now, it would seem that the hard part is done. Let's say you run this script and you've got a directory with a couple of dozen memory dump files. Well, you can have another script (or an addendum to this script) run through each of the files, running strings, and grep()'ing for other things...IP addresses, email addresses, specific content, etc. The script could even automatically dump that information into a spreadsheet or a database for analysis.

Like I said, just another tool...

Anonymous said...

I have been working recently on a tool very similar to this, and oddly enough, also using perl.

I have also been using using net-dns-nameserver to resolve any name lookups back to the local machine, with plans for a netcat listener. Very
useful for malware analysis.

Throw in some common unpackers, a file system/registry watcher, and a few other tools and you have a very nice surface/runtime analysis tool.

Very nice indeed. Keep it up.

H. Carvey said...

MacLeonard,

Great idea, resolving the DNS queries back to the local system. Do that, then fork() off a listening socket to capture requests...very cool!

As far as unpackers...I'm not sure where you'd need that, as you're running the malware and they usually unpack themselves. The monitoring tools are available from SysInternals.com, and of course, you can add any other tools you like.

It's very cool to see someone else working on something similar...do you have a web site you can share that shows your work?

Thanks,

Harlan

Anonymous said...

The use of unpackers such as upx, fsg, unaspack etc is useful for a more complete analysis of the malware, and maybe gain some useless statistics in the process.

By unpacking the malware, you often get a good view of information such as targeted organisations, email addresses, IP's, without ever having to run it.

Some malware only unpacks enough of itself in memory to be able to execute the next block of code, having the luxury of unpacking these on disk saves time on analysis, which is always a good thing.

Regmon and Filemon are great, but they have their limitations, if you want to automate this as much as you can, then using ChangeNotify() works just fine for the filesystem, and you can grep() dumps of various registry keys, or use a MOF file for registry change notifications.

Unfortunately as I am developing this as a tool for my organisation, I am unable (at this point) to make the code public.

H. Carvey said...

The use of unpackers such as upx, fsg, unaspack etc is useful for a more complete analysis of the malware,...

These will work only if the malware is packed in a way that can be unpacked. Early on, I took a look at a 'bot that looked like it was packed with UPX, but it was an older version that had been modified to (a) not be unpacked, and (b) execute commands once the files were unpacked.

Now, there are new delivery mechanisms being developed all the time. One method (encrypt the malware and append it to the end of a "normal" file) has been improved...the malware is encrypted and stuffed into the resource section of a stub file. When the stub file is executed, the malware is pulled out of the resource section of the file, decrypted, and executed in memory.

...and maybe gain some useless statistics in the process.

Useless? Do you mean "useful"?

Static analysis is always a good thing and yes, you can get a lot of great information from a file if you are able to view the import table, etc.

However, there are times that unless you know x86 intimately well, the only way you're going to get any real behavioral information about a file is to perform dynamic analysis; ie, run it under controlled conditions.

That's what my script is for. By running the code for a few seconds (or milliseconds, given the granularity of the timer) and then suspending the code and dumping the contents of memory, you can take a look at how things change as the process executes over time. I'm not guaranteing anything, but you may be able to detect strings, for example, that are encrypted or obfuscated in some way in the code, and only appear as "normal" in memory, and then only for a very short while.

Don't get me wrong...again, this is NOT meant to replace any other tools or techniques. Rather, it's simply another option.

Anonymous said...

I have another quick way to do that. I run the malware in a qemu virtual machine and dump the memory of the virtual machine in a file. Then I grep the file.

H. Carvey said...

Sure, I do the same thing with VMWare, only when I open the .vmem file, I don't have to 'grep' anything, b/c I can parse through the file itself and pull out all of the processes, as well as any details. The data is much more explicit than a simple grep.

Anonymous said...

I don't use malware.