読者です 読者をやめる 読者になる 読者になる

Pythonの簡易な壊し方

Python

r/pythonでバズったスレを垂れ流す作業。

MIT License

Copyright © 2017 Adhityaa Chandrasekar

adtac/destruction: Break Python programs with a simple import.

builtinsの名前がPython 2か3かにより違うので、ここでは3系前提で話す。

Pythonの組み込み識別子はbuiltinsに定義されている。builtinsの中身を書き換えるとおかしな挙動をするPythonを作れる。

import builtins

d = builtins.__dict__
fs = ["abs", "map", "max", "min", "sum"]

for f, g in zip(fs, reversed(fs)):
    d[f] = g

print(abs, map, max, min, sum, sep=' ')

出力

sum min max map abs

こんな感じで組み込み関数を書き換え、シッチャカメッチャカにすることができる。

モジュールについては、

sys.modules['math']

のような感じでモジュールオブジェクトを取得できる。ここからはbuiltinsと同様に__dict__itemの内容を書き換えていってもいいが、クラスを定義して同名のメソッドで上書きしてしまってよい。

https://github.com/adtac/destruction/blob/master/destruction/FakeMath.py

class FakeMath:
  def __init__(self):
    self.custom_pi = actual_math.pi
    self.custom_e = actual_math.e

    @property
    def pi(self):
        self.custom_pi += random.uniform(*RANGE)
        return self.custom_pi

    @property
    def e(self):
        self.custom_e += random.uniform(*RANGE)
        return self.custom_e

     def __getattr__(self, name):
        """
        We don't want to break the entire math module. So if we get anything
        other than `e` or `pi`, let's give it to the original module.
        """
        return getattr(actual_math, name)

変更したくない部分は__getattr__部で元のモジュールを呼び出している。お行儀がいい(?)