one_gadget 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 143e72f7753ab6351d2d2ff06fe551302c9e1e46
4
- data.tar.gz: 14892686d48601c9808f7819f1f4225b96cf4d52
3
+ metadata.gz: d381a734bccb70a6ffaac1b6e2ff82518adf2719
4
+ data.tar.gz: 406db08cea4fc116b4d81f61d585b7a25ec9ecd4
5
5
  SHA512:
6
- metadata.gz: 183163649946a1a1e541c05748efc462cdeabd09d0eaf8e4dc68b6db80eb8d466c326009c760c7606f43e30d2f692011dbc8d8e26c90d36603eb6ca9f6ad1cd9
7
- data.tar.gz: 4e8f94784b8eafcb83ad5c02e05d5be617c7baa5e84c57a24a1a19602b5d7e169ac3ecb8bf94c2ca48ed92d61d8661b449112837442c4826a3bb8efafc93d447
6
+ metadata.gz: 327cb7edce0f03ac5d43807d91c9850f63869e9041d59ed236b467fd6ca97aa4aaaa68361525daa1273259b7df96a00e69193ef1ddd3b4856126a61afb3148ad
7
+ data.tar.gz: 59b561675611597e011b5012574986138e041421eaecd8819ca40cdecc8f68056a2f42077eb7ad2f25f71ce2fd884b53aba9ea823791d250e18703d8e7228a3b
data/README.md CHANGED
@@ -28,9 +28,9 @@ Note: require ruby version >= 2.1.0, you can use `ruby --version` to check.
28
28
 
29
29
  ## Implementation
30
30
 
31
- OneGadget uses simple self-implement symbolic execution to find the constraints of gadgets to success.
31
+ OneGadget uses simple self-implement symbolic execution to find the constraints of gadgets to be successful.
32
32
 
33
- The article introducing how I develop this tool can be found [here](https://david942j.blogspot.com/2017/02/project-one-gadget-in-glibc.html).
33
+ The article introducing how I develop this tool can be found [in my blog](https://david942j.blogspot.com/2017/02/project-one-gadget-in-glibc.html).
34
34
 
35
35
  ## Usage
36
36
 
@@ -39,7 +39,7 @@ much more one-gadgets have been found.
39
39
  And gadgets become too many to show them all,
40
40
  they would be selected automatically according to the difficulty of constraints.
41
41
  Therefore, gadgets shown will be less than previous versions (before v1.5.0).
42
- You can use option `--level 1` to show more gadgets found.
42
+ But you can use option `--level 1` to show all gadgets found.
43
43
 
44
44
  ### Command Line Interface
45
45
 
@@ -55,6 +55,7 @@ $ one_gadget
55
55
  # -r, --[no-]raw Output gadgets offset only, split with one space.
56
56
  # -s, --script exploit-script Run exploit script with all possible gadgets.
57
57
  # The script will be run as 'exploit-script $offset'.
58
+ # --info BuildID Show version information given BuildID.
58
59
  # --version Current gem version.
59
60
 
60
61
  $ one_gadget -b 60131540dadc6796cab33388349e6e4e68692053
@@ -210,4 +211,4 @@ one_gadget('60131540dadc6796cab33388349e6e4e68692053')
210
211
  Any suggestion or feature request is welcome! Feel free to send a pull request.
211
212
 
212
213
  Please let me know if you find any libc that make OneGadget fail to find gadgets.
213
- And, if you like this work, I'll be happy to be [stared](https://github.com/david942j/one_gadget/stargazers) :grimacing:
214
+ And, if you like this work, I'll be happy to be [starred](https://github.com/david942j/one_gadget/stargazers) :grimacing:
@@ -31,6 +31,10 @@ parser = OptionParser.new do |opts|
31
31
  options[:script] = script
32
32
  end
33
33
 
34
+ opts.on('--info BuildID', 'Show version information given BuildID.') do |b|
35
+ options[:info] = b
36
+ end
37
+
34
38
  opts.on('--version', 'Current gem version.') do |v|
35
39
  options[:version] = v
36
40
  end
@@ -49,6 +53,13 @@ def execute(script, offset)
49
53
  Process.wait pid
50
54
  end
51
55
 
56
+ if options[:info]
57
+ result = OneGadget::Gadget.builds_info(options[:info])
58
+ exit(1) if result.nil? # error happend
59
+ OneGadget::Logger.info("Information of #{options[:info]}:\n#{result.join("\n")}\n")
60
+ exit(0)
61
+ end
62
+
52
63
  level = options[:level] || 0
53
64
  if options[:build_id]
54
65
  gadgets = OneGadget.gadgets(build_id: options[:build_id], details: true, level: level)
@@ -4,9 +4,12 @@ module OneGadget
4
4
  # Define class methods here.
5
5
  module ClassMethods
6
6
  # Registers in i386.
7
- LINUX_X86_32 = %w(eax ebx ecx edx edi esi ebp esp).freeze
7
+ LINUX_X86_32 = %w(eax ebx ecx edx edi esi ebp esp) + 0.upto(7).map { |i| "xmm#{i}" }
8
8
  # Registers in x86_64/
9
- LINUX_X86_64 = LINUX_X86_32 + %w(rax rbx rcx rdx rdi rsi rbp rsp) + 8.upto(15).map { |i| "r#{i}" }
9
+ LINUX_X86_64 = LINUX_X86_32 +
10
+ %w(rax rbx rcx rdx rdi rsi rbp rsp) +
11
+ 8.upto(15).map { |i| "r#{i}" } +
12
+ 8.upto(15).map { |i| "xmm#{i}" }
10
13
  # Registers' name in amd64.
11
14
  # @return [Array<String>] List of registers.
12
15
  def amd64
@@ -0,0 +1,49 @@
1
+ require 'one_gadget/gadget'
2
+ # ubuntu17.10-libc-2.26.so
3
+ #
4
+ # Advanced Micro Devices X86-64
5
+ #
6
+ # GNU C Library (Ubuntu GLIBC 2.26-0ubuntu2.1) stable release version 2.26, by Roland McGrath et al.
7
+ # Copyright (C) 2017 Free Software Foundation, Inc.
8
+ # This is free software; see the source for copying conditions.
9
+ # There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
10
+ # PARTICULAR PURPOSE.
11
+ # Compiled by GNU CC version 6.4.0 20171010.
12
+ # Available extensions:
13
+ # crypt add-on version 2.1 by Michael Glad and others
14
+ # GNU Libidn by Simon Josefsson
15
+ # Native POSIX Threads Library by Ulrich Drepper et al
16
+ # BIND-8.2.3-T5B
17
+ # libc ABIs: UNIQUE IFUNC
18
+ # For bug reporting instructions, please see:
19
+ # <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
20
+
21
+ build_id = File.basename(__FILE__, '.rb').split('-').last
22
+ OneGadget::Gadget.add(build_id, 293958,
23
+ constraints: ["rax == NULL"],
24
+ effect: "execve(\"/bin/sh\", rsp+0x30, environ)")
25
+ OneGadget::Gadget.add(build_id, 294042,
26
+ constraints: ["[rsp+0x30] == NULL"],
27
+ effect: "execve(\"/bin/sh\", rsp+0x30, environ)")
28
+ OneGadget::Gadget.add(build_id, 890723,
29
+ constraints: ["[r13] == NULL || r13 == NULL", "[rbx] == NULL || rbx == NULL"],
30
+ effect: "execve(\"/bin/sh\", r13, rbx)")
31
+ OneGadget::Gadget.add(build_id, 891441,
32
+ constraints: ["[[rbp-0xa0]] == NULL || [rbp-0xa0] == NULL", "[[rbp-0x70]] == NULL || [rbp-0x70] == NULL"],
33
+ effect: "execve(\"/bin/sh\", [rbp-0xa0], [rbp-0x70])")
34
+ OneGadget::Gadget.add(build_id, 891448,
35
+ constraints: ["[rcx] == NULL || rcx == NULL", "[[rbp-0x70]] == NULL || [rbp-0x70] == NULL"],
36
+ effect: "execve(\"/bin/sh\", rcx, [rbp-0x70])")
37
+ OneGadget::Gadget.add(build_id, 891452,
38
+ constraints: ["[rcx] == NULL || rcx == NULL", "[rdx] == NULL || rdx == NULL"],
39
+ effect: "execve(\"/bin/sh\", rcx, rdx)")
40
+ OneGadget::Gadget.add(build_id, 1035486,
41
+ constraints: ["[rsp+0x40] == NULL"],
42
+ effect: "execve(\"/bin/sh\", rsp+0x40, environ)")
43
+ OneGadget::Gadget.add(build_id, 1035498,
44
+ constraints: ["[rsi] == NULL || rsi == NULL", "[[rax]] == NULL || [rax] == NULL"],
45
+ effect: "execve(\"/bin/sh\", rsi, [rax])")
46
+ OneGadget::Gadget.add(build_id, 1039246,
47
+ constraints: ["[rsp+0x70] == NULL"],
48
+ effect: "execve(\"/bin/sh\", rsp+0x70, environ)")
49
+
@@ -0,0 +1,52 @@
1
+ require 'one_gadget/gadget'
2
+ # ubuntu17.10-libc-2.26.so
3
+ #
4
+ # Intel 80386
5
+ #
6
+ # GNU C Library (Ubuntu GLIBC 2.26-0ubuntu2.1) stable release version 2.26, by Roland McGrath et al.
7
+ # Copyright (C) 2017 Free Software Foundation, Inc.
8
+ # This is free software; see the source for copying conditions.
9
+ # There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
10
+ # PARTICULAR PURPOSE.
11
+ # Compiled by GNU CC version 6.4.0 20171010.
12
+ # Available extensions:
13
+ # crypt add-on version 2.1 by Michael Glad and others
14
+ # GNU Libidn by Simon Josefsson
15
+ # Native POSIX Threads Library by Ulrich Drepper et al
16
+ # BIND-8.2.3-T5B
17
+ # libc ABIs: UNIQUE IFUNC
18
+ # For bug reporting instructions, please see:
19
+ # <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
20
+
21
+ build_id = File.basename(__FILE__, '.rb').split('-').last
22
+ OneGadget::Gadget.add(build_id, 248879,
23
+ constraints: ["esi is the GOT address of libc", "[esp+0x34] == NULL"],
24
+ effect: "execve(\"/bin/sh\", esp+0x34, environ)")
25
+ OneGadget::Gadget.add(build_id, 248881,
26
+ constraints: ["esi is the GOT address of libc", "[esp+0x38] == NULL"],
27
+ effect: "execve(\"/bin/sh\", esp+0x38, environ)")
28
+ OneGadget::Gadget.add(build_id, 248885,
29
+ constraints: ["esi is the GOT address of libc", "[esp+0x3c] == NULL"],
30
+ effect: "execve(\"/bin/sh\", esp+0x3c, environ)")
31
+ OneGadget::Gadget.add(build_id, 248892,
32
+ constraints: ["esi is the GOT address of libc", "[esp+0x40] == NULL"],
33
+ effect: "execve(\"/bin/sh\", esp+0x40, environ)")
34
+ OneGadget::Gadget.add(build_id, 248927,
35
+ constraints: ["esi is the GOT address of libc", "[eax] == NULL || eax == NULL", "[[esp]] == NULL || [esp] == NULL"],
36
+ effect: "execve(\"/bin/sh\", eax, [esp])")
37
+ OneGadget::Gadget.add(build_id, 248928,
38
+ constraints: ["esi is the GOT address of libc", "[[esp]] == NULL || [esp] == NULL", "[[esp+0x4]] == NULL || [esp+0x4] == NULL"],
39
+ effect: "execve(\"/bin/sh\", [esp], [esp+0x4])")
40
+ OneGadget::Gadget.add(build_id, 421503,
41
+ constraints: ["edi is the GOT address of libc", "eax == NULL"],
42
+ effect: "execl(\"/bin/sh\", eax)")
43
+ OneGadget::Gadget.add(build_id, 421504,
44
+ constraints: ["edi is the GOT address of libc", "[esp] == NULL"],
45
+ effect: "execl(\"/bin/sh\", [esp])")
46
+ OneGadget::Gadget.add(build_id, 1257406,
47
+ constraints: ["esi is the GOT address of libc", "eax == NULL"],
48
+ effect: "execl(\"/bin/sh\", eax)")
49
+ OneGadget::Gadget.add(build_id, 1257407,
50
+ constraints: ["esi is the GOT address of libc", "[esp] == NULL"],
51
+ effect: "execl(\"/bin/sh\", [esp])")
52
+
@@ -0,0 +1,47 @@
1
+ require 'one_gadget/gadget'
2
+ # spec/data/libc-2.27-63b3d43ad45e1b0f601848c65b067f9e9b40528b.so
3
+ #
4
+ # Intel 80386
5
+ #
6
+ # GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
7
+ # Copyright (C) 2018 Free Software Foundation, Inc.
8
+ # This is free software; see the source for copying conditions.
9
+ # There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
10
+ # PARTICULAR PURPOSE.
11
+ # Compiled by GNU CC version 7.3.0.
12
+ # libc ABIs: UNIQUE IFUNC
13
+ # For bug reporting instructions, please see:
14
+ # <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
15
+
16
+ build_id = File.basename(__FILE__, '.rb').split('-').last
17
+ OneGadget::Gadget.add(build_id, 248810,
18
+ constraints: ["esi is the GOT address of libc", "[esp+0x34] == NULL"],
19
+ effect: "execve(\"/bin/sh\", esp+0x34, environ)")
20
+ OneGadget::Gadget.add(build_id, 248812,
21
+ constraints: ["esi is the GOT address of libc", "[esp+0x38] == NULL"],
22
+ effect: "execve(\"/bin/sh\", esp+0x38, environ)")
23
+ OneGadget::Gadget.add(build_id, 248816,
24
+ constraints: ["esi is the GOT address of libc", "[esp+0x3c] == NULL"],
25
+ effect: "execve(\"/bin/sh\", esp+0x3c, environ)")
26
+ OneGadget::Gadget.add(build_id, 248823,
27
+ constraints: ["esi is the GOT address of libc", "[esp+0x40] == NULL"],
28
+ effect: "execve(\"/bin/sh\", esp+0x40, environ)")
29
+ OneGadget::Gadget.add(build_id, 248858,
30
+ constraints: ["esi is the GOT address of libc", "[eax] == NULL || eax == NULL", "[[esp]] == NULL || [esp] == NULL"],
31
+ effect: "execve(\"/bin/sh\", eax, [esp])")
32
+ OneGadget::Gadget.add(build_id, 248859,
33
+ constraints: ["esi is the GOT address of libc", "[[esp]] == NULL || [esp] == NULL", "[[esp+0x4]] == NULL || [esp+0x4] == NULL"],
34
+ effect: "execve(\"/bin/sh\", [esp], [esp+0x4])")
35
+ OneGadget::Gadget.add(build_id, 422559,
36
+ constraints: ["esi is the GOT address of libc", "eax == NULL"],
37
+ effect: "execl(\"/bin/sh\", eax)")
38
+ OneGadget::Gadget.add(build_id, 422560,
39
+ constraints: ["esi is the GOT address of libc", "[esp] == NULL"],
40
+ effect: "execl(\"/bin/sh\", [esp])")
41
+ OneGadget::Gadget.add(build_id, 1267518,
42
+ constraints: ["ebx is the GOT address of libc", "eax == NULL"],
43
+ effect: "execl(\"/bin/sh\", eax)")
44
+ OneGadget::Gadget.add(build_id, 1267519,
45
+ constraints: ["ebx is the GOT address of libc", "[esp] == NULL"],
46
+ effect: "execl(\"/bin/sh\", [esp])")
47
+
@@ -0,0 +1,41 @@
1
+ require 'one_gadget/gadget'
2
+ # spec/data/libc-2.27-b417c0ba7cc5cf06d1d1bed6652cedb9253c60d0.so
3
+ #
4
+ # Advanced Micro Devices X86-64
5
+ #
6
+ # GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
7
+ # Copyright (C) 2018 Free Software Foundation, Inc.
8
+ # This is free software; see the source for copying conditions.
9
+ # There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
10
+ # PARTICULAR PURPOSE.
11
+ # Compiled by GNU CC version 7.3.0.
12
+ # libc ABIs: UNIQUE IFUNC
13
+ # For bug reporting instructions, please see:
14
+ # <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
15
+
16
+ build_id = File.basename(__FILE__, '.rb').split('-').last
17
+ OneGadget::Gadget.add(build_id, 324293,
18
+ constraints: ["rcx == NULL"],
19
+ effect: "execve(\"/bin/sh\", rsp+0x40, environ)")
20
+ OneGadget::Gadget.add(build_id, 324386,
21
+ constraints: ["[rsp+0x40] == NULL"],
22
+ effect: "execve(\"/bin/sh\", rsp+0x40, environ)")
23
+ OneGadget::Gadget.add(build_id, 939679,
24
+ constraints: ["[r14] == NULL || r14 == NULL", "[r12] == NULL || r12 == NULL"],
25
+ effect: "execve(\"/bin/sh\", r14, r12)")
26
+ OneGadget::Gadget.add(build_id, 940120,
27
+ constraints: ["[[rbp-0x88]] == NULL || [rbp-0x88] == NULL", "[[rbp-0x70]] == NULL || [rbp-0x70] == NULL"],
28
+ effect: "execve(\"/bin/sh\", [rbp-0x88], [rbp-0x70])")
29
+ OneGadget::Gadget.add(build_id, 940127,
30
+ constraints: ["[r10] == NULL || r10 == NULL", "[[rbp-0x70]] == NULL || [rbp-0x70] == NULL"],
31
+ effect: "execve(\"/bin/sh\", r10, [rbp-0x70])")
32
+ OneGadget::Gadget.add(build_id, 940131,
33
+ constraints: ["[r10] == NULL || r10 == NULL", "[rdx] == NULL || rdx == NULL"],
34
+ effect: "execve(\"/bin/sh\", r10, rdx)")
35
+ OneGadget::Gadget.add(build_id, 1090444,
36
+ constraints: ["[rsp+0x70] == NULL"],
37
+ effect: "execve(\"/bin/sh\", rsp+0x70, environ)")
38
+ OneGadget::Gadget.add(build_id, 1090456,
39
+ constraints: ["[rsi] == NULL || rsi == NULL", "[[rax]] == NULL || [rax] == NULL"],
40
+ effect: "execve(\"/bin/sh\", rsi, [rax])")
41
+
@@ -4,7 +4,7 @@ module OneGadget
4
4
  class Instruction
5
5
  attr_reader :inst # @return [String] The instruction name.
6
6
  attr_reader :argc # @return [Integer] Count of arguments.
7
- # Instantiate a n{Instruction} object.
7
+ # Instantiate a {Instruction} object.
8
8
  # @param [String] inst The instruction name.
9
9
  # @param [Integer] argc
10
10
  # Count of arguments.
@@ -23,7 +23,7 @@ module OneGadget
23
23
  args = cmd[idx + inst.size..-1].split(',')
24
24
  raise ArgumentError, "Incorrect argument number in #{cmd}, expect: #{argc}" if argc >= 0 && args.size != argc
25
25
  args.map do |arg|
26
- arg.gsub(/QWORD|DWORD|WORD|BYTE|PTR/, '').strip
26
+ arg.gsub(/XMMWORD|QWORD|DWORD|WORD|BYTE|PTR/, '').strip
27
27
  end
28
28
  end
29
29
 
@@ -95,9 +95,9 @@ module OneGadget
95
95
  # If +arg+ contains number only, return it.
96
96
  # Otherwise, return a {Lambda} object.
97
97
  # @example
98
- # obj = parse('[rsp+0x50]')
98
+ # obj = Lambda.parse('[rsp+0x50]')
99
99
  # #=> #<Lambda @obj='rsp', @immi=80, @deref_count=1>
100
- # parse('obj+0x30', predefined: { 'obj' => obj }).to_s
100
+ # Lambda.parse('obj+0x30', predefined: { 'obj' => obj }).to_s
101
101
  # #=> '[rsp+0x50]+0x30'
102
102
  def parse(arg, predefined: {})
103
103
  deref_count = 0
@@ -110,10 +110,10 @@ module OneGadget
110
110
  val = 0
111
111
  if sign
112
112
  raise ArgumentError, "Not support #{arg}" unless OneGadget::Helper.integer?(arg[sign..-1])
113
- val = Integer(arg[sign..-1])
114
- arg = arg[0, sign]
113
+ val = Integer(arg.slice!(sign..-1))
115
114
  end
116
- obj = (predefined[arg] || Lambda.new(arg)) + val
115
+ obj = predefined[arg] || Lambda.new(arg)
116
+ obj += val unless val.zero?
117
117
  deref_count.zero? ? obj : obj.deref
118
118
  end
119
119
  end
@@ -10,13 +10,13 @@ module OneGadget
10
10
  # Instantiate a {Processor} object.
11
11
  # @param [Array<String>] registers Registers that supported in the architecture.
12
12
  def initialize(registers)
13
- @registers = registers.map { |reg| [reg, OneGadget::Emulators::Lambda.new(reg)] }.to_h
13
+ @registers = registers.map { |reg| [reg, to_lambda(reg)] }.to_h
14
14
  @stack = {}
15
15
  end
16
16
 
17
17
  # Parse one command into instruction and arguments.
18
18
  # @param [String] cmd One line of result of objdump.
19
- # @return [Array(Instruction, Array<String>)]
19
+ # @return [(Instruction, Array<String>)]
20
20
  # The parsing result.
21
21
  def parse(cmd)
22
22
  inst = instructions.find { |i| i.match?(cmd) }
@@ -33,6 +33,12 @@ module OneGadget
33
33
  # @return [Array<Instruction>] The support instructions.
34
34
  def instructions; raise NotImplementedError
35
35
  end
36
+
37
+ private
38
+
39
+ def to_lambda(reg)
40
+ OneGadget::Emulators::Lambda.new(reg)
41
+ end
36
42
  end
37
43
  end
38
44
  end
@@ -1,5 +1,7 @@
1
- require 'one_gadget/emulators/processor'
2
1
  require 'one_gadget/emulators/instruction'
2
+ require 'one_gadget/emulators/lambda'
3
+ require 'one_gadget/emulators/processor'
4
+ require 'one_gadget/error'
3
5
 
4
6
  module OneGadget
5
7
  module Emulators
@@ -13,10 +15,10 @@ module OneGadget
13
15
  @sp = sp
14
16
  @pc = pc
15
17
  @stack = Hash.new do |h, k|
16
- lmda = OneGadget::Emulators::Lambda.new(sp)
17
- lmda.immi = k
18
- lmda.deref!
19
- h[k] = lmda
18
+ h[k] = OneGadget::Emulators::Lambda.new(sp).tap do |lmda|
19
+ lmda.immi = k
20
+ lmda.deref!
21
+ end
20
22
  end
21
23
  end
22
24
 
@@ -24,22 +26,22 @@ module OneGadget
24
26
  # Will raise exceptions when encounter unhandled instruction.
25
27
  # @param [String] cmd
26
28
  # One line from result of objdump.
27
- # @return [void]
29
+ # @return [Boolean]
28
30
  def process!(cmd)
29
31
  inst, args = parse(cmd)
30
32
  # return registers[pc] = args[0] if inst.inst == 'call'
31
33
  return true if inst.inst == 'jmp' # believe the fetcher has handled jmp.
32
34
  sym = "inst_#{inst.inst}".to_sym
33
- send(sym, *args) != :fail
35
+ __send__(sym, *args) != :fail
34
36
  end
35
37
 
36
38
  # Process one command, without raising any exceptions.
37
39
  # @param [String] cmd
38
40
  # See {#process!} for more information.
39
- # @return [void]
41
+ # @return [Boolean]
40
42
  def process(cmd)
41
43
  process!(cmd)
42
- rescue ArgumentError
44
+ rescue ArgumentError, OneGadget::Error::Error
43
45
  false
44
46
  end
45
47
 
@@ -55,7 +57,10 @@ module OneGadget
55
57
  Instruction.new('nop', -1),
56
58
  Instruction.new('push', 1),
57
59
  Instruction.new('sub', 2),
58
- Instruction.new('xor', 2)
60
+ Instruction.new('xor', 2),
61
+ Instruction.new('movq', 2),
62
+ Instruction.new('movaps', 2),
63
+ Instruction.new('movhps', 2)
59
64
  ]
60
65
  end
61
66
 
@@ -83,12 +88,53 @@ module OneGadget
83
88
  # Just ignore strange case...
84
89
  return unless tar.include?(sp)
85
90
  tar = OneGadget::Emulators::Lambda.parse(tar, predefined: registers)
86
- return if tar.deref_count != 1 # should not happened
91
+ return if tar.deref_count != 1 # should not happen
87
92
  tar.ref!
88
93
  stack[tar.evaluate(eval_dict)] = src
89
94
  end
90
95
  end
91
96
 
97
+ # This instruction moves 128bits.
98
+ def inst_movaps(tar, src)
99
+ # XXX: here we only support `movaps [sp+*], xmm*`
100
+ # TODO: This need an extra constraint: sp & 0xf == 0
101
+ src, tar = check_xmm_sp(src, tar) { raise_unsupported('movaps', tar, src) }
102
+ off = tar.evaluate(eval_dict)
103
+ (128 / self.class.bits).times do |i|
104
+ stack[off + i * size_t] = src[i]
105
+ end
106
+ end
107
+
108
+ # Mov *src to tar[:64]
109
+ def inst_movq(tar, src)
110
+ # XXX: here we only support `movq xmm*, [sp+*]`
111
+ tar, src = check_xmm_sp(tar, src) { raise_unsupported('movq', tar, src) }
112
+ off = src.evaluate(eval_dict)
113
+ (64 / self.class.bits).times do |i|
114
+ tar[i] = stack[off + i * size_t]
115
+ end
116
+ end
117
+
118
+ # Move *src to tar[64:128]
119
+ def inst_movhps(tar, src)
120
+ # XXX: here we only support `movhps xmm*, [sp+*]`
121
+ tar, src = check_xmm_sp(tar, src) { raise_unsupported('movhps', tar, src) }
122
+ off = src.evaluate(eval_dict)
123
+ (64 / self.class.bits).times do |i|
124
+ tar[i + 64 / self.class.bits] = stack[off + i * size_t]
125
+ end
126
+ end
127
+
128
+ # check if (tar, src) in form (xmm*, [sp+*])
129
+ def check_xmm_sp(tar, src)
130
+ return yield unless tar.start_with?('xmm') && register?(tar) && src.include?(sp)
131
+ tar_lm = OneGadget::Emulators::Lambda.parse(tar, predefined: registers)
132
+ src_lm = OneGadget::Emulators::Lambda.parse(src, predefined: registers)
133
+ return yield if src_lm.deref_count != 1
134
+ src_lm.ref!
135
+ [tar_lm, src_lm]
136
+ end
137
+
92
138
  def inst_lea(tar, src)
93
139
  src = OneGadget::Emulators::Lambda.parse(src, predefined: registers)
94
140
  src.ref!
@@ -97,7 +143,7 @@ module OneGadget
97
143
 
98
144
  def inst_push(val)
99
145
  val = OneGadget::Emulators::Lambda.parse(val, predefined: registers)
100
- registers[sp] -= bytes
146
+ registers[sp] -= size_t
101
147
  cur_top = registers[sp].evaluate(eval_dict)
102
148
  raise ArgumentError, "Corrupted stack pointer: #{cur_top}" unless cur_top.is_a?(Integer)
103
149
  stack[cur_top] = val
@@ -150,14 +196,23 @@ module OneGadget
150
196
  :fail
151
197
  end
152
198
 
153
- def bytes
199
+ def size_t
154
200
  self.class.bits / 8
155
201
  end
156
202
 
157
203
  def eval_dict
158
- dict = {}
159
- dict[sp] = 0
160
- dict
204
+ { sp => 0 }
205
+ end
206
+
207
+ def raise_unsupported(inst, *args)
208
+ raise OneGadget::Error::UnsupportedInstructionArguments, "#{inst} #{args.join(', ')}"
209
+ end
210
+
211
+ def to_lambda(reg)
212
+ return super unless reg =~ /^xmm\d+$/
213
+ Array.new(128 / self.class.bits) do |i|
214
+ OneGadget::Emulators::Lambda.new("#{reg}__#{i}")
215
+ end
161
216
  end
162
217
  end
163
218
  end
@@ -0,0 +1,9 @@
1
+ module OneGadget
2
+ module Error
3
+ class Error < StandardError
4
+ end
5
+
6
+ class UnsupportedInstructionArguments < Error
7
+ end
8
+ end
9
+ end
@@ -15,9 +15,7 @@ module OneGadget
15
15
  # @return [Array<OneGadget::Gadget::Gadget>?]
16
16
  # +nil+ is returned if cannot find target id in database.
17
17
  def from_build_id(build_id, remote: true)
18
- if (build_id =~ /\A#{OneGadget::Helper::BUILD_ID_FORMAT}\Z/).nil?
19
- raise ArgumentError, format('invalid BuildID format: %p', build_id)
20
- end
18
+ OneGadget::Helper.verify_build_id!(build_id)
21
19
  OneGadget::Gadget.builds(build_id, remote: remote)
22
20
  end
23
21
 
@@ -64,6 +64,33 @@ module OneGadget
64
64
  BUILDS[build_id]
65
65
  end
66
66
 
67
+ # Returns the comments in builds/libc-*-<build_id>*.rb
68
+ # @param [String] build_id
69
+ # Supports give only few starting bytes, but a warning will be shown
70
+ # if multiple BulidIDs are matched.
71
+ # @return [String?]
72
+ # Lines of comments.
73
+ # @example
74
+ # puts OneGadget::Gadget.builds_info('3bbdc')
75
+ # # https://gitlab.com/libcdb/libcdb/blob/master/libc/libc6-amd64-2.19-18+deb8u4/lib64/libc-2.19.so
76
+ # #
77
+ # # Advanced Micro Devices X86-64
78
+ # # ...
79
+ def builds_info(build_id)
80
+ raise ArgumentError, "Invalid BuildID #{build_id.inspect}" if build_id =~ /[^0-9a-f]/
81
+ files = Dir.glob(File.join(BUILDS_PATH, "*-#{build_id}*.rb")).sort
82
+ return OneGadget::Logger.not_found(build_id) && nil if files.empty?
83
+ if files.size > 1
84
+ OneGadget::Logger.warn("Multiple BuildIDs match /^#{build_id}/\n")
85
+ show = files.map do |f|
86
+ File.basename(f, '.rb').reverse.split('-', 2).join(' ').reverse
87
+ end
88
+ OneGadget::Logger.warn("Candidates are:\n#{show * "\n"}\n")
89
+ return nil
90
+ end
91
+ OneGadget::Helper.comments_of_file(files.first)
92
+ end
93
+
67
94
  # Add a gadget, for scripts in builds/ to use.
68
95
  # @param [String] build_id The target's build id.
69
96
  # @param [Integer] offset The relative address offset of this gadget.
@@ -1,9 +1,10 @@
1
- require 'elftools'
2
1
  require 'net/http'
3
2
  require 'openssl'
4
3
  require 'pathname'
5
4
  require 'tempfile'
6
5
 
6
+ require 'elftools'
7
+
7
8
  require 'one_gadget/logger'
8
9
 
9
10
  module OneGadget
@@ -13,6 +14,26 @@ module OneGadget
13
14
  BUILD_ID_FORMAT = /[0-9a-f]{40}/
14
15
  # Define class methods here.
15
16
  module ClassMethods
17
+ # Verify if `build_id` is a valid SHA1 hex format.
18
+ # @param [String] build_id
19
+ # BuildID.
20
+ # @raise [ArgumentError]
21
+ # Raises error if invalid.
22
+ # @return [void]
23
+ def verify_build_id!(build_id)
24
+ return if build_id =~ /\A#{OneGadget::Helper::BUILD_ID_FORMAT}\Z/
25
+ raise ArgumentError, format('invalid BuildID format: %p', build_id)
26
+ end
27
+
28
+ # Fetch lines start with '#'.
29
+ # @param [String] file
30
+ # Filename.
31
+ # @return [Array<String>]
32
+ # Lines of comments.
33
+ def comments_of_file(file)
34
+ File.readlines(file).map { |s| s[2..-1].rstrip if s.start_with?('# ') }.compact
35
+ end
36
+
16
37
  # Get absolute path from relative path. Support symlink.
17
38
  # @param [String] path Relative path.
18
39
  # @return [String] Absolute path, with symlink resolved.
@@ -30,7 +51,7 @@ module OneGadget
30
51
  # build_id_of('/lib/x86_64-linux-gnu/libc-2.23.so')
31
52
  # #=> '60131540dadc6796cab33388349e6e4e68692053'
32
53
  def build_id_of(path)
33
- ELFTools::ELFFile.new(File.open(path)).build_id
54
+ File.open(path) { |f| ELFTools::ELFFile.new(f).build_id }
34
55
  end
35
56
 
36
57
  # Disable colorize.
@@ -48,7 +69,7 @@ module OneGadget
48
69
  # Is colorify output enabled?
49
70
  # @return [Boolean]
50
71
  # True or false.
51
- def enable_color
72
+ def color_enabled?
52
73
  # if not set, use tty to check
53
74
  return $stdout.tty? if @disable_color.nil?
54
75
  !@disable_color
@@ -68,7 +89,7 @@ module OneGadget
68
89
  # @param [Symbol] sev Specific which kind of color want to use, valid symbols are defined in +COLOR_CODE+.
69
90
  # @return [String] Wrapper with color codes.
70
91
  def colorize(str, sev: :normal_s)
71
- return str unless enable_color
92
+ return str unless color_enabled?
72
93
  cc = COLOR_CODE
73
94
  color = cc.key?(sev) ? cc[sev] : ''
74
95
  "#{color}#{str.sub(cc[:esc_m], color)}#{cc[:esc_m]}"
@@ -96,9 +117,8 @@ module OneGadget
96
117
  def download_build(file)
97
118
  temp = Tempfile.new(['gadgets', file + '.rb'])
98
119
  url_request(url_of_file(File.join('lib', 'one_gadget', 'builds', file + '.rb')))
99
- temp.write url_request(url_of_file(File.join('lib', 'one_gadget', 'builds', file + '.rb')))
100
- temp.close
101
- temp
120
+ temp.write(url_request(url_of_file(File.join('lib', 'one_gadget', 'builds', file + '.rb'))))
121
+ temp.tap(&:close)
102
122
  end
103
123
 
104
124
  # Get the latest builds list from repo.
@@ -132,14 +152,14 @@ module OneGadget
132
152
  # @return [void]
133
153
  def ask_update(msg: '')
134
154
  name = 'one_gadget'
135
- cmd = colorize("gem update #{name}")
155
+ cmd = colorize("gem update #{name} && gem cleanup #{name}")
136
156
  OneGadget::Logger.info(msg + "\n" + "Update with: $ #{cmd}" + "\n")
137
157
  end
138
158
 
139
159
  # Fetch the file archiecture of +file+.
140
160
  # @param [String] file The target ELF filename.
141
- # @return [String]
142
- # Only supports :amd64, :i386 now.
161
+ # @return [Symbol]
162
+ # Only supports architecture amd64 and i386 now.
143
163
  def architecture(file)
144
164
  f = File.open(file)
145
165
  str = ELFTools::ELFFile.new(f).machine
@@ -25,13 +25,13 @@ module OneGadget
25
25
  # @param [String] build_id
26
26
  # Build ID.
27
27
  def not_found(build_id)
28
- warn("Cannot find BuildID [#{build_id}]")
28
+ warn("Cannot find BuildID [#{build_id}]\n")
29
29
  []
30
30
  end
31
31
 
32
32
  %i[info warn].each do |sym|
33
33
  define_method(sym) do |msg|
34
- @logger.send(sym, msg)
34
+ @logger.__send__(sym, msg)
35
35
  end
36
36
  end
37
37
  end
@@ -53,8 +53,8 @@ module OneGadget
53
53
  FileUtils.mkdir_p(dir) unless File.directory?(dir)
54
54
  IO.binwrite(CACHE_FILE, '') unless File.exist?(CACHE_FILE)
55
55
  CACHE_FILE
56
- rescue # prevent dir is not writable
57
- return nil
56
+ rescue Errno::EACCES # prevent dir is not writable
57
+ nil
58
58
  end
59
59
  end
60
60
  end
@@ -1,4 +1,4 @@
1
1
  module OneGadget
2
2
  # Current gem version.
3
- VERSION = '1.5.0'.freeze
3
+ VERSION = '1.6.0'.freeze
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: one_gadget
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - david942j
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-06 00:00:00.000000000 Z
11
+ date: 2018-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: elftools
@@ -24,76 +24,62 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
- - !ruby/object:Gem::Dependency
28
- name: codeclimate-test-reporter
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0.6'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '0.6'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: rake
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - "~>"
46
32
  - !ruby/object:Gem::Version
47
- version: '12.0'
33
+ version: '12.3'
48
34
  type: :development
49
35
  prerelease: false
50
36
  version_requirements: !ruby/object:Gem::Requirement
51
37
  requirements:
52
38
  - - "~>"
53
39
  - !ruby/object:Gem::Version
54
- version: '12.0'
40
+ version: '12.3'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: rspec
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - "~>"
60
46
  - !ruby/object:Gem::Version
61
- version: '3.5'
47
+ version: '3.7'
62
48
  type: :development
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
- version: '3.5'
54
+ version: '3.7'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: rubocop
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - "~>"
74
60
  - !ruby/object:Gem::Version
75
- version: '0.49'
61
+ version: '0.55'
76
62
  type: :development
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
- version: '0.49'
68
+ version: '0.55'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: simplecov
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
73
  - - "~>"
88
74
  - !ruby/object:Gem::Version
89
- version: 0.13.0
75
+ version: 0.16.1
90
76
  type: :development
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
- version: 0.13.0
82
+ version: 0.16.1
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: yard
99
85
  requirement: !ruby/object:Gem::Requirement
@@ -792,12 +778,17 @@ files:
792
778
  - lib/one_gadget/builds/libc-2.25-912fc00c0da67045111928bd5c8a350e5be18c41.rb
793
779
  - lib/one_gadget/builds/libc-2.25-eae5038c2b9ae67d9eda345aa9fbe0a7185ab436.rb
794
780
  - lib/one_gadget/builds/libc-2.26-2104f3d4ad5cf68603afbe7ba1a17f5ac99c5988.rb
781
+ - lib/one_gadget/builds/libc-2.26-ddcc13122ddbfe5e5ef77d4ebe66d124ae5762c2.rb
782
+ - lib/one_gadget/builds/libc-2.26-f65648a832414f2144ce795d75b6045a1ec2e252.rb
783
+ - lib/one_gadget/builds/libc-2.27-63b3d43ad45e1b0f601848c65b067f9e9b40528b.rb
784
+ - lib/one_gadget/builds/libc-2.27-b417c0ba7cc5cf06d1d1bed6652cedb9253c60d0.rb
795
785
  - lib/one_gadget/emulators/amd64.rb
796
786
  - lib/one_gadget/emulators/i386.rb
797
787
  - lib/one_gadget/emulators/instruction.rb
798
788
  - lib/one_gadget/emulators/lambda.rb
799
789
  - lib/one_gadget/emulators/processor.rb
800
790
  - lib/one_gadget/emulators/x86.rb
791
+ - lib/one_gadget/error.rb
801
792
  - lib/one_gadget/fetcher.rb
802
793
  - lib/one_gadget/fetchers/amd64.rb
803
794
  - lib/one_gadget/fetchers/base.rb
@@ -827,7 +818,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
827
818
  version: '0'
828
819
  requirements: []
829
820
  rubyforge_project:
830
- rubygems_version: 2.5.2
821
+ rubygems_version: 2.6.14
831
822
  signing_key:
832
823
  specification_version: 4
833
824
  summary: one_gadget