Monday, May 18, 2009

PDF Decoding Bugfix and Open Source from Adobe

I fixed a bug today, which was causing some of the scripts to fail decoding.
Basically, the JavaScript contained within a PDF file can be part of a special tag where it escapes special characters like (, ), &, \, and so on. The problem with this is that some of the regular expressions would incorrectly show up like this:
p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c])

In those cases, you could make them function correctly by replacing '\\' with a single '\' fixes the problem.
p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])

This bug has been corrected in any future decodings see examples here and here.

I originally thought this might be related to custom Adobe Reader javascript engine, since Adobe uses a custom version of SpiderMonkey. I would still like to integrate Adobe reader's custom JavaScript engine whenever processing PDF files, however, their website says
In some Adobe products, Adobe uses a modified version of the open source SpiderMonkey code. Use of that source is subject to the Mozilla Public License Version 1.1 (the License). You may obtain a copy of the License on the Mozilla website or in the download files.

However, read on and you will see "Download files - Coming soon!". There goes that plan! Anyone at Adobe care to comment on when they plan to release this code?

Thursday, May 14, 2009

Command Line API for jsunpack

Thanks Jesse!
Yesterday, he sent me this script, which takes URLs as parameters then provides the decoding as output. The "api" script does not escape HTML characters whenever the User-Agent is "jsunpack" and the parameter "apikey=exploitme" is set (to prevent accidental accesses of a malicious page).

#!/usr/bin/perl -w
use strict;
use CGI;
use LWP::Simple;
use LWP::UserAgent;
use HTTP::Request::Common;

my $unpackurl = '';
my $apikey = '&apikey=exploitme';

my $ua = LWP::UserAgent->new;

for my $url (@ARGV){
my $req = HTTP::Request->new( GET => ($unpackurl . CGI::escape($url) . $apikey));
my $res = $ua->request($req);

if ($res->is_success){
print $res->content;
else {
print "\n\n"."Failed to fetch remote file"."\n\n";
print "jsunpack"."\n".$res->status_line, "\n";

One feature that could improve this script would have it POST the contents of a local file. Does anyone feel like doing some scripting to extend this?

Wednesday, May 13, 2009

Using ClamAV on the command line as an automatic unpacker

A few people have asked me about how exactly the automatic unpacking in jsunpack works whenever it finds an executable. Well, here is the answer.

Take this executable submitted on 05/13/09 as an example:
Sections ( UPX0 UPX1 UPX2 )
File: MS-DOS executable PE for MS Windows (GUI) Intel 80386 32-bit, UPX compressed
Strings:.NET CLR
Strings:UNPACKED c:\43214354.bat
Strings:UNPACKED Us%se%sla/4.0 (compatible; MSIE 7.0; %s; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Strings:UNPACKED http://%s%s
Strings:UNPACKED c:\win
Strings:UNPACKED c:\wi%sft%df44.dat
Strings:UNPACKED %s\jopaxx_%d.exe
Strings:UNPACKED c:\w%sws\t55ft%df44.dat
Strings:UNPACKED %s\st_%d.exe
Strings:UNPACKED %s\yoo_%d.exe
Strings:UNPACKED %s\lim_%d.exe
Strings:UNPACKED c:\windows\%s%s.exe
Strings:UNPACKED reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable /t REG_DWORD /d 00 /f
Strings:UNPACKED reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable /t REG_DWORD /d 00 /f
Strings:UNPACKED Software\Microsoft\Windows\CurrentVersion\Internet Settings
Strings:UNPACKED tmp_%d_%d.exe
Size: 14848 bytes,
MD5: 78d18e15a1ce15d4869f8db16f4e8642

UPX isn't particularly impressive because "upx -d" works fine most of the time, but this method gets a lot of other packed files too. It uses clamscan (from with --leave-temps, then it looks for URLs, Registry keys, domain names, and anything else interesting it could find in the strings. If it finds the same string in the original binary, then it does not display UNPACKED before outputting it. In this way, the analyst can see if it was really hidden or available in the original strings output.

The --leave-temps method is not perfect, but it has helped me on a number of occassions when I was in a hurry to evaluate the likelihood that a binary was malicious or find the purpose of an unknown binary or large number of malicious samples. In particular, I found it the most useful when it finds an autoit-compiled executable. In those cases, you get the entire autoit script from taking this simple step, which is much easier to quickly analyze.

Jsunpack blog online

Hey guys,
It's Blake. I finally added a proper blog! Add it to your RSS reader at
I've been getting some good feedback from users and I plan to add some new features soon. Stay tuned and I'll update you soon on some raw data feeds and command line utilities.

Example of malicious site with rogue anti-virus with javascript exploits

[23/Feb/2009:11:10:26 -0500] Interesting JavaScript case here -> link, looks like a rogue AV that is either infected or spreading exploits too. Send me ones you decode if you think they are interesting (or if they fail too)

Shmoocon and Presentation Slides (pdf)

[09/Feb/2009:09:37:18 -0500] Shmoocon was lots of fun. Here is a copy my talk on jsunpack. [02/Feb/2009:11:36:39 -0500] Shmoocon! I'll be speaking about jsunpack on Sunday Feb 8 [more]. Also, brief update - I added meta refresh static crawling to jsunpack this morning.

PDF and SWF decoding in jsunpack

[29/Jan/2009:11:26:02 -0500] I added PDF decoding to jsunpack several months ago, and I noticed some exploit toolkits using SWF files to redirect to additional exploit pages recently. Please let me know if you like or dislike the new SWF decoding.

Contact me for samples or data

[09/Jan/2009:00:16:16 -0500] I noticed someone looking for data/logs and they were getting 404 as responses. Please contact me if you would like access to my data -