Lenny Zeltser sent me an article last week about a new keylogger (md5sum 21f8b9d9a6fa3a0cd3a3f0644636bf09). The article mentioned the fact that the keylogger uses ToR to make attribution more difficult. That's interesting, sure. But once I got the sample, I noticed that it wasn't compiled with the Visual Studio of Delphi I'm used to seeing malware use. Then I re-read the article and found a mention of it being compiled in Free Pascal. Well, that changes the calling conventions a little, but nothing we can't handle. However, it is worth noting that IDA doesn't seem to have FLIRT signatures for this compiler, so library identification is out (sad panda time).
EDIT: FLIRT is used by IDA to identify runtime libraries that are compiled into a program. Reverse engineers can save time by not analyzing code that is linked into the binary, but not written by the malware author. It is not unusual for a binary to get 30-50% (or more) of it's functions from libraries. In this case, IDA identifies 3446 functions. However, none of them are identified as library functions. To find probable user code, we'll anchor on cross references from interesting APIs unlikely to be called from library code.
The first thing I need here is an IOC to track this thing. After all, as I tell all my classes, IOCs pay the bills when it comes to malware analysis. Sure, I could fire it up in a sandbox, but I'd so much rather do some reversing (okay, if not for this blog post, I'd use a sandbox, especially given the lack of FLIRT signatures for this sample).
For IOCs, I always like to find a filename, something that is written to the system. I searched the imports table for API's that would return a known directory path. In this case, I found GetTempPath, a favorite of malware authors. Guess where system.log can be found? You guessed it, in the %TEMP% directory of the user who executed the code.
However, it is worth noting that later in the function, there is a call to DeleteFile. I didn't take the time to fully reverse the function yet so I don't know if this will always be called (a quick look makes it appear so). But we're after some quick wins here (and this isn't a paid gig), so we're moving on. This means that our %TEMP%\system.log file may not be there after all. Bollocks... Well, you win a few, you lose a few.
Well, now that's interesting... A call to GetTickCount where the return value is placed in a global variable. This might be some sort of application coded timer. Or, it could be a timing defense. Sometimes malware will check the time throughout program execution. If too much time has passed between checks, the malware author can infer that they are being run under a debugger (a bad thing for a malware author). Note that GetTickCount returns the number of milliseconds since the machine booted. Millisecond precision may not be sufficient for some manufacturing processes, but for detecting debuggers it will do just fine.
Let's see if we can find the timing check and see what's actually being done here. To do this, cross reference from dword_462D30.
Good: there's only two other references that IDA found. This might be easy after all. Also, to keep myself sane, I'm going to rename this global variable to time_check.
So is this a debugger timing check? If it is, the malware author is doing it wrong (really, really, wrong). Nope, in this case, the malware author is checking to see if more than a full day has passed since the original check to GetTickCount. The old value is moved into ecx. The return value of GetTickCount is placed in eax (like the return value from all Windows APIs, per the stdcall convention). Then, the old value is subtracted from the new value. A check is performed to determine whether more than 86,400,000 milliseconds have passed since the original GetTickCount call. That value should look familiar to programmers, it's the number of milliseconds in a 24 hour period. Okay, so this means that the malware is going to do something once per day while the machine is booted...
Examining the code further, we note that the only difference in execution at this location is a possible call to sub_42BBB0. Wow. Glad I wasn't debugging this! I might never have seen whatever was in that subroutine (my debugging sessions tend to last far less than 24 hours).
After jumping to sub_42BBB0, I found that it was the subroutine that brought us here in the first place. This makes sense. To prevent this code from executing over and over, the value in the time_check global variable would have to be updated. So maybe the %TEMP%\system.log IOC is a winner after all... Maybe it is purged and recreated once every 24 hours? I don't know yet, but I've started to unravel some functionality that my sandbox wouldn't have (and that's what real reversing is all about).
I'll continue later this week with a further look at the malware. I know we didn't hit the keylogger portions at all. However, in all fairness I was writing this as I was reversing. I still have holiday shopping (and courseware updates) to do today, so this will have to suffice for now. Hopefully this is of some value to those who are interested in reversing.
I fully expect this sample to show up in one of my SANS courses (FOR526 and/or FOR610). It has some neat properties and is a real treat to dive in to. If you'd like to get a copy of this (and other samples), join me at the SANS CTI Summit in DC this February where I'll be teaching malware reverse engineering. This year, I added a sixth day to the course: a pure malware Netwars capture the flag challenge. This means you get a chance to put your new reversing skills to the test in the class! I look forward to seeing you in a future course.