furnace-avm2 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +17 -0
- data/abcdump.abc +0 -0
- data/bin/furnace-avm2 +175 -0
- data/bin/furnace-avm2-benchmark +38 -0
- data/darkorbit.abc +0 -0
- data/furnace-avm2.gemspec +22 -0
- data/lib/avm2.rb +13 -0
- data/lib/avm2/abc.rb +65 -0
- data/lib/avm2/abc/metadata/const_pool_info.rb +18 -0
- data/lib/avm2/abc/metadata/exception_info.rb +29 -0
- data/lib/avm2/abc/metadata/file.rb +27 -0
- data/lib/avm2/abc/metadata/instance_info.rb +53 -0
- data/lib/avm2/abc/metadata/klass_info.rb +7 -0
- data/lib/avm2/abc/metadata/metadata_info.rb +9 -0
- data/lib/avm2/abc/metadata/method_body_info.rb +31 -0
- data/lib/avm2/abc/metadata/method_info.rb +57 -0
- data/lib/avm2/abc/metadata/multiname_info.rb +42 -0
- data/lib/avm2/abc/metadata/multiname_kind_genericname.rb +16 -0
- data/lib/avm2/abc/metadata/multiname_kind_multiname.rb +18 -0
- data/lib/avm2/abc/metadata/multiname_kind_multinamel.rb +17 -0
- data/lib/avm2/abc/metadata/multiname_kind_qname.rb +44 -0
- data/lib/avm2/abc/metadata/multiname_kind_rtqname.rb +17 -0
- data/lib/avm2/abc/metadata/multiname_kind_rtqnamel.rb +11 -0
- data/lib/avm2/abc/metadata/namespace_info.rb +22 -0
- data/lib/avm2/abc/metadata/ns_set_info.rb +13 -0
- data/lib/avm2/abc/metadata/option_detail.rb +26 -0
- data/lib/avm2/abc/metadata/option_info.rb +5 -0
- data/lib/avm2/abc/metadata/script_info.rb +7 -0
- data/lib/avm2/abc/metadata/trait_class.rb +9 -0
- data/lib/avm2/abc/metadata/trait_function.rb +9 -0
- data/lib/avm2/abc/metadata/trait_info.rb +55 -0
- data/lib/avm2/abc/metadata/trait_method.rb +12 -0
- data/lib/avm2/abc/metadata/trait_slot.rb +11 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_add.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_add_i.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_declocal.rb +14 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_declocal_i.rb +14 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_decrement.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_decrement_i.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_divide.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_equals.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_greaterequals.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_greaterthan.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_inclocal.rb +14 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_inclocal_i.rb +18 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_increment.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_increment_i.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_lessequals.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_lessthan.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_modulo.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_multiply.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_multiply_i.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_negate.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_negate_i.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_not.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_strictequals.rb +8 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_subtract.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic/as3_subtract_i.rb +10 -0
- data/lib/avm2/abc/opcodes/arithmetic_opcode.rb +4 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_bitand.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_bitnot.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_bitor.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_bitxor.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_lshift.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_rshift.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise/as3_urshift.rb +8 -0
- data/lib/avm2/abc/opcodes/bitwise_opcode.rb +4 -0
- data/lib/avm2/abc/opcodes/contextual_opcode.rb +32 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifeq.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_iffalse.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifge.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifgt.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifle.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_iflt.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifne.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifnge.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifngt.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifnle.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifnlt.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifstricteq.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_ifstrictne.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_iftrue.rb +14 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_jump.rb +22 -0
- data/lib/avm2/abc/opcodes/control_transfer/as3_lookupswitch.rb +34 -0
- data/lib/avm2/abc/opcodes/control_transfer_opcode.rb +37 -0
- data/lib/avm2/abc/opcodes/exception/as3_newcatch.rb +16 -0
- data/lib/avm2/abc/opcodes/exception_opcode.rb +4 -0
- data/lib/avm2/abc/opcodes/function_invocation/as3_call.rb +16 -0
- data/lib/avm2/abc/opcodes/function_invocation/as3_callproperty.rb +7 -0
- data/lib/avm2/abc/opcodes/function_invocation/as3_callpropvoid.rb +7 -0
- data/lib/avm2/abc/opcodes/function_invocation/as3_callsuper.rb +7 -0
- data/lib/avm2/abc/opcodes/function_invocation/as3_callsupervoid.rb +7 -0
- data/lib/avm2/abc/opcodes/function_invocation_opcode.rb +17 -0
- data/lib/avm2/abc/opcodes/function_return/as3_returnvalue.rb +8 -0
- data/lib/avm2/abc/opcodes/function_return/as3_returnvoid.rb +8 -0
- data/lib/avm2/abc/opcodes/function_return_opcode.rb +4 -0
- data/lib/avm2/abc/opcodes/generic/as3_astypelate.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_checkfilter.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_dup.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_dxnslate.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_escxattr.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_getglobalscope.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_getlex.rb +16 -0
- data/lib/avm2/abc/opcodes/generic/as3_getscopeobject.rb +16 -0
- data/lib/avm2/abc/opcodes/generic/as3_getslot.rb +16 -0
- data/lib/avm2/abc/opcodes/generic/as3_hasnext.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_hasnext2.rb +17 -0
- data/lib/avm2/abc/opcodes/generic/as3_in.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_instanceof.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_istypelate.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_kill.rb +16 -0
- data/lib/avm2/abc/opcodes/generic/as3_label.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_nextname.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_nextvalue.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_nop.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_pop.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_popscope.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_setslot.rb +16 -0
- data/lib/avm2/abc/opcodes/generic/as3_swap.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_throw.rb +8 -0
- data/lib/avm2/abc/opcodes/generic/as3_typeof.rb +8 -0
- data/lib/avm2/abc/opcodes/load_store/as3_getlocal.rb +15 -0
- data/lib/avm2/abc/opcodes/load_store/as3_getlocal_0.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_getlocal_1.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_getlocal_2.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_getlocal_3.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_setlocal.rb +15 -0
- data/lib/avm2/abc/opcodes/load_store/as3_setlocal_0.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_setlocal_1.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_setlocal_2.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store/as3_setlocal_3.rb +11 -0
- data/lib/avm2/abc/opcodes/load_store_opcode.rb +18 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_construct.rb +12 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_constructsuper.rb +16 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_newactivation.rb +8 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_newarray.rb +12 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_newclass.rb +12 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_newfunction.rb +12 -0
- data/lib/avm2/abc/opcodes/object_manipulation/as3_newobject.rb +12 -0
- data/lib/avm2/abc/opcodes/object_manipulation_opcode.rb +4 -0
- data/lib/avm2/abc/opcodes/opcode.rb +127 -0
- data/lib/avm2/abc/opcodes/property/as3_constructprop.rb +20 -0
- data/lib/avm2/abc/opcodes/property/as3_deleteproperty.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_findproperty.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_findpropstrict.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_getdescendants.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_getproperty.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_getsuper.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_initproperty.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_setproperty.rb +9 -0
- data/lib/avm2/abc/opcodes/property/as3_setsuper.rb +9 -0
- data/lib/avm2/abc/opcodes/property_opcode.rb +13 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushbyte.rb +11 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushdouble.rb +11 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushfalse.rb +7 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushint.rb +11 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushnan.rb +7 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushnull.rb +7 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushscope.rb +8 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushshort.rb +11 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushstring.rb +11 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushtrue.rb +7 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushundefined.rb +7 -0
- data/lib/avm2/abc/opcodes/push_literal/as3_pushwith.rb +8 -0
- data/lib/avm2/abc/opcodes/push_literal_opcode.rb +18 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_applytype.rb +12 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_coerce.rb +16 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_coerce_a.rb +8 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_coerce_b.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_coerce_s.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_convert_d.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_convert_i.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_convert_o.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_convert_s.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion/as3_convert_u.rb +10 -0
- data/lib/avm2/abc/opcodes/type_conversion_opcode.rb +4 -0
- data/lib/avm2/abc/primitives/opcode_sequence.rb +195 -0
- data/lib/avm2/abc/primitives/record.rb +132 -0
- data/lib/avm2/binary/choice_definition.rb +21 -0
- data/lib/avm2/binary/record.rb +469 -0
- data/lib/avm2/transform.rb +6 -0
- data/lib/avm2/transform/ast_build.rb +206 -0
- data/lib/avm2/transform/ast_normalize.rb +0 -0
- data/lib/avm2/version.rb +3 -0
- data/test/exception.abc +0 -0
- data/test/exception.as +29 -0
- data/test/literal.abc +0 -0
- data/test/literal.as +5 -0
- data/test/logic.abc +0 -0
- data/test/logic.as +23 -0
- data/test/loops.abc +0 -0
- data/test/loops.as +30 -0
- data/test/number.abc +0 -0
- data/test/number.as +14 -0
- data/test/switch.abc +0 -0
- data/test/switch.as +38 -0
- data/test/ternary.abc +0 -0
- data/test/ternary.as +22 -0
- metadata +579 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
.rbx/
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/abcdump.abc
ADDED
Binary file
|
data/bin/furnace-avm2
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "bundler/setup"
|
5
|
+
|
6
|
+
$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
7
|
+
|
8
|
+
require "trollop"
|
9
|
+
require "avm2"
|
10
|
+
require "thread"
|
11
|
+
require "benchmark"
|
12
|
+
|
13
|
+
opts = Trollop::options do
|
14
|
+
version "furnace-as3 #{AVM2::VERSION}"
|
15
|
+
banner <<-EOS
|
16
|
+
furnace-avm2 is a processing tool which operates on ActionScript3 bytecode.
|
17
|
+
|
18
|
+
Usage: #{__FILE__} [options]
|
19
|
+
EOS
|
20
|
+
|
21
|
+
opt :input, "Input file", :type => :string
|
22
|
+
opt :output, "Output file", :type => :string
|
23
|
+
opt :verbose, "Be verbose", :default => false
|
24
|
+
|
25
|
+
opt :only, "Only operate on methods <i+>", :type => :ints, :short => '-O'
|
26
|
+
opt :except, "Operate on all methods except <i+>", :type => :ints, :short => '-E'
|
27
|
+
opt :grep, "Search <s> in method names", :type => :string, :short => '-G'
|
28
|
+
|
29
|
+
opt :collect, "Collect failed methods instead of exiting", :default => false
|
30
|
+
opt :smallest, "Find method with smallest body", :default => false
|
31
|
+
|
32
|
+
opt :disasm_before, "Disassemble methods before transforming", :default => false, :short => '-B'
|
33
|
+
opt :disasm_after, "Disassemble methods after transforming", :default => false, :short => '-A'
|
34
|
+
opt :cfg, "Emit CFG in Graphviz format for methods", :default => false, :short => '-C'
|
35
|
+
|
36
|
+
opt :dce, "Eliminate dead code", :default => false
|
37
|
+
opt :ast, "Build AST", :default => false
|
38
|
+
end
|
39
|
+
|
40
|
+
Trollop::die "Input file is required" unless opts[:input]
|
41
|
+
Trollop::die "Stray arguments: #{ARGV}" unless ARGV.empty?
|
42
|
+
|
43
|
+
abc = nil
|
44
|
+
File.open(opts[:input]) do |file|
|
45
|
+
abc = AVM2::ABC::File.new
|
46
|
+
abc.read(file)
|
47
|
+
end
|
48
|
+
|
49
|
+
disasm = lambda do |body, after|
|
50
|
+
puts
|
51
|
+
puts "Method #{body.method_idx}," <<
|
52
|
+
" max stack #{body.max_stack}, local count #{body.local_count}"
|
53
|
+
if after
|
54
|
+
puts "After transformation"
|
55
|
+
else
|
56
|
+
puts "Before transformation"
|
57
|
+
end
|
58
|
+
puts body.code.disassemble
|
59
|
+
|
60
|
+
if body.exceptions.any?
|
61
|
+
puts
|
62
|
+
puts "Exceptions"
|
63
|
+
body.exceptions.each do |exception|
|
64
|
+
puts " #{exception.from_offset} -> #{exception.to_offset}: " <<
|
65
|
+
"catch(#{exception.exc_type} #{exception.var_name}) #{exception.target_offset}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
failed = []
|
71
|
+
dced = []
|
72
|
+
smallest = nil
|
73
|
+
|
74
|
+
if opts[:grep]
|
75
|
+
regexp = Regexp.new(opts[:grep])
|
76
|
+
|
77
|
+
(abc.klasses + abc.instances).each do |scope|
|
78
|
+
if scope.is_a? AVM2::ABC::InstanceInfo
|
79
|
+
if scope.name.to_s =~ regexp
|
80
|
+
puts "Inst Constructor #{scope.name} #{scope.initializer_idx}"
|
81
|
+
end
|
82
|
+
|
83
|
+
type = "Inst "
|
84
|
+
else
|
85
|
+
type = "Class"
|
86
|
+
end
|
87
|
+
|
88
|
+
scope.traits.each do |trait|
|
89
|
+
if [:Function, :Method].include? trait.kind
|
90
|
+
if trait.name.to_s =~ regexp
|
91
|
+
puts "#{type} #{trait.kind.to_s.ljust 12} #{trait.name} #{trait.data.method_idx}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
exit
|
98
|
+
end
|
99
|
+
|
100
|
+
Thread.abort_on_exception = true
|
101
|
+
|
102
|
+
threads = []
|
103
|
+
bodies = abc.method_bodies.dup
|
104
|
+
mutex = Mutex.new
|
105
|
+
|
106
|
+
5.times do
|
107
|
+
threads << Thread.new do
|
108
|
+
loop do
|
109
|
+
body = mutex.synchronize { bodies.pop }
|
110
|
+
break if body.nil?
|
111
|
+
|
112
|
+
if (opts[:except] && opts[:except].include?(body.method_idx)) ||
|
113
|
+
(opts[:only] && !opts[:only].include?(body.method_idx))
|
114
|
+
next
|
115
|
+
end
|
116
|
+
|
117
|
+
begin
|
118
|
+
disasm[body, false] if opts[:disasm_before]
|
119
|
+
|
120
|
+
if opts[:smallest]
|
121
|
+
if smallest.nil? || smallest.code_length > body.code_length
|
122
|
+
smallest = body
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
if opts[:dce]
|
127
|
+
dced << body.method_idx if body.code.eliminate_dead!
|
128
|
+
end
|
129
|
+
|
130
|
+
if opts[:ast]
|
131
|
+
ast, = body.build_ast
|
132
|
+
puts ast.to_sexp
|
133
|
+
end
|
134
|
+
|
135
|
+
if opts[:cfg]
|
136
|
+
cfg = body.code.build_cfg
|
137
|
+
File.open("method-#{body.method_idx}.dot", "w") do |dot|
|
138
|
+
dot.write cfg.to_graphviz
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
disasm[body, true] if opts[:disasm_after]
|
143
|
+
rescue Exception => e
|
144
|
+
if opts[:collect]
|
145
|
+
#puts "Failure at method body idx=#{body.method_idx}: #{e.class} (#{e.message}) at #{e.backtrace.first}."
|
146
|
+
failed << body.method_idx
|
147
|
+
else
|
148
|
+
raise e
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
threads.each &:join
|
156
|
+
|
157
|
+
if opts[:verbose]
|
158
|
+
if opts[:dce]
|
159
|
+
puts "List of methods undergone DCE transform (#{dced.count}):"
|
160
|
+
puts " #{dced.join " "}"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
if opts[:smallest]
|
165
|
+
puts "Smallest method is #{smallest.method_idx} with #{smallest.code_length} bytes"
|
166
|
+
end
|
167
|
+
|
168
|
+
if opts[:collect] && failed.any?
|
169
|
+
puts "To skip #{failed.count} failed methods, append this command-line argument:"
|
170
|
+
puts " --except #{failed.join " "}"
|
171
|
+
elsif opts[:output]
|
172
|
+
File.open(opts[:output], "w") do |file|
|
173
|
+
abc.write(file)
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "bundler/setup"
|
5
|
+
|
6
|
+
$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
7
|
+
|
8
|
+
require "avm2"
|
9
|
+
require "benchmark"
|
10
|
+
|
11
|
+
puts "Working on #{RUBY_DESCRIPTION}"
|
12
|
+
|
13
|
+
Benchmark.bm(7) do |x|
|
14
|
+
5.times do
|
15
|
+
abc = nil
|
16
|
+
|
17
|
+
GC.start
|
18
|
+
|
19
|
+
x.report("read ") do
|
20
|
+
File.open(ARGV.first) do |file|
|
21
|
+
abc = AVM2::ABC::File.new
|
22
|
+
abc.read(file)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
x.report("dce ") do
|
27
|
+
abc.method_bodies.each do |body|
|
28
|
+
body.code.eliminate_dead!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
x.report("write ") do
|
33
|
+
File.open("/dev/null", "w") do |file|
|
34
|
+
abc.write(file)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/darkorbit.abc
ADDED
Binary file
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "avm2/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "furnace-avm2"
|
7
|
+
s.version = AVM2::VERSION
|
8
|
+
s.authors = ["Peter Zotov"]
|
9
|
+
s.email = ["whitequark@whitequark.org"]
|
10
|
+
s.homepage = "http://github.com/whitequark/furnace-avm2"
|
11
|
+
s.summary = %q{AVM2 analysis framework based on Furnace}
|
12
|
+
s.description = %q{furnace-avm2 allows one to load, modify and write back} <<
|
13
|
+
%q{Flash ActionScript3 bytecode. It can also decompile it.}
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_runtime_dependency "furnace"
|
21
|
+
s.add_runtime_dependency "trollop"
|
22
|
+
end
|
data/lib/avm2.rb
ADDED
data/lib/avm2/abc.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
module AVM2::ABC
|
2
|
+
AST = Furnace::AST
|
3
|
+
CFG = Furnace::CFG
|
4
|
+
end
|
5
|
+
|
6
|
+
require "avm2/binary/choice_definition"
|
7
|
+
require "avm2/binary/record"
|
8
|
+
|
9
|
+
require "avm2/abc/primitives/record"
|
10
|
+
require "avm2/abc/primitives/opcode_sequence"
|
11
|
+
|
12
|
+
require "avm2/abc/opcodes/opcode"
|
13
|
+
require "avm2/abc/opcodes/contextual_opcode"
|
14
|
+
|
15
|
+
require "avm2/abc/opcodes/load_store_opcode"
|
16
|
+
require "avm2/abc/opcodes/arithmetic_opcode"
|
17
|
+
require "avm2/abc/opcodes/bitwise_opcode"
|
18
|
+
require "avm2/abc/opcodes/type_conversion_opcode"
|
19
|
+
require "avm2/abc/opcodes/push_literal_opcode"
|
20
|
+
require "avm2/abc/opcodes/control_transfer_opcode"
|
21
|
+
require "avm2/abc/opcodes/function_invocation_opcode"
|
22
|
+
require "avm2/abc/opcodes/function_return_opcode"
|
23
|
+
require "avm2/abc/opcodes/exception_opcode"
|
24
|
+
|
25
|
+
require "avm2/abc/opcodes/property_opcode"
|
26
|
+
|
27
|
+
Dir[File.join(File.dirname(__FILE__), "abc", "opcodes", "*", "*.rb")].each do |file|
|
28
|
+
require file
|
29
|
+
end
|
30
|
+
|
31
|
+
AVM2::ABC::Opcode::MAP.freeze
|
32
|
+
|
33
|
+
require "avm2/abc/metadata/namespace_info"
|
34
|
+
require "avm2/abc/metadata/ns_set_info"
|
35
|
+
require "avm2/abc/metadata/multiname_kind_multiname"
|
36
|
+
require "avm2/abc/metadata/multiname_kind_multinamel"
|
37
|
+
require "avm2/abc/metadata/multiname_kind_qname"
|
38
|
+
require "avm2/abc/metadata/multiname_kind_rtqname"
|
39
|
+
require "avm2/abc/metadata/multiname_kind_rtqnamel"
|
40
|
+
require "avm2/abc/metadata/multiname_kind_genericname"
|
41
|
+
require "avm2/abc/metadata/multiname_info"
|
42
|
+
require "avm2/abc/metadata/const_pool_info"
|
43
|
+
|
44
|
+
require "avm2/abc/metadata/option_detail"
|
45
|
+
require "avm2/abc/metadata/option_info"
|
46
|
+
require "avm2/abc/metadata/method_info"
|
47
|
+
|
48
|
+
require "avm2/abc/metadata/metadata_info"
|
49
|
+
|
50
|
+
require "avm2/abc/metadata/trait_slot"
|
51
|
+
require "avm2/abc/metadata/trait_method"
|
52
|
+
require "avm2/abc/metadata/trait_class"
|
53
|
+
require "avm2/abc/metadata/trait_function"
|
54
|
+
require "avm2/abc/metadata/trait_info"
|
55
|
+
require "avm2/abc/metadata/instance_info"
|
56
|
+
require "avm2/abc/metadata/klass_info"
|
57
|
+
|
58
|
+
require "avm2/abc/metadata/script_info"
|
59
|
+
|
60
|
+
require "avm2/abc/metadata/exception_info"
|
61
|
+
require "avm2/abc/metadata/method_body_info"
|
62
|
+
|
63
|
+
require "avm2/abc/metadata/file"
|
64
|
+
|
65
|
+
AVM2::Binary::Record.codegen_each
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module AVM2::ABC
|
2
|
+
class ConstPoolInfo < Record
|
3
|
+
def self.cpool_array_of(name, type, options={})
|
4
|
+
field_size, field_array = :"#{name}_count", :"#{name}s"
|
5
|
+
|
6
|
+
vuint30 field_size, :value => lambda { send(field_array).count == 0 ? 0 : send(field_array).count + 1 }
|
7
|
+
array field_array, :type => type, :initial_length => lambda { send(field_size) - 1 }, :options => options
|
8
|
+
end
|
9
|
+
|
10
|
+
cpool_array_of :int, :vint32
|
11
|
+
cpool_array_of :uint, :vuint32
|
12
|
+
cpool_array_of :double, :double
|
13
|
+
cpool_array_of :string, :vstring
|
14
|
+
cpool_array_of :namespace, :nested, :class => NamespaceInfo
|
15
|
+
cpool_array_of :ns_set, :nested, :class => NsSetInfo
|
16
|
+
cpool_array_of :multiname, :nested, :class => MultinameInfo
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module AVM2::ABC
|
2
|
+
class ExceptionInfo < Record
|
3
|
+
vuint30 :from_offset
|
4
|
+
vuint30 :to_offset
|
5
|
+
vuint30 :target_offset
|
6
|
+
const_ref :exc_type, :string
|
7
|
+
const_ref :var_name, :string
|
8
|
+
|
9
|
+
attr_reader :from, :to, :target
|
10
|
+
|
11
|
+
def initialize_record(options)
|
12
|
+
@parent = options[:parent]
|
13
|
+
end
|
14
|
+
|
15
|
+
def resolve!
|
16
|
+
sequence = @parent.code
|
17
|
+
|
18
|
+
@from = sequence.opcode_at(@from_offset)
|
19
|
+
@to = sequence.opcode_at(@to_offset)
|
20
|
+
@target = sequence.opcode_at(@target_offset)
|
21
|
+
end
|
22
|
+
|
23
|
+
def lookup!
|
24
|
+
@from_offset = @from.offset
|
25
|
+
@to_offset = @to.offset
|
26
|
+
@target_offset = @target.offset
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module AVM2::ABC
|
2
|
+
class File < Record
|
3
|
+
uint16 :minor_version
|
4
|
+
uint16 :major_version
|
5
|
+
|
6
|
+
nested :constant_pool, :class => ConstPoolInfo
|
7
|
+
|
8
|
+
abc_array_of :method, :nested, :class => MethodInfo
|
9
|
+
|
10
|
+
abc_array_of :metadata, :nested, :class => MetadataInfo
|
11
|
+
|
12
|
+
vuint30 :klass_count, :value => lambda { instances.count }
|
13
|
+
array :instances, :type => :nested, :initial_length => :klass_count,
|
14
|
+
:options => { :class => InstanceInfo }
|
15
|
+
array :klasses, :type => :nested, :initial_length => :klass_count,
|
16
|
+
:options => { :class => KlassInfo }
|
17
|
+
subset :interfaces, :instances, :interface?
|
18
|
+
|
19
|
+
abc_array_of :script, :nested, :class => ScriptInfo
|
20
|
+
|
21
|
+
abc_array_of :method_body, :nested, :class => MethodBodyInfo, :plural => :method_bodies
|
22
|
+
|
23
|
+
def root
|
24
|
+
self
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module AVM2::ABC
|
2
|
+
class InstanceInfo < Record
|
3
|
+
CLASS_SEALED = 0x01
|
4
|
+
CLASS_FINAL = 0x02
|
5
|
+
CLASS_INTERFACE = 0x04
|
6
|
+
CLASS_PROTECTED_NS = 0x08
|
7
|
+
|
8
|
+
const_ref :name, :multiname
|
9
|
+
const_ref :super_name, :multiname
|
10
|
+
|
11
|
+
uint8 :flags
|
12
|
+
flag :sealed, :flags, CLASS_SEALED
|
13
|
+
flag :final, :flags, CLASS_FINAL
|
14
|
+
flag :interface, :flags, CLASS_INTERFACE
|
15
|
+
flag :protected_ns, :flags, CLASS_PROTECTED_NS
|
16
|
+
|
17
|
+
const_ref :protected_ns, :namespace, :if => :protected_ns?
|
18
|
+
|
19
|
+
const_array_of :interface, :multiname
|
20
|
+
|
21
|
+
root_ref :initializer, :method
|
22
|
+
|
23
|
+
abc_array_of :trait, :nested, :class => TraitInfo
|
24
|
+
|
25
|
+
def to_astlet
|
26
|
+
if interface?
|
27
|
+
root = AST::Node.new(:interface)
|
28
|
+
else
|
29
|
+
root = AST::Node.new(:instance)
|
30
|
+
end
|
31
|
+
|
32
|
+
root.children << name.to_astlet
|
33
|
+
|
34
|
+
unless interface?
|
35
|
+
if super_name
|
36
|
+
root.children << super_name.to_astlet
|
37
|
+
else
|
38
|
+
root.children << nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
if interfaces.any?
|
43
|
+
root.children << AST::Node.new(:interfaces, interfaces.map(&:to_astlet))
|
44
|
+
end
|
45
|
+
|
46
|
+
if traits.any?
|
47
|
+
root.children << AST::Node.new(:traits, traits.map(&:to_astlet))
|
48
|
+
end
|
49
|
+
|
50
|
+
root.normalize_hierarchy!
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|