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.
- checksums.yaml +4 -4
- data/README.md +141 -94
- data/bin/one_gadget +4 -3
- data/lib/one_gadget/abi.rb +42 -22
- data/lib/one_gadget/builds/libc-2.19-397c84e78c14cbffba39a48184db482211df9fb3.rb +38 -0
- data/lib/one_gadget/builds/libc-2.19-4eda8ff01be3fba1c7bdd442a8690c3dc7397b6a.rb +44 -0
- data/lib/one_gadget/builds/libc-2.19-509ee0c9616c4c3ed81951501a8950e1f529bbff.rb +38 -0
- data/lib/one_gadget/builds/libc-2.19-6aff6d091954955fe931bb720a17708513aabda7.rb +41 -0
- data/lib/one_gadget/builds/libc-2.19-8d935a42f2f2a1149aa52d3098b32b1d5012cb67.rb +38 -0
- data/lib/one_gadget/builds/libc-2.19-a820f849dda0b99ed06dd59bb88404969b3a5f88.rb +41 -0
- data/lib/one_gadget/builds/libc-2.19-d9a10b8ef90300628dd0a3a535106967714d7328.rb +47 -0
- data/lib/one_gadget/builds/libc-2.21-169a143e9c40cfd9d09695333e45fd67743cd2d6.rb +37 -0
- data/lib/one_gadget/builds/libc-2.21-2e9718e58257bda1dc0d751665a3ee233bf606f2.rb +37 -0
- data/lib/one_gadget/builds/libc-2.23-29e38445a740bba5a77b86691e3c51a7e48dc79b.rb +46 -0
- data/lib/one_gadget/builds/libc-2.23-679ad41a6bc9e718a11a36cf9879cac97197e565.rb +37 -0
- data/lib/one_gadget/builds/libc-2.23-b5381a457906d279073822a5ceb24c4bfef94ddb.rb +37 -0
- data/lib/one_gadget/builds/libc-2.23-d10fbfd9328f5ffaca50aa93562cb3bfb618fbcc.rb +43 -0
- data/lib/one_gadget/builds/libc-2.23-dd5192a769e33ed6ca68a6ab5740ff9e8ec678a7.rb +46 -0
- data/lib/one_gadget/builds/libc-2.24-1f7bdfb9a24714835cee6e6597ea7aa782821371.rb +46 -0
- data/lib/one_gadget/builds/libc-2.24-206b2bb216b6cdb6b1be565a6fcd29f3862db060.rb +49 -0
- data/lib/one_gadget/builds/libc-2.24-26e84118fee5788eb5d8dda66b7e7f029d2c7800.rb +43 -0
- data/lib/one_gadget/builds/libc-2.24-43adbb1e7368c94fba1ba9020d8ef0808bff5bc4.rb +37 -0
- data/lib/one_gadget/builds/libc-2.24-497931f8d2346a6d0e300a65d8fc6106c6c88c15.rb +37 -0
- data/lib/one_gadget/builds/libc-2.24-4fa7401566d6b3e2c7ee5df3b4d85a01f85b595c.rb +37 -0
- data/lib/one_gadget/builds/libc-2.24-568d20b7e0d08bc282fb42ae405c7054e4209ede.rb +37 -0
- data/lib/one_gadget/builds/libc-2.24-5b72576ff331e93852355123afecdec70fd247b5.rb +49 -0
- data/lib/one_gadget/builds/libc-2.24-a4c01d397b6584f7040ef266b16a5d4da0b7a087.rb +43 -0
- data/lib/one_gadget/builds/libc-2.24-b81a06f0ac241c4aa8860602d9abcc903adbb675.rb +46 -0
- data/lib/one_gadget/builds/libc-2.24-be6d412ecc4816c46eb49e750b02f714a9131c4e.rb +46 -0
- data/lib/one_gadget/builds/libc-2.24-d2a8a8ac188a6c3bafa4813a3d2789240ee49489.rb +46 -0
- data/lib/one_gadget/builds/libc-2.24-dff06414a29b97b865ef938e06a7751fe8b1b2d0.rb +46 -0
- data/lib/one_gadget/builds/libc-2.24-e5dc6c0caa39828fa10ed37e642723a581acdb6d.rb +37 -0
- data/lib/one_gadget/builds/libc-2.24-fd0655c4d2073eda4235084e1d0e558f0251be8a.rb +37 -0
- data/lib/one_gadget/builds/libc-2.25-e5eb6347f0629b37bf698200022a683b7efb10ed.rb +37 -0
- data/lib/one_gadget/builds/libc-2.26-1c39b3b3faa2a2cbb0fa0b6845b29332562262d3.rb +37 -0
- data/lib/one_gadget/builds/libc-2.26-499b381aaf00ce85ee5d4a12770ea369b30d2a41.rb +52 -0
- data/lib/one_gadget/builds/libc-2.26-4cc84abfe1fd26a485fc2b1b954c281ce9d358fd.rb +52 -0
- data/lib/one_gadget/builds/libc-2.26-4ea852c9d6a5084b8b58509b3b3d37d3d8cddb90.rb +52 -0
- data/lib/one_gadget/builds/libc-2.26-6d2b609f0c8e7b338f767b08c5ac712fac809d31.rb +49 -0
- data/lib/one_gadget/builds/libc-2.26-fb587bc4429e7d1b0de31a3b9ee8ae78ee797eb0.rb +37 -0
- data/lib/one_gadget/builds/libc-2.27-0e188ec5f09c187a7a92784d4b97aa251b15a93c.rb +47 -0
- data/lib/one_gadget/builds/libc-2.27-53f40c1d2f3739ae017dcdcef1a17314786e3709.rb +38 -0
- data/lib/one_gadget/builds/libc-2.27-9dd0bb57f81671704475d1e5163405f7b4d4b454.rb +32 -0
- data/lib/one_gadget/builds/libc-2.28-44f5a3efb0e5733fa9d97e690cb36cd4c682bcdb.rb +41 -0
- data/lib/one_gadget/builds/libc-2.28-5784a31a1c26f6d2157e585205ebb63dd19ff90f.rb +41 -0
- data/lib/one_gadget/builds/libc-2.28-5b157f49586a3ca84d55837f97ff466767dd3445.rb +38 -0
- data/lib/one_gadget/builds/libc-2.28-6ee9454b96efa9e343f9e8105f2fa4529265ea05.rb +38 -0
- data/lib/one_gadget/emulators/aarch64.rb +176 -0
- data/lib/one_gadget/emulators/amd64.rb +1 -1
- data/lib/one_gadget/emulators/i386.rb +1 -1
- data/lib/one_gadget/emulators/instruction.rb +36 -7
- data/lib/one_gadget/emulators/lambda.rb +36 -25
- data/lib/one_gadget/emulators/processor.rb +94 -6
- data/lib/one_gadget/emulators/x86.rb +43 -95
- data/lib/one_gadget/error.rb +15 -3
- data/lib/one_gadget/fetcher.rb +3 -1
- data/lib/one_gadget/fetchers/aarch64.rb +41 -0
- data/lib/one_gadget/fetchers/amd64.rb +4 -2
- data/lib/one_gadget/fetchers/base.rb +35 -11
- data/lib/one_gadget/fetchers/i386.rb +2 -2
- data/lib/one_gadget/fetchers/x86.rb +23 -0
- data/lib/one_gadget/gadget.rb +63 -11
- data/lib/one_gadget/helper.rb +282 -203
- data/lib/one_gadget/one_gadget.rb +12 -4
- data/lib/one_gadget/version.rb +1 -1
- metadata +57 -6
@@ -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 [
|
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]
|
26
|
-
|
27
|
-
raise Error::
|
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
|
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::
|
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 [
|
54
|
-
# @raise [Error::
|
53
|
+
# @return [self]
|
54
|
+
# @raise [Error::InstrutionArgumentError] When this object cannot be referenced anymore.
|
55
55
|
def ref!
|
56
|
-
raise Error::
|
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::
|
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
|
95
|
-
# @param [String]
|
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 +
|
100
|
-
# Otherwise,
|
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
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
-
|
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
|
13
|
-
|
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
|
-
@
|
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::
|
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
|
-
#
|
31
|
-
|
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
|
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?(
|
94
|
-
registers[
|
54
|
+
if register?(dst)
|
55
|
+
registers[dst] = src
|
95
56
|
else
|
96
57
|
# Just ignore strange case...
|
97
|
-
return unless
|
58
|
+
return unless dst.include?(sp)
|
98
59
|
|
99
|
-
|
100
|
-
return if
|
60
|
+
dst = OneGadget::Emulators::Lambda.parse(dst, predefined: registers)
|
61
|
+
return if dst.deref_count != 1 # should not happen
|
101
62
|
|
102
|
-
|
103
|
-
stack[
|
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(
|
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,
|
112
|
-
off =
|
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
|
119
|
-
def inst_movq(
|
79
|
+
# Mov *src to dst[:64]
|
80
|
+
def inst_movq(dst, src)
|
120
81
|
# XXX: here we only support `movq xmm*, [sp+*]`
|
121
|
-
|
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
|
-
|
85
|
+
dst[i] = stack[off + i * size_t]
|
125
86
|
end
|
126
87
|
end
|
127
88
|
|
128
|
-
# Move *src to
|
129
|
-
def inst_movhps(
|
89
|
+
# Move *src to dst[64:128]
|
90
|
+
def inst_movhps(dst, src)
|
130
91
|
# XXX: here we only support `movhps xmm*, [sp+*]`
|
131
|
-
|
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
|
-
|
95
|
+
dst[i + 64 / self.class.bits] = stack[off + i * size_t]
|
135
96
|
end
|
136
97
|
end
|
137
98
|
|
138
|
-
# check if (
|
139
|
-
def check_xmm_sp(
|
140
|
-
return yield unless
|
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
|
-
|
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
|
-
[
|
108
|
+
[dst_lm, src_lm]
|
148
109
|
end
|
149
110
|
|
150
|
-
def inst_lea(
|
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[
|
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::
|
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::
|
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(
|
138
|
+
def inst_add(dst, src)
|
139
|
+
check_register!(dst)
|
140
|
+
|
174
141
|
src = OneGadget::Emulators::Lambda.parse(src, predefined: registers)
|
175
|
-
registers[
|
142
|
+
registers[dst] += src
|
176
143
|
end
|
177
144
|
|
178
|
-
def inst_sub(
|
145
|
+
def inst_sub(dst, src)
|
179
146
|
src = OneGadget::Emulators::Lambda.parse(src, predefined: registers)
|
180
|
-
raise Error::
|
147
|
+
raise Error::UnsupportedInstructionArgumentError, "Unhandled -= of type #{src.class}" unless src.is_a?(Integer)
|
181
148
|
|
182
|
-
registers[
|
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 => :
|
207
|
-
'__sigaction' => { 1 => :
|
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
|
|