摘要:在調(diào)試程序的時候,一般我們只能通過以下幾種方式進行調(diào)試程序中已經(jīng)有的日志在代碼中插入但是以上的方法也有不方便的地方,比如對于已經(jīng)在運行中的程序,就不可能停止程序后加入調(diào)試代碼和增加新的日志從的項目得到靈感,嘗試對正在運行的進程插入代碼,在程
在調(diào)試 Python 程序的時候,一般我們只能通過以下幾種方式進行調(diào)試:
程序中已經(jīng)有的日志
在代碼中插入 import pdb; pdb.set_trace()
但是以上的方法也有不方便的地方, 比如對于已經(jīng)在運行中的程序, 就不可能停止程序后加入 調(diào)試代碼和增加新的日志.
從 JAVA 的 BTrace(https://kenai.com/projects/btrace) 項目得到靈感,嘗試對正在運行的 Python 進程插入代碼,在程序運行到指定的函數(shù)后,自動連接遠程主機進行調(diào)試
首先介紹三個開源的項目, 本實驗需要用到這三個項目
Pyasite https://github.com/lmacken/pyrasite Tools for injecting code into running Python processes
Byteplay https://github.com/serprex/byteplay 一個字節(jié)碼維護項目,類似 java的asm/cglib
Rpdb-Shell https://github.com/alex8224/Rpdb-Shell
待注入的代碼, 用官方的 tornado hello demo 做例子
import tornado.ioloop import tornado.web import os class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") application = tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": application.listen(8888) print(os.getpid()) tornado.ioloop.IOLoop.instance().start()
注入以下代碼(testinject.py)到 get 中
import sys import dis import inspect from byteplay import * def wearedcode(fcode): c = Code.from_code(fcode) if c.code[1] == (LOAD_CONST, "injected"): return fcode c.code[1:1] = [ (LOAD_CONST, injected"), (STORE_FAST, "name"), (LOAD_FAST, "name"), (PRINT_ITEM, None), (PRINT_NEWLINE, None), (LOAD_CONST, -1), (LOAD_CONST, None), (IMPORT_NAME, "rpdb"), (STORE_FAST, "rpdb"), (LOAD_FAST, "rpdb"), (LOAD_ATTR, "trace_to_remote"), (LOAD_CONST, "192.168.1.1"), (CALL_FUNCTION, 1), (POP_TOP, None) ] return c.to_code() def trace(frame, event, arg): if event != "call": return co = frame.f_code func_name = co.co_name if func_name == "write": return if func_name == "get": import tornado.web args = inspect.getargvalues(frame) if "self" in args.locals: if isinstance(args.locals["self"], tornado.web.RequestHandler): getmethod = args.locals["self"].get code = getmethod.__func__.__code__ getmethod.__func__.__code__ = wearedcode(code) return sys.settrace(trace)環(huán)境
ubuntu 14.04 64bit LTS
Python 2.7.6
步驟在機器上安裝上面需要用到的三個項目
python server.py
在 192.168.1.1 執(zhí)行 nc -l 4444
pyrasite $(ps aux |grep server.py |grep -v grep|awk "{print $2}") testinject.py
執(zhí)行 curl http://localhost:8000 兩次, 在第二次請求時替換的 bytecode 才會生效
結(jié)果在執(zhí)行上面的步驟后, 在執(zhí)行第二次 curl http://127.0.0.1:8000 后, 應(yīng)該能夠看到控制臺輸入 injected 的字樣,并且 nc -l 4444 監(jiān)聽的終端會出現(xiàn) (pdb)> 的字樣, 這樣就能夠?qū)φ谶\行中的程序進行調(diào)試了.
原理Pyasite 可以注入代碼到運行中的 Python 進程,它利用了 Python 的 PyRun_SimpleString 這個API插入代碼, 至于進程注入應(yīng)該是使用了 ptrace
Byteplay 是一個可以維護 Python bytecode的工具, 這部分跟 cglib/asm類似
Pyasite 只能把代碼注入到進程中并運行,不能定位到具體的函數(shù)并注入 bytecode, 在 testinject.py 中結(jié)合 Byteplay 完成了函數(shù)定位和替換 get 函數(shù)字節(jié)碼的功能.
函數(shù)的定位用到了 sys.settrace 這個API,他提供了 call, line, return, exception事件,在合適的時機調(diào)用用戶提供的函數(shù), 具體可以參考 https://docs.python.org/2/library/sys.html#sys.settrace 的解釋
理論上可以插入任意字節(jié)碼到程序中的任意位置, 實現(xiàn)對現(xiàn)有進程中代碼的任意修改.
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/37537.html
摘要:進程可創(chuàng)建多個線程來執(zhí)行同一程序的不同部分。就緒等待線程調(diào)度。運行線程正常運行阻塞暫停運行,解除阻塞后進入狀態(tài)重新等待調(diào)度。消亡線程方法執(zhí)行完畢返回或者異常終止。多線程多的情況下,依次執(zhí)行各線程的方法,前頭一個結(jié)束了才能執(zhí)行后面一個。 淺談Python多線程 作者簡介: 姓名:黃志成(小黃)博客: 博客 線程 一.什么是線程? 操作系統(tǒng)原理相關(guān)的書,基本都會提到一句很經(jīng)典的話: 進程...
摘要:其次,解釋器的主循環(huán),一個名為的函數(shù),讀取字節(jié)碼并逐個執(zhí)行其中的指令。所有線程都運行相同的代碼,并以相同的方式定期從它們獲取鎖定。無論如何,其他線程無法并行運行。 概述 如今我也是使用Python寫代碼好多年了,但是我卻很少關(guān)心GIL的內(nèi)部機制,導(dǎo)致在寫Python多線程程序的時候。今天我們就來看看CPython的源代碼,探索一下GIL的源碼,了解為什么Python里要存在這個GIL,...
摘要:倘若該回答是正確的,則立即有如下推論在處理信號的過程中,字節(jié)碼具有原子性。因此,除了在兩個字節(jié)碼之間,應(yīng)該還有其他時機喚起了。行的是信號處理函數(shù)的最外層包裝,由系統(tǒng)調(diào)用或注冊至內(nèi)核,并在信號發(fā)生時被內(nèi)核回調(diào),是異??刂屏鞯娜肟?。 寫在前面 前幾天工作時遇到了一個匪夷所思的問題。經(jīng)過幾次嘗試后問題得以解決,但問題產(chǎn)生的原因卻仍令人費解。查找 SO 無果,我決定翻看 Python 的源碼。...
摘要:軟件包存儲庫正成為供應(yīng)鏈攻擊的熱門目標(biāo),和等流行存儲庫已經(jīng)受到惡意軟件攻擊,研究人員稱。當(dāng)應(yīng)用程序中的第三代碼方庫不能保持在最新狀態(tài)時,對企業(yè)來說后果可能很嚴重。 .markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:15px;overflow-x:hidden;color:#333}...
摘要:摘要性能彪悍的引擎。深入淺出系列深入淺出第課箭頭函數(shù)中的究竟是什么鬼深入淺出第課函數(shù)是一等公民是什么意思呢深入淺出第課什么是垃圾回收算法深入淺出第課是如何工作的最近,生態(tài)系統(tǒng)又多了個非常硬核的項目。 摘要: 性能彪悍的V8引擎。 《JavaScript深入淺出》系列: JavaScript深入淺出第1課:箭頭函數(shù)中的this究竟是什么鬼? JavaScript深入淺出第2課:函數(shù)是一...
閱讀 2806·2019-08-30 15:53
閱讀 590·2019-08-29 17:22
閱讀 1215·2019-08-29 13:10
閱讀 2377·2019-08-26 13:45
閱讀 2805·2019-08-26 10:46
閱讀 3242·2019-08-26 10:45
閱讀 2568·2019-08-26 10:14
閱讀 525·2019-08-23 18:23