Ptrace 0.9.1

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 ADDED
@@ -0,0 +1,105 @@
1
+
2
+ Ptrace
3
+
4
+ A Ruby C extension (and gem) for the POSIX ptrace facility.
5
+
6
+ NOTE: This is currently alpha software, and is released only to publish the
7
+ API of the module. This should not be used in production software, as
8
+ many features are incomplete.
9
+
10
+ BUILD
11
+ -----
12
+
13
+ The standard C extension build process is used:
14
+
15
+ bash# ruby extconf.rb
16
+ bash# make
17
+
18
+ Note that the Ruby headers must be installed. On Ubuntu, these are in the
19
+ ruby-dev or ruby1.9-dev package.
20
+
21
+
22
+ The gem is built using the standard gem build command:
23
+
24
+ bash# gem build Ptrace.gemspec
25
+
26
+
27
+ The top-level Makefile supports each of these builds with the commands
28
+ 'make' and 'make gem'.
29
+
30
+ bash# make
31
+ # builds C extension
32
+ bash# make gem
33
+ # builds the gem
34
+
35
+
36
+
37
+ EXAMPLES
38
+
39
+ Extended examples are provided in the 'examples' directory. The following
40
+ code snippets give a brief overview of using the Ptrace extension.
41
+
42
+ # attach to process
43
+ pid = 10167 # just an example, use a real PID!
44
+ tgt = Ptrace::Target.attach(pid)
45
+ # terminate process
46
+ tgt.kill
47
+
48
+ # launch process
49
+ cmd = './a.out'
50
+ tgt = Ptrace::Target.launch cmd
51
+ # detach
52
+ tgt.detach
53
+
54
+ # step first 10 instructions, printing general registers
55
+ tgt = Ptrace::Target.launch cmd
56
+ 10.times do |i|
57
+ puts "DEBUGGER STEP #{i}"
58
+ # print registers
59
+ tgt.regs.read.each { |name, val| puts "%s: %016X" % name, val }
60
+ tgt.step
61
+ end
62
+ # continue process
63
+ tgt.cont
64
+
65
+
66
+ # print register contents on syscall in/out
67
+ tgt = Ptrace::Target.launch cmd
68
+ cont = true
69
+ while cont
70
+ begin
71
+ tgt.syscall
72
+ puts "IN: #{tgt.regs.read.inspect}"
73
+ tgt.syscall
74
+ puts "OUT: #{tgt.regs.read.inspect}"
75
+ rescue Ptrace::InvalidProcessError
76
+ cont = false
77
+ end
78
+
79
+ end
80
+
81
+ # step first ten instructions, printing bytes at EIP and ESP
82
+ tgt = Ptrace::Target.launch cmd
83
+ 10.times do |i|
84
+ sleep 1
85
+ begin
86
+ tgt.step
87
+
88
+ regs = tgt.regs.read
89
+ ip = (regs.include? 'rip') ? regs['rip'] : regs['eip']
90
+ puts ("DEBUGGER STEP %d: %X in %d" % [i, ip, tgt.pid])
91
+
92
+ v = tgt.text.peek(ip)
93
+ bytes = [v, v >> 8, v >> 12, v >> 16].map { |byte| byte & 0xFF }
94
+ puts " BYTES AT EIP: #{bytes.map{ |byte| "%02X" % byte }.join(' ')}"
95
+
96
+ esp_name = (regs.include? 'rsp') ? 'rsp' : 'esp'
97
+ v = tgt.data.peek(regs[esp_name])
98
+ bytes = [v, v >> 8, v >> 12, v >> 16].map { |byte| byte & 0xFF }
99
+ puts " BYTES AT ESP: #{bytes.map{ |byte| "%02X" % byte }.join(' ')}"
100
+
101
+ # Modify ESP, just because we can
102
+ puts " ...WRITING ESP..."
103
+ tgt.data.poke(regs[esp_name], v + 0x100)
104
+ end
105
+ tgt.cont
data/examples/kill.rb ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'Ptrace'
4
+
5
+ if __FILE__ == $0
6
+
7
+ cmd = ARGV.join(' ')
8
+
9
+ tgt = Ptrace::Target.launch cmd
10
+ puts "launched CMD #{tgt.pid}"
11
+ puts "Killing..."
12
+ tgt.kill
13
+ puts "Done."
14
+ end
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'Ptrace'
4
+
5
+ if __FILE__ == $0
6
+
7
+ cmd = ARGV.join(' ')
8
+
9
+ tgt = Ptrace::Target.launch cmd
10
+ return if not tgt
11
+
12
+ puts "launched CMD #{cmd} as #{tgt.pid}"
13
+ 10.times do |i|
14
+ sleep 1
15
+ begin
16
+ tgt.step
17
+
18
+ regs = tgt.regs.read
19
+ ip = (regs.include? 'rip') ? regs['rip'] : regs['eip']
20
+ puts ("DEBUGGER STEP %d: %X in %d" % [i, ip, tgt.pid])
21
+
22
+ v = tgt.text.peek(ip)
23
+ bytes = [v, v >> 8, v >> 12, v >> 16].map { |byte| byte & 0xFF }
24
+ puts " BYTES AT EIP: #{bytes.map{ |byte| "%02X" % byte }.join(' ')}"
25
+
26
+ esp_name = (regs.include? 'rsp') ? 'rsp' : 'esp'
27
+ v = tgt.data.peek(regs[esp_name])
28
+ bytes = [v, v >> 8, v >> 12, v >> 16].map { |byte| byte & 0xFF }
29
+ puts " BYTES AT ESP: #{bytes.map{ |byte| "%02X" % byte }.join(' ')}"
30
+
31
+ puts " ...WRITING ESP..."
32
+ tgt.data.poke(regs[esp_name], v + 0x100)
33
+
34
+ regs = tgt.regs.read
35
+ v1 = tgt.data.peek(regs[esp_name])
36
+ bytes = [v1, v1 >> 8, v1 >> 12, v1 >> 16].map { |byte| byte & 0xFF }
37
+ puts " BYTES AT EBP: #{bytes.map{ |byte| "%02X" % byte }.join(' ')}"
38
+
39
+ puts " ...REVERTING ESP..."
40
+ tgt.data.poke(regs[esp_name], v)
41
+
42
+ regs = tgt.regs.read
43
+ v2 = tgt.data.peek(regs[esp_name])
44
+ bytes = [v2, v2 >> 8, v2 >> 12, v2 >> 16].map { |byte| byte & 0xFF }
45
+ puts " BYTES AT EBP: #{bytes.map{ |byte| "%02X" % byte }.join(' ')}"
46
+ rescue Exception => e
47
+ puts e.message
48
+ puts e.backtrace.join("\n")
49
+ end
50
+ end
51
+ puts "DEBUGGER RESUME"
52
+ tgt.cont
53
+ end
data/examples/regs.rb ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env ruby
2
+ # TODO : read, write regs
3
+
4
+ require 'Ptrace'
5
+
6
+ if __FILE__ == $0
7
+
8
+ cmd = ARGV.join(' ')
9
+
10
+ tgt = Ptrace::Target.launch cmd
11
+ return if not tgt
12
+
13
+ puts "launched CMD #{cmd} as #{tgt.pid}"
14
+ 10.times do |i|
15
+ sleep 1
16
+ begin
17
+ tgt.step
18
+ regs = tgt.regs.read
19
+ ebx_name = (regs.include? 'rbx') ? 'rbx' : 'ebx'
20
+
21
+ v = regs[ebx_name]
22
+ puts "EBX ORIG : %016X" % v
23
+
24
+ tgt.regs[ebx_name] = v + 0x1000
25
+ tgt.regs.write
26
+
27
+ regs = tgt.regs.read
28
+ v1 = regs[ebx_name]
29
+ puts "EBX AFTER WRITE : %016X" % v1
30
+
31
+ tgt.regs[ebx_name] = v
32
+ tgt.regs.write
33
+
34
+ regs = tgt.regs.read
35
+ v2 = regs[ebx_name]
36
+ puts "EBX AFTER REVERT : %016X" % v2
37
+
38
+ # TODO: FPREGS
39
+
40
+ rescue Exception => e
41
+ puts e.message
42
+ puts e.backtrace.join("\n")
43
+ end
44
+ end
45
+ puts "DEBUGGER RESUME"
46
+ tgt.cont
47
+ end
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'Ptrace'
4
+
5
+ if __FILE__ == $0
6
+
7
+ cmd = ARGV.join(' ')
8
+
9
+ tgt = Ptrace::Target.launch cmd
10
+ puts "launched CMD #{tgt.pid}"
11
+ cont = true
12
+ while cont
13
+
14
+ begin
15
+ # test PT_SYSCALL directly
16
+ # call
17
+ tgt.syscall
18
+ puts "IN: #{tgt.regs.read.inspect}"
19
+
20
+ # ret
21
+ tgt.syscall
22
+ puts "OUT: #{tgt.regs.read.inspect}"
23
+
24
+ # test syscall wrapper
25
+ state = tgt.syscall_state
26
+ puts state.inspect
27
+ rescue Ptrace::InvalidProcessError
28
+ cont = false
29
+ end
30
+
31
+ end
32
+
33
+ end