I found way to protect Source Code! :)

D

Dmitry Severin

The last time you advertised this product here, we had proven the claims
on your website to be false.

http://www.ruby-forum.com/topic/166458#731051

You have not made any changes or corrections to the website since.

Found link to RubyEncoder on InfoQ (
http://www.infoq.com/news/2008/10/rubyencoder ), and just for fun,
decided to look how difficult would it be to crack it :)

It turns out, that RubyEncoder uses following scheme: modified
Ruby-1.8.7 interpreter,
that stores encoded AST nodes along with encoding/restriction options,
while rgloader simply decodes it back to AST and executes.

So, using just a few quick and dirty hacks it is possible to get source back:

1) one-byte change in library to call external ruby_exic instead of ruby_exec:
----------------
$ cmp -l rgloader.linux.so.original rgloader.linux.so
4616 145 151
----------------

2) A bit patched ruby, ruby-1.8.6/eval.c to keep injected AST:
----------------
NODE *ruby_eval_hack;
int
ruby_exic(){
volatile NODE *tmp;
int state;

Init_stack((void*)&tmp);
ruby_eval_hack = ruby_eval_tree;
state = ruby_exec_internal();
return state;
}
----------------

3) Patch for RawParseTree in ParseTree-3.0.1/lib to retrieve sexp from
intercepted tree:
----------------
builder.prefix " #{extern_mode} NODE *ruby_eval_hack; "
builder.c %Q{
static VALUE parse_tree_full() {
VALUE result = rb_ary_new();
add_to_parse_tree(self, result, ruby_eval_hack, NULL);
return result;
}
----------------

4) And, finally, simple environment to get source code back from RubyEncoder:
----------------
require 'rubygems'
require 'parse_tree'
require 'ruby2ruby'

require 'encoded_script' # protected code, you say?

RawParseTree.new.parse_tree_full().each do |sexp|
puts Ruby2Ruby.new.process(Unifier.new.process(sexp))
end
----------------

Example:
Original:
----------------
class EncodedHelloWorld
ENCODER_VERSION = "1.0"

def initialize
puts "Hello, world!"
end
end
----------------

Encoded:
----------------
# RubyEncoder v1.0 evaluation
_d = _d0 = File.expand_path(File.dirname(__FILE__)); while 1 do _f =
_d + '/rgloader/loader.rb'; break if File.exist?(_f); _d1 =
File.dirname(_d); if _d1 == _d then raise "Ruby script '"+__FILE__+"'
is protected by RubyEncoder and requires the RubyEncoder loader.
Please visit the http://www.rubyencoder.com/loaders/ RubyEncoder site
to download the required loader and unpack it into '"+_d0+"/rgloader/'
directory to run this protected script."; break; else _d = _d1; end;
end; require _f;
RGLoader::load('AAEAAAAEaAAAAIAAAAAA/1nu5hlzvK93ynRezwoJSWaAXO0XWYMyqYojzdIsXeg/n3sTUToqkcdtx9wMbCcidZy4WpqIq2fj9tHsyREq8dCcvPsiWYISiwZ2jFHadIF3FhHZ9eLhZWJTZuRZDYG3Zk0nttbBzuP6EgAAAPgAAACl6rEqW0Dbrjuf0Nl2ehDd4mtpWkb9bP504YjdDfJj1ZM0tqmLXWMXpXnXL1kFNqoEfnws38xmo1J0E/Ziw4typ+51d572ijDg17Xz7NWj9xEykyN4uXEKn/Dt1mKExla1mnX4eAKxbnOJrNqZPDmpIJdOEqOO+/CLfQIGvvKYt11MIyTZK9I2R4J+/oNK2RGwbmzynpFKV32zxdILn4thrQx3gDLbD5ZPbfR6qWsmtJT6pyxccj7RtwGSat4BetCUKmcHR6b/qvp6rvPtaA1m/1JuuGNLUzg3tHHLkA/U14GfF4af9VyqtLQy5ww+jHB6wz4BkFe06gAAAAA=');
----------------

Output:
----------------
class EncodedHelloWorld
ENCODER_VERSION = "1.0"
def initialize
puts("Hello, world!")
end
end
----------------
 
R

Ryan Davis

Trying to "protect" your Ruby source code is like trying to "protect"
music with DRM: doomed to ineffectiveness.

http://blogs.techrepublic.com.com/security/?p=363

well... to varying levels of difficulty, yes...

I can guarantee that I can obfuscate code better than rubyencoder
can... well enough that you can't get meaningful information back out
automatically (it would probably be quicker and more effective to
translate it back by hand after doing an automated pass on it). Well
enough that it isn't worth your time for nearly everything put through
it.
 
R

Ryan Davis

I can probably guarantee that, if you do that, it's not worth *your*
time
either.

You'd be wrong. The effort to refactor IP needing obfuscation and
getting it converted and tested/able in its new form took less than 30
minutes. After that all conversions are simply part of the rake build
process (read: free). The amount of time it'd take to decompile and
then discern actual meaning would be much much greater than that.
 
J

James Dinkel

Ryan said:
You'd be wrong. The effort to refactor IP needing obfuscation and
getting it converted and tested/able in its new form took less than 30
minutes. After that all conversions are simply part of the rake build
process (read: free). The amount of time it'd take to decompile and
then discern actual meaning would be much much greater than that.

I find that the best solution is just to write unreadable code from the
beginning.

James
 
C

Charles Oliver Nutter

Pedro said:
Forget it, decompiling classes to very readable java source has been
trivial for many years.

I had missed this...but even if you could decompile .class to .java,
it's still nearly worthless to you because it's a bunch of JRuby
internals calls. I suppose the important bit is what you're trying to
protect. If it's the original Ruby code, then compiling to .class is
certainly good enough.

- Cahrlie
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top