PageRenderTime 28ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/metasm/metasm/os/remote.rb

https://gitlab.com/leijianbin/metasploit-framework
Ruby | 527 lines | 455 code | 41 blank | 31 comment | 53 complexity | eb9bbaa47f6a7f23f8844359a9a2d691 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, GPL-2.0, LGPL-2.1
  1. # This file is part of Metasm, the Ruby assembly manipulation suite
  2. # Copyright (C) 2006-2009 Yoann GUILLOT
  3. #
  4. # Licence is LGPL, see LICENCE in the top-level directory
  5. require 'metasm/os/main'
  6. require 'socket'
  7. module Metasm
  8. # lowlevel interface to the gdbserver protocol
  9. class GdbClient
  10. GDBREGS_IA32 = %w[eax ecx edx ebx esp ebp esi edi eip eflags cs ss ds es fs gs].map { |r| r.to_sym } # XXX [77] = 'orig_eax'
  11. GDBREGS_X64 = %w[rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15 rip rflags cs ss ds es fs gs].map { |r| r.to_sym }
  12. # compute the hex checksum used in gdb protocol
  13. def gdb_csum(buf)
  14. '%02x' % (buf.unpack('C*').inject(0) { |cs, c| cs + c } & 0xff)
  15. end
  16. # send the buffer, waits ack
  17. # return true on success
  18. def gdb_send(cmd, buf='')
  19. buf = cmd + buf
  20. buf = '$' << buf << '#' << gdb_csum(buf)
  21. 5.times {
  22. @io.write buf
  23. loop do
  24. break if not IO.select([@io], nil, nil, 0.2)
  25. raise Errno::EPIPE if not ack = @io.read(1)
  26. case ack
  27. when '+'
  28. return true
  29. when '-'
  30. puts "gdb_send: ack neg" if $DEBUG
  31. break
  32. when nil
  33. return
  34. end
  35. end
  36. }
  37. log "send error #{cmd.inspect} (no ack)"
  38. false
  39. end
  40. def quiet_during
  41. pq = quiet
  42. @quiet = true
  43. yield
  44. ensure
  45. @quiet = pq
  46. end
  47. # return buf, or nil on error / csum error
  48. # waits IO.select(timeout) between each char
  49. # outstr is used internally only to handle multiline output string
  50. def gdb_readresp(timeout=nil, outstr=nil)
  51. @recv_ctx ||= {}
  52. @recv_ctx[:state] ||= :nosync
  53. buf = nil
  54. while @recv_ctx
  55. return unless IO.select([@io], nil, nil, timeout)
  56. raise Errno::EPIPE if not c = @io.read(1)
  57. case @recv_ctx[:state]
  58. when :nosync
  59. if c == '$'
  60. @recv_ctx[:state] = :data
  61. @recv_ctx[:buf] = ''
  62. end
  63. when :data
  64. if c == '#'
  65. @recv_ctx[:state] = :csum1
  66. @recv_ctx[:cs] = ''
  67. else
  68. @recv_ctx[:buf] << c
  69. end
  70. when :csum1
  71. @recv_ctx[:cs] << c
  72. @recv_ctx[:state] = :csum2
  73. when :csum2
  74. cs = @recv_ctx[:cs] << c
  75. buf = @recv_ctx[:buf]
  76. @recv_ctx = nil
  77. if cs.downcase == gdb_csum(buf).downcase
  78. @io.write '+'
  79. else
  80. log "transmit error"
  81. @io.write '-'
  82. return
  83. end
  84. end
  85. end
  86. case buf
  87. when /^E(..)$/
  88. e = $1.to_i(16)
  89. log "error #{e} (#{PTrace::ERRNO.index(e)})"
  90. return
  91. when /^O([0-9a-fA-F]*)$/
  92. if not outstr
  93. first = true
  94. outstr = ''
  95. end
  96. outstr << unhex($1)
  97. ret = gdb_readresp(timeout, outstr)
  98. outstr.split("\n").each { |e| log 'gdb: ' + e } if first
  99. return ret
  100. end
  101. puts "gdb_readresp: got #{buf[0, 64].inspect}#{'...' if buf.length > 64}" if $DEBUG
  102. buf
  103. end
  104. def gdb_msg(*a)
  105. gdb_readresp if gdb_send(*a)
  106. end
  107. # rle: build the regexp that will match repetitions of a character, skipping counts leading to invalid char
  108. rng = [3..(125-29)]
  109. [?+, ?-, ?#, ?$].sort.each { |invalid|
  110. invalid = invalid.unpack('C').first if invalid.kind_of? String
  111. invalid -= 29
  112. rng.each_with_index { |r, i|
  113. if r.include? invalid
  114. replace = [r.begin..invalid-1, invalid+1..r.end]
  115. replace.delete_if { |r_| r_.begin > r_.end }
  116. rng[i, 1] = replace
  117. end
  118. }
  119. }
  120. repet = rng.reverse.map { |r| "\\1{#{r.begin},#{r.end}}" }.join('|')
  121. RLE_RE = /(.)(#{repet})/m
  122. # rle-compress a buffer
  123. # a character followed by '*' followed by 'x' is asc(x)-28 repetitions of the char
  124. # eg '0* ' => '0' * (asc(' ') - 28) = '0000'
  125. # for the count character, it must be 32 <= char < 126 and not be '+' '-' '#' or '$'
  126. def rle(buf)
  127. buf.gsub(RLE_RE) {
  128. chr, len = $1, $2.length+1
  129. chr + '*' + (len+28).chr
  130. }
  131. end
  132. # decompress rle-encoded data
  133. def unrle(buf) buf.gsub(/(.)\*(.)/) { $1 * ($2.unpack('C').first-28) } end
  134. # send an integer as a long hex packed with leading 0 stripped
  135. def hexl(int) @pack_netint[[int]].unpack('H*').first.sub(/^0+(.)/, '\\1') end
  136. # send a binary buffer as a rle hex-encoded
  137. def hex(buf) buf.unpack('H*').first end
  138. # decode an rle hex-encoded buffer
  139. def unhex(buf)
  140. buf = buf[/^[a-fA-F0-9]*/]
  141. buf = '0' + buf if buf.length & 1 == 1
  142. [buf].pack('H*')
  143. end
  144. # retrieve remote regs
  145. def read_regs
  146. if buf = gdb_msg('g')
  147. regs = unhex(unrle(buf))
  148. p @unpack_int[regs].map { |v| '%x' % v } if $DEBUG
  149. if regs.length < @regmsgsize
  150. # retry once, was probably a response to something else
  151. puts "bad regs size!" if $DEBUG
  152. buf = gdb_msg('g')
  153. regs = unhex(unrle(buf)) if buf
  154. if not buf or regs.length < @regmsgsize
  155. raise "regs buffer recv is too short !"
  156. end
  157. end
  158. Hash[*@gdbregs.zip(@unpack_int[regs]).flatten]
  159. end
  160. end
  161. # send the reg values
  162. def send_regs(r = {})
  163. return if r.empty?
  164. regs = r.values_at(*@gdbregs)
  165. gdb_msg('G', hex(@pack_int[regs]))
  166. end
  167. # read memory (small blocks prefered)
  168. def getmem(addr, len)
  169. return '' if len == 0
  170. if mem = quiet_during { gdb_msg('m', hexl(addr) << ',' << hexl(len)) } and mem != ''
  171. unhex(unrle(mem))
  172. end
  173. end
  174. # write memory (small blocks prefered)
  175. def setmem(addr, data)
  176. len = data.length
  177. return if len == 0
  178. raise 'writemem error' if not gdb_msg('M', hexl(addr) << ',' << hexl(len) << ':' << rle(hex(data)))
  179. end
  180. def continue
  181. gdb_send('c')
  182. end
  183. def singlestep
  184. gdb_send('s')
  185. end
  186. def break
  187. @io.write("\3")
  188. end
  189. def kill
  190. gdb_send('k')
  191. end
  192. def detach
  193. gdb_send('D')
  194. end
  195. # monitor, aka remote command
  196. def rcmd(cmd)
  197. gdb_msg('qRcmd,' + hex(cmd))
  198. end
  199. attr_accessor :io, :cpu, :gdbregs
  200. def initialize(io, cpu='Ia32')
  201. cpu = Metasm.const_get(cpu).new if cpu.kind_of? String
  202. raise 'unknown cpu' if not cpu.kind_of? CPU
  203. setup_arch(cpu)
  204. @cpu = cpu
  205. case io
  206. when IO; @io = io
  207. when /^udp:(.*):(.*?)$/i; @io = UDPSocket.new ; @io.connect($1, $2)
  208. when /^(?:tcp:)?(.*):(.*?)$/i; @io = TCPSocket.open($1, $2) # XXX matches C:\fail
  209. # TODO pipe, serial port, etc ; also check ipv6
  210. else raise "unknown target #{io.inspect}"
  211. end
  212. gdb_setup
  213. end
  214. def gdb_setup
  215. gdb_msg('q', 'Supported')
  216. #gdb_msg('Hc', '-1')
  217. #gdb_msg('qC')
  218. if not gdb_msg('?')
  219. log "nobody on the line, waiting for someone to wake up"
  220. IO.select([@io], nil, nil, nil)
  221. log "who's there ?"
  222. end
  223. end
  224. def set_hwbp(type, addr, len=1, set=true)
  225. set = (set ? 'Z' : 'z')
  226. type = { 'r' => '3', 'w' => '2', 'x' => '1', 's' => '0' }[type.to_s] || raise("invalid bp type #{type.inspect}")
  227. gdb_msg(set, type << ',' << hexl(addr) << ',' << hexl(len))
  228. true
  229. end
  230. def unset_hwbp(type, addr, len=1)
  231. set_hwbp(type, addr, len, false)
  232. end
  233. # use qSymbol to retrieve a symbol value (uint)
  234. def request_symbol(name)
  235. resp = gdb_msg('qSymbol:', hex(name))
  236. if resp and a = resp.split(':')[1]
  237. @unpack_netint[unhex(a)].first
  238. end
  239. end
  240. def check_target(timeout=0)
  241. return if not msg = gdb_readresp(timeout)
  242. case msg[0]
  243. when ?S
  244. sig = unhex(msg[1, 2]).unpack('C').first
  245. { :state => :stopped, :info => "signal #{sig} #{PTrace::SIGNAL[sig]}" }
  246. when ?T
  247. sig = unhex(msg[1, 2]).unpack('C').first
  248. ret = { :state => :stopped, :info => "signal #{sig} #{PTrace::SIGNAL[sig]}" }
  249. ret.update msg[3..-1].split(';').inject({}) { |h, s| k, v = s.split(':', 2) ; h.update k => (v || true) } # 'thread' -> pid
  250. when ?W
  251. code = unhex(msg[1, 2]).unpack('C').first
  252. { :state => :dead, :info => "exited with code #{code}" }
  253. when ?X
  254. sig = unhex(msg[1, 2]).unpack('C').first
  255. { :state => :dead, :info => "signal #{sig} #{PTrace::SIGNAL[sig]}" }
  256. else
  257. log "check_target: unhandled #{msg.inspect}"
  258. { :state => :unknown }
  259. end
  260. end
  261. attr_accessor :logger, :quiet
  262. def log(s)
  263. return if quiet
  264. @logger ||= $stdout
  265. @logger.puts s
  266. end
  267. # setup the various function used to pack ints & the reg list
  268. # according to a target CPU
  269. def setup_arch(cpu)
  270. case cpu.shortname
  271. when 'ia32'
  272. @gdbregs = GDBREGS_IA32
  273. @regmsgsize = 4 * @gdbregs.length
  274. when 'x64'
  275. @gdbregs = GDBREGS_X64
  276. @regmsgsize = 8 * @gdbregs.length
  277. when 'arm'
  278. @gdbregs = cpu.dbg_register_list
  279. @regmsgsize = 4 * @gdbregs.length
  280. else
  281. # we can still use readmem/kill and other generic commands
  282. # XXX serverside setregs may fail if we give an incorrect regbuf size
  283. puts "unsupported GdbServer CPU #{cpu.shortname}"
  284. @gdbregs = [*0..32].map { |i| "r#{i}".to_sym }
  285. @regmsgsize = 0
  286. end
  287. # yay life !
  288. # do as if cpu is littleendian, fixup at the end
  289. case cpu.size
  290. when 16
  291. @pack_netint = lambda { |i| i.pack('n*') }
  292. @unpack_netint = lambda { |s| s.unpack('n*') }
  293. @pack_int = lambda { |i| i.pack('v*') }
  294. @unpack_int = lambda { |s| s.unpack('v*') }
  295. when 32
  296. @pack_netint = lambda { |i| i.pack('N*') }
  297. @unpack_netint = lambda { |s| s.unpack('N*') }
  298. @pack_int = lambda { |i| i.pack('V*') }
  299. @unpack_int = lambda { |s| s.unpack('V*') }
  300. when 64
  301. bswap = lambda { |s| s.scan(/.{8}/m).map { |ss| ss.reverse }.join }
  302. @pack_netint = lambda { |i| i.pack('Q*') }
  303. @unpack_netint = lambda { |s| s.unpack('Q*') }
  304. @pack_int = lambda { |i| bswap[i.pack('Q*')] }
  305. @unpack_int = lambda { |s| bswap[s].unpack('Q*') }
  306. if [1].pack('Q')[0] == ?\1 # ruby interpreter littleendian
  307. @pack_netint, @pack_int = @pack_int, @pack_netint
  308. @unpack_netint, @unpack_int = @unpack_int, @unpack_netint
  309. end
  310. else raise "GdbServer: unsupported cpu size #{cpu.size}"
  311. end
  312. # if target cpu is bigendian, use netint everywhere
  313. if cpu.endianness == :big
  314. @pack_int = @pack_netint
  315. @unpack_int = @unpack_netint
  316. end
  317. end
  318. end
  319. # virtual string to access the remote process memory
  320. class GdbRemoteString < VirtualString
  321. attr_accessor :gdb
  322. def initialize(gdb, addr_start=0, length=nil)
  323. @gdb = gdb
  324. length ||= 1 << (@gdb.cpu.size rescue 32)
  325. @pagelength = 512
  326. super(addr_start, length)
  327. end
  328. def dup(addr=@addr_start, len=@length)
  329. self.class.new(@gdb, addr, len)
  330. end
  331. def rewrite_at(addr, data)
  332. len = data.length
  333. off = 0
  334. while len > @pagelength
  335. @gdb.setmem(addr+off, data[off, @pagelength])
  336. off += @pagelength
  337. len -= @pagelength
  338. end
  339. @gdb.setmem(addr+off, data[off, len])
  340. end
  341. def get_page(addr, len=@pagelength)
  342. @gdb.getmem(addr, len)
  343. end
  344. end
  345. # this class implements a high-level API using the gdb-server network debugging protocol
  346. class GdbRemoteDebugger < Debugger
  347. attr_accessor :gdb, :check_target_timeout
  348. def initialize(url, cpu='Ia32')
  349. @gdb = GdbClient.new(url, cpu)
  350. @gdb.logger = self
  351. @cpu = @gdb.cpu
  352. @memory = GdbRemoteString.new(@gdb)
  353. @reg_val_cache = {}
  354. @regs_dirty = false
  355. # when checking target, if no message seen since this much seconds, send a 'status' query
  356. @check_target_timeout = 1
  357. super()
  358. end
  359. def invalidate
  360. sync_regs
  361. @reg_val_cache.clear
  362. super()
  363. end
  364. def get_reg_value(r)
  365. return @reg_val_cache[r] || 0 if @state != :stopped
  366. sync_regs
  367. @reg_val_cache = @gdb.read_regs || {} if @reg_val_cache.empty?
  368. @reg_val_cache[r] || 0
  369. end
  370. def set_reg_value(r, v)
  371. @reg_val_cache[r] = v
  372. @regs_dirty = true
  373. end
  374. def sync_regs
  375. @gdb.send_regs(@reg_val_cache) if @regs_dirty and not @reg_val_cache.empty?
  376. @regs_dirty = false
  377. end
  378. def do_check_target
  379. return if @state == :dead
  380. t = Time.now
  381. @last_check_target ||= t
  382. if @state == :running and t - @last_check_target > @check_target_timeout
  383. @gdb.io.write '$?#' << @gdb.gdb_csum('?')
  384. @last_check_target = t
  385. end
  386. return unless i = @gdb.check_target(0.01)
  387. invalidate if i[:state] == :stopped and @state != :stopped
  388. @state, @info = i[:state], i[:info]
  389. @info = nil if @info =~ /TRAP/
  390. end
  391. def do_wait_target
  392. return unless i = @gdb.check_target(nil)
  393. invalidate if i[:state] == :stopped and @state != :stopped
  394. @state, @info = i[:state], i[:info]
  395. @info = nil if @info =~ /TRAP/
  396. end
  397. def do_continue(*a)
  398. return if @state != :stopped
  399. @state = :running
  400. @info = 'continue'
  401. @gdb.continue
  402. @last_check_target = Time.now
  403. end
  404. def do_singlestep(*a)
  405. return if @state != :stopped
  406. @state = :running
  407. @info = 'singlestep'
  408. @gdb.singlestep
  409. @last_check_target = Time.now
  410. end
  411. def break
  412. @gdb.break
  413. end
  414. def kill(sig=nil)
  415. # TODO signal nr
  416. @gdb.kill
  417. @state = :dead
  418. @info = 'killed'
  419. end
  420. def detach
  421. super() # remove breakpoints & stuff
  422. @gdb.detach
  423. @state = :dead
  424. @info = 'detached'
  425. end
  426. # set to true to use the gdb msg to handle bpx, false to set 0xcc ourself
  427. attr_accessor :gdb_bpx
  428. def enable_bp(addr)
  429. return if not b = @breakpoint[addr]
  430. b.state = :active
  431. case b.type
  432. when :bpx
  433. if gdb_bpx
  434. @gdb.set_hwbp('s', addr, 1)
  435. else
  436. @cpu.dbg_enable_bp(self, addr, b)
  437. end
  438. when :hw
  439. @gdb.set_hwbp(b.mtype, addr, b.mlen)
  440. end
  441. end
  442. def disable_bp(addr)
  443. return if not b = @breakpoint[addr]
  444. b.state = :inactive
  445. case b.type
  446. when :bpx
  447. if gdb_bpx
  448. @gdb.unset_hwbp('s', addr, 1)
  449. else
  450. @cpu.dbg_disable_bp(self, addr, b)
  451. end
  452. when :hw
  453. @gdb.unset_hwbp(b.mtype, addr, b.mlen)
  454. end
  455. end
  456. def check_pre_run(*a)
  457. sync_regs
  458. super(*a)
  459. end
  460. def loadallsyms
  461. puts 'loadallsyms unsupported'
  462. end
  463. def ui_command_setup(ui)
  464. ui.new_command('monitor', 'send a remote command to run on the target') { |arg| @gdb.rcmd(arg) }
  465. end
  466. end
  467. end