indis-core 0.1.3 → 0.1.4

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.
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