Skip to content

Instantly share code, notes, and snippets.

@fate0
Last active August 11, 2023 08:55
Show Gist options
  • Star 25 You must be signed in to star a gist
  • Fork 22 You must be signed in to fork a gist
  • Save fate0/3e1d23bce9d4d2cfa93848dd92aba3d4 to your computer and use it in GitHub Desktop.
Save fate0/3e1d23bce9d4d2cfa93848dd92aba3d4 to your computer and use it in GitHub Desktop.
onmyoji: test
import types
import cStringIO
TYPE_NULL = '0'
TYPE_NONE = 'N'
TYPE_FALSE = 'F'
TYPE_TRUE = 'T'
TYPE_STOPITER = 'S'
TYPE_ELLIPSIS = '.'
TYPE_INT = 'i'
TYPE_INT64 = 'I'
TYPE_FLOAT = 'f'
TYPE_COMPLEX = 'x'
TYPE_LONG = 'l'
TYPE_STRING = 's'
TYPE_INTERNED = 't'
TYPE_STRINGREF = 'R'
TYPE_TUPLE = '('
TYPE_LIST = '['
TYPE_DICT = '{'
TYPE_CODE = 'c'
TYPE_UNICODE = 'u'
TYPE_UNKNOWN = '?'
TYPE_SET = '<'
TYPE_FROZENSET = '>'
UNKNOWN_BYTECODE = 0
class _NULL:
pass
class _Marshaller:
dispatch = {}
def __init__(self, writefunc, opmap=None):
self._write = writefunc
self._opmap = opmap or {}
def dump(self, x):
try:
self.dispatch[type(x)](self, x)
except KeyError:
for tp in type(x).mro():
func = self.dispatch.get(tp)
if func:
break
else:
raise ValueError("unmarshallable object")
func(self, x)
def w_long64(self, x):
self.w_long(x)
self.w_long(x >> 32)
def w_long(self, x):
a = chr(x & 0xff)
x >>= 8
b = chr(x & 0xff)
x >>= 8
c = chr(x & 0xff)
x >>= 8
d = chr(x & 0xff)
self._write(a + b + c + d)
def w_short(self, x):
self._write(chr((x) & 0xff))
self._write(chr((x >> 8) & 0xff))
def dump_none(self, x):
self._write(TYPE_NONE)
dispatch[type(None)] = dump_none
def dump_bool(self, x):
if x:
self._write(TYPE_TRUE)
else:
self._write(TYPE_FALSE)
dispatch[bool] = dump_bool
def dump_stopiter(self, x):
if x is not StopIteration:
raise ValueError("unmarshallable object")
self._write(TYPE_STOPITER)
dispatch[type(StopIteration)] = dump_stopiter
def dump_ellipsis(self, x):
self._write(TYPE_ELLIPSIS)
try:
dispatch[type(Ellipsis)] = dump_ellipsis
except NameError:
pass
# In Python3, this function is not used; see dump_long() below.
def dump_int(self, x):
y = x >> 31
if y and y != -1:
self._write(TYPE_INT64)
self.w_long64(x)
else:
self._write(TYPE_INT)
self.w_long(x)
dispatch[int] = dump_int
def dump_long(self, x):
self._write(TYPE_LONG)
sign = 1
if x < 0:
sign = -1
x = -x
digits = []
while x:
digits.append(x & 0x7FFF)
x = x >> 15
self.w_long(len(digits) * sign)
for d in digits:
self.w_short(d)
try:
long
except NameError:
dispatch[int] = dump_long
else:
dispatch[long] = dump_long
def dump_float(self, x):
write = self._write
write(TYPE_FLOAT)
s = repr(x)
write(chr(len(s)))
write(s)
dispatch[float] = dump_float
def dump_complex(self, x):
write = self._write
write(TYPE_COMPLEX)
s = repr(x.real)
write(chr(len(s)))
write(s)
s = repr(x.imag)
write(chr(len(s)))
write(s)
try:
dispatch[complex] = dump_complex
except NameError:
pass
def dump_string(self, x):
# XXX we can't check for interned strings, yet,
# so we (for now) never create TYPE_INTERNED or TYPE_STRINGREF
self._write(TYPE_STRING)
self.w_long(len(x))
self._write(x)
dispatch[bytes] = dump_string
def dump_unicode(self, x):
self._write(TYPE_UNICODE)
s = x.encode('utf8')
self.w_long(len(s))
self._write(s)
try:
unicode
except NameError:
dispatch[str] = dump_unicode
else:
dispatch[unicode] = dump_unicode
def dump_tuple(self, x):
self._write(TYPE_TUPLE)
self.w_long(len(x))
for item in x:
self.dump(item)
dispatch[tuple] = dump_tuple
def dump_list(self, x):
self._write(TYPE_LIST)
self.w_long(len(x))
for item in x:
self.dump(item)
dispatch[list] = dump_list
def dump_dict(self, x):
self._write(TYPE_DICT)
for key, value in x.items():
self.dump(key)
self.dump(value)
self._write(TYPE_NULL)
dispatch[dict] = dump_dict
def dump_code(self, x):
self._write(TYPE_CODE)
self.w_long(x.co_argcount)
self.w_long(x.co_nlocals)
self.w_long(x.co_stacksize)
self.w_long(x.co_flags)
# self.dump(x.co_code)
self.dump(self._transform_opcode(x.co_code))
self.dump(x.co_consts)
self.dump(x.co_names)
self.dump(x.co_varnames)
self.dump(x.co_freevars)
self.dump(x.co_cellvars)
self.dump(x.co_filename)
self.dump(x.co_name)
self.w_long(x.co_firstlineno)
self.dump(x.co_lnotab)
try:
dispatch[types.CodeType] = dump_code
except NameError:
pass
def _transform_opcode(self, x):
if not self._opmap:
return x
opcode = bytearray(x)
c = 0
while c < len(opcode):
try:
n = self._opmap[opcode[c]]
except:
print("unmaping %s" % opcode[c])
opcode[c] = n
if n < 90:
c += 1
else:
c += 3
return str(opcode)
def dump_set(self, x):
self._write(TYPE_SET)
self.w_long(len(x))
for each in x:
self.dump(each)
try:
dispatch[set] = dump_set
except NameError:
pass
def dump_frozenset(self, x):
self._write(TYPE_FROZENSET)
self.w_long(len(x))
for each in x:
self.dump(each)
try:
dispatch[frozenset] = dump_frozenset
except NameError:
pass
class _Unmarshaller:
dispatch = {}
def __init__(self, readfunc):
self._read = readfunc
self._stringtable = []
def load(self):
c = self._read(1)
if not c:
raise EOFError
try:
return self.dispatch[c](self)
except KeyError:
raise ValueError("bad marshal code: %c (%d)" % (c, ord(c)))
def r_short(self):
lo = ord(self._read(1))
hi = ord(self._read(1))
x = lo | (hi << 8)
if x & 0x8000:
x = x - 0x10000
return x
def r_long(self):
s = self._read(4)
a = ord(s[0])
b = ord(s[1])
c = ord(s[2])
d = ord(s[3])
x = a | (b << 8) | (c << 16) | (d << 24)
if d & 0x80 and x > 0:
x = -((1 << 32) - x)
return int(x)
else:
return x
def r_long64(self):
a = ord(self._read(1))
b = ord(self._read(1))
c = ord(self._read(1))
d = ord(self._read(1))
e = ord(self._read(1))
f = ord(self._read(1))
g = ord(self._read(1))
h = ord(self._read(1))
x = a | (b << 8) | (c << 16) | (d << 24)
x = x | (e << 32) | (f << 40) | (g << 48) | (h << 56)
if h & 0x80 and x > 0:
x = -((1 << 64) - x)
return x
def load_null(self):
return _NULL
dispatch[TYPE_NULL] = load_null
def load_none(self):
return None
dispatch[TYPE_NONE] = load_none
def load_true(self):
return True
dispatch[TYPE_TRUE] = load_true
def load_false(self):
return False
dispatch[TYPE_FALSE] = load_false
def load_stopiter(self):
return StopIteration
dispatch[TYPE_STOPITER] = load_stopiter
def load_ellipsis(self):
return Ellipsis
dispatch[TYPE_ELLIPSIS] = load_ellipsis
dispatch[TYPE_INT] = r_long
dispatch[TYPE_INT64] = r_long64
def load_long(self):
size = self.r_long()
sign = 1
if size < 0:
sign = -1
size = -size
x = 0
for i in range(size):
d = self.r_short()
x = x | (d << (i * 15))
return x * sign
dispatch[TYPE_LONG] = load_long
def load_float(self):
n = ord(self._read(1))
s = self._read(n)
return float(s)
dispatch[TYPE_FLOAT] = load_float
def load_complex(self):
n = ord(self._read(1))
s = self._read(n)
real = float(s)
n = ord(self._read(1))
s = self._read(n)
imag = float(s)
return complex(real, imag)
dispatch[TYPE_COMPLEX] = load_complex
def load_string(self):
n = self.r_long()
return self._read(n)
dispatch[TYPE_STRING] = load_string
def load_interned(self):
n = self.r_long()
ret = intern(self._read(n))
self._stringtable.append(ret)
return ret
dispatch[TYPE_INTERNED] = load_interned
def load_stringref(self):
n = self.r_long()
return self._stringtable[n]
dispatch[TYPE_STRINGREF] = load_stringref
def load_unicode(self):
n = self.r_long()
s = self._read(n)
ret = s.decode('utf8')
return ret
dispatch[TYPE_UNICODE] = load_unicode
def load_tuple(self):
return tuple(self.load_list())
dispatch[TYPE_TUPLE] = load_tuple
def load_list(self):
n = self.r_long()
list = [self.load() for i in range(n)]
return list
dispatch[TYPE_LIST] = load_list
def load_dict(self):
d = {}
while 1:
key = self.load()
if key is _NULL:
break
value = self.load()
d[key] = value
return d
dispatch[TYPE_DICT] = load_dict
def load_code(self):
argcount = self.r_long()
nlocals = self.r_long()
stacksize = self.r_long()
flags = self.r_long()
code = self.load()
consts = self.load()
names = self.load()
varnames = self.load()
freevars = self.load()
cellvars = self.load()
filename = self.load()
name = self.load()
firstlineno = self.r_long()
lnotab = self.load()
return types.CodeType(argcount, nlocals, stacksize, flags, code, consts,
names, varnames, filename, name, firstlineno,
lnotab, freevars, cellvars)
dispatch[TYPE_CODE] = load_code
def load_set(self):
n = self.r_long()
args = [self.load() for i in range(n)]
return set(args)
dispatch[TYPE_SET] = load_set
def load_frozenset(self):
n = self.r_long()
args = [self.load() for i in range(n)]
return frozenset(args)
dispatch[TYPE_FROZENSET] = load_frozenset
def dump(x, f, opmap=None):
m = _Marshaller(f.write, opmap)
m.dump(x)
def load(f):
um = _Unmarshaller(f.read)
return um.load()
def loads(content):
io = cStringIO.StringIO(content)
return load(io)
def dumps(x, opmap=None):
io = cStringIO.StringIO()
dump(x, io, opmap)
io.seek(0)
return io.read()
# from __future__ import division
# def_op('STOP_CODE', 0)
# ignore
# def_op('POP_TOP', 1)
a()
# def_op('ROT_TWO', 2)
(a, b) = (b, a)
# def_op('ROT_THREE', 3)
(a, a, a) = (a, a, a)
# def_op('DUP_TOP', 4)
exec 1
# def_op('ROT_FOUR', 5)
a[2:4] += 'abc'
# def_op('NOP', 9)
# ignore
# def_op('UNARY_POSITIVE', 10)
+ a
# def_op('UNARY_NEGATIVE', 11)
- a
# def_op('UNARY_NOT', 12)
not a
# def_op('UNARY_CONVERT', 13)
a = `a`
# def_op('UNARY_INVERT', 15)
a = ~a
# def_op('BINARY_POWER', 19)
a ** 1
# def_op('BINARY_MULTIPLY', 20)
a * 1
# def_op('BINARY_DIVIDE', 21)
a / 1
# def_op('BINARY_MODULO', 22)
a % 1
# def_op('BINARY_ADD', 23)
a + 1
# def_op('BINARY_SUBTRACT', 24)
a - 1
# def_op('BINARY_SUBSCR', 25)
a[1]
# def_op('BINARY_FLOOR_DIVIDE', 26)
a // 1
# def_op('BINARY_TRUE_DIVIDE', 27)
# add 'from __future__ import division' to header
# def_op('INPLACE_FLOOR_DIVIDE', 28)
a //= 1
# def_op('INPLACE_TRUE_DIVIDE', 29)
# add 'from __future__ import division' to header
# def_op('SLICE+0', 30)
a[:]
# def_op('SLICE+1', 31)
a[1:]
# def_op('SLICE+2', 32)
a[:2]
# def_op('SLICE+3', 33)
a[1:2]
# def_op('STORE_SLICE+0', 40)
a[:] = 1
# def_op('STORE_SLICE+1', 41)
a[1:] = 1
# def_op('STORE_SLICE+2', 42)
a[:2] = 1
# def_op('STORE_SLICE+3', 43)
a[1:2] =1
# def_op('DELETE_SLICE+0', 50)
del a[:]
# def_op('DELETE_SLICE+1', 51)
del a[1:]
# def_op('DELETE_SLICE+2', 52)
del a[:2]
# def_op('DELETE_SLICE+3', 53)
del a[1:2]
# def_op('STORE_MAP', 54)
{"1": 1}
# def_op('INPLACE_ADD', 55)
a += 1
# def_op('INPLACE_SUBTRACT', 56)
a -= 1
# def_op('INPLACE_MULTIPLY', 57)
a *= 1
# def_op('INPLACE_DIVIDE', 58)
a /= 1
# def_op('INPLACE_MODULO', 59)
a %= 1
# def_op('STORE_SUBSCR', 60)
a[1] = 1
# def_op('DELETE_SUBSCR', 61)
del a[1]
# def_op('BINARY_LSHIFT', 62)
a << 1
# def_op('BINARY_RSHIFT', 63)
a >> 1
# def_op('BINARY_AND', 64)
a & 1
# def_op('BINARY_XOR', 65)
a ^ 1
# def_op('BINARY_OR', 66)
a | 1
# def_op('INPLACE_POWER', 67)
a **= 1
# def_op('GET_ITER', 68)
for i in a:
pass
# def_op('PRINT_EXPR', 70)
# ignore
# def_op('PRINT_ITEM', 71)
print(1)
# def_op('PRINT_NEWLINE', 72)
print(1)
# def_op('PRINT_ITEM_TO', 73)
print >> fd, 1
# def_op('PRINT_NEWLINE_TO', 74)
print >> fd, 1
# def_op('INPLACE_LSHIFT', 75)
a <<= 1
# def_op('INPLACE_RSHIFT', 76)
a >>= 1
# def_op('INPLACE_AND', 77)
a &= 1
# def_op('INPLACE_XOR', 78)
a ^= 1
# def_op('INPLACE_OR', 79)
a |= 1
# def_op('BREAK_LOOP', 80)
while True:
break
# def_op('WITH_CLEANUP', 81)
with a:
pass
# def_op('LOAD_LOCALS', 82)
class a:
pass
# def_op('RETURN_VALUE', 83)
def a():
return
# def_op('IMPORT_STAR', 84)
from module import *
# def_op('EXEC_STMT', 85)
exec 1
# def_op('YIELD_VALUE', 86)
def a():
yield 1
# def_op('POP_BLOCK', 87)
while True:
pass
# def_op('END_FINALLY', 88)
with a:
pass
# def_op('BUILD_CLASS', 89)
class a:
pass
# name_op('STORE_NAME', 90) # Index in name list
a = 1
# name_op('DELETE_NAME', 91) # ""
del a
# def_op('UNPACK_SEQUENCE', 92) # Number of tuple items
a, b = 1, 2
# jrel_op('FOR_ITER', 93)
for i in a:
pass
# def_op('LIST_APPEND', 94)
[i for i in a]
# name_op('STORE_ATTR', 95) # Index in name list
a.a = 1
# name_op('DELETE_ATTR', 96) # ""
del a.a
# name_op('STORE_GLOBAL', 97) # ""
def a():
global aa
aa = 1
# name_op('DELETE_GLOBAL', 98) # ""
def a():
global aa
del aa
# def_op('DUP_TOPX', 99) # number of items to duplicate
b[a] += 1
# def_op('LOAD_CONST', 100) # Index in const list
123
# name_op('LOAD_NAME', 101) # Index in name list
a
# def_op('BUILD_TUPLE', 102) # Number of tuple items
(a, )
# def_op('BUILD_LIST', 103) # Number of list items
[]
# def_op('BUILD_SET', 104) # Number of set items
{1}
# def_op('BUILD_MAP', 105) # Number of dict entries (upto 255)
{}
# name_op('LOAD_ATTR', 106) # Index in name list
a.a
# def_op('COMPARE_OP', 107) # Comparison operator
a == a
# name_op('IMPORT_NAME', 108) # Index in name list
import a
# name_op('IMPORT_FROM', 109) # Index in name list
from a import b
# jrel_op('JUMP_FORWARD', 110) # Number of bytes to skip
if True:
pass
# jabs_op('JUMP_IF_FALSE_OR_POP', 111) # Target byte offset from beginning of code
0 and False
# jabs_op('JUMP_IF_TRUE_OR_POP', 112) # ""
0 or False
# jabs_op('JUMP_ABSOLUTE', 113) # ""
def a():
if b:
if c:
print('')
# jabs_op('POP_JUMP_IF_FALSE', 114) # ""
if True:
pass
# jabs_op('POP_JUMP_IF_TRUE', 115) # ""
if not True:
pass
# name_op('LOAD_GLOBAL', 116) # Index in name list
def a():
global b
return b
# jabs_op('CONTINUE_LOOP', 119) # Target address
while True:
try:
continue
except:
pass
# jrel_op('SETUP_LOOP', 120) # Distance to target address
while True:
pass
# jrel_op('SETUP_EXCEPT', 121) # ""
# jrel_op('SETUP_FINALLY', 122) # ""
try:
pass
except:
pass
finally:
pass
# def_op('LOAD_FAST', 124) # Local variable number
def a():
aa = 1
return aa
# def_op('STORE_FAST', 125) # Local variable number
def a():
aa = 1
# def_op('DELETE_FAST', 126) # Local variable number
def a():
aa = 1
del aa
# def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3)
raise
# def_op('CALL_FUNCTION', 131) # #args + (#kwargs << 8)
a()
# def_op('MAKE_FUNCTION', 132) # Number of args with default values
def a():
pass
# def_op('BUILD_SLICE', 133) # Number of items
a[::]
# def_op('MAKE_CLOSURE', 134)
# def_op('LOAD_CLOSURE', 135)
# def_op('LOAD_DEREF', 136)
# def_op('STORE_DEREF', 137)
def f():
a = 1
def g():
return a + 1
return g()
# def_op('CALL_FUNCTION_VAR', 140) # #args + (#kwargs << 8)
a(*args)
# def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8)
a(**kwargs)
# def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8)
a(*args, **kwargs)
# jrel_op('SETUP_WITH', 143)
with a:
pass
# def_op('EXTENDED_ARG', 145)
# ignore
# def_op('SET_ADD', 146)
{i for i in a}
# def_op('MAP_ADD', 147)
{i:i for i in a}
@Dong-Lin
Copy link

Dong-Lin commented Feb 7, 2017

FateZero 大神给力啊。求yys 100% 百鬼,script.npk。

@WyattShao
Copy link

@Dong-Lin 有script.npk文件吗,求帮砸个碗

@zdone
Copy link

zdone commented Mar 15, 2017

请教下pymarshal 这个模块;有下载吗?

@keeslient
Copy link

学习了 谢谢大神

@tuletule
Copy link

tuletule commented May 8, 2017

@spyy26224574
Copy link

@tuletule 文件已经失效 跪求email至26224574@163.com

@YJBeetle
Copy link

YJBeetle commented Oct 30, 2017

用Fate0的方法解出redirect.py:

# 2017.10.30 19:50:39 CST
#Embedded file name: redirect.py
import marshal
import zlib

def init_rotor():
    asdf_dn = 'j2h56ogodh3se'
    asdf_dt = '=dziaq.'
    asdf_df = '|os=5v7!"-234'
    asdf_tm = asdf_dn * 4 + (asdf_dt + asdf_dn + asdf_df) * 5 + '!' + '#' + asdf_dt * 7 + asdf_df * 2 + '*' + '&' + "'"
    import rotor
    rot = rotor.newrotor(asdf_tm)
    return rot


def _reverse_string(s):
    l = list(s)
    l = map(lambda x: chr(ord(x) ^ 154), l[0:128]) + l[128:]
    l.reverse()
    return ''.join(l)


class NpkImporter(object):
    rotor = init_rotor()
    ext = '.nxs'

    def __init__(self, path):
        self._path = path

    def find_module(self, fullname, path = None):
        import C_file
        if path is None:
            path = self._path
        fullname = fullname.replace('.', '/')
        pkg_name = fullname + '/__init__' + NpkImporter.ext
        if C_file.find_file(pkg_name, path):
            return self
        else:
            fullname += NpkImporter.ext
            if C_file.find_file(fullname, path):
                return self
            return

    def load_module(self, fullname):
        import C_file
        is_pkg = True
        mod_path = fullname.replace('.', '/') + '/__init__'
        mod_name = fullname
        if not C_file.find_file(mod_path + NpkImporter.ext, self._path):
            is_pkg = False
            mod_path = fullname.replace('.', '/')
            mod_name = fullname
        data = C_file.get_file(mod_path + NpkImporter.ext, self._path)
        data = NpkImporter.rotor.decrypt(data)
        data = zlib.decompress(data)
        data = _reverse_string(data)
        data = marshal.loads(data)
        path = None
        if is_pkg:
            path = [self._path]
        m = C_file.new_module(mod_name, data, path)
        return m


import sys
sys.path_hooks.append(NpkImporter)
+++ okay decompyling redirect.fix.pyc 
# decompiled 1 files: 1 okay, 0 failed, 0 verify failed
# 2017.10.30 19:50:40 CST

但是其中的C_file是什么呢?

@dhtfish
Copy link

dhtfish commented Dec 9, 2017

有没有研究终结者2的,终结者2里面很多都改了

@shenliuming
Copy link

大佬你好,在吾爱看过你的帖子,JAVA开发对这方面有很大兴趣,可以交个朋友吗。企鹅 597478495

@x4317350
Copy link

大佬你好,之前看过您的帖子,最近在接触pyc的反编译相关的工作,遇到些问题,想请教你一下,可以加个好友吗

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment