Tuesday, February 08, 2011


I was looking at a Windows 2003 system, and found that I was somewhat short on Event Log entries, with respect to the incident window. As I looked and used my evtrpt.pl Perl script to get statistics on the Sec, Sys, and App Event Logs, I noticed that Sec and Sys Event Logs only contained a few days of event records. The Application Event Logs actually went back a while past the incident window. I looked a bit closer to the output of evtrpt.pl and noticed that the Security Event Log had an event ID 517 record, indicating that the Event Log had been cleared.

So the first thing I did was run TSK blkls against the image to extract the unallocated space from the image file. I then ran MS's strings.exe (with the "-o" and "-n 4" switches), and then had two files to work with...the unallocated space, and a list of strings found in unallocated space, along with the offset of each string. So I then wrote a Perl script that would go through the strings output and find each line the contained "LfLe", the "magic number" for Windows 2000/XP/2003 event records.

With this list, the script would then run through the unallocated space by first going to the offset of the "LfLe" string, and backing up 4 bytes (DWORD). According to the well-documented event record structure, this DWORD should be the size of the record. As values can vary, and there is no one specific value that is correct, the way to check for a valid event record is to advance through unallocated space for the length provided by the DWORD, and the last DWORD in this blob should be the same as the size of the record. For example, if the initial size DWORD is 124 bytes, you should be able to advance through the file 120 bytes, and the next DWORD should also be 124.

Using this approach, I was able to extract over 330 deleted event records. I've used similar techniques in the past, to extract 100 bytes on either side of a keyword from the pagefile. This is an excellent way to gather additional information that you wouldn't normally be able to 'see' through most tools, as well as to look for and carve well-defined structures from unstructured data.


Anonymous said...

Are you going to post the perl script that goes through unallocated space looking for "LfLe" and parses them out?

H. Carvey said...

I hadn't planned on it...it's pretty trivial. Besides, who would I post it to? "Anonymous"? "Occupant"? ;-)

Is it something that you really feel would be useful? I guess from my perspective, it may be too resource intensive for most folks...I mean, you have to follow some steps, and do things right. I don't think it's that hard, but it's probably a bit much for the Nintendo forensics crowd.

Besides, when I do post stuff like that, I don't get any feedback.

Litmus said...

Hello Harlan,

first of all, I would like to say thank you for the books and the tools you developed. As a "noob" DFIR engineer who started getting interested in forensics little more than one year ago, I've learned a lot from all of the above.

I write this to inform you about a bug in the evtparse.pl script and provide a possible solution for it.

Lately, I've been involved in a case where event logs from a windows 2003 server had been cleared and it was important to recover them.

I had used evtparse.pl in the past, however the way I used it so far was:

-recover evt log files with scalpel
-running evtparse against the recovered files.

In this case, this approach didn't work very well and I was able to recover only 5 records related to the day I was interested in, so I started researching how to do better and recover all log fragments from the interesting places I could think of like pagefile, memory, unallocated and slack.

I stumbled upon this entry in your blog while doing this research. I suspect that the script you are mentioning there later became "evtparse.pl".

I started studying a way to implement your description of how to address the problem and studying the code of evtparse and was very surprised to find out that it looks straight for the header of a record (the famous. It doesn't care at all for header/footer of evt files, which means that it can be used against anything, be it unallocated, memory image, etc, etc. which opens quite a bit of possibilities, instead of using it only for evt files.

However, I had noticed in the past that sometimes the script will go in an apparently endless loop and ran again into this same issue when trying to run it against a 4gb memory image. Upon investigation, it looks like the issue is related to cases where the famous "LfLe" is found but the length of the record (the previous 4 bytes) is 0, meaning corrupted records. In this case the script will locate the magic number, consider it a valid record but will update the offset to offset + length (in this case 0) and enter a endless loop. I hope it is clear.

The solution is simple, I think. By changing line 78 of your script from

if ($l == $f) {


if (($l == $f) and ($l !=0)) {

a record with the valid header but with a length of 0 will be considered invalid and the offset will be updated to offset + 4 bytes.

I tested the script against big images (several gigabytes of data) and it seems to work fine with this modification.

Now I have a new weapon in my forensic arsenal. Thank you for that.

I hope this helps,

H. Carvey said...


Thanks for the email.

What you found is what happens when there is a dearth of information to test on, and folks who say that they want to use a tool like this tend to want someone to create it for them. Thanks for taking the time to actually troubleshoot the issue.