JRuby as a Java Obfuscation Utility

Earlier this week, I read an interesting post on the state of JRuby, the Java version of the Ruby programming language.

The post had briefly mentioned use of JRuby to obfuscate Java code. Since non-obfuscated Java class files can be decompiled, many obfuscate the class files containing their proprietary code. Using a higher-level compiler on top of the Java code seemed more simple than trying to use one of the class-obfuscator tools.

It had been quite a while since I’d toyed with Ruby, so I thought I would see how one might use JRuby to protect their Java code. I don’t really have any Java code to protect, so I’ll just try to see what a decompiled JRuby-compiled program looks like.

In April of 2009, I wrote up a post on a small Ruby utility that I wrote to help keep one of my POP3 inboxes free of spam.

I have been using a slightly modified version of poppy.rb that simply deletes POP3 mails larger than 100,000 bytes in size. I copied this Ruby file to a new file called JPoppy.rb. I’ll use this script as our sample code.

JPoppy.rb

# JPoppy# A POP3 mail-cleaner## License: MIT / X11# Copyright (c) 2010 by James K. Lawless# jimbo@radiks.net http://www.radiks.net/~jimbo# http://www.mailsend-online.com## Permission is hereby granted, free of charge, to any person# obtaining a copy of this software and associated documentation# files (the "Software"), to deal in the Software without# restriction, including without limitation the rights to use,# copy, modify, merge, publish, distribute, sublicense, and/or sell# copies of the Software, and to permit persons to whom the# Software is furnished to do so, subject to the following# conditions:## The above copyright notice and this permission notice shall be# included in all copies or substantial portions of the Software.## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR# OTHER DEALINGS IN THE SOFTWARE.require'socket'defremoveSpamsock=TCPSocket.new("your.pop.server",110)["","USER your.username","PASS your.password","STAT","QUIT"].eachdo|msg|ifmsg.length!=0sock.send(msg+"\r\n",0)ends=sock.recv(4000)ifs.downcase.split(" ")[0]!="+ok"returnfalseendifmsg=="STAT"lookThroughEmails(sock,s)endendsock.closeenddeflookThroughEmails(sock,status)numOfEmails=status.split(" ")[1]foriin1..numOfEmails.to_isock.send("LIST "+i.to_s+"\r\n",0)s=sock.recv(4000)sz=s.split(" ")[2].to_iifcheckForSpam(sock,i,sz)sock.send("dele "+i.to_s+" \r\n",0)s=sock.recv(4000)putssputs"(deleted)"elseputs"(kept)"endendenddefcheckForSpam(sock,i,sz)sock.send("TOP "+i.to_s+" 0 \r\n",0)flag=0subject=from=to=replyTo=""whileflag==0dos=sock.recv(8000)s.split("\r\n").eachdo|lin|iflin==""flag=1elseword=lin.downcase.split(" ")[0]ifword=="subject:"subject=lin.downcaseelsifword=="from:"from=lin.downcaseelsifword=="to:"to=lin.downcaseelsifword=="reply-to:"replyTo=lin.downcaseendendendendputs"------------"puts"# "+i.to_sputstoputsfromputsreplyToputssubjectputs"("+sz.to_s+")"return(sz>100000)endremoveSpam

I first ran this utility to see if it would work unchanged under JRuby.

jruby JPoppy.rb

I didn’t encounter any problems. The script ran just as it had under the native Ruby interpreter.

I then compiled the program leaving a Java class file as the output:

jruby -S jrubyc JPoppy.rb

The output JPoppy.class file executes just as the script had done in interpretive mode.

I tried to recompile the JAD output but was unable to do so. A lot of raw JVM instructions show up in the decompiled output that the stock Java compiler itself doesn’t handle.

The literal strings are not obfuscated ( as obfuscation really isn’t JRuby’s job ) so the strings that contain the POP3 user ID and password appear in cleartext as most of us would have expected.

I also tried to manually trace through this code and really couldn’t. I suppose that it’s possible for someone to make sense of it, but I would doubt that many developers could. I think that I now understand more about how JRuby could be leveraged to obfuscate Java code.

I believe that in order to really protect one’s code in this instance, the bulk of the logic ( if not the entire program ) should be written in JRuby; it’s really the JRuby code that’s being obfuscated. The more of your intellectual property that you’re able to capture in pure JRuby, the more likely your code will be protected. Your mileage may vary.

Please note that someone will likely come along and build a decompiler is aware of the way JRuby generates code.

Toying with JRuby has renewed my interest in both Ruby and Java. I’ll be writing more posts in the near future that pertain to these technologies.