Saya memutuskan sudah saatnya ada Pyarmor Unpacker yang tepat dirilis. Semua yang saat ini bersifat publik sudah ketinggalan zaman, tidak bekerja sama sekali atau hanya memberikan output parsial. Saya berencana untuk membuat yang ini mendukung versi terbaru PyaRarmor.
Silakan bintangi repositori jika Anda merasa terbantu. Saya sangat menghargainya.
Ada 3 metode berbeda untuk membongkar pyarmor, di folder metode di repositori ini Anda akan menemukan semua file yang diperlukan untuk setiap metode. Di bawah ini Anda akan menemukan tulisan terperinci tentang bagaimana saya memulai produk akhir ke produk akhir. Saya berharap lebih banyak orang benar -benar memahami cara kerjanya dengan cara ini daripada hanya menggunakan alat ini.
Ini adalah daftar semua masalah yang diketahui/fitur yang hilang. Saya tidak punya cukup waktu untuk memperbaikinya sendiri jadi saya sangat bergantung pada kontributor.
Masalah:
Fitur yang hilang:
PENTING: Gunakan versi Python yang sama di mana -mana, lihat apa program yang Anda bongkar disusun. Jika tidak, Anda akan menghadapi masalah.
method_1.pyrun.pydumps Anda dapat menemukan file .pyc yang sepenuhnya tidak dibongkar. CATATAN: Jangan gunakan statis Unpacker untuk apa pun di bawah versi 3.9.7, log audit marshal.loads hanya ditambahkan di dan setelah 3.9.7. Setiap kontributor dipersilakan untuk menambahkan dukungan
python3 bypass.py filename.pyc (ganti filename.pyc dengan nama file aktual, jelas)dumps Anda dapat menemukan file .pyc yang sepenuhnya tidak dibongkar.Kontribusi sangat penting. Saya tidak punya cukup waktu untuk memperbaiki semua masalah yang tercantum di atas. Harap berkontribusi jika Anda bisa.
Sumbangan juga sangat disambut:
BTC - 37RQ1XEB5Q8SCMMKK3MVMD4RBE5FV7EMMH
ETH - 0x28152666867856FA48B3924C185D7E1FB36F3B9A
LTC - Mfhdlrdzaqygzxuvxqfm4rwvgbmrzmdzao
Ini adalah penulisan yang telah lama ditunggu-tunggu tentang proses penuh yang saya lalui untuk Deobfuscate atau lebih tepatnya membongkar Pyararmor, saya akan melalui semua penelitian yang saya lakukan dan pada akhirnya memberikan 3 metode untuk membongkar Pyararmor, mereka semua unik dan berlaku dalam situasi yang berbeda. Saya ingin menyebutkan saya tidak tahu banyak tentang internal Python sehingga butuh lebih lama untuk saya daripada orang lain dengan lebih banyak pengalaman di internal Python.
Pyaarmor memiliki dokumentasi yang sangat luas tentang bagaimana mereka melakukan segalanya, saya akan merekomendasikan Anda membacanya sepenuhnya. Pyaarmor pada dasarnya melingkar melalui setiap objek kode dan mengenkripsi. Ada header dan footer tetap. Ini tergantung pada apakah "mode bungkus" diaktifkan, itu secara default.
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
Dari dokumen Pyatermor
Di header ada panggilan ke fungsi __armor_enter__ , yang akan mendekripsi objek kode dalam memori. Setelah objek kode selesai, fungsi __armor_exit__ akan dipanggil yang akan merevelasi ulang objek kode lagi sehingga tidak ada objek kode yang didekripsi yang tertinggal dalam memori.
Saat kami mengkompilasi skrip Pyarmor, kami dapat melihat ada file titik masuk, dan folder PyTransform. Folder ini berisi DLL dan file __init__.py .
dist
│ test.py
└───pytransform
| _pytransform.dll
| __init__.py
File __init__.py tidak perlu berbuat banyak dengan mendekripsi objek kode. Sebagian besar digunakan sehingga kami dapat mengimpor modul. Ini melakukan beberapa cek seperti OS apa yang Anda gunakan, jika Anda ingin membacanya, itu adalah sumber terbuka sehingga Anda bisa membukanya seperti skrip Python normal.
Hal terpenting yang dilakukannya adalah memuat _pytransform.dll dan mengekspos fungsinya ke global interpreter Python. Dalam semua skrip kita dapat melihatnya dari pytransform itu mengimpor pyaarmor_runtime.
from pytransform import pyarmor_runtime
pyarmor_runtime ()
__pyarmor__ ( __name__ , __file__ , b' x50 x59 x41 x5...' ) Fungsi ini akan membuat semua fungsi yang diperlukan untuk menjalankan skrip Pyaarmor, seperti fungsi __armor_enter__ dan __armor_exit__ .
Sumber daya pertama yang saya temukan adalah utas ini di forum tuts4you, di sini pengguna extremecoders menulis beberapa posting tentang bagaimana ia membongkar file yang dilindungi Pyaarmor. Dia mengedit kode sumber CPYTHON untuk membuang marshal dari setiap objek kode yang dieksekusi.
Meskipun metode ini bagus untuk mengekspos semua konstanta, itu kurang ideal jika Anda ingin mendapatkan bytecode, ini karena:
__armor_enter__ dipanggil, yang berada di awal objek kode. Karena fungsi __armor_enter__ mendekripsi dalam memori itu tidak akan dibuang oleh cpython. Ada beberapa orang yang telah bereksperimen dengan membuang objek kode yang didekripsi dari memori dengan menyuntikkan kode Python.
Dalam video ini seseorang menunjukkan bagaimana ia membongkar semua fungsi yang didekripsi dalam memori.
Namun, dia belum menemukan cara membuang modul utama, hanya berfungsi. Untungnya dia menerbitkan kodenya yang digunakannya untuk menyuntikkan kode Python. Pada repositori GitHub kita dapat melihat bahwa dia membuat DLL di mana dia menyebut fungsi yang diekspor dari Python DLL untuk menjalankan kode Python sederhana. Saat ini ia hanya menambahkan dukungan untuk menemukan DLL Python untuk versi 3.7 hingga 3.9 tetapi Anda dapat dengan mudah menambahkan lebih banyak versi dengan memodifikasi sumber dan mengkompilasi ulang. Dia membuatnya sehingga menjalankan kode yang ditemukan di code.py, dengan cara ini mudah untuk mengedit kode Python tanpa harus membangun kembali proyek setiap saat.
Dalam repositori ia menyertakan file Python yang akan membuang semua nama fungsi ke file dengan alamat yang sesuai dalam memori, jika tidak ada memori yang ditemukan itu berarti belum dipanggil sehingga juga belum didekripsi.
# 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 () Dari repositori Call-042pe
Dalam kode Anda dapat melihat dia menambahkan komentar yang mengatakan masalah yang dia miliki adalah bahwa dia tidak dapat mengakses objek kode modul utama.
Setelah banyak Googling saya bingung, tidak dapat menemukan apa pun tentang cara mendapatkan objek kode yang berjalan saat ini. Beberapa waktu kemudian dalam proyek yang tidak terkait, saya melihat panggilan fungsi ke sys._getframe() . Saya melakukan riset tentang apa yang dilakukannya, itu mendapatkan bingkai berjalan saat ini.
Anda dapat memberikan bilangan bulat sebagai argumen yang akan berjalan di atas tumpukan panggilan dan mendapatkan bingkai pada indeks tertentu.
sys . _getframe ( 1 ) # get the caller's frameSekarang alasan mengapa ini penting adalah karena bingkai dalam Python pada dasarnya hanyalah objek kode tetapi dengan lebih banyak informasi tentang keadaannya dalam memori. Untuk mendapatkan objek kode dari bingkai, kami dapat menggunakan atribut .f_code, Anda juga akan terbiasa dengan ini jika Anda telah membuat versi cpython khusus yang membuang objek kode yang dapat dieksekusi karena kami juga mendapatkan objek kode dari bingkai di sana.
...
1443 tstate -> frame = frame ;
1444 co = frame -> f_code ;
... Dari versi cpython kustom saya
Jadi sekarang kami telah menemukan cara untuk mendapatkan objek kode yang berjalan saat ini, kami bisa berjalan menaiki tumpukan panggilan sampai kami menemukan modul utama, yang akan didekripsi.
Sekarang kami sudah cukup menemukan gagasan utama tentang cara membongkar Pyarmor. Sekarang saya akan menunjukkan 3 metode pembongkaran yang secara pribadi saya temukan berguna dalam situasi yang berbeda.
Yang pertama mengharuskan Anda untuk menyuntikkan kode Python, jadi Anda harus menjalankan skrip Pyaarmor. Ketika kami membuang objek kode utama seperti yang saya jelaskan di atas masalah utama adalah bahwa beberapa fungsi masih akan dienkripsi, sehingga metode pertama memohon fungsi runtime Pyarmor sehingga semua fungsi yang diperlukan untuk mendekripsi objek kode dimuat, seperti __armor_enter__ dan __armor_exit__ .
Ini sepertinya hal yang sangat sederhana untuk dilakukan tetapi Pyaarmor memikirkan hal ini, mereka menerapkan mode pembatasan. Anda dapat menentukan ini saat menyusun skrip Pyaarmor, secara default mode pembatasan adalah 1.
Saya belum menguji setiap mode pembatasan tetapi berfungsi untuk yang default.
Ketika kami mencoba menjalankan kode ini di replikan kami, Anda akan mendapatkan kesalahan berikut:
> >> from pytransform import pyarmor_runtime
> >> pyarmor_runtime ()
Check bootstrap restrict mode failed Ini mencegah kita dari dapat menggunakan __armor_enter__ dan __armor_exit__ .
Jadi langkah selanjutnya yang saya ambil adalah menghubungi extremecoders di Tuts4you. Dia membantu saya dengan menyebutkan bahwa saya dapat secara asli menambal _pytransform.dll . Saya juga ingin berterima kasih padanya karena telah memberi saya solusi untuk melakukan ini semata -mata di Python.
Jika kita membuka _pytransform.dll dalam debugger asli, saya memilih X64DBG, kami akan mencari semua string dalam modul saat ini.
Jika kami memfilter ini sekarang dengan mencari "Bootstrap", kami akan mendapatkan yang berikut.
Ketika kami menyaksikan pembongkaran pada hasil pencarian pertama Anda melihat bahwa ada referensi _errno yang menunjukkan bahwa mungkin ada beberapa kesalahan yang dinaikkan, beberapa baris di bawah ini bahwa kita dapat melihat kesalahan yang kita dapatkan di Python.
Ketika kita hanya menyala semuanya dari titik lompatan yang melompati kode yang memicu kesalahan ke pengembalian, tidak ada cara kesalahan itu dapat dinaikkan.
Sekarang jika kita menyimpan ini dan mengganti _pytransform.dll Anda akan melihat bahwa ketika kami mencoba kode yang sama lagi, kesalahan tidak akan terjadi dan kami memiliki akses ke fungsi __armor_enter__ dan __armor_exit__ .
> >> from pytransform import pyarmor_runtime
> >> pyarmor_runtime ()
> >> __armor_enter__
< built - in function __armor_enter__ >
> >> __armor_exit__
< built - in function __armor_exit__ > Sekarang ini cukup melelahkan jika kita harus melakukan ini untuk setiap skrip Pyaarmor yang ingin kita bongkar, jadi extremecoders membuat skrip yang tidak menggunakan alamat spesifik dalam memori dalam 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" ) Jika kita meletakkan kode ini A ke dalam file yang disebut restrict_bypass.py kita dapat menggunakannya seperti berikut, menggunakan _pytransform.dll asli
> >> 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__ > Metode kedua dimulai sama dengan metode pertama, kami menyuntikkan skrip yang mendapatkan objek kode yang berjalan saat ini.
Hanya sekarang perbedaannya adalah bahwa kita tidak akan hanya membuangnya, kita akan "memperbaikinya". Maksud saya, menghapus Pyarmor dari itu sepenuhnya sehingga kami mendapatkan objek kode asli.
Karena Pyaarmor memiliki banyak opsi saat mengaburkan saya memutuskan untuk menambahkan dukungan untuk semua yang umum.
Ketika mendeteksi skrip memiliki __armor_enter__ di dalamnya itu akan memodifikasinya sehingga objek kode kembali tepat setelah __armor_enter__ telah dipanggil.
Ada opcode POP_TOP yang mengikuti panggilan fungsi, ini digunakan sehingga nilai pengembalian fungsi dihapus dari tumpukan, kami hanya menggantinya dengan opcode RETURN_VALUE sehingga kami bisa mendapatkan nilai pengembalian dari fungsi __armor_enter__ dan sehingga kami memiliki objek kode yang didekripsi dalam memori tanpa benar -benar menjalankan kode bytecode asli. Lihat contoh di bawah ini
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 ) Karena Pyaarmor mengedit objek kode dalam memori, perubahan akan tetap ada bahkan setelah kita keluar dari objek kode.
Sekarang kita dapat memohon (mengeksekusi) objek kode. Kami sekarang memiliki akses ke objek kode yang didekripsi. Yang tersisa sekarang hanyalah menghapus modifikasi Pyaarmor ke objek kode, yang menjadi header dan footer bungkus.
Setelah itu telah dibersihkan, kami harus menghapus __armor_enter__ dan __armor_exit__ dari co_names .
Kami mengulangi ini secara rekursif untuk semua objek kode.
Output akan menjadi objek kode asli. Ini akan seperti Pyarmor tidak pernah diterapkan.
Karena itu, kami dapat menggunakan semua alat favorit kami, misalnya Decompyle3 untuk mendapatkan kode sumber asli.
Metode ketiga memperbaiki masalah terakhir dengan metode #2.
Dalam metode #2 kita masih harus benar -benar menjalankan program dan menyuntikkannya.
Ini bisa menjadi masalah karena:
Metode ketiga mencoba untuk membongkar Pyarmor secara statis, yang saya maksud tanpa menjalankan apa pun dari program yang dikalahkan.
Ada beberapa cara yang bisa Anda lakukan secara statis membongkar itu tetapi metode yang akan saya jelaskan terlihat paling mudah diimplementasikan tanpa harus menggunakan alat dan/atau bahasa lain.
Kami akan menggunakan log audit, log audit diimplementasikan di Python untuk alasan keamanan. Sekarang ironisnya kita akan mengeksploitasi log audit untuk menghapus keamanan.
Log audit pada dasarnya mencatat fungsi cpython internal. Termasuk exec dan marshal.loads , yang keduanya dapat kita gunakan untuk mendapatkan objek kode utama yang dikaburkan tanpa harus menyuntikkan/menjalankan kode. Daftar lengkap log audit dapat ditemukan di sini
Cpython menambahkan sesuatu yang rapi yang disebut kait audit, setiap kali log audit dipicu itu akan melakukan panggilan balik ke kait yang kami instal. Hook hanya akan menjadi fungsi yang mengambil 2 argumen, event , arg .
Contoh kait audit:
import sys
def hook ( event , arg ):
print ( event , arg )
sys . addaudithook ( hook ) Satu -satunya cara untuk menyimpan objek kode ke disk adalah dengan mengarahkannya. Ini berarti Pyarmor harus mengenkripsi objek kode yang direset, jadi tentu saja mereka harus mendekripsi ketika mereka ingin mengaksesnya dalam Python.
Mereka, seperti kebanyakan orang lain, menggunakan marshaller bawaan. Paket ini disebut marshal dan ini adalah paket bawaan, yang ditulis dalam C. Ini adalah salah satu paket yang memiliki log audit, jadi ketika Pyaarmor menyebutnya kita dapat melihat argumen.
Objek kode masih akan memiliki bytecode terenkripsi, tetapi kami sudah berhasil melewati "lapisan" pertama, kami pada dasarnya dapat menggunakan kembali metode kami #2 dari tahap ini karena ia juga harus berurusan dengan objek kode terenkripsi. Satu -satunya perbedaan sekarang adalah bahwa setiap objek kode akan dienkripsi alih -alih yang biasanya sudah dijalankan, seperti objek kode utama.
Karena dalam Metode #2 kami menyuntikkan kode, kami sudah memiliki akses ke semua fungsi Pyarmor seperti __armor_enter__ dan __armor_exit__ . Karena kami mencoba membongkar secara statis, kami tidak memiliki kemewahan itu.
Seperti yang saya sebutkan di atas Pyarmor telah membatasi mode, saya sudah menunjukkan cara mem -bypass mode pembatasan bootstrap karena itu hanya akan dipicu ketika kita menjalankan fungsi pyarmor_runtime() .
Sekarang kita perlu menjalankan seluruh file yang dikaburkan, yang mencakup panggilan __pyarmor__ . Fungsi itu memicu mode pembatasan lain sehingga kita harus memotongnya. Pertama saya berpikir bahwa kami menggunakan metode serupa dengan menambalnya secara asli.
Seorang teman membantu dengan itu, ini adalah langkah -langkah yang dapat Anda lakukan untuk mengulanginya. Perlu diingat saya menemukan metode yang lebih baik dan lebih mudah. Pyarmor memeriksa apakah string Pyaarmor hadir pada alamat memori tertentu di __main__ . Kita perlu menambal cek ini. Lihat gambar di bawah ini
Sekarang metode yang lebih baik yang saya temukan adalah bahwa mode pembatasan Pyaarmor tidak memeriksa apakah file utama langsung dijalankan oleh Python atau jika dipanggil, jadi kami dapat melakukan ini:
exec ( open ( filename )) Tentu saja setelah kami memasang kait audit.
Masalah yang saya miliki adalah bahwa kait audit dipicu pada marshal.loads , tetapi jelas setelah itu memicu saya perlu memuat objek kode sendiri tetapi itu hanya akan memicu lagi jadi saya menambahkan cek untuk melihat apakah direktori dumps ada. Ini berbahaya karena jika masih ada folder dumps yang tersisa dari sebelum itu hanya akan mengakibatkan melaksanakan skrip yang dilindungi tanpa menghentikannya. Kita harus menemukan cara yang lebih baik untuk melakukan itu.
Sunting : Saya baru -baru ini menemukan bahwa saya lupa tentang bagian di mana kita perlu mengedit lompatan absolut. Bagian ini akan mencakup itu.
Ketika perlu melakukan ini di kedua metode #2 dan metode #3. Ketika kita menghapus footer, tidak akan ada koleksi dengan indeks. Ketika kita menghapus header namun itu akan menyebabkan indeks bergeser dengan ukuran header sehingga kita perlu mengulangi semua lompatan absolut dan mengurangi ukuran header. Bagian itu cukup mudah.
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 Dari Metode #3
Kami mengulangi bytecode dan memeriksa apakah opcode adalah opcode JUMP_ABSOLUTE . Jika itu kita akan menghitung argumen (mengingat EXTENDED_ARG dalam pikiran). Lalu kami mengambil try_start yang merupakan ukuran header (sebenarnya indeks opcode terakhir dari header, itulah sebabnya kami menambahkan 2) dan mengurangi dari argumen opcode JUMP_ABSOLUTE .
Bagian tersulit dari menerapkan ini adalah merawat opcodes EXTENDED_ARG yang berpotensi kami harus tambahkan ketika argumen melampaui ukuran maksimum 1 byte (255). Kami menanganinya di 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 Dari Metode #3
Untuk menulis kode ini, saya pertama -tama harus memahami bagaimana EXTENDED_ARG bekerja dengan tepat.
Artikel ini banyak membantu untuk memahami opcode ini.
Instruksi dalam Python adalah 2 byte dalam versi yang lebih baru (3.6+). Satu byte digunakan untuk opcode dan satu byte adalah untuk argumen. Ketika kita perlu melebihi satu byte, kita menggunakan EXTENDED_ARG . Ini pada dasarnya berfungsi seperti ini:
arg = 300 # Let's say this is the size of our argumentKami tahu maksimum yang diizinkan adalah 255 jadi kami perlu menggunakan extended_arg, Anda akan berpikir itu akan seperti ini:
extended_arg = 255
arg = 45Itulah yang pertama kali saya asumsikan tetapi setelah melihat kode yang dihasilkan Python, saya perhatikan seperti ini:
extended_arg = 1
arg = 44 Saya sangat bingung mengapa itu seperti itu karena saya tidak melihat korelasi antara apa yang saya harapkan dan kenyataan. Artikel yang ditautkan di atas menjelaskan semuanya.
Python menangani extended_arg seperti berikut:
extended_arg = extended_arg * 256Setelah melihat ini semuanya jelas karena itu berarti itu
extended_arg = 1 * 256
arg = 44
print ( extended_arg + arg ) Akan menghasilkan 300 .
Saya menerapkan logika itu ke fungsi sehingga mengembalikan daftar opcodes extended_arg yang diperlukan dan nilai argumen baru (yang akan berada di bawah atau sama dengan 255).
Saya kemudian hanya memasukkan extended_arg pada indeks yang benar.