2019-04-19に更新

Nuitka はあなたの python code の変数名、関数名、クラス名その他を見えなくしてくれるのか?

背景

Does Nuitka Remove Or Obscure Names of Variables, Functions, Classes, Etc. From Your Python Code? という記事をたまたま見つけて(というのをブログで見かけるとたいがい「ウソつけ!」ですよね ^^; かくいう私も嘘ついてて、本当は nuitka と decompile で検索してたらトップがこれだった)記事は「全部残ってるよ」という内容だったので、気になったので試してみました

Python の obfuscator って free のが見つからなくて(obfuscator-llvm みたいな OSS がある分だけ C++ っていいですね、ってC++ で Web アプリ書く気にはならないのですが ^^;;;)、で、別に obfuscate しなくても binary で strip してあれば実質、ほとんどのマリシャスな人は手ださないんじゃないかなと思い、ところで nuitka でコンパイルした binary ってどれぐらい元コードの情報残ってるもんなんだろ?と思ってググってたら冒頭のショッキングな記事が...

よくみるとこの記事、やっぱり高い obfuscator のベンダーさんが書いてるみたいですね

結論

記事に反して全然残ってないみたいに思えるのですが、自信ないのでこちらに晒しておこうと思いました次第です
マサカリ大歓迎です、というかそれが欲しくて晒してます

実験

version of Nuitka

pip list

Nuitka (0.6.3)

素のコード

たまたま書いてた(嘘、本当は obfuscate したいと思ってる)Tornado のアプリケーションです
protocol とか port とか文字列たくさん含んでます
Screen_WebHander とかクラス名もありますね

#-*- coding:utf-8 -*-
# Copy Right Takeyuki UEDA  © 2019 - All rights reserved.


import tornado.ioloop
import tornado.web
from tornado.options import define, options
import ssl
import os
import sys
import pprint
import importlib
import screen

if __name__ == "__main__":
# options
    define("protocol",               default="wss:", help="ws: or wss:(default)")
    define("port",                   default=8888, help="listening port", type=int)    
    define("data_dir",               default="", help="cert file path for running with ssl")
    define("cert_file",              default="cert.pem", help="cert file name for running with ssl")
    define("privkey_file",           default="privkey.pem", help="privkey file name for running with ssl")
    define("config_file",            default="",         help="config file path")
    define("static_path",            default="./",       help="[mandatory] handler class name of rhizome")

    options.parse_command_line()

    '''
    The priority of Option file

    1. options.config_file
    2. ./config.py
    '''
    if os.path.exists('./config.py'):
        options.parse_config_file('./config.py', final=False)
    if options.config_file:
        options.parse_config_file(options.config_file, final=False)

    '''
    command line is the first priority
    '''
    options.parse_command_line()


# app
    BASE_DIR = os.path.dirname(__file__)

    app_params = {}
    app_params["handler"] = [("/",                      screen.Screen_WebHander),
                             ("/screen_connection/(.*)",screen.Screen_WSHandler),
                             ("/remote_connection/(.*)",screen.Remote_WSHandler),
                             ("/remote/(.*)",           screen.Remote_WebHander)
                             ]
    app_params["static_path"]   = os.path.join(BASE_DIR, options.static_path)


    app = tornado.web.Application(
        app_params["handler"], 
        template_path = ".",
        static_path   = app_params["static_path"],
    )

    if options.protocol == "ws:":
        http_server = tornado.httpserver.HTTPServer(app)
    else:
        ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
        data_dir = options.data_dir
        ssl_ctx.load_cert_chain(os.path.join(data_dir, options.cert_file),
                                os.path.join(data_dir, options.privkey_file))
        http_server = tornado.httpserver.HTTPServer(app, ssl_options=ssl_ctx)

    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

コンパイル

こんな感じでコンパイルしました

python -m nuitka --follow-imports ソースファイル名

.bin ファイルができます

なかを見る

nm してみると

nm homeserver.bin
nm: homeserver.bin: no symbols

ちゃんと strip してあるみたいですので、-D をつけてみると

nm -D homeserver.bin
         U abort
005b5be0 B __bss_end__
005b5be0 B _bss_end__
005a2218 B __bss_start
005a2218 B __bss_start__
         U __ctype_b_loc
         U dirname
005a2218 D _edata
005b5be0 B _end
005b5be0 B __end__
005369f4 T _fini
         U getenv
         w __gmon_start__
00013b90 T _init
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
         w _Jv_RegisterClasses
         U __libc_start_main
         U mbstowcs
         U memcpy
         U memset
         U printf
         U _PyArg_NoKeywords
         U PyArg_ParseTuple
         U PyArg_ParseTupleAndKeywords
         U PyArg_UnpackTuple
0054be88 D _Py_ascii_whitespace
005a3690 B PyBaseObject_Type
005a3d98 B PyBaseString_Type
...

Python の構文用の文字列は残ってるみたいですけど前述の protocolportScreen_WebHander とかいった文字列はみつかりません

他に objdump -xT も試してみるのですがやっぱりみつかりません
念のために od -A -tx1z でダンプしてみたのですが、やっぱりなにもみつかりません

考察

試したかんじだと元記事の内容に反して「残ってなくて削除してくれてる」ようなのですが...
使ってる nuitka のバージョンが違うのかな?

Threats to validity

ぜんぜんわかりません ヽ(^o^)丿 ← お手上げ
なんか「そこ、おかしいよ」みたいなご指摘でも「それでいいんだよ」っていうご指摘でもどちらでもかまわないのでご意見いただけたら大歓迎です
つうか、全然 threat to validity になってないな...

References

ツイッターでシェア
みんなに共有、忘れないようにメモ

Dr. Takeyuki Ueda

Je suis un Japonipais, experimants ingénieur logiciel de mobile et cloud. Ph.D en ingénierie.

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント