node-marshal 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,227 +1,227 @@
1
- require_relative '../ext/node-marshal/nodemarshal.so'
2
- begin
3
- require 'zlib'
4
- rescue LoadError
5
- # If zlib library is absent in the system no support for
6
- # compression will be provided in
7
- end
8
-
9
- # Implementation of Array::to_h method for Ruby 1.9 (and probably 2.0)
10
- # Don't use for Ruby 2.2.x and Ruby 2.3.x
11
- if !defined?([].to_h)
12
- class Array
13
- def to_h
14
- h = {}
15
- a = self
16
- a.each do |x|
17
- raise "wrong array length" if x.length != 2
18
- h[x[0]] = x[1];
19
- end
20
- return h
21
- end
22
- end
23
- end
24
-
25
- class NodeMarshal
26
- # call-seq:
27
- # obj.to_compiled_rb(outfile, opts)
28
- #
29
- # Transforms node to the Ruby file
30
- # - +outfile+ -- name of the output file
31
- # - +opts+ -- Hash with options (+:compress+, +:so_path+)
32
- # +:compress+ can be +true+ or +false+, +:so_path+ is a test string
33
- # with the command for nodemarshal.so inclusion (default is
34
- # <tt>require_relative '../ext/node-marshal/nodemarshal.so'</tt>)
35
- #
36
- # See also NodeMarshal::compile_rb_file
37
- def to_compiled_rb(outfile, *args)
38
- compress = true
39
- so_path = "require_relative '../ext/node-marshal/nodemarshal.so'"
40
- if args.length > 0
41
- opts = args[0]
42
- if opts.has_key?(:compress)
43
- compress = opts[:compress]
44
- end
45
- if opts.has_key?(:so_path)
46
- so_path = opts[:so_path]
47
- end
48
- end
49
- # Compression
50
- if compress
51
- if !defined?(Zlib)
52
- raise "Compression is not supported: Zlib is absent"
53
- end
54
- zlib_include = "require 'zlib'"
55
- data_txt = NodeMarshal.base85r_encode(Zlib::deflate(self.to_bin))
56
- data_bin = "Zlib::inflate(NodeMarshal.base85r_decode(data_txt))"
57
- else
58
- zlib_include = "# No compression"
59
- data_txt = self.to_text
60
- data_bin = "NodeMarshal.base85r_decode(data_txt)"
61
- end
62
- # Document header
63
- txt = <<EOS
64
- # Ruby compressed source code
65
- # RUBY_PLATFORM: #{RUBY_PLATFORM}
66
- # RUBY_VERSION: #{RUBY_VERSION}
67
- #{zlib_include}
68
- #{so_path}
69
- data_txt = <<DATABLOCK
70
- #{data_txt}
71
- DATABLOCK
72
- data_bin = #{data_bin}
73
- node = NodeMarshal.new(:binmemory, data_bin)
74
- node.filename = __FILE__
75
- node.filepath = File.expand_path(node.filename)
76
- node.compile.eval
77
- EOS
78
- # Process input arguments
79
- if outfile != nil
80
- File.open(outfile, 'w') {|fp| fp << txt}
81
- end
82
- return txt
83
- end
84
-
85
- # call-seq:
86
- # NodeMarshal::compile_rb_file(outfile, inpfile, opts)
87
- #
88
- # Reads +.rb+ file (Ruby source) and compiles it to .rb file containing
89
- # compressed AST node and its loader. This functions is an envelope for
90
- # NodeMarshal#to_compiled_rb
91
- def self.compile_rb_file(outfile, inpfile, *args)
92
- node = NodeMarshal.new(:srcfile, inpfile)
93
- node.to_compiled_rb(outfile, *args)
94
- return true
95
- end
96
-
97
- # call-seq:
98
- # obj.replace_symbols(syms_subs)
99
- #
100
- # Replaces some symbols inside parsed AST to user-defined aliases.
101
- # It is designed to make code obfuscation easier. Be careful when using
102
- # this ability: it is possible to break external libraries calls,
103
- # operators overloading and some metaprogramming techniques.
104
- # - +syms_subs+ -- Hash with the table of aliases. Keys are original names,
105
- # values are aliases. Keys and values MUST BE strings (not symbols!).
106
- def replace_symbols(syms_subs)
107
- # Check input data
108
- # a) type
109
- if !(syms_subs.is_a?(Hash))
110
- raise "symb_subs must be a hash"
111
- end
112
- # b) uniqueness of values inside the hash
113
- values = syms_subs.values
114
- if values.size != values.uniq.size
115
- raise ArgumentError, "values (new names) must be unique"
116
- end
117
- # c) uniqueness of values after replacement
118
- # TODO: MAKE IT!!!
119
- # Use NodeMarshal C part to replace the symbols
120
- self.to_hash # To initialize Hash with preparsed Ruby AST NODE
121
- syms_subs.each do |key, value|
122
- change_symbol(key, value)
123
- end
124
- self
125
- end
126
-
127
- # call-seq:
128
- # obj.get_safe_symbols(our_symbols)
129
- #
130
- # Returns an array that contains strings with the names of symbols that are safe
131
- # to change. It excludes symbols that are present in the table of literals (and their derivatives
132
- # such as @x and x=). Such operation is useful for attr_readed, attr_writer and another similar
133
- # metaprogramming techniques handling
134
- #
135
- # - +our_symbols+ symbols created during node creation (must be found manually by the user
136
- # by means of Symbol.all_symbols calling BEFORE and AFTER node creation.
137
- def get_safe_symbols(our_symbols)
138
- self.to_hash # To initialize Hash with preparsed Ruby AST NODE
139
- symbolic_literals = self.literals.select {|x| x.is_a?(Symbol)}.map {|x| x.to_s}
140
- fixed_symbols = [] + symbolic_literals
141
- fixed_symbols += symbolic_literals.map {|x| "@#{x}"}
142
- fixed_symbols += symbolic_literals.map {|x| "#{x}="}
143
- our_symbols = our_symbols.dup
144
- our_symbols -= fixed_symbols
145
- end
146
-
147
- # call-seq:
148
- # obj.get_aliases_table(our_symbols)
149
- #
150
- # Returns a hash that has {"old_sym_name"=>"new_sym_name",...} format.
151
- # "new_sym_name" are generated automatically.
152
- #
153
- # - +our_symbols+ -- An array that contains the list of symbols (AS STRINGS,
154
- # NOT AS SYMBOLS) that can be renamed.
155
- def get_aliases_table(our_symbols)
156
- symbols_ary = get_safe_symbols(our_symbols)
157
- pos = 0;
158
- aliases_ary = symbols_ary.map do |sym|
159
- pos += 1
160
- if sym.length > 1 && sym[0..1] == '@@'
161
- "@@q#{pos}"
162
- elsif sym[0] == '@'
163
- "@q#{pos}"
164
- elsif sym[0] =~ /[A-Z]/
165
- "Q#{pos}"
166
- elsif sym[0] =~ /[a-z]/
167
- "q#{pos}"
168
- end
169
- end
170
- [symbols_ary, aliases_ary].transpose.to_h
171
- end
172
-
173
- # call-seq:
174
- # obj.rename_ivars
175
- def rename_ivars(*args)
176
- if args.size == 0
177
- excl_names = []
178
- else
179
- excl_names = args[0]
180
- end
181
-
182
- to_hash
183
- syms = @nodehash[:symbols].select {|x| (x =~ /@[^@]/) == 0}
184
- pos = 1;
185
- syms_new = syms.map do |x|
186
- if excl_names.find_index(x[1..-1]) != nil
187
- str = x
188
- else
189
- str = "@ivar#{pos}"
190
- end
191
- pos = pos + 1;
192
- str
193
- end
194
- syms_subs = [syms, syms_new].transpose.to_h
195
- replace_symbols(syms_subs)
196
- self
197
- end
198
-
199
- # call-seq:
200
- # obj.rebuild
201
- #
202
- # Rebuilds the node by converting it to the binary dump and further restoring
203
- # of it from this dump. It doesn't change the original node and returns rebuilt
204
- # node.
205
- def rebuild
206
- NodeMarshal.new(:binmemory, to_bin)
207
- end
208
- end
209
-
210
- # Designed for the logging of symbols table changes. When an example of
211
- # SymbolsLogger is created the current global table of symbols is saved
212
- # inside it. The created example can be used for finding new symbols in
213
- # the global table. This is useful for code obfuscation.
214
- class SymbolsLogger
215
- def initialize
216
- @symtbl_old = Symbol.all_symbols
217
- end
218
-
219
- def new_symbols
220
- symtbl_new = Symbol.all_symbols
221
- symtbl_new - @symtbl_old
222
- end
223
-
224
- def update
225
- @symtbl_old = Symbol.all_symbols
226
- end
227
- end
1
+ require_relative '../ext/node-marshal/nodemarshal.so'
2
+ begin
3
+ require 'zlib'
4
+ rescue LoadError
5
+ # If zlib library is absent in the system no support for
6
+ # compression will be provided in
7
+ end
8
+
9
+ # Implementation of Array::to_h method for Ruby 1.9 (and probably 2.0)
10
+ # Don't use for Ruby 2.2.x and Ruby 2.3.x
11
+ if !defined?([].to_h)
12
+ class Array
13
+ def to_h
14
+ h = {}
15
+ a = self
16
+ a.each do |x|
17
+ raise "wrong array length" if x.length != 2
18
+ h[x[0]] = x[1];
19
+ end
20
+ return h
21
+ end
22
+ end
23
+ end
24
+
25
+ class NodeMarshal
26
+ # call-seq:
27
+ # obj.to_compiled_rb(outfile, opts)
28
+ #
29
+ # Transforms node to the Ruby file
30
+ # - +outfile+ -- name of the output file
31
+ # - +opts+ -- Hash with options (+:compress+, +:so_path+)
32
+ # +:compress+ can be +true+ or +false+, +:so_path+ is a test string
33
+ # with the command for nodemarshal.so inclusion (default is
34
+ # <tt>require_relative '../ext/node-marshal/nodemarshal.so'</tt>)
35
+ #
36
+ # See also NodeMarshal::compile_rb_file
37
+ def to_compiled_rb(outfile, *args)
38
+ compress = true
39
+ so_path = "require_relative '../ext/node-marshal/nodemarshal.so'"
40
+ if args.length > 0
41
+ opts = args[0]
42
+ if opts.has_key?(:compress)
43
+ compress = opts[:compress]
44
+ end
45
+ if opts.has_key?(:so_path)
46
+ so_path = opts[:so_path]
47
+ end
48
+ end
49
+ # Compression
50
+ if compress
51
+ if !defined?(Zlib)
52
+ raise "Compression is not supported: Zlib is absent"
53
+ end
54
+ zlib_include = "require 'zlib'"
55
+ data_txt = NodeMarshal.base85r_encode(Zlib::deflate(self.to_bin))
56
+ data_bin = "Zlib::inflate(NodeMarshal.base85r_decode(data_txt))"
57
+ else
58
+ zlib_include = "# No compression"
59
+ data_txt = self.to_text
60
+ data_bin = "NodeMarshal.base85r_decode(data_txt)"
61
+ end
62
+ # Document header
63
+ txt = <<EOS
64
+ # Ruby compressed source code
65
+ # RUBY_PLATFORM: #{RUBY_PLATFORM}
66
+ # RUBY_VERSION: #{RUBY_VERSION}
67
+ #{zlib_include}
68
+ #{so_path}
69
+ data_txt = <<DATABLOCK
70
+ #{data_txt}
71
+ DATABLOCK
72
+ data_bin = #{data_bin}
73
+ node = NodeMarshal.new(:binmemory, data_bin)
74
+ node.filename = __FILE__
75
+ node.filepath = File.expand_path(node.filename)
76
+ node.compile.eval
77
+ EOS
78
+ # Process input arguments
79
+ if outfile != nil
80
+ File.open(outfile, 'w') {|fp| fp << txt}
81
+ end
82
+ return txt
83
+ end
84
+
85
+ # call-seq:
86
+ # NodeMarshal::compile_rb_file(outfile, inpfile, opts)
87
+ #
88
+ # Reads +.rb+ file (Ruby source) and compiles it to .rb file containing
89
+ # compressed AST node and its loader. This functions is an envelope for
90
+ # NodeMarshal#to_compiled_rb
91
+ def self.compile_rb_file(outfile, inpfile, *args)
92
+ node = NodeMarshal.new(:srcfile, inpfile)
93
+ node.to_compiled_rb(outfile, *args)
94
+ return true
95
+ end
96
+
97
+ # call-seq:
98
+ # obj.replace_symbols(syms_subs)
99
+ #
100
+ # Replaces some symbols inside parsed AST to user-defined aliases.
101
+ # It is designed to make code obfuscation easier. Be careful when using
102
+ # this ability: it is possible to break external libraries calls,
103
+ # operators overloading and some metaprogramming techniques.
104
+ # - +syms_subs+ -- Hash with the table of aliases. Keys are original names,
105
+ # values are aliases. Keys and values MUST BE strings (not symbols!).
106
+ def replace_symbols(syms_subs)
107
+ # Check input data
108
+ # a) type
109
+ if !(syms_subs.is_a?(Hash))
110
+ raise "symb_subs must be a hash"
111
+ end
112
+ # b) uniqueness of values inside the hash
113
+ values = syms_subs.values
114
+ if values.size != values.uniq.size
115
+ raise ArgumentError, "values (new names) must be unique"
116
+ end
117
+ # c) uniqueness of values after replacement
118
+ # TODO: MAKE IT!!!
119
+ # Use NodeMarshal C part to replace the symbols
120
+ self.to_hash # To initialize Hash with preparsed Ruby AST NODE
121
+ syms_subs.each do |key, value|
122
+ change_symbol(key, value)
123
+ end
124
+ self
125
+ end
126
+
127
+ # call-seq:
128
+ # obj.get_safe_symbols(our_symbols)
129
+ #
130
+ # Returns an array that contains strings with the names of symbols that are safe
131
+ # to change. It excludes symbols that are present in the table of literals (and their derivatives
132
+ # such as @x and x=). Such operation is useful for attr_readed, attr_writer and another similar
133
+ # metaprogramming techniques handling
134
+ #
135
+ # - +our_symbols+ symbols created during node creation (must be found manually by the user
136
+ # by means of Symbol.all_symbols calling BEFORE and AFTER node creation.
137
+ def get_safe_symbols(our_symbols)
138
+ self.to_hash # To initialize Hash with preparsed Ruby AST NODE
139
+ symbolic_literals = self.literals.select {|x| x.is_a?(Symbol)}.map {|x| x.to_s}
140
+ fixed_symbols = [] + symbolic_literals
141
+ fixed_symbols += symbolic_literals.map {|x| "@#{x}"}
142
+ fixed_symbols += symbolic_literals.map {|x| "#{x}="}
143
+ our_symbols = our_symbols.dup
144
+ our_symbols -= fixed_symbols
145
+ end
146
+
147
+ # call-seq:
148
+ # obj.get_aliases_table(our_symbols)
149
+ #
150
+ # Returns a hash that has {"old_sym_name"=>"new_sym_name",...} format.
151
+ # "new_sym_name" are generated automatically.
152
+ #
153
+ # - +our_symbols+ -- An array that contains the list of symbols (AS STRINGS,
154
+ # NOT AS SYMBOLS) that can be renamed.
155
+ def get_aliases_table(our_symbols)
156
+ symbols_ary = get_safe_symbols(our_symbols)
157
+ pos = 0;
158
+ aliases_ary = symbols_ary.map do |sym|
159
+ pos += 1
160
+ if sym.length > 1 && sym[0..1] == '@@'
161
+ "@@q#{pos}"
162
+ elsif sym[0] == '@'
163
+ "@q#{pos}"
164
+ elsif sym[0] =~ /[A-Z]/
165
+ "Q#{pos}"
166
+ elsif sym[0] =~ /[a-z]/
167
+ "q#{pos}"
168
+ end
169
+ end
170
+ [symbols_ary, aliases_ary].transpose.to_h
171
+ end
172
+
173
+ # call-seq:
174
+ # obj.rename_ivars
175
+ def rename_ivars(*args)
176
+ if args.size == 0
177
+ excl_names = []
178
+ else
179
+ excl_names = args[0]
180
+ end
181
+
182
+ to_hash
183
+ syms = @nodehash[:symbols].select {|x| (x =~ /@[^@]/) == 0}
184
+ pos = 1;
185
+ syms_new = syms.map do |x|
186
+ if excl_names.find_index(x[1..-1]) != nil
187
+ str = x
188
+ else
189
+ str = "@ivar#{pos}"
190
+ end
191
+ pos = pos + 1;
192
+ str
193
+ end
194
+ syms_subs = [syms, syms_new].transpose.to_h
195
+ replace_symbols(syms_subs)
196
+ self
197
+ end
198
+
199
+ # call-seq:
200
+ # obj.rebuild
201
+ #
202
+ # Rebuilds the node by converting it to the binary dump and further restoring
203
+ # of it from this dump. It doesn't change the original node and returns rebuilt
204
+ # node.
205
+ def rebuild
206
+ NodeMarshal.new(:binmemory, to_bin)
207
+ end
208
+ end
209
+
210
+ # Designed for the logging of symbols table changes. When an example of
211
+ # SymbolsLogger is created the current global table of symbols is saved
212
+ # inside it. The created example can be used for finding new symbols in
213
+ # the global table. This is useful for code obfuscation.
214
+ class SymbolsLogger
215
+ def initialize
216
+ @symtbl_old = Symbol.all_symbols
217
+ end
218
+
219
+ def new_symbols
220
+ symtbl_new = Symbol.all_symbols
221
+ symtbl_new - @symtbl_old
222
+ end
223
+
224
+ def update
225
+ @symtbl_old = Symbol.all_symbols
226
+ end
227
+ end