Class: WWMD::ViewState

Inherits:
Object
  • Object
show all
Includes:
ViewStateUtils
Defined in:
lib/wwmd/viewstate.rb,
lib/wwmd/viewstate/viewstate.rb,
lib/wwmd/viewstate/viewstate_from_xml.rb,
lib/wwmd/viewstate/viewstate_deserializer_methods.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ViewStateUtils

#deserialize_type, #dlog, #magic?, #next_type, #offset, #putd, #read, #read_7bit_encoded_int, #read_double, #read_int, #read_int32, #read_raw_byte, #read_short, #read_string, #serialize_type, #slog, #throw, #write_7bit_encoded_int, #write_double, #write_int, #write_int32, #write_short

Constructor Details

#initialize(b64 = nil) ⇒ ViewState

Returns a new instance of ViewState.



18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/wwmd/viewstate/viewstate.rb', line 18

def initialize(b64=nil)
  @b64 = b64
  @raw = ""
  @stack = ""
  @obj_queue = []
  @size = 0
  @indexed_strings = []
  @mac = nil
  @debug = false
  @obj_counts = {}
  self.deserialize if b64
end

Instance Attribute Details

#b64Object

Returns the value of attribute b64.



3
4
5
# File 'lib/wwmd/viewstate/viewstate.rb', line 3

def b64
  @b64
end

#bufObject (readonly)

Returns the value of attribute buf.



9
10
11
# File 'lib/wwmd/viewstate/viewstate.rb', line 9

def buf
  @buf
end

#debugObject

Returns the value of attribute debug.



6
7
8
# File 'lib/wwmd/viewstate/viewstate.rb', line 6

def debug
  @debug
end

#indexed_stringsObject (readonly)

Returns the value of attribute indexed_strings.



12
13
14
# File 'lib/wwmd/viewstate/viewstate.rb', line 12

def indexed_strings
  @indexed_strings
end

#last_offsetObject (readonly)

Returns the value of attribute last_offset.



13
14
15
# File 'lib/wwmd/viewstate/viewstate.rb', line 13

def last_offset
  @last_offset
end

#macObject

Returns the value of attribute mac.



5
6
7
# File 'lib/wwmd/viewstate/viewstate.rb', line 5

def mac
  @mac
end

#magicObject (readonly)

Returns the value of attribute magic.



10
11
12
# File 'lib/wwmd/viewstate/viewstate.rb', line 10

def magic
  @magic
end

#ndocObject (readonly)

Returns the value of attribute ndoc.



15
16
17
# File 'lib/wwmd/viewstate/viewstate.rb', line 15

def ndoc
  @ndoc
end

#obj_countsObject (readonly)

Returns the value of attribute obj_counts.



16
17
18
# File 'lib/wwmd/viewstate/viewstate.rb', line 16

def obj_counts
  @obj_counts
end

#obj_queueObject

Returns the value of attribute obj_queue.



4
5
6
# File 'lib/wwmd/viewstate/viewstate.rb', line 4

def obj_queue
  @obj_queue
end

#rawObject (readonly)

Returns the value of attribute raw.



7
8
9
# File 'lib/wwmd/viewstate/viewstate.rb', line 7

def raw
  @raw
end

#sizeObject (readonly)

Returns the value of attribute size.



11
12
13
# File 'lib/wwmd/viewstate/viewstate.rb', line 11

def size
  @size
end

#stackObject (readonly)

Returns the value of attribute stack.



8
9
10
# File 'lib/wwmd/viewstate/viewstate.rb', line 8

def stack
  @stack
end

#xmlObject (readonly)

Returns the value of attribute xml.



14
15
16
# File 'lib/wwmd/viewstate/viewstate.rb', line 14

def xml
  @xml
end

#xmlstackObject (readonly)

this is pretty silly but it didn’t take me very long so…



6
7
8
# File 'lib/wwmd/viewstate/viewstate_from_xml.rb', line 6

def xmlstack
  @xmlstack
end

Instance Method Details

#array(t = nil) ⇒ Object



79
80
81
82
83
84
85
86
87
88
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 79

def array(t=nil)
  typeref,typeval = self.deserialize_type
  len = read_7bit_encoded_int
  dlog(t,"typeref = 0x#{typeref.to_s(16)} typeval = #{typeval} len = #{len}")
  me = VSStubs::VSArray.new(typeref,typeval)
  (1..len).each do |i|
    me.add(self.deserialize_value)
  end
  return me
end

#binary_serialized(t = nil) ⇒ Object



34
35
36
37
38
39
40
41
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 34

def binary_serialized(t=nil)
  count = self.read_7bit_encoded_int
  dlog(t,count)
  bin = self.read(count)
  me = VSStubs::VSBinarySerialized.new()
  me.set(bin)
  return me
end

#bool_false(t = nil) ⇒ Object



198
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 198

def bool_false(t=nil);  dlog(t,nil); return VSStubs::VSValue.new(t); end

#bool_true(t = nil) ⇒ Object



197
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 197

def bool_true(t=nil);   dlog(t,nil); return VSStubs::VSValue.new(t); end

#byte(t = nil) ⇒ Object



163
164
165
166
167
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 163

def byte(t=nil)
  val = self.read_byte
  dlog(t,val)
  VSStubs::VSByte.new(val)
end

#char(t = nil) ⇒ Object



169
170
171
172
173
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 169

def char(t=nil)
  val = self.read_byte
  dlog(t,val)
  VSStubs::VSChar.new(val)
end

#color(t = nil) ⇒ Object

VSStubs::VSReadValue types



139
140
141
142
143
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 139

def color(t=nil)
  val = self.read_int32
  dlog(t,val.to_s(16))
  VSStubs::VSColor.new(val)
end

#date_time(t = nil) ⇒ Object



175
176
177
178
179
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 175

def date_time(t=nil)
  val = self.read_double
  dlog(t,val)
  VSStubs::VSDateTime.new(val)
end

#decode_text(node) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/wwmd/viewstate/viewstate_from_xml.rb', line 32

def decode_text(node)
  case node['encoding']
    when "urlencoded"
      node.inner_text.unescape
    when "quoted-printable"
      node.inner_text.from_qp
    when "base64"
      node.inner_text.b64d
    when "hexify"
      node.inner_text.dehexify
    else
#          node.inner_text
      node.inner_text.unescape # ZZZZ auto-unescape for fuzzing
  end
end

#deserialize(b64 = nil) ⇒ Object Also known as: parse

deserialize



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/wwmd/viewstate/viewstate.rb', line 37

def deserialize(b64=nil)
  @obj_queue = []
  @b64 = b64 if b64
  @raw = @b64.b64d
  @buf = StringIO.new(@raw)
  @size = @buf.size
  raise "Invalid ViewState" if not self.magic?
  @obj_queue << self.deserialize_value
  if (@buf.size - @buf.pos) == 20 then
    @mac = @buf.read(20)
    dlog(0x00,"MAC = #{@mac.hexify}")
  end
  raise "Error Parsing Viewstate (left: #{@buf.size - @buf.pos})" if not (@buf.size - @buf.pos) == 0
  return !self.raw.nil?
end

#deserialize_valueObject

deserialize_value



203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 203

def deserialize_value
  @last_offset = @buf.pos
  token = self.read_byte # self.read_raw_byte
  if not (tsym = VIEWSTATE_TYPES[token])
    STDERR.puts "TOKEN: [0x#{token.to_s(16)}] at #{last_offset}"
    STDERR.puts @buf.read(32).hexdump
    raise "Invalid Type [0x#{token.to_s(16)}] at #{last_offset}" if not (tsym = VIEWSTATE_TYPES[token])
  end
  nobj = self.send(tsym,token)
  raise "Invalid Class Returned #{nobj.class}" if not VIEWSTATE_TYPES.include?(nobj.opcode)
  return nobj
end

#double(t = nil) ⇒ Object



181
182
183
184
185
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 181

def double(t=nil)
  val = self.read_double
  dlog(t,val)
  VSStubs::VSDouble.new(val)
end

#empty_byte(t = nil) ⇒ Object



195
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 195

def empty_byte(t=nil);  dlog(t,nil); return VSStubs::VSValue.new(t); end

#empty_color(t = nil) ⇒ Object



199
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 199

def empty_color(t=nil); dlog(t,nil); return VSStubs::VSValue.new(t); end

#empty_unit(t = nil) ⇒ Object



200
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 200

def empty_unit(t=nil);  dlog(t,nil); return VSStubs::VSValue.new(t); end

#from_xml(xml) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
# File 'lib/wwmd/viewstate/viewstate_from_xml.rb', line 116

def from_xml(xml)
  @xmlstack = ""
  doc = Nokogiri::XML.parse(xml)
  root = doc.root
  raise "Invalid ViewState Version" if not root.has_attribute?("version")
  @xmlstack << root['version'].b64d
  root.children.each do |c|
    serialize_xml(c)
  end
  self.deserialize(@xmlstack.b64e)
end

#from_yaml(yaml) ⇒ Object



92
93
94
# File 'lib/wwmd/viewstate/viewstate.rb', line 92

def from_yaml(yaml)
  @obj_queue = YAML.load(yaml)
end

#get_sym(str) ⇒ Object



8
9
10
# File 'lib/wwmd/viewstate/viewstate_from_xml.rb', line 8

def get_sym(str)
  str.split(":").last.gsub(/[A-Z]+/,'\1_\0').downcase[1..-1].gsub(/\Avs/,"").to_sym
end

#hashtable(t = nil) ⇒ Object



59
60
61
62
63
64
65
66
67
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 59

def hashtable(t=nil)
  len = read_7bit_encoded_int
  dlog(t,"len = #{len}")
  me = VSStubs::VSHashtable.new()
  (1..len).each do |i|
    me.add(self.deserialize_value,self.deserialize_value)
  end
  return me
end

#hybrid_dict(t = nil) ⇒ Object



69
70
71
72
73
74
75
76
77
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 69

def hybrid_dict(t=nil)
  len = read_7bit_encoded_int
  dlog(t,"len = #{len}")
  me = VSStubs::VSHybridDict.new()
  (1..len).each do |i|
    me.add(self.deserialize_value,self.deserialize_value)
  end
  return me
end

#indexed_string(t = nil) ⇒ Object



119
120
121
122
123
124
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 119

def indexed_string(t=nil)
  str = self.read_string
  @indexed_strings << str
  dlog(t,"idx = #{@indexed_strings.size - 1} val = #{str}")
  VSStubs::VSIndexedString.new(str)
end

#indexed_string_ref(t = nil) ⇒ Object



126
127
128
129
130
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 126

def indexed_string_ref(t=nil)
  ref = self.read_int
  dlog(t,"ref = #{ref} val = #{@indexed_strings[ref]}")
  VSStubs::VSIndexedStringRef.new(ref)
end

#int16(t = nil) ⇒ Object



151
152
153
154
155
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 151

def int16(t=nil)
  val = read_short
  dlog(t,val)
  VSStubs::VSInt16.new(val)
end

#int32(t = nil) ⇒ Object



157
158
159
160
161
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 157

def int32(t=nil)
  val = self.read_7bit_encoded_int
  dlog(t,val)
  VSStubs::VSInt32.new(val)
end

#int_enum(t = nil) ⇒ Object



27
28
29
30
31
32
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 27

def int_enum(t=nil)
  typeref,typeval = self.deserialize_type
  index = self.read_7bit_encoded_int
  dlog(t,"typeref = 0x#{typeref.to_s(16)} typeval = #{typeval} index = #{index}")
  VSStubs::VSIntEnum.new(typeref,typeval,index)
end

#known_color(t = nil) ⇒ Object



145
146
147
148
149
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 145

def known_color(t=nil)
  index = self.read_7bit_encoded_int
  dlog(t,"index = #{index.to_s(16)}")
  VSStubs::VSKnownColor.new(index)
end

#list(t = nil) ⇒ Object



102
103
104
105
106
107
108
109
110
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 102

def list(t=nil)
  len = read_7bit_encoded_int
  dlog(t,"len = #{len}")
  me = VSStubs::VSList.new()
  (1..len).each do |i|
    me.add(self.deserialize_value)
  end
  return me
end

#mac_enabled?Boolean

mac_enabled?

Returns:

  • (Boolean)


32
33
34
# File 'lib/wwmd/viewstate/viewstate.rb', line 32

def mac_enabled?
  return !@mac.nil?
end

#null(t = nil) ⇒ Object

VSStubs::VSValue types



194
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 194

def null(t=nil);        dlog(t,nil); return VSStubs::VSValue.new(t); end

#opcode(name, val) ⇒ Object



12
13
14
15
16
17
18
19
20
# File 'lib/wwmd/viewstate/viewstate_from_xml.rb', line 12

def opcode(name,val)
  sym = get_sym(name)
  if sym == :value
    ret = VIEWSTATE_TYPES.index(val.to_sym)
  else
    ret = VIEWSTATE_TYPES.index(sym)
  end
  ret
end

#pair(t = nil) ⇒ Object

complex types



4
5
6
7
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 4

def pair(t=nil)
  dlog t,"next = #{next_type}"
  VSStubs::VSPair.new(self.deserialize_value,self.deserialize_value)
end

#pp(*args) ⇒ Object

move pp due to to_xml returning self this is all for the sake of getting #search to work



87
88
89
90
# File 'lib/wwmd/viewstate/viewstate.rb', line 87

def pp(*args)
  return "Undefined" if !@xml
  @xml.pp(*args)
end

#search(*args) ⇒ Object

xpath search the nokogiri doc if we have one



80
81
82
83
# File 'lib/wwmd/viewstate/viewstate.rb', line 80

def search(*args)
  return "No XML" if !@ndoc
  @ndoc.search(*args)
end

#serialize(objs = nil, version = 2) ⇒ Object



54
55
56
57
58
59
60
# File 'lib/wwmd/viewstate/viewstate.rb', line 54

def serialize(objs=nil,version=2)
  @obj_queue = objs if objs
  @stack << "\xFF\x01"
  @stack << @obj_queue.first.serialize
  @stack << @mac if @mac
  return !self.stack.nil?
end

#serialize_hashtable(node) ⇒ Object



22
23
24
25
26
27
28
29
30
# File 'lib/wwmd/viewstate/viewstate_from_xml.rb', line 22

def serialize_hashtable(node)
  tstack = ""
  tstack << self.write_7bit_encoded_int(node['size'].to_i)
  node.children.each do |c|
    next if c.text?
    raise "Invalid Hashtable: got #{c.name}" if not c.name == "Pair"
  end
  tstack
end

#serialize_xml(node) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
# File 'lib/wwmd/viewstate/viewstate_from_xml.rb', line 104

def serialize_xml(node)
  begin
    write_node(node)
  rescue => e
    STDERR.puts "ERROR parsing node:\n#{node.to_s}"
    raise e
  end
  node.children.each do |c|
    serialize_xml(c)
  end
end

#single(t = nil) ⇒ Object



187
188
189
190
191
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 187

def single(t=nil)
    val = self.read_single
    dlog(t,val)
    VSStubs::VSSingle.new(val)
end

#sparse_array(t = nil) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 43

def sparse_array(t=nil)
  typeref,typeval = self.deserialize_type
  size  = read_7bit_encoded_int
  elems = read_7bit_encoded_int
  dlog(t,"typeref = 0x#{typeref.to_s(16)} typeval = #{typeval} size = #{size} elems = #{elems}")
  me = VSStubs::VSSparseArray.new(typeref,typeval,size,elems)
  if elems > size
    raise "Invalid sparse_array"
  end
  (1..elems).each do |i|
    idx = read_7bit_encoded_int
    me.add(idx,self.deserialize_value)
  end
  return me
end

#string(t = nil) ⇒ Object



132
133
134
135
136
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 132

def string(t=nil)
  str = self.read_string
  dlog(t,str)
  VSStubs::VSString.new(str)
end

#string_array(t = nil) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 90

def string_array(t=nil)
  len = read_7bit_encoded_int
  dlog(t,"len = #{len}")
  me = VSStubs::VSStringArray.new()
  (1..len).each do |i|
    str = self.read_string
    me.add(str)
    dlog(t,"string_array_elem: #{str}")
  end
  return me
end

#string_formatted(t = nil) ⇒ Object



20
21
22
23
24
25
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 20

def string_formatted(t=nil)
  typeref,typeval = self.deserialize_type
  str = self.read_string
  dlog(t,"typeref = 0x#{typeref.to_s(16)} typeval = #{typeval} string = #{str}")
  VSStubs::VSStringFormatted.new(typeref,typeval,str)
end

#to_xmlObject



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/wwmd/viewstate/viewstate.rb', line 62

def to_xml
  @xml = REXML::Document.new()
  header = REXML::Element.new("ViewState")
  header.add_attribute("version", @magic.b64e)
  header.add_attribute("version_string", @magic.hexify)
  header.add_element(@obj_queue.first.to_xml)
  if self.mac_enabled?
    max = REXML::Element.new("Mac")
    max.add_attribute("encoding","hexify")
    max.add_text(@mac.hexify)
    header.add_element(max)
  end
  @xml.add_element(header)
  @ndoc = Nokogiri::XML.parse(@xml.to_s)
  self
end

#to_yamlObject



96
97
98
# File 'lib/wwmd/viewstate/viewstate.rb', line 96

def to_yaml
  @obj_queue.to_yaml
end

#triplet(t = nil) ⇒ Object



9
10
11
12
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 9

def triplet(t=nil)
  dlog t,"next = #{next_type}"
  VSStubs::VSTriplet.new(self.deserialize_value,self.deserialize_value,self.deserialize_value)
end

#type(t = nil) ⇒ Object



14
15
16
17
18
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 14

def type(t=nil)
  typeref,typeval = self.deserialize_type
  dlog(t,"typeref = 0x#{typeref.to_s(16)} typeval = #{typeval}")
  VSStubs::VSType.new(typeref,typeval)
end

#unit(t = nil) ⇒ Object



112
113
114
115
116
117
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 112

def unit(t=nil)
  s1 = read_double
  s2 = read_int32
  dlog(t,"#{s1.to_s(16).rjust(16,"0")},#{s2.to_s(16).rjust(8,"0")}")
  VSStubs::VSUnit.new(s1,s2)
end

#write_node(node) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/wwmd/viewstate/viewstate_from_xml.rb', line 48

def write_node(node)
  return false if node.text?
  tstack = ""
  # this is a hack to get sparse_array to work
  return false if ["Pair","Key","Value"].include?(node.name) # skip and fall through
  if ["Index","Size","Elements"].include?(node.name)
    @xmlstack << self.write_7bit_encoded_int(node.inner_text.to_i)
    return false
  end
  if node.name == "Mac"
    @xmlstack << decode_text(node)
    return false
  end
  # end hack
  flag = true # begin; sillyness; rescue => me; end
  case get_sym(node.name)
    when :pair, :triplet, :value, :sparse_array, :type, :string_formatted
    when :int_enum, :known_color, :int32
      tstack << self.write_7bit_encoded_int(node.inner_text.to_i)
    when :int16
      tstack << self.write_short(node.inner_text.to_i)
    when :byte, :char, :indexed_string_ref
      tstack << self.write_byte(node.inner_text.to_i)
    when :color, :single
      tstack << self.write_int32(node.inner_text.to_i)
    when :double, :date_time
      tstack << self.write_double(node.inner_text.to_i)
    when :unit
      tstack << self.write_double(node['dword'].to_i)
      tstack << self.write_single(node['word'].to_i)
    when :list, :string_array, :array
      tstack << self.write_7bit_encoded_int(node['size'].to_i)
    when :string, :indexed_string, :binary_serialized
      flag = false if ([:string_array,:string_formatted].include?(get_sym(node.parent.name)))
      # get encoding
      str = decode_text(node)
      tstack << self.write_7bit_encoded_int(str.size)
      tstack << str
    when :hashtable, :hybrid_dict
      tstack << serialize_hashtable(node)
    else
      raise "Invalid Node:\n#{node.name}"
  end

  # [flag] is a hack to get around string_array and string_formatted emitting opcodes
  @xmlstack << self.write_byte(opcode(node.name,node.inner_text)) if flag
  if node.has_attribute?("typeref")
    if node['typeref'].to_i == 0x2b
      @xmlstack << self.serialize_type(node['typeref'].to_i,node['typeval'].to_i)
    else
      @xmlstack << self.serialize_type(node['typeref'].to_i,node['typeval'])
    end
  end
  @xmlstack << tstack
end

#zeroint32(t = nil) ⇒ Object



196
# File 'lib/wwmd/viewstate/viewstate_deserializer_methods.rb', line 196

def zeroint32(t=nil);   dlog(t,nil); return VSStubs::VSValue.new(t); end