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

The problem is that you have the original code in memory as you run
the program... just stopping the program while it's running and
inspecting the memory will give away the source without needing any
magic tricks. What i would do, would be to run the program inside
'gdb', then interrupt it by sending it a signal, then dump the memory
currently in use to a file, and scan the file for code.
Now i just ran it with valgrind, and i guess i was just lucky,
as you can see further down.

I think it's a better approach to use a good obfuscator for
method/variable/class/parameter renaming, and then encrypt the
obfuscated code. You could generate a private/public key pair for each
customer, encrypt the obfuscated code with the public key and encrypt
the private key with the license details of the customer (something
commonly used in shareware), then you write a decryption routine in C
(C extension) to decrypt the private key with the customer details
(name).

I don't know whether it's a good 'barrier' against piracy, but since
each copy would be encrypted with different keys, a simple patch would
be useless. But it'd be a better barrier against 'code-stealing' if
that's what you're concerned about.

The hard part is making a good obfuscator for ruby, is there already a
kind of analysis framework available for ruby ?  Because it seems to
me that a lot of work done for ruby code refactoring would be very
usefull for a code obfuscator... code obfuscation is just a kind of
automatic code refactoring ? (well, with quite the opposite intention :)

Just my thoughts...

Ruben

========================================

ruben@beast ruben $ valgrind --gdb-attach=yes ./foo
==5680== Memcheck, a.k.a. Valgrind, a memory error detector for x86-linux.
==5680== Copyright (C) 2002-2003, and GNU GPL'd, by Julian Seward.
==5680== Using valgrind-2.0.0, a program supervision framework for x86-linux.
==5680== Copyright (C) 2000-2003, and GNU GPL'd, by Julian Seward.
==5680== Estimated CPU clock rate is 1700 MHz
==5680== For more details, rerun with: -v
==5680==
==5680== Invalid read of size 1
==5680==    at 0x402D114C: rb_str_new2 (in /usr/lib/libruby18.so.1.8.1)
==5680==    by 0x4026A6CF: rb_eval_string (in /usr/lib/libruby18.so.1.8.1)
==5680==    by 0x4026A7C2: rb_eval_string_protect (in /usr/lib/libruby18.so.1.8.1)
==5680==    by 0x80486CC: (within /home/ruben/foo)
==5680==    Address 0x412EB0B6 is 0 bytes after a block of size 146 alloc'd
==5680==    at 0x40028A51: malloc (in /usr/lib/valgrind/vgskin_memcheck.so)
==5680==    by 0x804867C: (within /home/ruben/foo)
==5680==    by 0x40325C3B: __libc_start_main (in /lib/libc-2.3.2.so)
==5680==    by 0x80485B0: (within /home/ruben/foo)
==5680==
==5680== ---- Attach to GDB ? --- [Return/N/n/Y/y/C/c] ---- n
==5680==
==5680== Conditional jump or move depends on uninitialised value(s)
==5680==    at 0x40008DAE: _dl_relocate_object (in /lib/ld-2.3.2.so)
==5680==    by 0x4040D48D: (within /lib/libc-2.3.2.so)
==5680==    by 0x4000B265: _dl_catch_error (in /lib/ld-2.3.2.so)
==5680==    by 0x4040D6F2: _dl_open (in /lib/libc-2.3.2.so)
==5680==
==5680== ---- Attach to GDB ? --- [Return/N/n/Y/y/C/c] ---- y
==5680== starting GDB with cmd: /usr/bin/gdb -nw /proc/5680/exe 5680
...

so, then just checking the malloc-ed memory...

(gdb) p /x (0x412EB0B6 - 146)
$1 = 0x412eb024
(gdb) dump memory testje_foo 0x412eb024 0x412EB0B6

ruben@beast ruben $ cat testje_foo
require 'openssl'
puts "obfuscated ruby - woohoo!"
puts "Here's a hash:"
foo = OpenSSL::Digest::SHA1.new
foo.update("obfuscate me baby")
puts foo