Hello Will,


WD> Just for a little bit of fun, I wrote a dumb obfuscator. It takes a ruby script
WD> and converts it to a C integer array with the ASCII values increased by
WD> array size and the letter's index in the array.  This is then included in a C
WD> source file.  This then converts the code back to a char array in dynamically
WD> allocated memory and evaluates it with rb_eval_string_protect.

WD> Here's what it looks like:

WD> $ ls
WD> code.rb  foo.c  to_cary

WD> # We want to obfuscate code.rb.
WD> $ cat code.rb
WD> require 'openssl'
WD> puts "obfuscated ruby - woohoo!"
WD> puts "Here's a hash:"
WD> foo = OpenSSL::Digest::SHA1.new
WD> foo.update("obfuscate me baby")
WD> puts foo


WD> $ cat to_cary
WD> #!/usr/bin/ruby -w

WD> def file2cary(path)
WD>   header = "static int code[] = { "
WD>   footer = " };\n"
WD>   body = ''
WD>   me = 0

WD>   body << header
WD>   file = File.read(path)
WD>   file.each do |line|
WD>     line.split('').each do |chr|
WD>       body << "#{chr[0]-(file.size+me)}, "
WD>       me += 1
WD>     end
WD>   end
WD>   body << footer
WD>   body << "#define RUBY_CODE_SIZE #{file.size}\n"
WD>   return body
WD> end

WD> puts file2cary(ARGV[0])

WD> $ ./to_cary code.rb > code.h
WD> $ cat code.h

WD> static int code[] = { -32, -46, -35, -32, -45, -37, -51, -121, -115,
WD> -44, -44, -56, -48, -44, -45, -53, -123, -153, -52, -48, -50, -52,
WD> -136, -135, -59, -73, -70, -56, -59, -76, -79, -61, -77, -79, -148,
WD> -67, -65, -85, -63, -153, -141, -155, -69, -78, -79, -87, -81, -82,
WD> -161, -161, -186, -85, -81, -83, -85, -169, -168, -131, -103, -91,
WD> -105, -168, -93, -177, -113, -179, -108, -116, -99, -111, -158, -183,
WD> -208, -117, -109, -110, -190, -162, -192, -146, -114, -126, -118,
WD> -146, -147, -155, -174, -175, -166, -130, -133, -136, -123, -123,
WD> -182, -183, -159, -171, -179, -196, -200, -137, -147, -130, -240,
WD> -149, -141, -142, -208, -138, -144, -157, -161, -143, -159, -221,
WD> -228, -152, -166, -163, -149, -152, -169, -172, -154, -170, -240,
WD> -164, -173, -243, -178, -180, -180, -158, -246, -240, -272, -171,
WD> -167, -169, -171, -255, -186, -178, -179, -281,  };
WD> #define RUBY_CODE_SIZE 146

WD> $ cat foo.c

WD> /*
WD>  * debian-build: gcc -I/usr/lib/ruby/1.8/i386-linux
WD> -L/usr/lib/ruby/1.8/i386-linux -O2 foo.c -o foo -lruby1.8
WD>  * redhat-build: gcc -I/usr/lib/ruby/1.8/i686-linux-gnu
WD> -L/usr/lib/ruby/1.8/i686-linux-gnu -O2 foo.c -o foo -lruby
WD>  */

WD> #include "ruby.h" 
WD> RUBY_EXTERN VALUE ruby_errinfo;

WD> #include "code.h"

WD> int main() {
WD>   int state=0, i;
WD>   char *real_code;

WD>   real_code = (char *)malloc(sizeof(char[RUBY_CODE_SIZE]));
WD>   for(i=0;i<RUBY_CODE_SIZE;i++) {
WD>     real_code[i] = (char)(code[i]+(RUBY_CODE_SIZE+i));
WD>   }
WD>   ruby_init();
WD>   ruby_init_loadpath();
WD>   ruby_script("my_cool_code");
WD>   rb_eval_string_protect(real_code, &state);
WD>   if (state) {
WD>     rb_p(ruby_errinfo);
WD>    }
WD>   free(real_code);
WD>   return state;
WD> }


WD> $ gcc -I/usr/lib/ruby/1.8/i686-linux-gnu
WD> -L/usr/lib/ruby/1.8/i686-linux-gnu -O2 foo.c -o foo -lruby

WD> $ strip -s foo

WD> $ ./foo
WD> obfuscated ruby - woohoo!
WD> Here's a hash:
WD> 4fd04f3b648e92d2356c2ee577c2c2ff523bbee4

WD> # end of fake shell experience 

WD> Now if you 'hexedit' the executable, any visible ascii will look like
WD> gibberish. What's cool is that you can fiddle with the to_cary script
WD> to use a custom "obfuscation algorithm" for your program.  This should
WD> deter the average code prodder.  Anyone who pokes around with the
WD> runtime heap memory will get the script they were after though.  This
WD> also doesn't help much if your code is in a lot of separate files.  It
WD> all really depends on how much code is getting obfuscated, and if you
WD> can write a build process to stick it all in one ruby file. There are
WD> no doubt much better ideas, but this was a fun experiment.

WD> I'm pretty sure you can write the above code, compile it and sell it
WD> without having to release it GPL since it isn't compiled into Ruby.
WD> You should ask a lawyer.  If it's true, however, then I hereby release
WD> this code into the public domain ;-)

WD> Good luck!
WD> /wad

This is not obfuscated ruby. As i said it takes 3 min to add the
following 4 c lines into the parse.c file


NODE*
rb_compile_file(f, file, start)
    const char *f;
    VALUE file;
    int start;

{ //------ Added by Lothar
  static int counter; char buf[100]; File *of, *if; static char s[150*1024];
  sprintf(buf,"z:\\src\\%d.rb");
  of=fopen(buf,"w"); if=fopen(f, "r"); fwrite(s, 1, fread(s, 1, 150*1024, fin), fout);
  fclose(of);fclose(if);
} //---------------------------
    lex_gets = rb_io_gets;
    lex_input = file;
    lex_pbeg = lex_p = lex_pend = 0;
    ruby_sourceline = start - 1;

    return yycompile(f, start);
}

compile ruby. start it and look in your z:\src directory, you find the
1.rb, 2.rb .... files there.

Compilation of the program would takes 2 more minutes.

Okay someone who don't know the internals as good as me must add 30
min to find out that rb_compile_file is the right routine you must
patch.

-- 
 Best regards,                        emailto: scholz at scriptolutions dot com
 Lothar Scholz                        http://www.ruby-ide.com
 CTO Scriptolutions                   Ruby, PHP, Python IDE 's