亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

使用pyrasite進行python進程調試,改變運行中進程的代碼

Y3G / 3690人閱讀

摘要:反之,如果是使用并通過進行調用,那么就應當進行修改如果一個函數(shù)內部有阻塞式的,那么改變這個函數(shù)是沒有用的,顯然要應用改變的對象需要對象下一次被調用,這個不難理解但是容易漏想到

后端開發(fā)中有時會遇到這種情況:進程運行中偶現(xiàn),重啟進程問題就消失;或者是,進程一定要運行一段時間才會出現(xiàn)問題;又或是,極難復現(xiàn)的問題出現(xiàn)了,然而已有的log不足以定位

對于這些情況,盡管大部分時候,我們可以通過在可能的地方加log,然后重啟進程等待問題復現(xiàn),但這樣相對被動。我們都知道如果要調試C/C++程序,gdb attach上進程就可以,而python雖然有相似的工具pdb,但它無法附加到一個進程上,必須要用pdb啟動進程,在實際環(huán)境中顯然不管用,那么python是否有類似的辦法來改變運行中進程的代碼呢?這樣我們就可以通過實時加log來定位問題,這樣幾乎可以解決python層面的任何問題

可以參考兩篇文章:

https://mozillazg.com/2018/07...
https://mozillazg.com/2017/07...

簡單來說,可以直接用gdb使用類似調試c程序的方式,但要求python進程是使用python-debug這種版本的python,同樣不夠實用。這里介紹博客中提到的“純gdb”的方式,通過github上一個開源python包pyrasite,本質上是通過gdb的-eval-command和它的PyRun_SimpleString來向進程注入代碼。

這個庫有一些附加功能,可以通過它的文檔去了解。這里只說實現(xiàn)進程注入的核心,是其中一個很短的文件injector.py,這里去掉了原文件中用于windows平臺的一段代碼,我們這里只考慮linux,核心代碼如下:

import os
import subprocess
import platform

def inject(pid, filename, verbose=False, gdb_prefix=""):
    """Executes a file in a running Python process."""
    filename = os.path.abspath(filename)
    gdb_cmds = [
        "PyGILState_Ensure()",
        "PyRun_SimpleString(""
            "import sys; sys.path.insert(0, "%s"); "
            "sys.path.insert(0, "%s"); "
            "exec(open("%s").read())")" %
                (os.path.dirname(filename),
                os.path.abspath(os.path.join(os.path.dirname(__file__), "..")),
                filename),
        "PyGILState_Release($1)",
        ]
    p = subprocess.Popen("%sgdb -p %d -batch %s" % (gdb_prefix, pid,
        " ".join(["-eval-command="call %s"" % cmd for cmd in gdb_cmds])),
        shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    out, err = p.communicate()
    if verbose:
        print(out)
        print(err)
        

這個函數(shù)做的事很簡單,不難看懂,所以,我們需要做的就是調用這個函數(shù),傳入pid和文件名,文件是一個你要對這個進程執(zhí)行的python代碼?,F(xiàn)在我們運行一個很簡單的python進程test.py

import time
def b():
  print("b")

while 1:
  b()
  time.sleep(1)
  

然后創(chuàng)建一個文件patch.py

print("injecting")
def newb():
  print("new b")
b = newb

injector.py的末尾加上一段,以便接收命令行調用:

import sys
pid = sys.argv[1]
filename = sys.argv[2]

inject(int(pid), filename)

通過ps aux|grep test.py查看上面進程的pid,然后執(zhí)行python injector.py pid patch.py,為方便反復測試可以這樣:

pid=`ps aux | grep test.py | grep -v grep | awk "{print $2}"`;python injector.py $pid patch.py;echo $pid injected

輸出如下:

至此就實現(xiàn)了進程注入。

注意點:

修改類或類方法和函數(shù)同理,改變類的方法時,直接使用類名classA.method = new_method會將變化應用到所有實例,注意對類方法來說在patch.py中定義時也要加上self參數(shù)

patch.py中,我們可以直接對b賦值,因為我們gdb進入一個進程后,所在的上下文環(huán)境就是該進程的入口模塊,可以通過打印globals()來看到有哪些全局變量,這些就是可以直接訪問的對象。如果是在一個普通的業(yè)務進程中,必然有大量import,這種情況下你需要import相應模塊再對該模塊的函數(shù)或類進行修改,如import x.y.z as z; z.b = newb

特別需要注意的是,如果一個模塊A使用了from B import func,那么如果你想改變A中運行的func,需要import A; A.func = newfunc,像這樣改變B是沒有用的:import B; B.func = newfunc,因為from .. import ..會將對象復制一份到本地命名空間。反之,如果A是使用import B并通過B.func進行調用,那么就應當import B進行修改

如果一個函數(shù)內部有阻塞式的while True,那么改變這個函數(shù)是沒有用的,顯然要應用改變的對象需要對象下一次被調用,這個不難理解但是容易漏想到

文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://www.ezyhdfw.cn/yun/43988.html

相關文章

  • 將任意Bytecode注入運行Python進程

    摘要:在調試程序的時候,一般我們只能通過以下幾種方式進行調試程序中已經(jīng)有的日志在代碼中插入但是以上的方法也有不方便的地方,比如對于已經(jīng)在運行中的程序,就不可能停止程序后加入調試代碼和增加新的日志從的項目得到靈感,嘗試對正在運行的進程插入代碼,在程 在調試 Python 程序的時候,一般我們只能通過以下幾種方式進行調試: 程序中已經(jīng)有的日志 在代碼中插入 import pdb; pdb.s...

    endiat 評論0 收藏0
  • Python 調試方法

    摘要:背景這幾天一直在查一個線上程序住的問題這個程序總是在運行分鐘后住通過以下的一些調試手段發(fā)現(xiàn)是打日志的時候因為滿被了日志是默認打到的無論日志級別而我這個程序是被另一個程序調起的父進程沒有接收子進程的導致了被打滿在調試的過程中用到了以下幾種調試 FROM http://kamushin.github.io/debug/python.html 背景 這幾天一直在查一個線上程序 hang 住的...

    klivitamJ 評論0 收藏0
  • 【openQPA】教你DIY進程流量捕獲工具

    摘要:開源項目起因最近做病毒分析的時候遇到遠控馬,需要記錄連接的遠程地址用火絨劍或者可以看到一部分,但是我想要更全面的信息,于是搗鼓了和。使用比較簡單,但是只能看到的流量,雖然能捕獲所有流量,但沒法過濾特定進程的包,而且過濾規(guī)則對我來說太復雜了。 開源項目QPA 起因最近做病毒分析的時候遇到遠控馬,需要記錄連接的遠程地址!用火絨劍或者ProcessMonitr可以看到一部分,但是我想要更全面...

    SimonMa 評論0 收藏0

發(fā)表評論

0條評論

Y3G

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<