OcultandoCodigoPython

Muitas pessoas querem, por diversos motivos, ocultar o código fonte dos seus programas. Muitas acham que compilando o mesmo para bytecode ou binário (nome dado ao bytecode da máquina hospedeira) vão conseguir fazê-lo. Vale lembrar, porém, que existem disassemblers que conseguem converter para instruções básicas legíveis pelo usuário final e até mesmo alguns que conseguem converter para estruturas de mais alto nível, ficando razoavelmente legível. Tais disassemblers existem para várias linguagens/bytecodes e o Python não é diferente.

O Python utiliza um bytecode para sua própria Virtual Machine (VM), ao rodar um código legível (.py) ele converte automaticamente para o bytecode e executa-o, sendo que por motivos de desempenho as bibliotecas/módulos são salvos como bytecode para um arquivo, em geral com extensão .pyc ou .pyo (otimizado, sem doc-strings). Pode-se, porém, distribuir somente o bytecode e tudo funcionará perfeitamente.

Deve ser lembrado que não só é possível como também é fácil transformar o bytecode do Python de volta para um arquivo legível a humanos. Veja http://packages.qa.debian.org/d/decompyle.html .

Como gerar bytecode para o arquivo principal

Ao executarmos um programa python, apenas os módulos importados serão salvos em bytecode, o arquivo principal, o qual foi chamado na linha de comando não. Para convertermos, podemos usar dois métodos:

Trivial

A maneira trivial é fazer import do seu módulo, para um arquivo chamado meucodigo.py:

python -OO -c "import meucodigo"

Esse método tem como efeito colateral que meucodigo é executado e não apenas compilado.

Usando py_compile

O Python provê um módulo para compilar arquivos, é o py_compile http://www.python.org/doc/lib/module-pycompile.html.

Criando um compilador

Use o programa pycompiler.py:

   1 """
   2 PyCompiler: compile python files to bytecode.
   3 Author: Gustavo Sverzut Barbieri <barbieri@gmail.com>
   4 License: GPL
   5 """
   6 
   7 import sys
   8 import os
   9 import getopt
  10 import py_compile
  11 import compileall
  12 
  13 def usage():
  14     print >> sys.stderr, """\
  15 Usage:
  16 
  17         %s [options] <file1> ... <fileN>
  18 
  19 where options are:
  20    -h, --help        This message.
  21    -r, --recursive   Enter directories recursively.
  22    -d, --maxdepth=N  Maximum depth in recursion.
  23    -f, --force       Force recompiling already compiled files.
  24    -q, --quiet       Be quiet.
  25 
  26 """ % sys.argv[ 0 ]
  27 
  28 
  29 def compile_file( filename, force=False, quiet=False ):
  30     if not quiet:
  31         print "Compiling %s ..." %  filename
  32     py_compile.compile( filename )
  33 
  34 def compile_dir( dirname, depth=1, force=False, quiet=False ):
  35     compileall.compile_dir( dirname, depth, force=force, quiet=quiet )
  36 
  37 def compile( name, depth=1, force=False, quiet=False ):
  38     if os.path.isdir( name ):
  39         compile_dir( name, depth, force, quiet )
  40     elif os.path.exists( name ):
  41         compile_file( name, force, quiet )
  42     else:
  43         if not quiet:
  44             print >> sys.stderr, "File '%s' doesn't exists!" % name
  45 
  46 
  47 
  48 if __name__ == "__main__":
  49     try:
  50         opts, args = getopt.getopt( sys.argv[ 1: ],
  51                                     "hrd:qf",
  52                                     [ "help",
  53                                   "recursive",
  54                                   "maxdepth=",
  55                                   "quiet",
  56                                   "force" ] )
  57     except getopt.GetoptError:
  58         usage()
  59         sys.exit( 2 )
  60 
  61 
  62     depth = 0
  63     quiet = False
  64     force = True
  65 
  66     for o, a in opts:
  67         if   o in ( "-h", "--help" ):
  68             usage()
  69             sys.exit( 0 )
  70         elif o in ( "-r", "--recursive" ):
  71             if not depth:
  72                 depth = 20
  73         elif o in ( "-d", "--maxdepth" ):
  74             depth = int( a )
  75         elif o in ( "-q", "--quiet" ):
  76             quiet = True
  77         elif o in ( "-f", "--force" ):
  78             force = True
  79 
  80 
  81     for name in args:
  82         compile( name, depth, force, quiet )

Linha de comando

Caso não queira criar um script para compilar os seus programas, pode usar:

python -OO -c "import py_compile; py_compile.main()" meucodigo1.py meucodigo2.py

Outras Técnicas

Outra técnica para ocultar o código é o obfuscamento, na qual você programa de uma maneira que ninguém entende, ou escreve as partes principais de maneira ilegível, ou que pareça fazer uma coisa e faz outra. Existe obfuscadores de código que pegam as variáveis e dão nomes curtos e sem sentido, como s1, s2, i1, i2, ... e amontoam o código, como for i in [1,2,3]: print i; print i+1.

OcultandoCodigoPython (editada pela última vez em 2008-09-26 14:05:59 por localhost)