indis-core 0.1.0

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/README.md ADDED
@@ -0,0 +1,5 @@
1
+ [![Build Status](https://secure.travis-ci.org/indis/indis-core.png?branch=master)](http://travis-ci.org/indis/indis-core)
2
+
3
+ # Indis::Core
4
+
5
+ This is the base of indis framework, core classes that deal with target image load and analysis.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require "bundler/gem_tasks"
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ require 'rspec/core/rake_task'
7
+ RSpec::Core::RakeTask.new('spec')
8
+
9
+ task :default => :spec
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/indis-core/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Vladimir Pouzanov"]
6
+ gem.email = ["farcaller@gmail.com"]
7
+ gem.description = "Core components of indis, the intelligent disassembler framework"
8
+ gem.summary = "Core indis components"
9
+ gem.homepage = "http://www.indis.org/"
10
+ gem.license = "GPL-3"
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.name = "indis-core"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = Indis::VERSION
18
+
19
+ gem.add_development_dependency 'rspec'
20
+ end
data/lib/indis-core.rb ADDED
@@ -0,0 +1,22 @@
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/version'
20
+
21
+ module Indis
22
+ end
@@ -0,0 +1,61 @@
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
+ # BinaryFormat manages a set of known binary formats and provides support
22
+ # for guessing the correct format for target binary.
23
+ module BinaryFormat
24
+
25
+ # Returns a list of all known binary formats.
26
+ #
27
+ # @return [Array] all known binary formats.
28
+ def self.known_formats
29
+ fmt = []
30
+ self.constants.each do |c|
31
+ e = const_get(c)
32
+ fmt << e if e.is_a?(Class) && e.superclass == Format
33
+ end
34
+ fmt
35
+ end
36
+
37
+ # Base class for any binary format.
38
+ class Format
39
+ # Basic constructor takes care of storing the target and io stream.
40
+ def initialize(target, io)
41
+ @target = target
42
+ @io = io
43
+ end
44
+
45
+ # @abstract Returns the format magic bytes.
46
+ #
47
+ # @return [Fixnum] Magic bytes that are checked against the first bytes in binary.
48
+ def self.magic
49
+ raise RuntimeError
50
+ end
51
+
52
+ # @abstract Returns the human-readable format name.
53
+ #
54
+ # @return [String] Human-readable format name.
55
+ def self.name
56
+ raise RuntimeError
57
+ end
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,64 @@
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
+ # DataEntity represens "data bytes" that are directly used e.g. in a load
24
+ # to register instruction. There are four sizes of data: 8, 16, 32 and 64
25
+ # bits long, namely +byte+, +word+, +dword+ and +qword+
26
+ class DataEntity < Entity
27
+ KIND = {
28
+ 1 => :byte,
29
+ 2 => :word,
30
+ 4 => :dword,
31
+ 8 => :qword,
32
+ }
33
+
34
+ NAMED_TYPE = {
35
+ byte: 'DCB',
36
+ word: 'DCW',
37
+ dword: 'DCD',
38
+ qword: 'DCQ'
39
+ }
40
+
41
+ attr_reader :value # @return [Fixnum] the value of entity
42
+
43
+ # @param [Fixnum] ofs virtual address
44
+ # @param [Fixnum] size entity size in bytes
45
+ # @param [Indus::VMMap] vmmap map of the target to load value from
46
+ # @raise [AttributeError] if the size is not one of the known values
47
+ def initialize(ofs, size, vmmap)
48
+ raise ArgumentError, "Unaligned size" unless KIND[size]
49
+ super ofs
50
+ @size = size
51
+ @value = vmmap.bytes_at(ofs, size).reverse_each.reduce(0) { |v, i| (v << 8) + i }
52
+ end
53
+
54
+ # @return [KIND] entity kind
55
+ def kind
56
+ KIND[@size]
57
+ end
58
+
59
+ def to_s
60
+ "#{NAMED_TYPE[kind]}\t#{sprintf("%0#{@size*2}X", @value)}"
61
+ end
62
+ end
63
+
64
+ end
@@ -0,0 +1,43 @@
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
+ # Entity represens an object mapped to some given bytes in the traget's
22
+ # virtual address space
23
+ class Entity
24
+ attr_reader :vmaddr # @return [Fixnum] virtaul address of the entity
25
+
26
+ # @abstract You must provide @size value in a subclass
27
+ # @return [Fixnum] entity size in bytes
28
+ attr_reader :size
29
+
30
+ attr_reader :tags # @return [Hash] cross-references and additional attributes of entity
31
+
32
+ def initialize(ofs)
33
+ @vmaddr = ofs
34
+ @tags = {}
35
+ end
36
+
37
+ def unmap
38
+ # TODO: Reverse unmap tags
39
+ @tags = nil
40
+ end
41
+ end
42
+
43
+ end
@@ -0,0 +1,44 @@
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
+ class Section
22
+ attr_reader :name, :segment
23
+ attr_reader :vmaddr, :vmsize, :bytes
24
+
25
+ def initialize(seg, name, vmaddr, vmsize, iooff)
26
+ @segment = seg
27
+ @name = name
28
+ @vmaddr = vmaddr
29
+ @vmsize = vmsize
30
+ @iooff = iooff
31
+ end
32
+
33
+ def to_vmrange
34
+ @vmaddr..(@vmaddr+@vmsize)
35
+ end
36
+
37
+ def bytes
38
+ s = @iooff - @segment.iooff
39
+ e = s + @vmsize
40
+ @segment.bytes[s...e]
41
+ end
42
+ end
43
+
44
+ end
@@ -0,0 +1,75 @@
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
+ # A segment describes one given segment contained in the target binary.
22
+ # Segment's virtual size might be different from physical (stored in file),
23
+ # in this case the data is padded with zeroes
24
+ #
25
+ # @note this class is heavily based on Mach-O
26
+ class Segment
27
+ # Contains a list of current segment sections
28
+ # @return [Array]
29
+ attr_reader :sections
30
+
31
+ attr_reader :target # @return [Indis::Target] owning target
32
+
33
+ attr_reader :name # @return [String] segment name
34
+
35
+ attr_reader :vmaddr # @return [Fixnum] starting virtual address
36
+
37
+ attr_reader :vmsize # @return [Fixnum] segment size
38
+
39
+ # The whole (zero-padded if required) bytes string for a segment
40
+ # @return [String]
41
+ attr_reader :bytes
42
+
43
+ attr_reader :iooff # @return [Fixnum] offset from the beginning of of file to segment data
44
+
45
+ # @param [Indis::Target] target the target containing a segment
46
+ # @param [String] name segment name
47
+ # @param [Fixnum] vmaddr starting virtual address
48
+ # @param [Fixnum] vmsize size (in bytes)
49
+ # @param [Fixnum] iooff offset from the beginning of of file to segment data
50
+ # @param [String] bytes known data bytes (loaded from binary)
51
+ def initialize(target, name, vmaddr, vmsize, iooff, bytes)
52
+ @target = target
53
+ @name = name
54
+ @sections = []
55
+
56
+ @vmaddr = vmaddr
57
+ @vmsize = vmsize
58
+ @iooff = iooff
59
+ @bytes = pad_bytes(bytes)
60
+ end
61
+
62
+ # Constructs a Range of virtual addresses used by segment
63
+ #
64
+ # @return [Range] the range of all addresses
65
+ def to_vmrange
66
+ @vmaddr..(@vmaddr+@vmsize)
67
+ end
68
+
69
+ private
70
+ def pad_bytes(bytes)
71
+ bytes + ("\x0" * (@vmsize - bytes.length))
72
+ end
73
+ end
74
+
75
+ end
@@ -0,0 +1,33 @@
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
+ class Symbol
22
+ attr_reader :name, :section, :format_sym, :image, :vmaddr
23
+
24
+ def initialize(name, section, image, vmaddr, format_sym)
25
+ @name = name
26
+ @section = section
27
+ @image = image
28
+ @format_sym = format_sym
29
+ @vmaddr = vmaddr
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,68 @@
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/binary_format'
20
+ require 'indis-core/vmmap'
21
+
22
+ module Indis
23
+
24
+ # The main entry point for indis. Target describes a given binary, performs
25
+ # format matching, loading the binary into memory and primary processing.
26
+ class Target
27
+ attr_reader :io # @return [IO] IO object for target binary
28
+
29
+ attr_reader :format # @return [Indis::BinaryFormat::Format] binary format of the target
30
+
31
+ attr_reader :vmmap # @return [Indis::VMMap] virtual memory map
32
+
33
+ attr_accessor :segments # @return [Array] list of all processed {Indis::Segment segments}
34
+
35
+ attr_accessor :symbols # @return [Array] list of all processed {Indis::Symbol symbols}
36
+
37
+ # @param [String] filename target binary file name
38
+ # @raise [AttributeError] if the file does not exist
39
+ # @raise [RuntimeError] if there is no known format for magic or there are several matching formats
40
+ def initialize(filename)
41
+ raise AttributeError, "File does not exist" unless FileTest.file?(filename)
42
+ @filename = filename
43
+ @io = StringIO.new(File.open(filename).read().force_encoding('BINARY'))
44
+
45
+ magic = @io.read(4).unpack('V')[0]
46
+ @io.seek(-4, IO::SEEK_CUR)
47
+
48
+ fmts = BinaryFormat.known_formats.map { |f| f if f.magic == magic }.compact
49
+
50
+ raise RuntimeError, "Unknown format for magic #{magic.to_s(16)}" if fmts.length == 0
51
+ raise RuntimeError, "Several possible formats: #{fmts}" if fmts.length > 1
52
+
53
+ @format = fmts.first.new(self, @io)
54
+
55
+ @vmmap = VMMap.new(self)
56
+ end
57
+
58
+ # A target can consist of several other targets (e.g. fat mach-o). In such
59
+ # a case the target is +meta+. It does not have any segments, sections or vmmap,
60
+ # but it has one or several subtargets.
61
+ # @todo implement meta targets
62
+ # @return True if the target is a meta target
63
+ def meta?
64
+ @subtargets && @subtargets.length > 0
65
+ end
66
+ end
67
+
68
+ end