• XSS.stack #1 – первый литературный журнал от юзеров форума

Самописный obfuscator Python кода

DarkBLUP

(L2) cache
Пользователь
Регистрация
29.11.2021
Сообщения
382
Реакции
99
Гарант сделки
5
Депозит
0.00
Всем привет, хоть петухон и не возможно тщательно защитить от опытных ревёрсеров, но от школьников это сделать ещё возможно. Решил поделиться самой простой обфускацией исходника на python.
Минусы этого метода в том что код должен быть процедурным и без сторонних модулей или библиотек, так же не возможно использовать под многофайловый проект.
P.S: если хочешь посмотреть полный код обфускатора листай в самый низ этой статьи.
Начнём с алгоритмов работы обфускатора. Моя реализация будет:

1) Используя исходный код шифровать / путать его
2) Записывать зашифрованное значение в новый файл
3) Расшифровывать код и запускать в оперативной памяти

У меня будет 2 файла: obf.py (обфускатор), test.py (тестовый файл). Тестовый файл выглядит вот так:

test.py
Python:
from os import getlogin
print(getlogin())

Начнём с алгоритма шифрования, я буду использовать обычное сложение индекса ASCII символов с "ключём" (если его можно так назвать).
Python:
KEY = 4 # это мой ключ

def encrypt(src: bytes, key: int) -> str:
    buffer = ""
    for index in src:
        buffer += chr(index + key)
    return buffer

Вот такой простенький шифратор я накинул буквально за пару секунд. Усложнять обфускатор можно до бесконечность это зависит от вашей фантазии.
Приступим к дешифратору, тому звену, которое будет расшифровывать наш код перед запуском в оперативной памяти:

Python:
def decrypt(enc: bytes, key: int) -> str:
    buffer = ""
    for index in enc:
        buffer += chr(index - key)
    return buffer

Теперь перейдем к генератору стаба, он должен создавать зашифрованный / запутанный сорц файл:

Python:
def gen_stub(enc: str, key: int) -> None:
    with open("stub.py", "w") as create:
        create.write("from obf import run_exec\n")
        create.write(f"run_exec('{enc}', {key})")
        create.close()

Генератор стаба импортирует функцию запуска зашифрованного / запутанного кода и исполняет её предварительно подставив параметры.
Теперь остаётся главная функция обфускатора - загрузчик.

Python:
def run_exec(enc: str, key: int):
    src = decrypt(enc.encode(), key)
    exec(compile(src, "test.py", "exec"))

Вот и вссе функции нашего обфускатора, призапуске обфускатора из:

test.py
Python:
from os import getlogin
print(getlogin())

Получается вот такой код:

stub.py
Python:
from obf import run_exec
run_exec('jvsq$sw$mqtsvx$kixpskmrtvmrx,kixpskmr,--', 4)

Теперь нужно этот код проверить, вот вывод при запуске этого кода:

Screenshot from 2022-10-13 19-09-22.png


Попробуем теперь компилировать этот же код и проверить его уже скомпилированным ( я буду использовать pyinstaller для этих целей ).
Из за того что петухон и pyinstaller вес вышел вот такой:

Screenshot from 2022-10-13 19-14-31.png


Можно воспользоваться nuitka тогда файл будет весить в разы меньше (проверенно).
Теперь самое время запустить и проверить уже скомпилированный и обфусцированный файл:

Screenshot from 2022-10-13 19-18-07.png


Как вы можете замететь обфусцированный файл работает отлично.
А вот полный код обфускатора:

Python:
def encrypt(src: bytes, key: int) -> str:
    buffer = ""
    for byte in src:
        buffer += chr(byte + key)

    return buffer


def decrypt(enc: bytes, key: int) -> str:
    buffer = ""
    for byte in enc:
        buffer += chr(byte - key)
    return buffer


def gen_stub(enc: str, key: int) -> None:
    with open("stub.py", "w") as create:
        create.write("from obf import run_exec\n")
        create.write(f"run_exec('{enc}', {key})")
        create.close()


def run_exec(enc: str, key: int):
    src = decrypt(enc.encode(), key)
    exec(compile(src, "test.py", "exec"))


if __name__ == "__main__":
    Key = 4
    FILENAME = "test.py"
    enc = encrypt(open(FILENAME, "rb").read(), Key)
    gen_stub(enc, Key)

Пишите свои идеи по поводу обфускации python кода, будет интересно послушать чьи то мнения по защите питухона от злых хацкерс :)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
У Петухона есть встроенный модуль ast, которым можно распарсить код в абстрактное синтаксической дерево, потом обойти его алгоритмами обфускации, и преобразовать обратно в код с помощью модуля astunparse (ставится через pip).
 
У Петухона есть встроенный модуль ast, которым можно распарсить код в абстрактное синтаксической дерево, потом обойти его алгоритмами обфускации, и преобразовать обратно в код с помощью модуля astunparse (ставится через pip).
Ну к сожалению с этим ничего не поделать. Это же петухон, а не Сишка.
 
Нужно подумать, как можно защитить от дебагера
Мне кажется вряд ли это хоть немного возможно сделать, если брать Сишку то там защита строится на вызовах ассемблерной инструкции INT3 (один из методов ), но это Сишка и нативный код. Петухон так сделать не получится.
 
Мне кажется вряд ли это хоть немного возможно сделать, если брать Сишку то там защита строится на вызовах ассемблерной инструкции INT3 (один из методов ), но это Сишка и нативный код. Петухон так сделать не получится.
Ну тащем то можно скомпилить ситоном и подрубать отдельно либы.
Но если уж совсем сильно надо что-то спрятать, мы можем удаленно (например по https) грузить в память наши модули. Что собственно будет правельнее дабы не таскать с собой 30мб бинарь (по факту архив) питонячий "скомпилированный".
 
если уж идти дальше, я помню что есть в python такая штука как "pickle", который сохраняет в файл состояния переменных, классов. те по сути своей если будет нужно можно подгружать именно "сохраниния" а не держать в самом скрипте строки и тому подобные штуки
если я ошибаюсь поправте, но помоему это оно, не?
 
Пожалуйста, обратите внимание, что пользователь заблокирован
если уж идти дальше, я помню что есть в python такая штука как "pickle", который сохраняет в файл состояния переменных, классов. те по сути своей если будет нужно можно подгружать именно "сохраниния" а не держать в самом скрипте строки и тому подобные штуки
если я ошибаюсь поправте, но помоему это оно, не?
Pickle не все может сохранять, и от версии к версии формат бинарщины, которую генерит pickle может меняться (то есть, у тебя не обязательно получится сохранить на одной версии Петухона, а потом загрузить на другой). Но так в частном случае, да. Есть еще модуль marshal, более низко уровневый штоле, но у него скорее всего будут те же проблемы, что и у pickle, в этом плане.
 
у тебя не обязательно получится сохранить на одной версии Петухона, а потом загрузить на другой
а об этом не знал. спасибо что просвятил. хотя лезть в ту реку и не собирался.
слушай у меня вопрос к тебе еще: меня интересует автоматический расчет хешей в чистом си, а не с++, я сделал расчет как раз с помощью петухона.
в самом си нет встроенного ничего такого из коробки??? - по крайней мере не нашел самостоятельно.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
в самом си нет встроенного ничего такого из коробки???
Каких хешей? Такого нет, для криптографических - возьми реализацию MD5 или SHA из любой крипто библиотеки, типа mbedtls и тд, для некриптографических - бери любой, типа CRC, Jenkins, FNV, murmur и тд, в зависимости от того, какие данные ты будешь хешировать, чтобы минимизировать вероятность коллизий.
 
Каких хешей? Такого нет, для криптографических - возьми реализацию MD5 или SHA из любой крипто библиотеки, типа mbedtls и тд, для некриптографических - бери любой, типа CRC, Jenkins, FNV, murmur и тд, в зависимости от того, какие данные ты будешь хешировать, чтобы минимизировать вероятность коллизий.
я про вычисление хешей во время компиляции, как в си++. я тоже самое сделал вычисление во время компиляции с помощью портабельного петухона но в си. вот пример приведу:

Код:
from string import Template
import random, string

def hash_djb2(s):                                                                                                                               
    hash = 5381
    for x in s:
        hash = (( hash << 5) + hash) + ord(x)
    return hash & 0xFFFFFFFF

def write_tamplate(tamplate, prepared_string):
    with open (tamplate, 'w') as f:
        f.write(prepared_string)

def create_settings(tamplate_name, resoult_name):
    odata = read_tamplate(tamplate_name)
    template_string = Template(odata)
    
    k1 = randomword(1)
    k2 = randomword(1)
    k3 = randomword(1)
    
    xor_key = [ k1, k2, k3 ]

    prepared_string = template_string.substitute (
        kernelhash = str( hash_djb2( u'kernel32.dll' ) ),
        ntdllhash = str( hash_djb2( u'ntdll.dll' ) ),
        fn_getmodhndlehash = str( hash_djb2( u'GetModuleHandleW' ) ),
        fn_loadlibhash = str( hash_djb2( u'LoadLibraryA' ) ),
        fn_ldrloaddll = str( hash_djb2( u'LdrLoadDll' ) ),
        fn_messagebx = str( hash_djb2( u'MessageBoxA' ) ),
        key1 = k1,
        key2 = k2,
        key3 = k3
    )
    write_tamplate(resoult_name, prepared_string)

create_settings('template-settings.h', 'settings.h')

те перед компиляцией для си у меня создается файлик с уже прочитаными хешами по которым я ищу функции в библиотеках которые загружены в процесс, что бы почистить таблицу импорта, а так же что бы было более удобно что то делать с этим exe. У меня вопрос заключался в том, есть ли в си такая же сила, фича как в си++ делать тоже самое из коробки?
 
Пожалуйста, обратите внимание, что пользователь заблокирован
У меня вопрос заключался в том, есть ли в си такая же сила, фича как в си++ делать тоже самое из коробки?
Нету. Можно изъебаться и сделать через "рекурсивный" макрос препроцессора, но это неадекватная дрочь. Под "рекурсивным" имеется ввиду макрос HASH_N, который вызывает макрос HASH_N-1 до нуля.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх