Ptrace 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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