나는 적절한 Pyarmor 풀기가 출시 될 때가되었다고 결정했다. 현재 공개 된 모든 것은 구식이며 전혀 작동하지 않거나 부분 출력 만 제공합니다. 나는 이것을 최신 버전의 Pyarmor를 지원할 계획입니다.
도움이된다면 저장소를 별표로 표시하십시오. 정말 감사합니다.
Pyarmor를 풀기위한 3 가지 방법이 있으며,이 저장소의 메소드 폴더에서 각 방법에 필요한 모든 파일을 찾을 수 있습니다. 아래에서 최종 제품까지 시작한 방법에 대한 자세한 글을 찾을 수 있습니다. 더 많은 사람들이 도구를 사용하는 것보다 이런 식으로 어떻게 작동하는지 이해하기를 바랍니다.
이것은 알려진 모든 문제/누락 된 기능의 목록입니다. 나는 그들을 직접 고칠 시간이 충분하지 않아서 기고자들에게 크게 의존하고 있습니다.
문제 :
누락 된 기능 :
중요 : 모든 곳에서 동일한 Python 버전을 사용하고 포장을 풀고있는 프로그램이 무엇인지 살펴보십시오. 그렇지 않으면 문제에 직면하게됩니다.
method_1.py 파일을 실행하십시오run.py 사용하여 부분적으로 포장되지 않은 프로그램을 실행할 수 있습니다.dumps 디렉토리에서 완전히 포장되지 않은 .pyc 파일을 찾을 수 있습니다. 참고 : 버전 3.9.7 아래에 정적 풀기를 사용하지 마십시오. marshal.loads 감사 로그는 3.9.7 이후에만 추가되었습니다. 모든 기고자는 지원을 추가 할 수 있습니다
python3 bypass.py filename.pyc ( filename.pyc 실제 파일 이름으로 바꾸십시오.dumps 디렉토리에서 완전히 포장되지 않은 .pyc 파일을 찾을 수 있습니다.기여는 정말 중요합니다. 위에 나열된 모든 문제를 해결할 시간이 충분하지 않습니다. 가능하면 기여하십시오.
기부금도 정말 환영합니다.
BTC -37RQ1XEB5Q8SCMMKKK3MVMD4RBE5FV7EMMH
ETH -0x2815266867856FA48B3924C185D7E1FB36F3B9A
ltc -mfhdlrdzaqygzxuvxqfm4rwvgbmrzmdzao
이것은 내가 Pyarmor를 멸관 시키거나 포장을 풀기 위해 겪은 전체 과정에 대한 오랫동안 기다려온 글입니다. 나는 내가 한 모든 연구를 거치게 될 것이며 결국 Pyarmor를 풀기위한 3 가지 방법을 제공 할 것입니다. 모두 다른 상황에서 독특하고 적용 할 수 있습니다. 나는 파이썬 내부에 대해 많이 알지 못했기 때문에 파이썬 내부에서 더 많은 경험을 가진 다른 사람들보다 더 오래 걸렸습니다.
Pyarmor는 그들이 모든 일을하는 방법에 대한 매우 광범위한 문서를 가지고 있습니다. 나는 당신이 그것을 완전히 읽는 것이 좋습니다. Pyarmor는 본질적으로 모든 코드 객체를 반복하여 암호화합니다. 그래도 고정 헤더와 바닥 글이 있습니다. 이는 "랩 모드"가 활성화되어 있는지에 따라 다릅니다. 기본적으로입니다.
wrap header:
LOAD_GLOBALS N (__armor_enter__) N = length of co_consts
CALL_FUNCTION 0
POP_TOP
SETUP_FINALLY X (jump to wrap footer) X = size of original byte code
changed original byte code:
Increase oparg of each absolute jump instruction by the size of wrap header
Obfuscate original byte code
...
wrap footer:
LOAD_GLOBALS N + 1 (__armor_exit__)
CALL_FUNCTION 0
POP_TOP
END_FINALLY
Pyarmor Docs에서
헤더에는 __armor_enter__ 함수에 대한 호출이 있으며, 이는 메모리의 코드 객체를 해독합니다. 코드 객체가 완료되면 __armor_exit__ 함수가 호출되어 코드 객체를 다시 암호화하여 해독 된 코드 객체가 메모리에 남아 있지 않습니다.
Pyarmor 스크립트를 컴파일하면 진입 점 파일과 pytransform 폴더가 있음을 알 수 있습니다. 이 폴더에는 dll과 __init__.py 파일이 포함되어 있습니다.
dist
│ test.py
└───pytransform
| _pytransform.dll
| __init__.py
__init__.py 파일은 코드 객체를 해독하는 데 많은 도움이되지 않습니다. 모듈을 가져올 수 있도록 주로 사용됩니다. 사용중인 OS와 같은 점검을 수행합니다. 읽으려면 오픈 소스이므로 일반적인 파이썬 스크립트처럼 열 수 있습니다.
가장 중요한 것은 _pytransform.dll 을로드하고 그 기능을 Python 통역사의 글로벌에 노출시키는 것입니다. 모든 스크립트에서 pytransform에서 pyarmor_runtime을 가져 오는 것을 볼 수 있습니다.
from pytransform import pyarmor_runtime
pyarmor_runtime ()
__pyarmor__ ( __name__ , __file__ , b' x50 x59 x41 x5...' ) 이 기능은 __armor_enter__ 및 __armor_exit__ 함수와 같은 Pyarmor 스크립트를 실행하는 데 필요한 모든 기능을 만듭니다.
내가 찾은 첫 번째 리소스는 포럼 Tuts4you 의이 스레드였습니다. 여기서 extremecoders 는 Pyarmor Protected 파일을 풀었던 방법에 대한 몇 가지 게시물을 썼습니다. 그는 CPYTHON 소스 코드를 편집하여 실행되는 모든 코드 객체의 마샬을 버렸습니다.
이 방법은 모든 상수를 노출시키는 데 적합하지만 바이트 코드를 얻으려면 이상적이지 않습니다.
__armor_enter__ 함수가 호출되는 경우에만 코드 개체가 아직 해독되지 않았습니다. 이는 코드 개체의 시작 부분에 있습니다. __armor_enter__ 함수는 메모리에서 해독되므로 cpython에 의해 덤프되지 않습니다. 파이썬 코드를 주입하여 메모리에서 해독 된 코드 객체를 덤핑하는 실험을 한 사람들이 있습니다.
이 비디오에서 누군가는 메모리의 모든 해독 된 기능을 어떻게 분해하는지 보여줍니다.
그러나 그는 아직 기본 모듈을 버리는 방법, 기능 만 찾지 못했습니다. 고맙게도 그는 Python 코드를 주입하는 데 사용한 코드를 게시했습니다. GitHub 저장소에서 우리는 그가 Python DLL에서 내보내기 기능을 호출하여 간단한 Python 코드를 실행하는 DLL을 생성한다는 것을 알 수 있습니다. 현재 그는 버전 3.7 ~ 3.9 용 Python DLL을 찾기위한 지원을 추가했지만 소스를 수정하고 다시 컴파일하여 더 많은 버전을 쉽게 추가 할 수 있습니다. 그는 Code.py에서 발견 된 코드를 실행하도록 만들었습니다.이 방법으로 매번 프로젝트를 재건 할 필요없이 Python 코드를 쉽게 편집 할 수 있습니다.
저장소에는 메모리에 해당 주소가있는 파일에 모든 함수 이름을 파일에 버리는 Python 파일이 포함되어 있습니다. 메모리가 없으면 아직 호출되지 않았다는 것을 의미하므로 아직 해독되지 않았습니다.
# Copyright holder: https://github.com/call-042PE
# License: GNU GPL v3.0 (https://github.com/call-042PE/PyInjector/blob/main/LICENSE)
import os , sys , inspect , re , dis , json , types
hexaPattern = re . compile ( r'b0x[0-9A-F]+b' )
def GetAllFunctions (): # get all function in a script
functionFile = open ( "dumpedMembers.txt" , "w+" )
members = inspect . getmembers ( sys . modules [ __name__ ]) # the code will take all the members in the __main__ module, the main problem is that it can't dump main code function
for member in members :
match = re . search ( hexaPattern , str ( member [ 1 ]))
if ( match ):
functionFile . write ( "{ " functionName " : " " + str ( member [ 0 ]) + " " , " functionAddr " : " " + match . group ( 0 ) + " " } n " )
else :
functionFile . write ( "{ " functionName " : " " + str ( member [ 0 ]) + " " , " functionAddr " :null} n " )
functionFile . close ()
GetAllFunctions () Call-042PE의 저장소에서
코드에서 당신은 그가 가지고있는 문제는 그가 기본 모듈 코드 객체에 액세스 할 수 없다는 주석을 추가했습니다.
많은 인터넷 검색을 마친 후 나는 울부 짖었고, 현재 실행중인 코드의 객체를 얻는 방법에 대해 아무것도 찾을 수 없었습니다. 나중에 관련없는 프로젝트에서 나는 sys._getframe() 에 대한 함수 호출을 보았다. 나는 그것이 무엇을하는지에 대한 연구를했는데, 그것은 현재 러닝 프레임을 얻습니다.
통화 스택을 걸어 특정 색인으로 프레임을 가져 오는 인수로 정수를 줄 수 있습니다.
sys . _getframe ( 1 ) # get the caller's frame이제 이것이 중요한 이유는 파이썬의 프레임이 기본적으로 코드 객체 일뿐 만 아니라 메모리의 상태에 대한 자세한 정보가 있기 때문입니다. 프레임에서 코드 객체를 가져 오려면 .f_code 속성을 사용할 수 있습니다. 프레임에서 코드 객체를 얻을 때 실행되는 코드 객체를 덤프하는 사용자 정의 CPYTHON 버전을 만든 경우에도 익숙해집니다.
...
1443 tstate -> frame = frame ;
1444 co = frame -> f_code ;
... 내 Custom Cpython 버전에서
이제 우리는 현재 실행중인 코드 객체를 얻는 방법을 알아 냈습니다. 메인 모듈을 찾을 때까지 단순히 통화 스택을 걸어 갈 수 있습니다.
이제 우리는 Pyarmor를 풀리는 방법에 대한 주요 아이디어를 거의 알아 냈습니다. 이제 다른 상황에서 개인적으로 유용한 것을 발견 한 3 가지 포장 방법을 보여 드리겠습니다.
첫 번째는 Python 코드를 주입해야하므로 Pyarmor 스크립트를 실행해야합니다. 위에서 설명한 것과 같이 기본 코드 객체를 덤프 할 때 일부 기능은 일부 기능이 여전히 암호화되므로 첫 번째 메소드는 pyarmor 런타임 기능을 호출하여 __armor_enter__ 및 __armor_exit__ 와 같이 코드 객체를 해독하는 데 필요한 모든 함수가로드됩니다.
이것은 매우 간단한 일처럼 보이지만 Pyarmor는 이것을 생각했고 제한 모드를 구현했습니다. Pyarmor 스크립트를 컴파일 할 때이를 지정할 수 있습니다. 기본적으로 제한 모드는 1입니다.
모든 제한 모드를 테스트하지는 않았지만 기본 모드에서 작동합니다.
이 코드를 REPL에서 실행하려고하면 다음 오류가 발생합니다.
> >> from pytransform import pyarmor_runtime
> >> pyarmor_runtime ()
Check bootstrap restrict mode failed 이것은 우리가 __armor_enter__ 및 __armor_exit__ 사용할 수 없게합니다.
다음 단계는 Tuts4you의 extremecoders 에 연락하는 것이 었습니다. 그는 _pytransform.dll 기본적으로 패치 할 수 있다고 언급함으로써 저를 도와주었습니다. 또한 파이썬에서만이 작업을 수행하는 솔루션을 제공해 주셔서 감사합니다.
기본 디버거에서 _pytransform.dll 을 열면 x64dbg를 선택하면 현재 모듈의 모든 문자열을 찾습니다.
"부트 스트랩"을 검색하여 지금 필터링하면 다음을 얻을 수 있습니다.
첫 번째 검색 결과에서 분해를 볼 때 _errno 에 대한 참조가 있음을 알 수 있습니다. 이는 일부 오류가 발생할 수 있음을 나타내며, 아래 몇 줄 아래에 파이썬에서 발생하는 오류를 볼 수 있습니다.
오류를 반환하기 위해 오류를 트리거하는 코드를 넘어서 점프의 지점에서 모든 것을 노출시킬 때 오류를 올릴 수있는 방법은 없습니다.
이제 이것을 저장하고 _pytransform.dll 을 바꾸면 같은 코드를 다시 시도하면 오류가 발생하지 않으며 __armor_enter__ 및 __armor_exit__ 함수에 액세스 할 수 있습니다.
> >> from pytransform import pyarmor_runtime
> >> pyarmor_runtime ()
> >> __armor_enter__
< built - in function __armor_enter__ >
> >> __armor_exit__
< built - in function __armor_exit__ > 이제 우리가 포장을 풀고 싶은 모든 Pyarmor 스크립트에 대해이 작업을 수행해야한다면 이것은 매우 피곤합니다. 따라서 extremecoders Python에서 메모리의 특정 주소를 가리키는 스크립트를 만들었습니다.
# Credit to extremecoders (https://forum.tuts4you.com/profile/79240-extreme-coders/) for writing the script
# Credit to me for adding the comments explaining it
import ctypes
from ctypes . wintypes import *
VirtualProtect = ctypes . windll . kernel32 . VirtualProtect
VirtualProtect . argtypes = [ LPVOID , ctypes . c_size_t , DWORD , PDWORD ]
VirtualProtect . restype = BOOL
# Load the dll in memory, this is useful because once it's loaded in memory it won't need to get loaded again so all the changes we make will be kept, including the bootstrap bypass
h_pytransform = ctypes . cdll . LoadLibrary ( "pytransform \ _pytransform.dll" )
pytransform_base = h_pytransform . _handle # Get the memory address where the dll is loaded
print ( "[+] _pytransform.dll loaded at" , hex ( pytransform_base ))
# We got this offset like I showed above with x64dbg, it's the first address where we start the NOP
patch_offset = 0x70A18F80 - pytransform_base
num_nops = 0x70A18FD5 - 0x70A18F80 # Minus the end address, this is the size that the NOP will be. The result will be 0x55
oldprotect = DWORD ( 0 )
PAGE_EXECUTE_READWRITE = DWORD ( 0x40 )
print ( "[+] Setting memory permissions" )
VirtualProtect ( pytransform_base + patch_offset , num_nops , PAGE_EXECUTE_READWRITE , ctypes . byref ( oldprotect ))
print ( "[+] Patching bootstrap restrict mode" )
ctypes . memset ( pytransform_base + patch_offset , 0x90 , num_nops ) # 0x90 is NOP
print ( "[+] Restoring memory permission" )
VirtualProtect ( pytransform_base + patch_offset , num_nops , oldprotect , ctypes . byref ( oldprotect ))
print ( "[+] All done! Pyarmor bootstrap restrict mode disabled" ) 이 코드를 a a를 restrict_bypass.py 라는 파일에 넣으면 원래 _pytransform.dll 사용하여 다음과 같이 사용할 수 있습니다.
> >> import restrict_bypass
[ + ] _pytransform . dll loaded at 0x70a00000
[ + ] Setting memory permissions
[ + ] Patching bootstrap restrict mode
[ + ] Restoring memory permission
[ + ] All done ! Pyarmor bootstrap restrict mode disabled
>> > from pytransform import pyarmor_runtime
>> > pyarmor_runtime ()
>> > __armor_enter__
< built - in function __armor_enter__ >
> >> __armor_exit__
< built - in function __armor_exit__ > 두 번째 방법은 첫 번째 방법과 동일하게 시작합니다. 현재 실행중인 코드 객체를 가져 오는 스크립트를 주입합니다.
이제 만 차이점은 우리가 단지 그것을 버리지 않고 "고정"한다는 것입니다. 즉, Pyarmor를 완전히 제거하여 원래 코드 객체를 얻을 수 있습니다.
Pyarmor에는 난독 화 될 때 여러 가지 옵션이 있기 때문에 모든 일반적인 것들에 대한 지원을 추가하기로 결정했습니다.
스크립트에 __armor_enter__ 가있는 스크립트가 감지되면 __armor_enter__ 호출 된 직후 코드 객체가 반환되도록 수정됩니다.
함수 호출 후에 POP_TOP OPCODE가 있습니다. 기능의 반환 값이 스택에서 제거되도록 사용됩니다. RETURN_VALUE opcode로 교체하여 __armor_enter__ 함수의 반환 값을 가져 오도록 원래 바이오드 코드를 실행하지 않고 해독 된 코드 객체를 메모리에 가져올 수 있습니다. 아래 예제를 참조하십시오
1 0 JUMP_ABSOLUTE 18
2 NOP
4 NOP
>> 6 POP_BLOCK
3 8 < 53 >
10 NOP
12 NOP
14 NOP
7 16 JUMP_ABSOLUTE 82
>> 18 LOAD_GLOBAL 5 ( __armor_enter__ )
20 CALL_FUNCTION 0
22 POP_TOP # we change this to RETURN_VALUE
9 24 NOP
26 NOP
28 NOP
30 SETUP_FINALLY 50 ( to 82 ) Pyarmor는 메모리에서 코드 객체를 편집하기 때문에 코드 객체를 종료 한 후에도 변경 사항이 유지됩니다.
이제 코드 객체를 호출 할 수 있습니다. 이제 해독 된 코드 객체에 액세스 할 수 있습니다. 지금 남은 것은 랩 헤더와 바닥 글이있는 코드 객체에 대한 Pyarmor 수정을 제거하는 것입니다.
그 후 청소 한 후 우리는 co_names 에서 __armor_enter__ 및 __armor_exit__ 제거해야합니다.
우리는 모든 코드 객체에 대해 재귀 적으로 반복합니다.
출력은 원래 코드 객체입니다. Pyarmor가 적용되지 않은 것 같습니다.
이로 인해 우리는 좋아하는 모든 도구 (예 : decompyle3)를 사용하여 원본 소스 코드를 얻을 수 있습니다.
세 번째 메소드는 방법 #2로 마지막 문제를 해결합니다.
방법 #2에서는 여전히 프로그램을 실행하여 주입해야합니다.
이것은 다음과 같은 문제가 될 수 있습니다.
세 번째 방법은 정적으로 Pyarmor를 포장하지 않으려 고 시도하며, 이는 난독 화 된 프로그램의 어떤 것도 실행하지 않고 의미합니다.
정적으로 포장을 풀 수있는 몇 가지 방법이 있지만 설명 할 방법은 다른 도구 및/또는 언어를 사용하지 않고도 가장 쉽게 구현하기가 쉽습니다.
감사 로그를 사용하고 보안상의 이유로 감사 로그가 파이썬에서 구현되었습니다. 이제 아이러니하게도 우리는 보안을 제거하기 위해 감사 로그를 이용할 것입니다.
감사 로그는 본질적으로 내부 cpython 기능을 기록합니다. exec 및 marshal.loads 포함하여, 둘 다 코드를 주입/실행하지 않고도 메인 난독 화 코드 객체를 얻는 데 사용할 수 있습니다. 감사 로그의 전체 목록은 여기에서 찾을 수 있습니다.
Cpython은 감사 후크 (Audit Hooks)라는 깔끔한 것을 추가했으며, 감사 로그가 트리거 될 때마다 설치 한 후크에 대한 콜백을 수행합니다. 후크는 단순히 2 인수, event , arg 취하는 함수 일 것입니다.
감사 후크의 예 :
import sys
def hook ( event , arg ):
print ( event , arg )
sys . addaudithook ( hook ) 코드 객체를 디스크에 저장하는 유일한 방법은 마샬링하는 것입니다. 이는 Pyarmor가 마샬링 된 코드 객체를 암호화해야하므로 당연히 Python에서 액세스하려면 해독해야합니다.
그들은 대부분의 다른 사람들과 마찬가지로 내장 마샬러를 사용합니다. 패키지는 marshal 이라고하며 C로 작성된 내장 패키지입니다. 감사 로그가있는 패키지 중 하나이므로 Pyarmor가 호출 할 때 인수를 볼 수 있습니다.
코드 객체는 여전히 바이트 코드를 암호화했지만 이미 첫 번째 "레이어"를 지나갈 수 있었으며, 암호화 된 코드 객체를 다루어야하므로 기본적 으로이 단계에서 메소드 #2를 재사용 할 수 있습니다. 이제 유일한 차이점은 모든 코드 객체가 메인 코드 객체와 같이 이미 실행 된 것 대신 암호화된다는 것입니다.
방법 #2에서 코드를 주입하므로 이미 __armor_enter__ 및 __armor_exit__ 와 같은 모든 pyarmor 함수에 액세스 할 수 있습니다. 우리는 그것을 정적으로 풀려고 노력하기 때문에 우리는 그 사치가 없습니다.
위에서 언급했듯이 Pyarmor는 제한 모드를 가지고 있으며, pyarmor_runtime() 함수를 실행할 때만 트리거되기 때문에 Bootstrap 제한 모드를 우회하는 방법을 이미 보여주었습니다.
이제 __pyarmor__ 호출을 포함하여 난독 화 된 전체 파일을 실행해야합니다. 이 기능은 다른 제한 모드를 트리거하므로이를 우회해야합니다. 먼저 기본적으로 패치하여 비슷한 방법을 사용한다고 생각했습니다.
친구가 도움을주었습니다. 이것들은 당신이 그것을 반복하기 위해 할 수있는 단계입니다. 더 좋고 쉬운 방법을 찾았습니다. Pyarmor는 Pyarmor 문자열이 __main__ 의 특정 메모리 주소에 있는지 확인합니다. 이 수표를 패치해야합니다. 아래 이미지를 참조하십시오
이제 내가 찾은 더 나은 방법은 Pyarmor의 제한 모드가 기본 파일이 Python에 의해 직접 실행되었는지 또는 호출되었는지 확인하지 않으므로 간단히 할 수 있다는 것입니다.
exec ( open ( filename )) 물론 감사 후크를 설치 한 후.
내가 가진 문제는 감사 후크가 marshal.loads 에서 트리거되었다는 것이었지만 분명히 트리거 된 후 코드 객체를 직접로드해야했지만 다시 트리거되어 dumps 디렉토리가 있는지 확인하기 위해 검사를 추가했습니다. 이전에 남은 dumps 폴더가 있으면 보호 된 스크립트를 중지하지 않고 보호 된 스크립트를 실행할 수 있기 때문에 이것은 위험합니다. 더 나은 방법을 찾아야합니다.
편집 : 최근에 절대 점프를 편집 해야하는 부분을 잊었다는 것을 발견했습니다. 이 부분은 그것을 다룰 것입니다.
방법 #2와 메소드 #3 에서이 작업을 수행 해야하는 경우. 바닥 글을 제거하면 인덱스와 콜리온이 없습니다. 헤더를 제거하면 인덱스가 헤더 크기에 따라 변하는 것이므로 모든 절대 점프를 반복하고 헤더의 크기를 빼야합니다. 그 부분은 상당히 쉽습니다.
for i in range ( 0 , len ( raw_code ), 2 ):
opcode = raw_code [ i ]
if opcode == JUMP_ABSOLUTE :
argument = calculate_arg ( raw_code , i )
new_arg = argument - ( try_start + 2 )
extended_args , new_arg = calculate_extended_args ( new_arg )
for extended_arg in extended_args :
raw_code . insert ( i , EXTENDED_ARG )
raw_code . insert ( i + 1 , extended_arg )
i += 2
raw_code [ i + 1 ] = new_arg 방법 #3에서
우리는 바이트 코드를 통과하고 Opcode가 JUMP_ABSOLUTE Opcode인지 확인합니다. 그것이 있다면 우리는 인수를 계산할 것입니다 ( EXTENDED_ARG 염두에두고). 그런 다음 헤더 크기 인 try_start (실제로 헤더에서 마지막 Opcode의 인덱스이므로 2를 추가하는 이유)를 가져 와서 JUMP_ABSOLUTE opcode의 인수에서 빼냅니다.
이것을 구현하는 가장 어려운 부분은 인수가 최대 크기 1 바이트 (255)를 넘을 때 잠재적으로 추가해야 할 EXTENDED_ARG opcodes를 처리하는 것이 었습니다. 우리는 calculate_extended_args 에서 처리합니다.
def calculate_extended_args ( arg : int ): # This function will calculate the necessary extended_args needed
extended_args = []
new_arg = arg
if arg > 255 :
extended_arg = arg >> 8
while True :
if extended_arg > 255 :
extended_arg -= 255
extended_args . append ( 255 )
else :
extended_args . append ( extended_arg )
break
new_arg = arg % 256
return extended_args , new_arg 방법 #3에서
이 코드를 작성하기 위해 먼저 EXTENDED_ARG 가 정확히 어떻게 작동했는지 이해해야했습니다.
이 기사는이 opcode를 이해하는 데 많은 도움이되었습니다.
Python의 명령어는 최신 버전 (3.6+)에서 2 바이트입니다. One Byte는 Opcode에 사용되며 하나의 바이트는 인수입니다. 하나의 바이트를 초과 해야하는 경우 EXTENDED_ARG 를 사용합니다. 기본적으로 다음과 같이 작동합니다.
arg = 300 # Let's say this is the size of our argument우리는 허용되는 최대 값이 255라는 것을 알고 있으므로 Extended_arg를 사용해야합니다. 다음과 같이 생각할 것입니다.
extended_arg = 255
arg = 45그것이 제가 처음 가정했지만 Python이 생성 한 코드를 살펴본 후에는 다음과 같습니다.
extended_arg = 1
arg = 44 나는 내가 기대했던 것과 현실 사이의 상관 관계를 보지 못했기 때문에 왜 그런지 매우 혼란 스러웠습니다. 위에 연결된 기사는 모든 것을 설명했습니다.
Python은 다음과 같은 Extended_arg를 처리합니다.
extended_arg = extended_arg * 256이것을 본 후에는 모든 것이 분명했습니다.
extended_arg = 1 * 256
arg = 44
print ( extended_arg + arg ) 출력 300 .
필요한 extended_arg opcodes의 목록과 새로운 인수 값 (255 이상)의 목록을 반환하도록 해당 논리를 함수에 적용했습니다.
그런 다음 올바른 인덱스에 Extended_arg를 삽입합니다.