indis-core 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .rbx
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --color
2
2
  --format progress
3
+ -rspec_helper
@@ -2,4 +2,5 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
4
  - jruby-19mode
5
+ - rbx-19mode
5
6
  gemfile: Gemfile.ci
@@ -0,0 +1,50 @@
1
+ ##############################################################################
2
+ # Indis framework #
3
+ # Copyright (C) 2012 Vladimir "Farcaller" Pouzanov <farcaller@gmail.com> #
4
+ # #
5
+ # This program is free software: you can redistribute it and/or modify #
6
+ # it under the terms of the GNU General Public License as published by #
7
+ # the Free Software Foundation, either version 3 of the License, or #
8
+ # (at your option) any later version. #
9
+ # #
10
+ # This program is distributed in the hope that it will be useful, #
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of #
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
13
+ # GNU General Public License for more details. #
14
+ # #
15
+ # You should have received a copy of the GNU General Public License #
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>. #
17
+ ##############################################################################
18
+
19
+ module Indis
20
+
21
+ # BinaryArchitecture manages all known architectures and provides support
22
+ # for resolving the correct class for named architecture
23
+ module BinaryArchitecture
24
+
25
+ def self.known_archs
26
+ fmt = {}
27
+ self.constants.each do |c|
28
+ e = const_get(c)
29
+ fmt[e.name] = e if e.is_a?(Class) && e.superclass == Architecture
30
+ end
31
+ fmt
32
+ end
33
+
34
+ # Base class for any binary architecture
35
+ class Architecture
36
+ # Basic constructor takes care of storing the target
37
+ def initialize(target)
38
+ @target = target
39
+ end
40
+
41
+ # @abstract Returns the format magic bytes.
42
+ #
43
+ # @return [Symbol] symbolicated name of the architecture
44
+ def self.name
45
+ raise RuntimeError, "#name not implemented in architecture #{self.class}"
46
+ end
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,54 @@
1
+ ##############################################################################
2
+ # Indis framework #
3
+ # Copyright (C) 2012 Vladimir "Farcaller" Pouzanov <farcaller@gmail.com> #
4
+ # #
5
+ # This program is free software: you can redistribute it and/or modify #
6
+ # it under the terms of the GNU General Public License as published by #
7
+ # the Free Software Foundation, either version 3 of the License, or #
8
+ # (at your option) any later version. #
9
+ # #
10
+ # This program is distributed in the hope that it will be useful, #
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of #
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
13
+ # GNU General Public License for more details. #
14
+ # #
15
+ # You should have received a copy of the GNU General Public License #
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>. #
17
+ ##############################################################################
18
+
19
+ # BinaryopsFixnum is a lightweight BinaryopsString, a few methods extending
20
+ # Fixnum with enough operations so that it's usable in bit calculations.
21
+ class Fixnum
22
+ def bitlen=(bitlen)
23
+ @bitlen = bitlen
24
+ end
25
+
26
+ def bitlen
27
+ @bitlen ||= self.to_s(2).length
28
+ end
29
+
30
+ def set_bitlen(i)
31
+ @bitlen = i
32
+ self
33
+ end
34
+
35
+ def msb
36
+ self >> (self.bitlen-1)
37
+ end
38
+
39
+ def to_signed
40
+ if msb == 1
41
+ - ((1 << @bitlen) - self)
42
+ else
43
+ self
44
+ end
45
+ end
46
+
47
+ alias :old_range :[]
48
+
49
+ def [](range)
50
+ return old_range(range) unless range.is_a?(Range)
51
+ raise ArgumentError, "Only inclusive ranges are supported" if range.exclude_end?
52
+ (self >> range.begin) & ((1 << (range.end-range.begin+1)) - 1)
53
+ end
54
+ end
@@ -0,0 +1,52 @@
1
+ ##############################################################################
2
+ # Indis framework #
3
+ # Copyright (C) 2012 Vladimir "Farcaller" Pouzanov <farcaller@gmail.com> #
4
+ # #
5
+ # This program is free software: you can redistribute it and/or modify #
6
+ # it under the terms of the GNU General Public License as published by #
7
+ # the Free Software Foundation, either version 3 of the License, or #
8
+ # (at your option) any later version. #
9
+ # #
10
+ # This program is distributed in the hope that it will be useful, #
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of #
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
13
+ # GNU General Public License for more details. #
14
+ # #
15
+ # You should have received a copy of the GNU General Public License #
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>. #
17
+ ##############################################################################
18
+
19
+ require 'indis-core/entity'
20
+
21
+ module Indis
22
+
23
+ class CStringEntity < Entity
24
+ attr_reader :value # @return [String] the value of entity
25
+
26
+ # @param [Fixnum] ofs virtual address
27
+ # @param [Indus::VMMap] vmmap map of the target to load value from
28
+ def initialize(ofs, vmmap)
29
+ super ofs
30
+
31
+ @value = ''
32
+ addr = ofs
33
+ begin
34
+ c = vmmap.byte_at(addr)
35
+ @value += c.chr
36
+ addr += 1
37
+ end while c != 0
38
+
39
+ @size = @value.length
40
+ end
41
+
42
+ def to_s
43
+ "DCB\t\"#{@value[0...-1]}\",0"
44
+ end
45
+
46
+ def to_a
47
+ ['DCB', "\"#{@value[0...-1]}\",0"]
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -59,6 +59,10 @@ module Indis
59
59
  def to_s
60
60
  "#{NAMED_TYPE[kind]}\t#{sprintf("%0#{@size*2}X", @value)}"
61
61
  end
62
+
63
+ def to_a
64
+ [NAMED_TYPE[kind], sprintf("%0#{@size*2}X", @value)]
65
+ end
62
66
  end
63
67
 
64
68
  end
@@ -34,7 +34,7 @@ module Indis
34
34
  end
35
35
 
36
36
  def to_vmrange
37
- @vmaddr..(@vmaddr+@vmsize)
37
+ @vmaddr...(@vmaddr+@vmsize)
38
38
  end
39
39
 
40
40
  def bytes
@@ -63,7 +63,7 @@ module Indis
63
63
  #
64
64
  # @return [Range] the range of all addresses
65
65
  def to_vmrange
66
- @vmaddr..(@vmaddr+@vmsize)
66
+ @vmaddr...(@vmaddr+@vmsize)
67
67
  end
68
68
 
69
69
  private
@@ -19,18 +19,17 @@
19
19
  module Indis
20
20
 
21
21
  class Symbol
22
- attr_reader :name, :section, :format_sym, :image, :vmaddr
22
+ attr_reader :name, :section, :image, :vmaddr, :type
23
23
 
24
- def initialize(name, section, image, vmaddr, format_sym)
24
+ def initialize(name, section, image, vmaddr)
25
25
  @name = name
26
26
  @section = section
27
27
  @image = image
28
- @format_sym = format_sym
29
28
  @vmaddr = vmaddr
30
29
  end
31
30
 
32
31
  def to_s
33
- "#<Indis::Symbol #{@name} at #{@vmaddr.to_s 16}>"
32
+ "#<#{self.class} #{@name} at #{@vmaddr.to_s 16}>"
34
33
  end
35
34
  end
36
35
 
@@ -18,6 +18,7 @@
18
18
 
19
19
  require 'stringio'
20
20
  require 'indis-core/binary_format'
21
+ require 'indis-core/binary_architecture'
21
22
  require 'indis-core/vmmap'
22
23
 
23
24
  module Indis
@@ -29,6 +30,8 @@ module Indis
29
30
 
30
31
  attr_reader :format # @return [Indis::BinaryFormat::Format] binary format of the target
31
32
 
33
+ attr_reader :architecture # @return [Indis::BinaryArchitecture::Arcitecture] binary architecture of the target
34
+
32
35
  attr_reader :vmmap # @return [Indis::VMMap] virtual memory map
33
36
 
34
37
  attr_accessor :segments # @return [Array<Indis::Segment>] list of all processed {Indis::Segment segments}
@@ -61,6 +64,10 @@ module Indis
61
64
  @format = @format_class.new(self, @io)
62
65
  @format_class = nil
63
66
 
67
+ archClass = BinaryArchitecture.known_archs[@format.architecture]
68
+ raise RuntimeError, "Architecture not defined" unless archClass
69
+ @architecture = archClass.new(self)
70
+
64
71
  @vmmap = VMMap.new(self)
65
72
 
66
73
  @format_load_complete = true
@@ -107,7 +114,9 @@ module Indis
107
114
  def resolve_symbol_at_address(vmaddr)
108
115
  s = @symbols.find { |sym| sym.vmaddr == vmaddr }
109
116
  return s if s
110
- return @format.resolve_symbol_at_address(vmaddr) if @format.respond_to?(:resolve_symbol_at_address)
117
+ s = @format.resolve_symbol_at_address(vmaddr) if @format.respond_to?(:resolve_symbol_at_address)
118
+ @symbols << s if s
119
+ s
111
120
  end
112
121
 
113
122
  private
@@ -17,5 +17,5 @@
17
17
  ##############################################################################
18
18
 
19
19
  module Indis
20
- VERSION = "0.1.3"
20
+ VERSION = "0.1.4"
21
21
  end
@@ -115,25 +115,27 @@ module Indis
115
115
  def [](range)
116
116
  return entity_at(range) if range.is_a?(Fixnum)
117
117
 
118
- raise ArgumentError unless range.is_a?(Range)
118
+ raise ArgumentError, "Unknown argument type #{range.class}" unless range.is_a?(Range)
119
119
  seg = segment_at(range.begin)
120
- raise ArgumentError unless seg
121
- raise ArgumentError unless seg == segment_at(range.max)
120
+ raise ArgumentError, "No segment mapped at #{range.begin}" unless seg
121
+ range_max = range.exclude_end? ? range.last-1 : range.last
122
+ raise ArgumentError, "Segment #{seg} at #{range.begin}, but segment #{segment_at(range_max)} at #{range.end}" unless seg == segment_at(range_max)
122
123
 
123
- a = []
124
+ a = Array.new(range_max - range.begin + 1)
124
125
  ofs = range.begin
126
+ range_begin = range.begin
127
+ seg_vmaddr = seg.vmaddr
125
128
 
126
129
  begin
127
130
  b = @blocks[ofs]
128
131
  if b
129
- a << b
130
- (b.size-1).times { a << nil }
132
+ a[ofs-range_begin] = b
131
133
  ofs += b.size
132
134
  else
133
- a << seg.bytes[ofs-seg.vmaddr].ord
135
+ a[ofs-range_begin] = seg.bytes[ofs-seg_vmaddr].ord
134
136
  ofs += 1
135
137
  end
136
- end while ofs <= range.max
138
+ end while ofs <= range_max
137
139
  a
138
140
  end
139
141
  end
@@ -0,0 +1,12 @@
1
+ require 'indis-core/cstring_entity'
2
+
3
+ describe Indis::CStringEntity do
4
+ it "should load its value from vmmap" do
5
+ str = "hello\0world".unpack('C*')
6
+ map = double('VMMap')
7
+ map.should_receive(:byte_at) { |i| str[i] }.exactly(6).times
8
+ e = Indis::CStringEntity.new(0, map)
9
+ e.to_s.should == "DCB\t\"hello\",0"
10
+ e.value.should == "hello\x0"
11
+ end
12
+ end
@@ -3,7 +3,7 @@ require 'indis-core/section'
3
3
  describe Indis::Section do
4
4
  it "should provide a correct range for its vm region" do
5
5
  sect = Indis::Section.new(double('Segment'), '__text', 0x4096, 120, 0, :undef, [])
6
- sect.to_vmrange.should == (0x4096..0x410e)
6
+ sect.to_vmrange.should == (0x4096...0x410e)
7
7
  end
8
8
 
9
9
  it "should provide bytes value from segment based on io offset" do
@@ -3,7 +3,7 @@ require 'indis-core/segment'
3
3
  describe Indis::Segment do
4
4
  it "should provide a correct range for its vm region" do
5
5
  seg = Indis::Segment.new(double('Target'), '__TEXT', 0x4096, 120, 0, '')
6
- seg.to_vmrange.should == (0x4096..0x410e)
6
+ seg.to_vmrange.should == (0x4096...0x410e)
7
7
  end
8
8
 
9
9
  it "should provide bytes value based on io offset" do
@@ -1,12 +1,24 @@
1
1
  require 'indis-core/target'
2
2
 
3
+ def macho_format_cls_double
4
+ double('MachO Class', magic: 0xfeedface, name: 'Mach-O',
5
+ new: double('MachO', architecture: :test)
6
+ )
7
+ end
8
+
9
+ module Indis; module BinaryArchitecture;
10
+ class TestArch < Architecture
11
+ def self.name; :test; end
12
+ end
13
+ end; end
14
+
3
15
  describe Indis::Target do
4
16
  it "should require an existing file to operate" do
5
17
  expect { Indis::Target.new("qwerty") }.to raise_error
6
18
  end
7
19
 
8
20
  it "should load file for known format" do
9
- fmt = double('MachO Class', magic: 0xfeedface, name: 'Mach-O', new: double('MachO'))
21
+ fmt = macho_format_cls_double
10
22
  Indis::BinaryFormat.stub(:known_formats).and_return([fmt])
11
23
  t = Indis::Target.new("spec/fixtures/single-object.o")
12
24
  t.load
@@ -14,12 +26,21 @@ describe Indis::Target do
14
26
  t.format.should_not be_nil
15
27
  end
16
28
 
29
+ it "should have an architecture set up after loading" do
30
+ fmt = macho_format_cls_double
31
+ Indis::BinaryFormat.stub(:known_formats).and_return([fmt])
32
+ t = Indis::Target.new("spec/fixtures/single-object.o")
33
+ t.architecture.should be_nil
34
+ t.load
35
+ t.architecture.should_not be_nil
36
+ end
37
+
17
38
  it "should raise if there is no known format to process binary" do
18
39
  expect { Indis::Target.new("spec/fixtures/single-object.o") }.to raise_error(RuntimeError)
19
40
  end
20
41
 
21
42
  it "should trigger load event" do
22
- fmt = double('MachO Class', magic: 0xfeedface, name: 'Mach-O', new: double('MachO'))
43
+ fmt = macho_format_cls_double
23
44
  Indis::BinaryFormat.stub(:known_formats).and_return([fmt])
24
45
  t = Indis::Target.new("spec/fixtures/single-object.o")
25
46
 
@@ -32,7 +53,7 @@ describe Indis::Target do
32
53
  end
33
54
 
34
55
  it "should queue up events that happen before load" do
35
- fmt = double('MachO Class', magic: 0xfeedface, name: 'Mach-O', new: double('MachO'))
56
+ fmt = macho_format_cls_double
36
57
  Indis::BinaryFormat.stub(:known_formats).and_return([fmt])
37
58
  t = Indis::Target.new("spec/fixtures/single-object.o")
38
59
 
@@ -48,7 +69,7 @@ describe Indis::Target do
48
69
  end
49
70
 
50
71
  it "should pass arguments to event subscriptions" do
51
- fmt = double('MachO Class', magic: 0xfeedface, name: 'Mach-O', new: double('MachO'))
72
+ fmt = macho_format_cls_double
52
73
  Indis::BinaryFormat.stub(:known_formats).and_return([fmt])
53
74
  t = Indis::Target.new("spec/fixtures/single-object.o")
54
75
  t.load
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: indis-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-18 00:00:00.000000000 Z
12
+ date: 2012-05-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -44,8 +44,11 @@ files:
44
44
  - Rakefile
45
45
  - indis-core.gemspec
46
46
  - lib/indis-core.rb
47
+ - lib/indis-core/binary_architecture.rb
47
48
  - lib/indis-core/binary_format.rb
49
+ - lib/indis-core/binaryops_fixnum.rb
48
50
  - lib/indis-core/binaryops_string.rb
51
+ - lib/indis-core/cstring_entity.rb
49
52
  - lib/indis-core/data_entity.rb
50
53
  - lib/indis-core/entity.rb
51
54
  - lib/indis-core/section.rb
@@ -57,6 +60,7 @@ files:
57
60
  - spec/fixtures/single-object.o
58
61
  - spec/indis-core/binary_format_spec.rb
59
62
  - spec/indis-core/binaryops_string_spec.rb
63
+ - spec/indis-core/cstring_entity_spec.rb
60
64
  - spec/indis-core/data_entity_spec.rb
61
65
  - spec/indis-core/section_spec.rb
62
66
  - spec/indis-core/segment_spec.rb
@@ -93,6 +97,7 @@ test_files:
93
97
  - spec/fixtures/single-object.o
94
98
  - spec/indis-core/binary_format_spec.rb
95
99
  - spec/indis-core/binaryops_string_spec.rb
100
+ - spec/indis-core/cstring_entity_spec.rb
96
101
  - spec/indis-core/data_entity_spec.rb
97
102
  - spec/indis-core/section_spec.rb
98
103
  - spec/indis-core/segment_spec.rb