rmarshal 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ require 'rmarshal/unmarshal'
2
+ require 'rmarshal/pyc'
@@ -0,0 +1,56 @@
1
+ require 'rmarshal/opcodes'
2
+
3
+ class Disasm
4
+ def initialize(code, consts, varnames, names)
5
+ @code = code
6
+ @consts = consts
7
+ @varnames = varnames
8
+ @names = names
9
+ @insts = []
10
+ @off = 0
11
+
12
+ while @off != @code.size
13
+ @insts[@insts.size] = parse
14
+ end
15
+ end
16
+
17
+ def insts() @insts end
18
+ def byte()
19
+ val = @code[@off].ord
20
+ @off += 1
21
+ val
22
+ end
23
+ def short()
24
+ val = @code[@off...@off+2].unpack('s')[0]
25
+ @off += 2
26
+ val
27
+ end
28
+
29
+ def parse
30
+ off = @off
31
+ opcd = byte
32
+ if not $opcodes.has_key? opcd
33
+ raise "Unknown opcode #{opcd}"
34
+ end
35
+
36
+ name, arg = $opcodes[opcd]
37
+ if arg == nil
38
+ [off, name]
39
+ else
40
+ val = short
41
+ arg = case arg
42
+ when :const then @consts[val]
43
+ when :name then @names[val]
44
+ when :jrel then @off + val
45
+ when :local then @varnames[val]
46
+ else val
47
+ end
48
+
49
+ [off, name, arg]
50
+ end
51
+ end
52
+ end
53
+
54
+ def disasm(*args)
55
+ Disasm.new(*args).insts
56
+ end
@@ -0,0 +1,115 @@
1
+ $opcodes = {
2
+ 0x00 => [:STOP_CODE, nil],
3
+ 0x01 => [:POP_TOP, nil],
4
+ 0x02 => [:ROT_TWO, nil],
5
+ 0x03 => [:ROT_THREE, nil],
6
+ 0x04 => [:DUP_TOP, nil],
7
+ 0x05 => [:ROT_FOUR, nil],
8
+ 0x09 => [:NOP, nil],
9
+ 0x0A => [:UNARY_POSITIVE, nil],
10
+ 0x0B => [:UNARY_NEGATIVE, nil],
11
+ 0x0C => [:UNARY_NOT, nil],
12
+ 0x0D => [:UNARY_CONVERT, nil],
13
+ 0x0F => [:UNARY_INVERT, nil],
14
+ 0x12 => [:LIST_APPEND, nil],
15
+ 0x13 => [:BINARY_POWER, nil],
16
+ 0x14 => [:BINARY_MULTIPLY, nil],
17
+ 0x15 => [:BINARY_DIVIDE, nil],
18
+ 0x16 => [:BINARY_MODULO, nil],
19
+ 0x17 => [:BINARY_ADD, nil],
20
+ 0x18 => [:BINARY_SUBTRACT, nil],
21
+ 0x19 => [:BINARY_SUBSCR, nil],
22
+ 0x1A => [:BINARY_FLOOR_DIVIDE, nil],
23
+ 0x1B => [:BINARY_TRUE_DIVIDE, nil],
24
+ 0x1C => [:INPLACE_FLOOR_DIVIDE, nil],
25
+ 0x1D => [:INPLACE_TRUE_DIVIDE, nil],
26
+ 0x1E => [:SLICE_0, nil],
27
+ 0x1F => [:SLICE_1, nil],
28
+ 0x20 => [:SLICE_2, nil],
29
+ 0x21 => [:SLICE_3, nil],
30
+ 0x28 => [:STORE_SLICE_0, nil],
31
+ 0x29 => [:STORE_SLICE_1, nil],
32
+ 0x2A => [:STORE_SLICE_2, nil],
33
+ 0x2B => [:STORE_SLICE_3, nil],
34
+ 0x32 => [:DELETE_SLICE_0, nil],
35
+ 0x33 => [:DELETE_SLICE_1, nil],
36
+ 0x34 => [:DELETE_SLICE_2, nil],
37
+ 0x35 => [:DELETE_SLICE_3, nil],
38
+ 0x36 => [:STORE_MAP, nil],
39
+ 0x37 => [:INPLACE_ADD, nil],
40
+ 0x38 => [:INPLACE_SUBTRACT, nil],
41
+ 0x39 => [:INPLACE_MULTIPLY, nil],
42
+ 0x3A => [:INPLACE_DIVIDE, nil],
43
+ 0x3B => [:INPLACE_MODULO, nil],
44
+ 0x3C => [:STORE_SUBSCR, nil],
45
+ 0x3D => [:DELETE_SUBSCR, nil],
46
+ 0x3E => [:BINARY_LSHIFT, nil],
47
+ 0x3F => [:BINARY_RSHIFT, nil],
48
+ 0x40 => [:BINARY_AND, nil],
49
+ 0x41 => [:BINARY_XOR, nil],
50
+ 0x42 => [:BINARY_OR, nil],
51
+ 0x43 => [:INPLACE_POWER, nil],
52
+ 0x44 => [:GET_ITER, nil],
53
+ 0x46 => [:PRINT_EXPR, nil],
54
+ 0x47 => [:PRINT_ITEM, nil],
55
+ 0x48 => [:PRINT_NEWLINE, nil],
56
+ 0x49 => [:PRINT_ITEM_TO, nil],
57
+ 0x4A => [:PRINT_NEWLINE_TO, nil],
58
+ 0x4B => [:INPLACE_LSHIFT, nil],
59
+ 0x4C => [:INPLACE_RSHIFT, nil],
60
+ 0x4D => [:INPLACE_AND, nil],
61
+ 0x4E => [:INPLACE_XOR, nil],
62
+ 0x4F => [:INPLACE_OR, nil],
63
+ 0x50 => [:BREAK_LOOP, nil],
64
+ 0x51 => [:WITH_CLEANUP, nil],
65
+ 0x52 => [:LOAD_LOCALS, nil],
66
+ 0x53 => [:RETURN_VALUE, nil],
67
+ 0x54 => [:IMPORT_STAR, nil],
68
+ 0x55 => [:EXEC_STMT, nil],
69
+ 0x56 => [:YIELD_VALUE, nil],
70
+ 0x57 => [:POP_BLOCK, nil],
71
+ 0x58 => [:END_FINALLY, nil],
72
+ 0x59 => [:BUILD_CLASS, nil],
73
+ 0x5A => [:STORE_NAME, :name],
74
+ 0x5B => [:DELETE_NAME, :name],
75
+ 0x5C => [:UNPACK_SEQUENCE, nil],
76
+ 0x5D => [:FOR_ITER, :jrel],
77
+ 0x5F => [:STORE_ATTR, :name],
78
+ 0x60 => [:DELETE_ATTR, :name],
79
+ 0x61 => [:STORE_GLOBAL, :name],
80
+ 0x62 => [:DELETE_GLOBAL, :name],
81
+ 0x63 => [:DUP_TOPX, nil],
82
+ 0x64 => [:LOAD_CONST, :const],
83
+ 0x65 => [:LOAD_NAME, :name],
84
+ 0x66 => [:BUILD_TUPLE, nil],
85
+ 0x67 => [:BUILD_LIST, nil],
86
+ 0x68 => [:BUILD_MAP, nil],
87
+ 0x69 => [:LOAD_ATTR, :name],
88
+ 0x6A => [:COMPARE_OP, :compare],
89
+ 0x6B => [:IMPORT_NAME, :name],
90
+ 0x6C => [:IMPORT_FROM, :name],
91
+ 0x6E => [:JUMP_FORWARD, :jrel],
92
+ 0x6F => [:JUMP_IF_FALSE, :jrel],
93
+ 0x70 => [:JUMP_IF_TRUE, :jrel],
94
+ 0x71 => [:JUMP_ABSOLUTE, :jabs],
95
+ 0x74 => [:LOAD_GLOBAL, :name],
96
+ 0x77 => [:CONTINUE_LOOP, :jabs],
97
+ 0x78 => [:SETUP_LOOP, :jrel],
98
+ 0x79 => [:SETUP_EXCEPT, :jrel],
99
+ 0x7A => [:SETUP_FINALLY, :jrel],
100
+ 0x7C => [:LOAD_FAST, :local],
101
+ 0x7D => [:STORE_FAST, :local],
102
+ 0x7E => [:DELETE_FAST, :local],
103
+ 0x82 => [:RAISE_VARARGS, nil],
104
+ 0x83 => [:CALL_FUNCTION, nil],
105
+ 0x84 => [:MAKE_FUNCTION, nil],
106
+ 0x85 => [:BUILD_SLICE, nil],
107
+ 0x86 => [:MAKE_CLOSURE, nil],
108
+ 0x87 => [:LOAD_CLOSURE, :free],
109
+ 0x88 => [:LOAD_DEREF, :free],
110
+ 0x89 => [:STORE_DEREF, :free],
111
+ 0x8C => [:CALL_FUNCTION_VAR, nil],
112
+ 0x8D => [:CALL_FUNCTION_KW, nil],
113
+ 0x8E => [:CALL_FUNCTION_VAR_KW, nil],
114
+ 0x8F => [:EXTENDED_ARG, nil],
115
+ }
@@ -0,0 +1,9 @@
1
+ require 'rmarshal'
2
+
3
+ def pyc(fn)
4
+ fp = File.open fn
5
+
6
+ magic, timestamp = fp.read(8).unpack('ii')
7
+
8
+ unmarshal fp
9
+ end
@@ -0,0 +1,113 @@
1
+ require 'rmarshal/disasm'
2
+ require 'set'
3
+
4
+ class Code
5
+ def initialize(
6
+ argcount, nlocals, stacksize, flags, code, consts, names, varnames, freevars,
7
+ cellvars, filename, name, firstlineno, lnotab
8
+ )
9
+
10
+ @argcount, @nlocals, @stacksize, @flags = argcount, nlocals, stacksize, flags
11
+ @code, @consts, @names, @varnames = code, consts, names, varnames
12
+ @freevars, @cellvars, @filename, @name = freevars, cellvars, filename, name
13
+ @firstlineno, @lnotab = firstlineno, lnotab
14
+ end
15
+
16
+ def method_missing(sym)
17
+ instance_variable_get sym
18
+ end
19
+
20
+ def disassemble
21
+ disasm @code, @consts, @varnames, @names
22
+ end
23
+ end
24
+
25
+ class Unmarshal
26
+ def initialize(fp)
27
+ @fp = fp
28
+ @interned = []
29
+
30
+ @value = unmarshal
31
+ end
32
+
33
+ def value() @value end
34
+ def byte() @fp.read 1 end
35
+ def long() @fp.read(4).unpack('i')[0] end
36
+ def double() @fp.read(8).unpack('E')[0] end
37
+
38
+ def unmarshal
39
+ type = byte
40
+ case type
41
+ when '.' then :Ellipsis
42
+ when '0' then :null # Special!
43
+ when 'N' then nil
44
+ when 'T' then true
45
+ when 'F' then false
46
+
47
+ when 'c'
48
+ argcount, nlocals, stacksize, flags = long, long, long, long
49
+
50
+ code_, consts, names, varnames, freevars = unmarshal, unmarshal, unmarshal, unmarshal, unmarshal
51
+ cellvars, filename, name = unmarshal, unmarshal, unmarshal
52
+ firstlineno, lnotab = long, unmarshal
53
+
54
+ Code.new(
55
+ argcount, nlocals, stacksize, flags,
56
+ code_, consts, names, varnames, freevars,
57
+ cellvars, filename, name, firstlineno, lnotab
58
+ )
59
+
60
+ when 'f' then @fp.read(byte).to_f
61
+ when 'g' then double
62
+ when 'i' then long
63
+ when 'I' then @fp.read(8).unpack('q')[0]
64
+
65
+ when 'R'
66
+ @interned[long]
67
+
68
+ when 's' then @fp.read long
69
+
70
+ when 'S' then :StopIteration
71
+
72
+ when 't'
73
+ str = @fp.read long
74
+ @interned[@interned.size] = str
75
+ str
76
+
77
+ when 'u' then @fp.read(long).force_encoding 'utf-8'
78
+
79
+ when 'x'
80
+ Complex @fp.read(byte).to_f(), @fp.read(byte).to_f()
81
+ when 'y'
82
+ Complex double, double
83
+
84
+ when '(', '['
85
+ (0...long).map { unmarshal }
86
+
87
+ when '{'
88
+ val = {}
89
+
90
+ while true
91
+ key = unmarshal
92
+ break if key == :null
93
+
94
+ val[key] = unmarshal
95
+ end
96
+
97
+ val
98
+
99
+ when '<', '>'
100
+ Set.new((0...long).map { unmarshal })
101
+
102
+ when '?'
103
+ raise 'TYPE_UNKNOWN encountered. Incomplete marshal.'
104
+
105
+ else
106
+ raise "Unknown type '#{type}'"
107
+ end
108
+ end
109
+ end
110
+
111
+ def unmarshal(fp)
112
+ Unmarshal.new(fp).value
113
+ end
@@ -0,0 +1,33 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # Creates a file containing all possible marshal types
4
+
5
+ import marshal
6
+
7
+ def testfunc():
8
+ print 'Test'
9
+
10
+ def exhaustive():
11
+ return (
12
+ None, # TYPE_NONE 'N'
13
+ False, # TYPE_FALSE 'F'
14
+ True, # TYPE_TRUE 'T'
15
+ 0, # TYPE_INT 'i'
16
+ #1L, # TYPE_LONG 'l'
17
+ 0.0, # TYPE_BINARY_FLOAT 'g'
18
+ 1j, # TYPE_BINARY_COMPLEX 'y'
19
+ 'foo', # TYPE_STRING 's'
20
+ 'bar', # TYPE_INTERNED 't'
21
+ 'bar', # TYPE_STRINGREF 'R'
22
+ u'unicode €', # TYPE_UNICODE 'u'
23
+ [0, 'test', True], # TYPE_LIST '['
24
+ {0 : 1, 'bar' : 'baz'}, # TYPE_DICT '{'
25
+ testfunc.func_code, # TYPE_CODE 'c'
26
+
27
+ set([0, 1, 2]), # TYPE_SET
28
+ frozenset([3, 4, 5]), # TYPE_FROZENSET
29
+ StopIteration, # TYPE_STOPITER
30
+ Ellipsis, # TYPE_ELLIPSIS
31
+ )
32
+
33
+ marshal.dump(exhaustive(), file('tests\exhaustive.mrsh', 'wb'))
@@ -0,0 +1,5 @@
1
+ require 'rmarshal'
2
+ require 'pp'
3
+
4
+ fp = File.open 'exhaustive.mrsh'
5
+ pp unmarshal fp
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rmarshal
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Cody Brocious
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-20 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: cody.brocious@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/rmarshal/disasm.rb
26
+ - lib/rmarshal/opcodes.rb
27
+ - lib/rmarshal/pyc.rb
28
+ - lib/rmarshal/unmarshal.rb
29
+ - lib/rmarshal.rb
30
+ - test/exhaustive.py
31
+ - test/test.rb
32
+ has_rdoc: true
33
+ homepage: http://github.com/daeken/RMarshal
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.3.5
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: Ruby gem to support the Python marshal format
60
+ test_files: []
61
+