Svenskithesource / PyArmor-Unpacker

A deobfuscator for PyArmor.
GNU General Public License v3.0
536 stars 75 forks source link

Fix RETURN_VALUE changed to JUMP_ABSOLUTE when it's not at the end of the bytecode #4

Closed Svenskithesource closed 2 years ago

Svenskithesource commented 2 years ago

Because PyArmor puts a header and footer around the original bytecode it doesn't allow you to return anything in the original bytecode because that would mean it wouldn't reach the footer so it doesn't get encrypted again. PyArmor fixed that by jumping to the __armor_exit__ function, which will re-encrypt it and then continue the bytecode to return the value. Example:

  7           0 JUMP_ABSOLUTE            9 (to 18)
              2 NOP
              4 NOP
        >>    6 POP_BLOCK

  9           8 LOAD_GLOBAL              6 (__armor_exit__)
             10 CALL_FUNCTION            0
             12 POP_TOP
             14 RETURN_VALUE

 10          16 NOP
        >>   18 LOAD_GLOBAL              5 (__armor_enter__)
             20 CALL_FUNCTION            0
             22 RETURN_VALUE

 12          24 NOP
             26 NOP
             28 NOP
             30 SETUP_FINALLY           26 (to 84)
             32 LOAD_CONST               0 (0)
             34 LOAD_CONST               1 (None)
             36 IMPORT_NAME              0 (time)
             38 STORE_NAME               0 (time)
             40 LOAD_CONST               2 (<code object yes at 0x0000020954E7C500, file "<frozen test>", line 3>)
             42 LOAD_CONST               3 ('yes')
             44 MAKE_FUNCTION            0
             46 STORE_NAME               1 (yes)
             48 LOAD_NAME                2 (input)
             50 LOAD_CONST               4 ('mhm: ')
             52 CALL_FUNCTION            1
             54 STORE_NAME               3 (num)
             56 LOAD_NAME                4 (int)
             58 LOAD_NAME                3 (num)
             60 CALL_FUNCTION            1
             62 POP_JUMP_IF_FALSE       37 (to 74)
             64 LOAD_NAME                1 (yes)
             66 CALL_FUNCTION            0
             68 POP_TOP
             70 LOAD_CONST               1 (None)
             72 JUMP_ABSOLUTE            3 (to 6) # This can be seen as a fake "RETURN_VALUE"
        >>   74 LOAD_NAME                1 (yes)
             76 CALL_FUNCTION            0
             78 POP_TOP
             80 LOAD_CONST               1 (None)
             82 JUMP_ABSOLUTE            3 (to 6)
        >>   84 LOAD_GLOBAL              6 (__armor_exit__)
             86 CALL_FUNCTION            0
             88 POP_TOP
             90 RERAISE                  0
             92 RETURN_VALUE
             94 NOP
             96 NOP
             98 NOP
            100 BINARY_POWER
            102 <210>                  233
            104 ROT_THREE
            106 <228>                  135
            108 <190>                  239