one_gadget 1.6.2 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +141 -94
  3. data/bin/one_gadget +4 -3
  4. data/lib/one_gadget/abi.rb +42 -22
  5. data/lib/one_gadget/builds/libc-2.19-397c84e78c14cbffba39a48184db482211df9fb3.rb +38 -0
  6. data/lib/one_gadget/builds/libc-2.19-4eda8ff01be3fba1c7bdd442a8690c3dc7397b6a.rb +44 -0
  7. data/lib/one_gadget/builds/libc-2.19-509ee0c9616c4c3ed81951501a8950e1f529bbff.rb +38 -0
  8. data/lib/one_gadget/builds/libc-2.19-6aff6d091954955fe931bb720a17708513aabda7.rb +41 -0
  9. data/lib/one_gadget/builds/libc-2.19-8d935a42f2f2a1149aa52d3098b32b1d5012cb67.rb +38 -0
  10. data/lib/one_gadget/builds/libc-2.19-a820f849dda0b99ed06dd59bb88404969b3a5f88.rb +41 -0
  11. data/lib/one_gadget/builds/libc-2.19-d9a10b8ef90300628dd0a3a535106967714d7328.rb +47 -0
  12. data/lib/one_gadget/builds/libc-2.21-169a143e9c40cfd9d09695333e45fd67743cd2d6.rb +37 -0
  13. data/lib/one_gadget/builds/libc-2.21-2e9718e58257bda1dc0d751665a3ee233bf606f2.rb +37 -0
  14. data/lib/one_gadget/builds/libc-2.23-29e38445a740bba5a77b86691e3c51a7e48dc79b.rb +46 -0
  15. data/lib/one_gadget/builds/libc-2.23-679ad41a6bc9e718a11a36cf9879cac97197e565.rb +37 -0
  16. data/lib/one_gadget/builds/libc-2.23-b5381a457906d279073822a5ceb24c4bfef94ddb.rb +37 -0
  17. data/lib/one_gadget/builds/libc-2.23-d10fbfd9328f5ffaca50aa93562cb3bfb618fbcc.rb +43 -0
  18. data/lib/one_gadget/builds/libc-2.23-dd5192a769e33ed6ca68a6ab5740ff9e8ec678a7.rb +46 -0
  19. data/lib/one_gadget/builds/libc-2.24-1f7bdfb9a24714835cee6e6597ea7aa782821371.rb +46 -0
  20. data/lib/one_gadget/builds/libc-2.24-206b2bb216b6cdb6b1be565a6fcd29f3862db060.rb +49 -0
  21. data/lib/one_gadget/builds/libc-2.24-26e84118fee5788eb5d8dda66b7e7f029d2c7800.rb +43 -0
  22. data/lib/one_gadget/builds/libc-2.24-43adbb1e7368c94fba1ba9020d8ef0808bff5bc4.rb +37 -0
  23. data/lib/one_gadget/builds/libc-2.24-497931f8d2346a6d0e300a65d8fc6106c6c88c15.rb +37 -0
  24. data/lib/one_gadget/builds/libc-2.24-4fa7401566d6b3e2c7ee5df3b4d85a01f85b595c.rb +37 -0
  25. data/lib/one_gadget/builds/libc-2.24-568d20b7e0d08bc282fb42ae405c7054e4209ede.rb +37 -0
  26. data/lib/one_gadget/builds/libc-2.24-5b72576ff331e93852355123afecdec70fd247b5.rb +49 -0
  27. data/lib/one_gadget/builds/libc-2.24-a4c01d397b6584f7040ef266b16a5d4da0b7a087.rb +43 -0
  28. data/lib/one_gadget/builds/libc-2.24-b81a06f0ac241c4aa8860602d9abcc903adbb675.rb +46 -0
  29. data/lib/one_gadget/builds/libc-2.24-be6d412ecc4816c46eb49e750b02f714a9131c4e.rb +46 -0
  30. data/lib/one_gadget/builds/libc-2.24-d2a8a8ac188a6c3bafa4813a3d2789240ee49489.rb +46 -0
  31. data/lib/one_gadget/builds/libc-2.24-dff06414a29b97b865ef938e06a7751fe8b1b2d0.rb +46 -0
  32. data/lib/one_gadget/builds/libc-2.24-e5dc6c0caa39828fa10ed37e642723a581acdb6d.rb +37 -0
  33. data/lib/one_gadget/builds/libc-2.24-fd0655c4d2073eda4235084e1d0e558f0251be8a.rb +37 -0
  34. data/lib/one_gadget/builds/libc-2.25-e5eb6347f0629b37bf698200022a683b7efb10ed.rb +37 -0
  35. data/lib/one_gadget/builds/libc-2.26-1c39b3b3faa2a2cbb0fa0b6845b29332562262d3.rb +37 -0
  36. data/lib/one_gadget/builds/libc-2.26-499b381aaf00ce85ee5d4a12770ea369b30d2a41.rb +52 -0
  37. data/lib/one_gadget/builds/libc-2.26-4cc84abfe1fd26a485fc2b1b954c281ce9d358fd.rb +52 -0
  38. data/lib/one_gadget/builds/libc-2.26-4ea852c9d6a5084b8b58509b3b3d37d3d8cddb90.rb +52 -0
  39. data/lib/one_gadget/builds/libc-2.26-6d2b609f0c8e7b338f767b08c5ac712fac809d31.rb +49 -0
  40. data/lib/one_gadget/builds/libc-2.26-fb587bc4429e7d1b0de31a3b9ee8ae78ee797eb0.rb +37 -0
  41. data/lib/one_gadget/builds/libc-2.27-0e188ec5f09c187a7a92784d4b97aa251b15a93c.rb +47 -0
  42. data/lib/one_gadget/builds/libc-2.27-53f40c1d2f3739ae017dcdcef1a17314786e3709.rb +38 -0
  43. data/lib/one_gadget/builds/libc-2.27-9dd0bb57f81671704475d1e5163405f7b4d4b454.rb +32 -0
  44. data/lib/one_gadget/builds/libc-2.28-44f5a3efb0e5733fa9d97e690cb36cd4c682bcdb.rb +41 -0
  45. data/lib/one_gadget/builds/libc-2.28-5784a31a1c26f6d2157e585205ebb63dd19ff90f.rb +41 -0
  46. data/lib/one_gadget/builds/libc-2.28-5b157f49586a3ca84d55837f97ff466767dd3445.rb +38 -0
  47. data/lib/one_gadget/builds/libc-2.28-6ee9454b96efa9e343f9e8105f2fa4529265ea05.rb +38 -0
  48. data/lib/one_gadget/emulators/aarch64.rb +176 -0
  49. data/lib/one_gadget/emulators/amd64.rb +1 -1
  50. data/lib/one_gadget/emulators/i386.rb +1 -1
  51. data/lib/one_gadget/emulators/instruction.rb +36 -7
  52. data/lib/one_gadget/emulators/lambda.rb +36 -25
  53. data/lib/one_gadget/emulators/processor.rb +94 -6
  54. data/lib/one_gadget/emulators/x86.rb +43 -95
  55. data/lib/one_gadget/error.rb +15 -3
  56. data/lib/one_gadget/fetcher.rb +3 -1
  57. data/lib/one_gadget/fetchers/aarch64.rb +41 -0
  58. data/lib/one_gadget/fetchers/amd64.rb +4 -2
  59. data/lib/one_gadget/fetchers/base.rb +35 -11
  60. data/lib/one_gadget/fetchers/i386.rb +2 -2
  61. data/lib/one_gadget/fetchers/x86.rb +23 -0
  62. data/lib/one_gadget/gadget.rb +63 -11
  63. data/lib/one_gadget/helper.rb +282 -203
  64. data/lib/one_gadget/one_gadget.rb +12 -4
  65. data/lib/one_gadget/version.rb +1 -1
  66. metadata +57 -6
@@ -1,5 +1,5 @@
1
- require 'one_gadget/emulators/x86'
2
1
  require 'one_gadget/abi'
2
+ require 'one_gadget/emulators/x86'
3
3
 
4
4
  module OneGadget
5
5
  module Emulators
@@ -1,5 +1,5 @@
1
- require 'one_gadget/emulators/x86'
2
1
  require 'one_gadget/abi'
2
+ require 'one_gadget/emulators/x86'
3
3
 
4
4
  module OneGadget
5
5
  module Emulators
@@ -5,26 +5,32 @@ module OneGadget
5
5
  # Define instruction name and it's argument count.
6
6
  class Instruction
7
7
  attr_reader :inst # @return [String] The instruction name.
8
- attr_reader :argc # @return [Integer] Count of arguments.
8
+ attr_reader :argc # @return [Range] Count of arguments.
9
9
  # Instantiate a {Instruction} object.
10
10
  # @param [String] inst The instruction name.
11
- # @param [Integer] argc
11
+ # @param [Range, Integer] argc
12
12
  # Count of arguments.
13
13
  # Negative integer for doesn't care the number of arguments.
14
14
  def initialize(inst, argc)
15
15
  @inst = inst
16
- @argc = argc
16
+ @argc = case argc
17
+ when -1 then 0..Float::INFINITY
18
+ when Range then argc
19
+ when Integer then argc..argc
20
+ end
17
21
  end
18
22
 
19
23
  # Extract arguments from command.
20
24
  # @param [String] cmd
21
25
  # @return [Array<String>] Arguments.
26
+ # @raise [OneGadget::Error::InstructionArgumentError]
22
27
  def fetch_args(cmd)
23
28
  idx = cmd.index(inst)
29
+ cmd = cmd[0...cmd.rindex('//')] if cmd.rindex('//')
24
30
  cmd = cmd[0...cmd.rindex('#')] if cmd.rindex('#')
25
- args = cmd[idx + inst.size..-1].split(',')
26
- if argc >= 0 && args.size != argc
27
- raise Error::ArgumentError, "Incorrect argument number in #{cmd}, expect: #{argc}"
31
+ args = parse_args(cmd[idx + inst.size..-1])
32
+ unless argc.include?(args.size)
33
+ raise OneGadget::Error::InstructionArgumentError, "Incorrect argument number in #{cmd}, expect: #{argc}"
28
34
  end
29
35
 
30
36
  args.map do |arg|
@@ -36,7 +42,30 @@ module OneGadget
36
42
  # @param [String] cmd
37
43
  # @return [Boolean]
38
44
  def match?(cmd)
39
- cmd.include?(inst + ' ')
45
+ (cmd =~ /#{inst}\s/) != nil
46
+ end
47
+
48
+ private
49
+
50
+ def parse_args(str)
51
+ args = []
52
+ cur = +''
53
+ bkt_cnt = 0
54
+ str.each_char do |c|
55
+ if c == ',' && bkt_cnt.zero?
56
+ args << cur
57
+ cur = +''
58
+ next
59
+ end
60
+
61
+ cur << c
62
+ case c
63
+ when '[' then bkt_cnt += 1
64
+ when ']' then bkt_cnt -= 1
65
+ end
66
+ end
67
+ args << cur unless cur.empty?
68
+ args
40
69
  end
41
70
  end
42
71
  end
@@ -24,7 +24,7 @@ module OneGadget
24
24
  # @param [Numeric] other Value to add.
25
25
  # @return [Lambda] The result.
26
26
  def +(other)
27
- raise Error::ArgumentError, 'Expect other to be Numeric.' unless other.is_a?(Numeric)
27
+ raise Error::InstructionArgumentError, "Expect other(#{other}) to be numeric." unless other.is_a?(Numeric)
28
28
 
29
29
  if deref_count > 0
30
30
  ret = Lambda.new(self)
@@ -50,12 +50,13 @@ module OneGadget
50
50
  end
51
51
 
52
52
  # Decrease dreference count with 1.
53
- # @return [void]
54
- # @raise [Error::ArgumentError] When this object cannot be referenced anymore.
53
+ # @return [self]
54
+ # @raise [Error::InstrutionArgumentError] When this object cannot be referenced anymore.
55
55
  def ref!
56
- raise Error::ArgumentError, 'Cannot reference anymore!' if @deref_count <= 0
56
+ raise Error::InstructionArgumentError, 'Cannot reference anymore!' if @deref_count <= 0
57
57
 
58
58
  @deref_count -= 1
59
+ self
59
60
  end
60
61
 
61
62
  # A new {Lambda} object with dereference count increase 1.
@@ -84,43 +85,53 @@ module OneGadget
84
85
  # The context.
85
86
  # @return [Integer] Result of evaluation.
86
87
  def evaluate(context)
87
- raise Error::ArgumentError, "Can't eval #{self}" if deref_count > 0
88
- raise Error::ArgumentError, "Can't eval #{self}" if obj && !context.key?(obj)
88
+ raise Error::InstructionArgumentError, "Can't eval #{self}" if deref_count > 0 || (obj && !context.key?(obj))
89
89
 
90
90
  context[obj] + immi
91
91
  end
92
92
 
93
93
  class << self
94
- # Target: parse things like <tt>[rsp+0x50]</tt> into a {Lambda} object.
95
- # @param [String] arg
94
+ # Target: parse string like <tt>[rsp+0x50]</tt> into a {Lambda} object.
95
+ # @param [String] argument
96
96
  # @param [Hash{String => Lambda}] predefined
97
97
  # Predfined values.
98
98
  # @return [OneGadget::Emulators::Lambda, Integer]
99
- # If +arg+ contains number only, return it.
100
- # Otherwise, return a {Lambda} object.
99
+ # If +argument+ contains number only, returns the value.
100
+ # Otherwise, returns a {Lambda} object.
101
101
  # @example
102
102
  # obj = Lambda.parse('[rsp+0x50]')
103
103
  # #=> #<Lambda @obj='rsp', @immi=80, @deref_count=1>
104
104
  # Lambda.parse('obj+0x30', predefined: { 'obj' => obj }).to_s
105
105
  # #=> '[rsp+0x50]+0x30'
106
- def parse(arg, predefined: {})
107
- deref_count = 0
108
- if arg[0] == '[' # a little hack because there should nerver something like +[[rsp+1]+2]+ to parse.
109
- arg = arg[1..-2]
110
- deref_count = 1
111
- end
106
+ # @example
107
+ # Lambda.parse('[x0, -104]')
108
+ # #=> #<Lambda @obj='x0', @immi=-104, @deref_count=1>
109
+ def parse(argument, predefined: {})
110
+ arg = argument.dup
112
111
  return Integer(arg) if OneGadget::Helper.integer?(arg)
112
+ # nested []
113
+ return parse(arg[1...arg.rindex(']')], predefined: predefined).deref if arg[0] == '['
114
+
115
+ base, disp = mem_obj(arg)
116
+ obj = predefined[base] || Lambda.new(base)
117
+ obj += disp unless disp.zero?
118
+ obj
119
+ end
120
+
121
+ private
113
122
 
114
- sign = arg =~ /[+-]/
115
- val = 0
116
- if sign
117
- raise Error::ArgumentError, "Not support #{arg}" unless OneGadget::Helper.integer?(arg[sign..-1])
123
+ # @return [(String, Integer)]
124
+ def mem_obj(arg)
125
+ # We have three forms:
126
+ # 0. reg
127
+ # 1. reg+imm / reg-imm
128
+ # 2. reg, imm / reg, -imm
129
+ tokens = arg.gsub(/[\+\-]/, ' \0').scan(/[\+\-\w]+/)
130
+ return [tokens.first, 0] if tokens.size == 1
131
+ raise Error::UnsupportedInstructionArgumentError, arg unless tokens.size == 2
132
+ raise Error::UnsupportedInstructionArgumentError, arg unless OneGadget::Helper.integer?(tokens.last)
118
133
 
119
- val = Integer(arg.slice!(sign..-1))
120
- end
121
- obj = predefined[arg] || Lambda.new(arg)
122
- obj += val unless val.zero?
123
- deref_count.zero? ? obj : obj.deref
134
+ [tokens.first, Integer(tokens.last)]
124
135
  end
125
136
  end
126
137
  end
@@ -8,11 +8,24 @@ module OneGadget
8
8
  class Processor
9
9
  attr_reader :registers # @return [Hash{String => OneGadget::Emulators::Lambda}] The current registers' state.
10
10
  attr_reader :stack # @return [Hash{Integer => OneGadget::Emulators::Lambda}] The content on stack.
11
+ attr_reader :sp # @return [String] Stack pointer.
12
+ attr_reader :pc # @return [String] Program counter.
13
+
11
14
  # Instantiate a {Processor} object.
12
- # @param [Array<String>] registers Registers that supported in the architecture.
13
- def initialize(registers)
15
+ # @param [Array<String>] registers
16
+ # Registers that supported in the architecture.
17
+ # @param [String] sp
18
+ # The stack register.
19
+ def initialize(registers, sp)
14
20
  @registers = registers.map { |reg| [reg, to_lambda(reg)] }.to_h
15
- @stack = {}
21
+ @sp = sp
22
+ @constraints = []
23
+ @stack = Hash.new do |h, k|
24
+ h[k] = OneGadget::Emulators::Lambda.new(sp).tap do |lmda|
25
+ lmda.immi = k
26
+ lmda.deref!
27
+ end
28
+ end
16
29
  end
17
30
 
18
31
  # Parse one command into instruction and arguments.
@@ -21,14 +34,31 @@ module OneGadget
21
34
  # The parsing result.
22
35
  def parse(cmd)
23
36
  inst = instructions.find { |i| i.match?(cmd) }
24
- raise Error::ArgumentError, "Not implemented instruction in #{cmd}" if inst.nil?
37
+ raise Error::UnsupportedInstructionError, "Not implemented instruction in #{cmd}" if inst.nil?
25
38
 
26
39
  [inst, inst.fetch_args(cmd)]
27
40
  end
28
41
 
42
+ # Process one command, without raising any exceptions.
43
+ # @param [String] cmd
44
+ # See {#process!} for more information.
45
+ # @return [Boolean]
46
+ def process(cmd)
47
+ process!(cmd)
48
+ # rescue OneGadget::Error::UnsupportedError # for debugging
49
+ rescue OneGadget::Error::Error
50
+ false
51
+ end
52
+
29
53
  # Method need to be implemented in inheritors.
30
- # @return [void]
31
- def process(_cmd); raise NotImplementedError
54
+ #
55
+ # Process one command.
56
+ # Will raise exceptions when encounter unhandled instruction.
57
+ # @param [String] _cmd
58
+ # One line from result of objdump.
59
+ # @return [Boolean]
60
+ # If successfully processed.
61
+ def process!(_cmd); raise NotImplementedError
32
62
  end
33
63
 
34
64
  # Method need to be implemented in inheritors.
@@ -36,11 +66,69 @@ module OneGadget
36
66
  def instructions; raise NotImplementedError
37
67
  end
38
68
 
69
+ # To be inherited.
70
+ #
71
+ # @param [Integer] _idx
72
+ # The idx-th argument.
73
+ #
74
+ # @return [Lambda, Integer]
75
+ # Return value can be a {Lambda} or an +Integer+.
76
+ def argument(_idx); raise NotImplementedError
77
+ end
78
+
79
+ # @return [Array<String>]
80
+ # Extra constraints found during execution.
81
+ def constraints
82
+ return [] if @constraints.empty?
83
+
84
+ # currently only ':writable' type
85
+ cons = @constraints.uniq { |_type, obj| obj.deref_count.zero? ? obj.obj.to_s : obj.to_s }
86
+ cons.map { |_type, obj| "writable: #{obj}" }.sort
87
+ end
88
+
39
89
  private
40
90
 
91
+ def check_register!(reg)
92
+ raise Error::InstructionArgumentError, "#{reg.inspect} is not a valid register" unless register?(reg)
93
+ end
94
+
95
+ def check_argument(idx, expect)
96
+ case expect
97
+ when :global_var? then global_var?(argument(idx))
98
+ when :zero? then argument(idx).is_a?(Integer) && argument(idx).zero?
99
+ end
100
+ end
101
+
102
+ def register?(reg)
103
+ registers.include?(reg)
104
+ end
105
+
41
106
  def to_lambda(reg)
42
107
  OneGadget::Emulators::Lambda.new(reg)
43
108
  end
109
+
110
+ def raise_unsupported(inst, *args)
111
+ raise OneGadget::Error::UnsupportedInstructionArgumentError, "#{inst} #{args.join(', ')}"
112
+ end
113
+
114
+ def eval_dict
115
+ { sp => 0 }
116
+ end
117
+
118
+ def size_t
119
+ self.class.bits / 8
120
+ end
121
+
122
+ def global_var?(obj)
123
+ obj.to_s.include?(pc)
124
+ end
125
+
126
+ class << self
127
+ # 32 or 64.
128
+ # @return [Integer] 32 or 64.
129
+ def bits; raise NotImplementedError
130
+ end
131
+ end
44
132
  end
45
133
  end
46
134
  end
@@ -7,19 +7,10 @@ module OneGadget
7
7
  module Emulators
8
8
  # Super class for amd64 and i386 processor.
9
9
  class X86 < Processor
10
- attr_reader :sp # @return [String] Stack pointer.
11
- attr_reader :pc # @return [String] Program counter.
12
10
  # Constructor for a x86 processor.
13
11
  def initialize(registers, sp, pc)
14
- super(registers)
15
- @sp = sp
12
+ super(registers, sp)
16
13
  @pc = pc
17
- @stack = Hash.new do |h, k|
18
- h[k] = OneGadget::Emulators::Lambda.new(sp).tap do |lmda|
19
- lmda.immi = k
20
- lmda.deref!
21
- end
22
- end
23
14
  end
24
15
 
25
16
  # Process one command.
@@ -27,6 +18,7 @@ module OneGadget
27
18
  # @param [String] cmd
28
19
  # One line from result of objdump.
29
20
  # @return [Boolean]
21
+ # If successfully processed.
30
22
  def process!(cmd)
31
23
  inst, args = parse(cmd)
32
24
  # return registers[pc] = args[0] if inst.inst == 'call'
@@ -36,16 +28,6 @@ module OneGadget
36
28
  __send__(sym, *args) != :fail
37
29
  end
38
30
 
39
- # Process one command, without raising any exceptions.
40
- # @param [String] cmd
41
- # See {#process!} for more information.
42
- # @return [Boolean]
43
- def process(cmd)
44
- process!(cmd)
45
- rescue OneGadget::Error::Error
46
- false
47
- end
48
-
49
31
  # Supported instruction set.
50
32
  # @return [Array<Instruction>] The supported instructions.
51
33
  def instructions
@@ -65,133 +47,111 @@ module OneGadget
65
47
  ]
66
48
  end
67
49
 
68
- class << self
69
- # 32 or 64.
70
- # @return [Integer] 32 or 64.
71
- def bits; raise NotImplementedError
72
- end
73
- end
74
-
75
- # To be inherited.
76
- #
77
- # @param [Integer] _idx
78
- # The idx-th argument.
79
- #
80
- # @return [Lambda, Integer]
81
- # Return value can be a {Lambda} or an +Integer+.
82
- def argument(_idx); raise NotImplementedError
83
- end
84
-
85
50
  private
86
51
 
87
- def register?(reg)
88
- registers.include?(reg)
89
- end
90
-
91
- def inst_mov(tar, src)
52
+ def inst_mov(dst, src)
92
53
  src = OneGadget::Emulators::Lambda.parse(src, predefined: registers)
93
- if register?(tar)
94
- registers[tar] = src
54
+ if register?(dst)
55
+ registers[dst] = src
95
56
  else
96
57
  # Just ignore strange case...
97
- return unless tar.include?(sp)
58
+ return unless dst.include?(sp)
98
59
 
99
- tar = OneGadget::Emulators::Lambda.parse(tar, predefined: registers)
100
- return if tar.deref_count != 1 # should not happen
60
+ dst = OneGadget::Emulators::Lambda.parse(dst, predefined: registers)
61
+ return if dst.deref_count != 1 # should not happen
101
62
 
102
- tar.ref!
103
- stack[tar.evaluate(eval_dict)] = src
63
+ dst.ref!
64
+ stack[dst.evaluate(eval_dict)] = src
104
65
  end
105
66
  end
106
67
 
107
68
  # This instruction moves 128bits.
108
- def inst_movaps(tar, src)
69
+ def inst_movaps(dst, src)
109
70
  # XXX: here we only support `movaps [sp+*], xmm*`
110
71
  # TODO: This need an extra constraint: sp & 0xf == 0
111
- src, tar = check_xmm_sp(src, tar) { raise_unsupported('movaps', tar, src) }
112
- off = tar.evaluate(eval_dict)
72
+ src, dst = check_xmm_sp(src, dst) { raise_unsupported('movaps', dst, src) }
73
+ off = dst.evaluate(eval_dict)
113
74
  (128 / self.class.bits).times do |i|
114
75
  stack[off + i * size_t] = src[i]
115
76
  end
116
77
  end
117
78
 
118
- # Mov *src to tar[:64]
119
- def inst_movq(tar, src)
79
+ # Mov *src to dst[:64]
80
+ def inst_movq(dst, src)
120
81
  # XXX: here we only support `movq xmm*, [sp+*]`
121
- tar, src = check_xmm_sp(tar, src) { raise_unsupported('movq', tar, src) }
82
+ dst, src = check_xmm_sp(dst, src) { raise_unsupported('movq', dst, src) }
122
83
  off = src.evaluate(eval_dict)
123
84
  (64 / self.class.bits).times do |i|
124
- tar[i] = stack[off + i * size_t]
85
+ dst[i] = stack[off + i * size_t]
125
86
  end
126
87
  end
127
88
 
128
- # Move *src to tar[64:128]
129
- def inst_movhps(tar, src)
89
+ # Move *src to dst[64:128]
90
+ def inst_movhps(dst, src)
130
91
  # XXX: here we only support `movhps xmm*, [sp+*]`
131
- tar, src = check_xmm_sp(tar, src) { raise_unsupported('movhps', tar, src) }
92
+ dst, src = check_xmm_sp(dst, src) { raise_unsupported('movhps', dst, src) }
132
93
  off = src.evaluate(eval_dict)
133
94
  (64 / self.class.bits).times do |i|
134
- tar[i + 64 / self.class.bits] = stack[off + i * size_t]
95
+ dst[i + 64 / self.class.bits] = stack[off + i * size_t]
135
96
  end
136
97
  end
137
98
 
138
- # check if (tar, src) in form (xmm*, [sp+*])
139
- def check_xmm_sp(tar, src)
140
- return yield unless tar.start_with?('xmm') && register?(tar) && src.include?(sp)
99
+ # check if (dst, src) in form (xmm*, [sp+*])
100
+ def check_xmm_sp(dst, src)
101
+ return yield unless dst.start_with?('xmm') && register?(dst) && src.include?(sp)
141
102
 
142
- tar_lm = OneGadget::Emulators::Lambda.parse(tar, predefined: registers)
103
+ dst_lm = OneGadget::Emulators::Lambda.parse(dst, predefined: registers)
143
104
  src_lm = OneGadget::Emulators::Lambda.parse(src, predefined: registers)
144
105
  return yield if src_lm.deref_count != 1
145
106
 
146
107
  src_lm.ref!
147
- [tar_lm, src_lm]
108
+ [dst_lm, src_lm]
148
109
  end
149
110
 
150
- def inst_lea(tar, src)
111
+ def inst_lea(dst, src)
112
+ check_register!(dst)
113
+
151
114
  src = OneGadget::Emulators::Lambda.parse(src, predefined: registers)
152
115
  src.ref!
153
- registers[tar] = src
116
+ registers[dst] = src
154
117
  end
155
118
 
156
119
  def inst_push(val)
157
120
  val = OneGadget::Emulators::Lambda.parse(val, predefined: registers)
158
121
  registers[sp] -= size_t
159
122
  cur_top = registers[sp].evaluate(eval_dict)
160
- raise Error::ArgumentError, "Corrupted stack pointer: #{cur_top}" unless cur_top.is_a?(Integer)
123
+ raise Error::InstructionArgumentError, "Corrupted stack pointer: #{cur_top}" unless cur_top.is_a?(Integer)
161
124
 
162
125
  stack[cur_top] = val
163
126
  end
164
127
 
165
128
  def inst_xor(dst, src)
129
+ check_register!(dst)
130
+
166
131
  # only supports dst == src
167
- raise Error::ArgumentError, 'xor operator only supports dst = src' unless dst == src
132
+ raise Error::UnsupportedInstructionArgumentError, 'xor operator only supports dst = src' unless dst == src
168
133
 
169
134
  dst[0] = 'r' if self.class.bits == 64 && dst.start_with?('e')
170
135
  registers[dst] = 0
171
136
  end
172
137
 
173
- def inst_add(tar, src)
138
+ def inst_add(dst, src)
139
+ check_register!(dst)
140
+
174
141
  src = OneGadget::Emulators::Lambda.parse(src, predefined: registers)
175
- registers[tar] += src
142
+ registers[dst] += src
176
143
  end
177
144
 
178
- def inst_sub(tar, src)
145
+ def inst_sub(dst, src)
179
146
  src = OneGadget::Emulators::Lambda.parse(src, predefined: registers)
180
- raise Error::ArgumentError, "Can't handle -= of type #{src.class}" unless src.is_a?(Integer)
147
+ raise Error::UnsupportedInstructionArgumentError, "Unhandled -= of type #{src.class}" unless src.is_a?(Integer)
181
148
 
182
- registers[tar] -= src
149
+ registers[dst] -= src
183
150
  end
184
151
 
185
152
  # yap, nop
186
153
  def inst_nop(*); end
187
154
 
188
- def check_argument(idx, expect)
189
- case expect
190
- when :global then argument(idx).to_s.include?(pc) # easy check
191
- when :zero? then argument(idx).is_a?(Integer) && argument(idx).zero?
192
- end
193
- end
194
-
195
155
  # Handle some valid calls.
196
156
  # For example, +sigprocmask+ will always be a valid call
197
157
  # because it just invokes syscall.
@@ -203,8 +163,8 @@ module OneGadget
203
163
  checker = {
204
164
  'sigprocmask' => {},
205
165
  '__close' => {},
206
- 'unsetenv' => { 0 => :global },
207
- '__sigaction' => { 1 => :global, 2 => :zero? }
166
+ 'unsetenv' => { 0 => :global_var? },
167
+ '__sigaction' => { 1 => :global_var?, 2 => :zero? }
208
168
  }
209
169
  func = checker.keys.find { |n| addr.include?(n) }
210
170
  return if func && checker[func].all? { |idx, sym| check_argument(idx, sym) }
@@ -213,18 +173,6 @@ module OneGadget
213
173
  :fail
214
174
  end
215
175
 
216
- def size_t
217
- self.class.bits / 8
218
- end
219
-
220
- def eval_dict
221
- { sp => 0 }
222
- end
223
-
224
- def raise_unsupported(inst, *args)
225
- raise OneGadget::Error::UnsupportedInstructionArgumentsError, "#{inst} #{args.join(', ')}"
226
- end
227
-
228
176
  def to_lambda(reg)
229
177
  return super unless reg =~ /^xmm\d+$/
230
178