파이썬 코드를 효과적으로 난독화하는 방법은?
저는 제 파이썬 소스 코드를 숨기는 방법을 찾고 있습니다.
print "Hello World!"
이 예제를 사람이 읽을 수 없도록 인코딩하려면 어떻게 해야 합니까?Base64를 사용하라는 말을 들었지만 방법을 잘 모르겠습니다.
이것은 제한된 1단계 난독화 솔루션이지만, Python에는 바이트 코드로 컴파일러가 내장되어 있습니다.
python -OO -m py_compile <your program.py>
합니다..pyo
바이트 코드를 포함하고, 문서 문자열이 제거된 파일 등.이름을 변경할 수 있습니다..pyo
로 .py
확장및python <your program.py>
프로그램처럼 실행되지만 소스 코드가 포함되어 있지 않습니다.
PS: "제한된" 수준의 난독화는 코드를 복구할 수 있는 수준입니다(변수 이름 중 일부는 사용하지만 주석과 문서 문자열은 사용하지 않습니다).방법은 첫 번째 설명을 참조하십시오.그러나 경우에 따라 이러한 수준의 난독화는 충분하다고 간주될 수 있습니다.
PPS: 만약 당신의 프로그램이 이렇게 난독화된 모듈을 가져온다면, 당신은 그것들의 이름을 다음과 같이 바꿔야 합니다..pyc
대신 접미사(언젠가 이것이 깨지지 않을 것이라는 확신이 들지 않음) 또는 당신은 그것으로 작업할 수 있습니다..pyo
그리고 그것들을 실행합니다.python -O ….pyo
(수입품이 작동해야 합니다.) Python은 수 은 모듈을 )..py
모듈)을 선택합니다.
사람이 읽을 수 없도록?
제 말은 모든 파일이 인코딩되었다는 것입니다!! 당신이 그것을 열었을 때 당신은 아무것도 이해할 수 없다는 것입니다.내가 원하는 것
소스를 바이트 코드로 컴파일한 다음 바이트 코드만 배포할 수 있습니다.하지만 이마저도 되돌릴 수 있습니다.바이트 코드를 반독점 소스로 압축 해제할 수 있습니다.
Base64는 누구나 해독할 수 있는 사소한 것이기 때문에 실제 보호 기능을 할 수 없으며 완전한 PC 문맹으로부터만 소스를 '숨깁니다.또한, 실제로 이 코드를 실행하려면 디코더를 스크립트(또는 정규 사용자가 실행해야 하는 배포의 다른 스크립트)에 바로 포함해야 하며, 그러면 인코딩/암호화가 즉시 제공됩니다.
난독화 기법은 일반적으로 주석/문서 스트리핑, 이름 망글링, 휴지통 코드 삽입 등이 수반되기 때문에 바이트코드를 디컴파일해도 읽을 수 있는 소스가 잘 나오지 않습니다.하지만 그들은 그럼에도 불구하고 파이썬 소스가 될 것이고 파이썬은 읽을 수 없는 엉망이 되는 것에 능숙하지 않습니다.
일부 기능을 보호해야 한다면 C나 C++와 같은 컴파일된 언어로 진행하고 .so/.dll을 컴파일하고 배포한 다음 보호된 코드에 파이썬 바인딩을 사용하는 것이 좋습니다.
코드를 C/C++에 내장하고 다른 응용 프로그램에 내장 파이썬을 컴파일할 수 있습니다.
내장된 .c
#include <Python.h>
int
main(int argc, char *argv[])
{
Py_SetProgramName(argv[0]); /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("print('Hello world !')");
Py_Finalize();
return 0;
}
Ubuntu/데비안에서
$ sudo apt-get install python-dev
센토스/레드햇/페도라에서
$ sudo yum install python-devel
로 편찬하다.
$ gcc -o embedded -fPIC -I/usr/include/python2.7 -lpython2.7 embedded.c
을 가지고 다니다.
$ chmod u+x ./embedded
$ time ./embedded
Hello world !
real 0m0.014s
user 0m0.008s
sys 0m0.004s
초기 스크립트: hello_world.py:
print('Hello World !')
대본을 실행합니다.
$ time python hello_world.py
Hello World !
real 0m0.014s
user 0m0.008s
sys 0m0.004s
그러나 파이썬 코드의 일부 문자열은 컴파일된 파일에서 찾을 수 있습니다.
$ grep "Hello" ./embedded
Binary file ./embedded matches
$ grep "Hello World" ./embedded
$
조금 더 난독화를 원한다면 base64를 사용할 수 있습니다.
...
PyRun_SimpleString("import base64\n"
"base64_code = 'your python code in base64'\n"
"code = base64.b64decode(base64_code)\n"
"exec(code)");
...
예:
코드의 기본 64 문자열을 만듭니다.
$ base64 hello_world.py
cHJpbnQoJ0hlbGxvIFdvcmxkICEnKQoK
embedded_base64.c
#include <Python.h>
int
main(int argc, char *argv[])
{
Py_SetProgramName(argv[0]); /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("import base64\n"
"base64_code = 'cHJpbnQoJ0hlbGxvIFdvcmxkICEnKQoK'\n"
"code = base64.b64decode(base64_code)\n"
"exec(code)\n");
Py_Finalize();
return 0;
}
모든 명령
$ gcc -o embedded_base64 -fPIC -I/usr/include/python2.7 -lpython2.7 ./embedded_base64.c
$ chmod u+x ./embedded_base64
$ time ./embedded_base64
Hello World !
real 0m0.014s
user 0m0.008s
sys 0m0.004s
$ grep "Hello" ./embedded_base64
$
업데이트:
이 프로젝트(pyarmor
) 또한 다음과 같은 이점이 있습니다.
https://pypi.org/project/pyarmor/
모듈을 사용하여 문자열을 인코딩하여 숄더 서핑을 중지할 수는 있지만 다른 사용자가 사용자의 파일에 액세스할 수 있는 경우 다른 사용자가 사용자의 코드를 찾는 것을 막지는 못합니다.
그런 다음 함수와 함수를 사용하여 코드를 디코딩한 후 실행할 수 있습니다.
>>> import base64
>>> mycode = "print 'Hello World!'"
>>> secret = base64.b64encode(mycode)
>>> secret
'cHJpbnQgJ2hlbGxvIFdvcmxkICEn'
>>> mydecode = base64.b64decode(secret)
>>> eval(compile(mydecode,'<string>','exec'))
Hello World!
따라서 30줄의 코드가 있다면 다음과 같은 방법으로 암호화하고 싶을 것입니다.
>>> f = open('myscript.py')
>>> encoded = base64.b64encode(f.read())
두 해야 합니다.compile()
그리고.eval()
여기에는 인코딩된 스크립트가 세 개의 따옴표로 묶인 문자열 리터럴로 포함될 수 있습니다.따라서 다음과 같이 보일 것입니다.
import base64
myscript = """IyBUaGlzIGlzIGEgc2FtcGxlIFB5d
GhvbiBzY3JpcHQKcHJpbnQgIkhlbG
xvIiwKcHJpbnQgIldvcmxkISIK"""
eval(compile(base64.b64decode(myscript),'<string>','exec'))
사이톤
이것에 대해 대답해야 할 것은 싸이톤인 것 같습니다.아직 아무도 언급하지 않았다니 정말 놀랍군요.홈 페이지는 다음과 같습니다: https://cython.org
간단히 말해서, 이것은 파이썬을 C로 변환하고 컴파일하여 "정상" 컴파일된 배포 가능한 C 프로그램만큼 잘 보호되도록 합니다.
하지만 한계가 있습니다.저는 그것들에 대해 깊이 탐구하지 않았습니다. 왜냐하면 제가 그것들에 대해 읽기 시작하면서, 저는 제 목적을 위해 아이디어를 포기했기 때문입니다.그래도 당신에겐 효과가 있을지도 몰라요기본적으로 Python이 제공하는 역동적인 멋으로는 Python을 최대한 사용할 수 없습니다.저에게 달려든 한 가지 주요 문제는 키워드 매개변수를 사용할 수 없다는 것이었습니다. :( 위치 매개변수만 사용하여 함수 호출을 작성해야 합니다.저는 이것을 확인하지 못했지만, 당신이 조건부 수입품, 즉 val을 사용할 수 있을지 의심스럽습니다.다형성이 어떻게 처리되는지는 잘 모르겠지만,
어쨌든, 만약 당신이 그 사실 이후에 거대한 코드 베이스를 난독화하려고 하지 않는다면, 또는 이상적으로는 당신이 처음부터 사이톤을 사용하는 것을 염두에 두고 있다면, 이것은 매우 주목할 만한 옵션입니다.
파이썬 코드의 난독화 및 최소화를 위해 다음 도구를 확인하십시오.
- pyarmor, https://pypi.org/project/pyarmor/ - 16진수를 사용한 완전 난독화; 분명히 변수/함수 이름의 부분 난독화만 허용하지 않습니다.
- python-miniifier, https://pypi.org/project/python-minifier/ - 코드를 최소화하고 함수/오류 이름을 난독화합니다(아래의 pyminiifier만큼 강렬하지는 않지만).
- pyminifier, https://pypi.org/project/pyminifier/ - 함수, 변수, 리터럴의 이름을 난독화하는 작업을 잘 수행합니다. 또한 pyarmor와 유사한 16진법(압축)을 수행할 수 있습니다.문제: 난독화 후 코드에 구문 오류가 포함되어 실행되지 않을 수 있습니다.
--obfuscate 및 --gzip과 함께 실행할 때 pyminiator에서 .py 출력 예:
pyminifier --certificate --gzip/tmp/tumult.py
#!/usr/bin/env python3
import zlib, base64
exec(zlib.decompress(base64.b64decode('eJx1kcFOwzAMhu95ClMO66apu0/KAQEbE5eJC+IUpa27haVJ5Ljb+vakLYJx4JAoiT/7/+3c3626SKvSuBW6M4Sej96Jq9y1wRM/E3kSexnIOBZObrSNKI7Sl59YsWDq1wLMiEKNrenoYCqB1woDwzXF9nn2rskZd1jDh+9mhOD8DVvAQ8WdtrZfwg74aNwp7ZpnMXHUaltk878ybR/ZNKbSjP8JPWk6wdn72ntodQ8lQucIrdGlxaHgq3QgKqtjhCY/zlN6jQ0oZZxhpfKItlkuNB3icrE4XYbDwEBICRP6NjG1rri3YyzK356CtsGwZuNd/o0kYitvrBd18qgmj3kcwoTckYPtJPAyCVzSKPCMNErs85+rMINdp1tUSspMqVYbp1Q2DWKTJpcGURRDr9DIJs8wJFlKq+qzZRaQ4lAnVRuJgjFynj36Ol7SX/iQXr8ANfezCw==')))
# Created by pyminifier.py (https://github.com/liftoff/pyminifier)
이 출력은 여기에 표시된 것처럼 40줄의 원래 입력 스크립트에 해당합니다.
누이트카
저는 싸이톤보다 누이트카를 정말 추천합니다.또한 Nuitka는 컴파일된 C 코드와 유사한 수준의 난독화를 제공하는 네이티브 플랫폼 코드로 Python을 컴파일합니다.
python -m pip install nuitka
python -m nuitka --follow-imports --include-package urllib3.util.ssl_ myprogram.py
./myprogram.bin
--follow-imports
가져온 모든 모듈을 포함하는 작업을 수행합니다.--include-package
컴파일된 프로그램을 시작할 때 일부 가져오기가 숨겨져 있고 누락된 경우 추가 패키지를 전달하는 데 도움이 될 수 있습니다.
를 추가합니다.--onefile
또는-standalone
만약 이것이 유통을 위한 패키지를 얻는 데 효과가 있다면.
저도 사용했습니다.pyarmor
했지만, 여서참조만지했기,만▁the▁referen,pytransform.so
또는pytransform.dll
의 pyarmor
제 프로젝트의 차단기였던 폐쇄 소스입니다.
반난독화된 코드를 만들고 싶다면 다음과 같은 코드를 만듭니다.
import base64
import zlib
def run(code): exec(zlib.decompress(base64.b16decode(code)))
def enc(code): return base64.b16encode(zlib.compress(code))
다음과 같은 파일을 만듭니다(위 코드 사용).
f = open('something.py','w')
f.write("code=" + enc("""
print("test program")
print(raw_input("> "))"""))
f.close()
파일 "something.py ":
code = '789CE352008282A2CCBC120DA592D4E212203B3FBD28315749930B215394581E9F9957500A5463A7A0A4A90900ADFB0FF9'
.py "을 "something.py "을 실행하면 .run(something.code)
파일에서 코드를 실행합니다.
한 가지 비결은 코드를 읽기 어렵게 만드는 것입니다. 어떤 것도 문서화하지 말고, 필요하다면, 기능의 출력을 제공하십시오. 어떻게 작동하는지가 아닙니다.광범위하게 만들거나, 참조를 , : 이 름 매 광 참 또 반 는 예 대 로 만 듭 니 다 조 상 동 영 게 하 을 우 범 위 만 듭 니 : ▁make 다 예 ▁very ▁names ▁refe os ▁variablebtmnsfavclr = 16777215
에 "면에반""로서btmnsfavclr
색은 "배트맨이가을좋장색는아하며의하미값은을,며▁means"하, 값은▁"▁is배"입니다.16777215
" 는의 " 진십 " 수형 " 식또 의▁의 소수 .ffffff
아니면 흰색.코드의 성가신 사람들을 유지하기 위해 다른 스타일의 이름을 혼합하는 것을 기억하세요.또한 다음 사이트에서 팁을 사용하십시오.유지관리 불가능한 코드를 개발하기 위한 11가지 팁.
아마도 당신은 파이 콘크리트를 입어볼 수 있을 것입니다, 그것은 제 오픈 소스 프로젝트입니다.
암호화하다.pyc
.pye
때 해독하기
OpenAES 라이브러리를 통한 암호화 및 암호 해독
사용.
전체 암호화
의 모든 두변환을 합니다.
.py
*.pye
$ pyconcrete-admin.py compile --source={your py script} --pye $ pyconcrete-admin.py compile --source={your py module dir} --pye
거한제를 합니다.
*.py
*.pyc
복사 는복사*.pye
main.py 이 메인으로 암호화되었습니다.파이, 정상적으로 실행할 수 없습니다.
python
사용해야 합니다.pyconcrete
메인을 처리합니다.파이 문자pyconcrete
(exe)가 시스템 경로에 설치됩니다(예: /usr/local/bin).pyconcrete main.pye src/*.pye # your libs
부분 암호화(pyconcrete as lib)
setup.py 에서 py 콘크리트 소스를 다운로드하고 설치합니다.
$ python setup.py install \ --install-lib={your project path} \ --install-scripts={where you want to execute pyconcrete-admin.py and pyconcrete(exe)}
주요 스크립트에서 py 콘크리트 가져오기
권장 사항 프로젝트 레이아웃
main.py # import pyconcrete and your lib pyconcrete/* # put pyconcrete lib in project root, keep it as original files src/*.pye # your libs
코드를 난독화하는 방법은 여러 가지가 있습니다.여기 한 가지 예가 있습니다.
(lambda _, __, ___, ____, _____, ______, _______, ________:
getattr(
__import__(True.__class__.__name__[_] + [].__class__.__name__[__]),
().__class__.__eq__.__class__.__name__[:__] +
().__iter__().__class__.__name__[_____:________]
)(
_, (lambda _, __, ___: _(_, __, ___))(
lambda _, __, ___:
chr(___ % __) + _(_, __, ___ // __) if ___ else
(lambda: _).func_code.co_lnotab,
_ << ________,
(((_____ << ____) + _) << ((___ << _____) - ___)) + (((((___ << __)
- _) << ___) + _) << ((_____ << ____) + (_ << _))) + (((_______ <<
__) - _) << (((((_ << ___) + _)) << ___) + (_ << _))) + (((_______
<< ___) + _) << ((_ << ______) + _)) + (((_______ << ____) - _) <<
((_______ << ___))) + (((_ << ____) - _) << ((((___ << __) + _) <<
__) - _)) - (_______ << ((((___ << __) - _) << __) + _)) + (_______
<< (((((_ << ___) + _)) << __))) - ((((((_ << ___) + _)) << __) +
_) << ((((___ << __) + _) << _))) + (((_______ << __) - _) <<
(((((_ << ___) + _)) << _))) + (((___ << ___) + _) << ((_____ <<
_))) + (_____ << ______) + (_ << ___)
)
)
)(
*(lambda _, __, ___: _(_, __, ___))(
(lambda _, __, ___:
[__(___[(lambda: _).func_code.co_nlocals])] +
_(_, __, ___[(lambda _: _).func_code.co_nlocals:]) if ___ else []
),
lambda _: _.func_code.co_argcount,
(
lambda _: _,
lambda _, __: _,
lambda _, __, ___: _,
lambda _, __, ___, ____: _,
lambda _, __, ___, ____, _____: _,
lambda _, __, ___, ____, _____, ______: _,
lambda _, __, ___, ____, _____, ______, _______: _,
lambda _, __, ___, ____, _____, ______, _______, ________: _
)
)
)
나는 그것이 오래된 질문이라는 것을 압니다.파이썬 3에서 재미있게 난독화된 "Hello world!"와 몇 가지 팁을 추가하고 싶습니다 ;)
#//'written in c++'
#include <iostream.h>
#define true false
import os
n = int(input())
_STACK_CALS= [ ];
_i_CountCals__= (0x00)
while os.urandom(0x00 >> 0x01) or (1 & True):
_i_CountCals__+= 0o0;break;# call shell command echo "hello world" > text.txt
""#print'hello'
__cal__= getattr( __builtins__ ,'c_DATATYPE_hFILE_radnom'[ 0x00 ]+'.h'[-1]+'getRndint'[3].lower() )
_o0wiXSysRdrct =eval ( __cal__(0x63) + __cal__(104) + 'r_RUN_CALLER'[0] );
_i1CLS_NATIVE= getattr (__builtins__ ,__cal__(101)+__cal__(118 )+_o0wiXSysRdrct ( 0b1100001 )+'LINE 2'[0].lower( ))#line 2 kernel call
__executeMAIN_0x07453320abef =_i1CLS_NATIVE ( 'map');
def _Main():
raise 0x06;return 0 # exit program with exit code 0
def _0o7af():_i1CLS_NATIVE('_int'.replace('_', 'programMain'[:2]))(''.join( __executeMAIN_0x07453320abef( _o0wiXSysRdrct ,_STACK_CALS)));return;_Main()
for _INCREAMENT in [0]*1024:
_STACK_CALS= [0x000 >> 0x001 ,True&False&True&False ,'c++', 'h', 'e', 'l', 'o',' ', 'w', 'o', 'r', 'l', 'd']
#if
for _INCREAMENT in [0]*1024:
_STACK_CALS= [40, 111, 41, 46, 46] * n
""""""#print'word'
while True:
break;
_0o7af();
while os.urandom(0x00 >> 0xfa) or (1 & True): # print "Hello, world!"
_i_CountCals__-= 0o0;break;
while os.urandom(0x00 >> 0x01) or (1 & True):
_i_CountCals__ += 0o0;
break;
수동으로 수행할 수 있습니다. 제 팁은 다음과 같습니다.
사용하다
eval
및/는exec
을 사용하여사용하다
[ord(i) for i in s]
/''.join(map(chr, [list of chars goes here]))
모호한 변수 이름 사용
읽을 수 없게 하다
True만 True만 쓰시고, True는 True로 쓰시면 됩니다.
1&True&0x00000001
;)다른 번호 체계를 사용합니다.
루프하는 동안 10행의 "2행" 또는 "0을 반환합니다"와 같은 혼란스러운 주석을 추가합니다.
사용하다
__builtins__
사용하다
getattr
그리고.setattr
코드를 다음과 같이 마스킹합니다.
def MakeSC():
c = raw_input(" Encode: ")
sc = "\\x" + "\\x".join("{0:x}".format(ord(c)) for c in c)
print "\n shellcode =('" + sc + "'); exec(shellcode)"; MakeSC();
텍스트 지우기:
import os; os.system("whoami")
인코딩됨:
Payload = ('\x69\x6d\x70\x6f\x72\x74\x20\x6f\x73\x3b\x20\x6f\x73\x2e\x73\x79\x73\x74\x65\x6d\x28\x22\x77\x68\x6f\x61\x6d\x69\x22\x29'); exec(Payload);
좋은 파일을 입니다.
전용 버전: Windows 버전요구 사항들
설치:
sudo pip install -U cython
.py 파일을 난독화하려면:
pyobfuscate.py myfile.py >obfuscated.py
.c 파일을 생성하려면,
.py파일에기능 추가(선택사항)cython --embed file.py
cp Python.h tcc\include
tcc file.c -o file.pyd -shared -I\path\to\Python\include -L\path\to\Python\lib
.pyd 파일을 app.exe로 가져옵니다.
소스 코드 저장을 위한 실제 암호 볼륨과 같은 간단한 것을 사용하는 것을 검토해야 할 것입니다. 그것이 당신의 관심사인 것 같습니다.USB 키에 암호화된 파일을 만들거나 코드가 맞는 경우 전체 볼륨을 암호화하여 하루가 끝날 때 키를 휴대할 수 있습니다.
그런 다음 PyInstaller 또는 py2exe와 같은 것을 사용하여 독립 실행 파일을 만들 수 있습니다.만약 당신이 정말로 더 많은 것을 하고 싶다면, 더 많은 난독화를 추가하기 위해 패커나 압축 유틸리티를 살펴보세요.이러한 옵션이 없는 경우 스크립트를 바이트 코드로 컴파일하여 즉시 읽을 수 없도록 할 수 있습니다.이러한 방법은 프로그램을 디버그하거나 디컴파일하려는 다른 사용자를 지연시킬 뿐입니다.
최근에 우연히 다음 블로그 게시물을 발견했습니다.작성자가 내장된 AST 모듈을 이용하여 파이썬 소스 파일 난독화에 대해 이야기하는 AST를 이용한 파이썬 소스 난독화컴파일된 바이너리는 HitB CTF에 사용되어야 했기 때문에 엄격한 난독화 요구사항이 있었습니다.
개별 AST 노드에 액세스할 수 있으므로 이 방법을 사용하면 원본 파일을 임의로 수정할 수 있습니다.수행하는 변환에 따라 결과 이진이 난독화되지 않은 원본과 정확히 일치하지 않을 수 있습니다.
이 파이썬 난독화기를 사용해 보십시오.
__all__ = ['foo']
a = 'a'
_b = 'b'
def foo():
print(a)
def bar():
print(_b)
def _baz():
print(a + _b)
foo()
bar()
_baz()
으로 변환할 것
__all__ =['foo']#line:1
OO00OO0OO0O00O0OO ='a'#line:3
_O00OO0000OO0O0O0O ='b'#line:4
def foo ():#line:6
print (OO00OO0OO0O00O0OO )#line:7
def O0000000OOOO00OO0 ():#line:9
print (_O00OO0000OO0O0O0O )#line:10
def _OOO00000O000O0OOO ():#line:12
print (OO00OO0OO0O00O0OO +_O00OO0000OO0O0O0O )#line:13
foo ()#line:15
O0000000OOOO00OO0 ()#line:16
_OOO00000O000O0OOO ()#line:17
오피
Opy는 당신의 광범위한 실제 다중 모듈 파이썬 소스 코드를 무료로 난독화할 것입니다!그리고 구성 파일을 편집하여 프로젝트별로 난독화할 항목과 난독화할 항목을 선택합니다.
You can recursively exclude all identifiers of certain modules from obfuscation. You can exclude human readable configuration files containing Python code. You can use getattr, setattr, exec and eval by excluding the identifiers they use. You can even obfuscate module file names and string literals. You can run your obfuscated code from any platform.
게시된 다른 옵션 중 일부와 달리, 이것은 Python 2와 3 모두에서 작동합니다!또한 무료/오픈 소스이며, 다른 일부 제품처럼 온라인 전용 도구(결제하지 않는 한)가 아닙니다.
저는 여전히 이것을 스스로 평가하고 있지만, 초기 테스트는 모두 완벽하게 작동했습니다.이게 바로 제가 찾던 것 같네요!
공식 버전은 독립 실행형 유틸리티로 실행되며, 원래 설계는 사용할 세부사항/옵션을 정의하는 구성 파일과 함께 난독화할 디렉토리의 루트에 스크립트를 삭제하는 것입니다.저는 그 계획이 마음에 들지 않았기 때문에 프로젝트에서 포크를 추가하여 대신 도서관에서 도구를 가져와 사용할 수 있도록 했습니다.그런 식으로 이를 보다 포괄적인 패키징 스크립트로 직접 롤할 수 있습니다. (물론 여러 py 스크립트를 bash/batch로 래핑할 수는 있지만 순수한 python 솔루션이 이상적입니다.)저는 제 포크를 원래 작업에 병합할 것을 요청했지만, 그런 일이 일어나지 않을 경우를 대비하여, 여기 제 수정 버전의 URL이 있습니다.
https://github.com/BuvinJT/Opy
파이썬 스크립트를 난독화하는 두 가지 방법이 있습니다.
- 각 코드 객체의 바이트 코드를 난독화합니다.
- 파이썬 모듈의 전체 코드 개체를 난독화합니다.
Python 스크립트 난독화
python 소스 파일을 코드 개체로 컴파일
char * filename = "xxx.py"; char * source = read_file( filename ); PyObject *co = Py_CompileString( source, filename, Py_file_input );
코드 개체를 반복하고 각 코드 개체의 바이트 코드를 다음 형식으로 감습니다.
0 JUMP_ABSOLUTE n = 3 + len(bytecode) 3 ... ... Here it's obfuscated bytecode ... n LOAD_GLOBAL ? (__armor__) n+3 CALL_FUNCTION 0 n+6 POP_TOP n+7 JUMP_ABSOLUTE 0
코드 개체를 직렬화하여 난독화합니다.
char *original_code = marshal.dumps( co ); char *obfuscated_code = obfuscate_algorithm( original_code );
래퍼 스크립트 "xxx.py "을 만듭니다. ${propertated_code}는 이전 단계에서 생성된 문자열 상수를 나타냅니다.
__pyarmor__(__name__, b'${obfuscated_code}')
난독화된 Python 스크립트 실행 또는 가져오기
이 래퍼 스크립트를 가져오거나 실행할 때 첫 번째 명령문은 CFunction을 호출하는 것입니다.
int __pyarmor__(char *name, unsigned char *obfuscated_code)
{
char *original_code = resotre_obfuscated_code( obfuscated_code );
PyObject *co = marshal.loads( original_code );
PyObject *mod = PyImport_ExecCodeModule( name, co );
}
이 함수는 모듈 이름과 난독화된 코드의 두 가지 매개 변수를 허용합니다.
- 난독화된 코드 복원
- 원래 코드로 코드 개체 만들기
- 원래 모듈 가져오기(Traceback에서 프레임이 중복됨)
난독화된 바이트 코드 실행 또는 가져오기
모듈을 가져온 후, 이 모듈의 코드 개체가 처음 호출될 때, 위 섹션에 설명된 래핑된 바이트 코드로부터, 우리는 알고 있습니다.
첫 번째 작업
JUMP_ABSOLUTE
n 프셋으점프로오▁n▁to▁jumps▁offset프.오프셋 n에서 명령은 PyCFunction을 호출하는 것입니다.이 함수는 오프셋 3과 n 사이의 난독화된 바이트 코드를 복원하고 원래 바이트 코드를 오프셋 0에 배치합니다.
함수 호출 후 마지막 명령이 다시 오프셋 0으로 점프합니다.이제 실제 바이트 코드가 실행됩니다.
Pyarmor 참조
다른 대답들이 말했듯이, 좋은 방법은 정말 없습니다.Base64는 디코딩할 수 있습니다.바이트 코드를 압축 해제할 수 있습니다.파이썬은 처음에는 그냥 해석되었고, 대부분의 해석된 언어들은 인간의 해석을 어렵게 하는 것보다 기계 해석 속도를 높이려고 노력합니다.
Python은 난독화되지 않고 읽기와 공유가 가능하도록 만들어졌습니다.코드가 어떻게 포맷되어야 하는지에 대한 언어 결정은 다른 저자들 사이에서 가독성을 촉진하는 것이었습니다.
파이썬 코드를 난독화하는 것은 언어와 잘 맞지 않습니다.코드를 난독화한 이유를 다시 평가합니다.
여기 제가 서킷에서 하고 있는 일에 대한 저의 아주 솔직한 접근법이 있습니다.파이썬.현재 부분적으로 테스트 중입니다.유용할 것 같아서 이 상태로 글을 올렸습니다.
두 가지 인수가 있습니다.
- 쉼표로 구분된 입력 파일 목록
- 쉼표로 구분된 출력 파일 목록
기능은 다음과 같습니다.
- 메서드 서명, 할당의 왼쪽, 모든 가져오기 별칭을 확인하여 모든 변수 이름을 찾습니다.
- 수정하지 않을 항목을 검역합니다.
- 나머지 이름을 의미 없는 토큰으로 바꿉니다.
- 내가 검역한 항목의 검역을 해제합니다.
코드를 이렇게 돌립니다.
degreeIncrement = 90
durationIncrement = 0.25
def GetEditGlyphParams(self, waveform, editIndex):
segments = waveform.leftSegments
waveformFunctionCount = len(self.waveformFunctions)
totalParameterCount = 0
segmentIndex = 0
while segmentIndex < len(segments):
segment = segments[segmentIndex]
segmentParameterCount = len(self.sineFunctions)
if segment.type == "line":
segmentParameterCount = len(self.lineFunctions)
...다음과 같은 코드로 변환:
a6 = 90 # degreeIncrement = 90
a7 = 0.25 # durationIncrement = 0.25
def a8(a9, a10, a11): # def GetEditGlyphParams(self, waveform, editIndex):
a12 = a10.leftSegments # segments = waveform.leftSegments
a13 = len(a9.a5) # waveformFunctionCount = len(self.waveformFunctions)
a14 = 0 # totalParameterCount = 0
a15 = 0 # segmentIndex = 0
while a15 < len(a12): # while segmentIndex < len(segments):
a16 = a12[a15] # segment = segments[segmentIndex]
a17 = len(a9.a3) # segmentParameterCount = len(self.sineFunctions)
if a16.a332 == "line": # if segment.type == "line":
a17 = len(a9.a4) # segmentParameterCount = len(self.lineFunctions)
필요한 경우 주석을 생략할 수 있습니다.
이를 수행하는 코드는 다음과 같습니다.
import sys, re
sourceDirectory = sys.argv[1]
print("sourceDirectory", sourceDirectory)
sourceFiles = sys.argv[2].split(",")
targetFiles = sys.argv[3].split(",")
if len(sourceFiles) != len(targetFiles):
raise Exception("Source file count must match target file count. Use comma to separate.")
print("uglify", sys.argv[1])
names = []
translations = []
class Analyser:
def AnalyseLines(self, lines):
for line in lines:
self._AnalyseLine(line)
def _AnalyseLine(self, line):
parts = self._GetParts(line)
if len(parts) > 1 and parts[0] == "import":
self._AnalyseImport(parts)
if len(parts) > 1 and parts[0] == "class":
self._AnalyseClass(parts)
if len(parts) > 1 and parts[1] == "=":
self._AnalyseAssignment(parts)
if len(parts) > 1 and parts[0] == "def":
self._AnalyseDef(parts)
def _GetParts(self, line):
minusTabs = line.strip().replace("\t", " ")
minusOpenSquare = minusTabs.replace("[", " ")
minusCloseSquare = minusOpenSquare.replace("]", " ")
minusDoubleSpace = minusCloseSquare.replace(" ", " ")
parts = minusDoubleSpace.split(" ")
while "#" in parts:
del parts[-1]
while len(parts) > 0 and parts[0] == "":
del parts[0]
nonEmptyParts = []
for part in parts:
if len(part) > 0:
nonEmptyParts.append(part)
return nonEmptyParts
def _AddName(self, name, elementType):
nameToAppend = name # + " " + elementType
if nameToAppend in names:
return
if nameToAppend == "sin" or nameToAppend == "value":
print("--> adding", nameToAppend, "as", elementType)
names.append(nameToAppend)
translation = "a" + str(len(names))
translations.append((name, translation))
def _AnalyseImport(self, parts):
if len(parts) == 4 and parts[0] == "import" and parts[2] == "as":
self._AddName(parts[3], "import")
def _AnalyseClass(self, parts):
p1 = parts[1].split(":")
p2 = p1[0].split("(")
self._AddName(p2[0], "class")
def _AnalyseAssignment(self, parts):
mutableName = parts[0].split(".")[0]
self._AddName(mutableName, "assignment")
def _AnalyseDef(self, parts):
methodNameParts = parts[1].split("(")
if methodNameParts[0] == "__init__":
return
self._AddName(methodNameParts[0], "method")
if len(methodNameParts) > 1:
self._AddName(methodNameParts[1].replace(",", "").replace("):", ""), "param1")
for part in parts[2:]:
params = part.split(",")
for param in params:
if param != "":
if param.replace(":", "").replace(")", "") == "value":
print("found value amongst", parts)
self._AddName(param.replace(":", "").replace(")", ""), "paramN")
class Translator:
def TranslateLines(self, content):
oldLines = content.split("\n")
content = content.replace('"', "_QUOTE_").replace("\\", "_BACKSLASH_")
for (oldWord, newWord) in translations:
content = re.sub(r"\b%s\b" % oldWord, newWord, content)
content = content.replace("_QUOTE_", '"').replace("_BACKSLASH_", "\\")
newLines = content.split("\n")
for i in range(len(newLines) - 1):
if newLines[i] != "":
newLines[i] += " # " + oldLines[i].strip()
return "\n".join(newLines)
def TranslateLines2(self, content):
oldLines = content.split("\n")
newLines = []
for lineNumber, oldLine in enumerate(oldLines):
# print("translating line of length", len(oldLine), ":", oldLine)
content = oldLine.split(" # ")[0]
if len(content.strip(" \t")) > 0:
content = content.replace('"', "_QUOTE_").replace("\\", "_BACKSLASH_")
for (oldWord, newWord) in translations:
try:
content = re.sub(r"\b%s\b" % oldWord, newWord, content)
except:
print("problem translating", oldWord, "into", newWord)
raise Exception("error in translation")
content = content.replace("_QUOTE_", '"').replace("_BACKSLASH_", "\\")
newLines.append(content + " # " + oldLine.strip())
return "\n".join(newLines)
lines = []
for i, sourceFileName in enumerate(sourceFiles):
names.append(sourceFileName)
targetFileName = targetFiles[i]
translations.append((sourceFileName, targetFileName))
for sourceFileName in sourceFiles:
fullFileName = sourceDirectory + sourceFileName + ".py"
sourceFile = open(fullFileName, 'r')
content = sourceFile.read()
fileLines = content.split("\n")
lines.extend(fileLines)
print("found", len(fileLines), "lines in", sourceFileName)
print("----------------")
print("found a total of", len(lines), "lines")
print("----------------")
analyser = Analyser()
analyser.AnalyseLines(lines)
for i, name in enumerate(names):
if len(name) < 1:
print("deleting name", i, "because it is zero length")
names.remove(name)
translation = translations[i]
translations.remove(translation)
# print(names)
# raise Exception("Not implemented beyond here.")
translator = Translator()
for i, sourceFileName in enumerate(sourceFiles):
print("translating", sourceFileName, "into", targetFiles[i])
fullFileName = sourceDirectory + sourceFileName + ".py"
targetFileName = sourceDirectory + targetFiles[i] + ".py"
sourceFile = open(fullFileName, 'r')
content = sourceFile.read()
targetFile = open(targetFileName, 'w')
fileLines = content.split("\n")
newContent = translator.TranslateLines2(content)
targetFile.write(newContent)
sourceFile.close()
targetFile.close()
# print(len(lines), "lines, starting with", lines[0])
# print(names)
# print(translations)
hello world 파이썬 코드를 다음 사이트에 붙여 보십시오.
http://enscryption.com/encrypt-and-obfuscate-scripts.html
암호화되고 난독화된 복잡한 스크립트를 생성하지만 완전히 작동합니다.스크립트를 크래킹하고 실제 코드를 공개할 수 있는지 확인합니다.또는 복잡성 수준이 마음의 평화에 대한 요구를 충족시키는지 확인합니다.
이 사이트를 통해 생성된 암호화된 스크립트는 파이썬이 설치된 모든 유닉스 시스템에서 작동해야 합니다.
다른 방법으로 암호화하려면 자체 암호화/난독화 알고리즘을 작성하는 것이 좋습니다(보안이 중요한 경우).그렇게 하면, 당신 말고는 아무도 그것이 어떻게 작동하는지 알아낼 수 없습니다.하지만, 이것이 실제로 효과가 있으려면, 많은 시간을 들여서 손이 많이 가는 사람이 악용할 수 있는 허점이 없는지 확인해야 합니다.또한 Unix 시스템에 이미 자연스러운 도구(예: openssl 또는 base64)를 사용해야 합니다.이렇게 하면 암호화된 스크립트를 더 쉽게 이동할 수 있습니다.
저는 제 답을 교훈적인 방식으로 쓸 것입니다.
파이썬 인터프리터의 첫 번째 유형:
import this
인 그럼파일보세요을가서▁file▁the▁를 살펴보세요.this.py
Python 배포판 내 Lib 디렉토리에서 사용하고 이 디렉토리가 수행하는 작업을 이해하려고 합니다.
그 후에, 다음을 살펴보세요.eval
설명서의 기능:
help(eval)
이제 코드를 보호할 수 있는 재미있는 방법을 찾았어야 합니다.하지만 조심하세요, 왜냐하면 그것은 당신보다 덜 지적인 사람들에게만 효과가 있기 때문입니다! (그리고 저는 불쾌하게 하려는 것이 아닙니다, 당신이 한 일을 이해할 만큼 똑똑한 사람은 그것을 되돌릴 수 있습니다.)
언급URL : https://stackoverflow.com/questions/3344115/how-to-obfuscate-python-code-effectively
'programing' 카테고리의 다른 글
자바스크립트에서 epoch 이후 초를 어떻게 얻을 수 있습니까? (0) | 2023.07.25 |
---|---|
파이썬에서 파일의 문자열을 어떻게 랩합니까? (0) | 2023.07.25 |
Oracle에서 문자 집합 불일치 오류 (0) | 2023.07.25 |
대규모 데이터셋을 위한 데이터베이스 설계 (0) | 2023.07.25 |
인텐트(최적의 솔루션)를 통해 열거나 개체 전달 (0) | 2023.07.25 |