2013-05-12 122 views
0

我有這個片段,它在Linux中讀取進程內存並搜索字符串,在某些發行版上工作正常,但在其他版本上只是出現此錯誤:Python Linux讀取進程內存 - int太大,無法轉換爲C long

maps_file = open("/proc/%s/maps"%pid, 'r') 
    mem_file = open("/proc/%s/mem"%pid, 'r') 
    for line in maps_file.readlines(): # for each mapped region 
     m = re.match(r'([0-9A-Fa-f]+)', line) 
     if m.group(3) == 'r': # if this is a readable region 
      start = int(m.group(1), 16) 
      end = int(m.group(2), 16) 
      mem_file.seek(start) # seek to region start 
      chunk = mem_file.read(end - start) # read region contents 
      #print chunk, # dump contents to standard output 
      mem_dump = open(working_dir+"/%s.bin"%pid, "ab") 
      mem_dump.write(chunk,) 
      mem_dump.close() 
    maps_file.close() 
    mem_file.close() 

錯誤:

scan process: 491 
Traceback (most recent call last): 
    File "./dump.py", line 106, in <module> 
    MainDump(pid) 
    File "./dump.py", line 79, in MainDump 
    mem_file.seek(start) # seek to region start 
OverflowError: Python int too large to convert to C long 

問題行是:

start = int(m.group(1), 16) 

mem_file.seek(start) 

應該聲明爲float?任何想法?

也試過long(),結果和錯誤都一樣。

編輯:我忘了說的是,我在「x64」系統上得到的錯誤。

+2

您正在使用64位操作系統和或Python的64位編譯?看起來起始地址超出了C實現可以處理的範圍,但是這意味着它會在64位機器上編譯爲32位應用程序? – 2013-05-12 10:20:21

+0

發行版官方是爲64位編譯的。 – bsteo 2013-05-12 10:24:32

+1

如果你不確定,你可以這樣做:'import ctypes;打印(ctypes.sizeof(ctypes.c_long))'。如果這說'4'而不是'8',那就是你的問題。 – abarnert 2013-05-12 10:24:34

回答

2

問題是你的地址是0xffffffffff600000L。 (有符號)C長只能保存從-0x80000000000000000x7fffffffffffffff的值。所以,這個地址確實「太大而不能轉換成C」了。

如果你看一下the source,你可以看到,這個問題是最有可能的,由於某種原因,當Python的是對非在職的發行配置的,它無法檢測到fseekooff_t存在。但是除非你想重建Python,否則這不會對你有所幫助。

那麼,你如何解決這個問題呢?有幾件事可以嘗試。


第一種可能性是從端部,而不是開始尋求。

mem_len = os.fstat(mem_file.fileno()).st_size 

if start >= 1<<63L: 
    mem_file.seek(mem_len - start, os.SEEK_END) 
else: 
    mem_file.seek(start) 

你也可以試試這個可怕的黑客:

if start >= 1<<63L: 
    start -= 1<<64L 

這將轉換您0xffffffffff600000L-0xa00000,這適合就好成long ...然後希望,即long實際上是被在C層內部轉換爲一些無符號的64位類型,這意味着它按照您的希望尋找到0xffffffffff600000L


您可能還可以通過使用mmap映射的頁面(S)你想獲得的,而不是seekread解決這個問題,。


如果出現最壞的情況,你可以使用​​(或cffi或任何你喜歡)直接調用fseeko你的文件句柄。


最後,確保你確實想讀這個區域。我可能是錯的,但我似乎記得linux保留了映射到用戶空間的內核頁面的上部區域。如果我是正確的,你要尋找的字符串是不會到這裏來,所以你可以跳過它們...

要跳過處理的區域,你可以移動內部的,如果處理:

start = int(m.group(1), 16) 
end = int(m.group(2), 16) 
if start <= sys.maxint: 
    mem_file.seek(start) # seek to region start 
    chunk = mem_file.read(end - start) # read region contents 
    # ... 

...或使用continue語句跳到循環的下一次迭代:

start = int(m.group(1), 16) 
end = int(m.group(2), 16) 
if start > sys.maxint: 
    continue 
mem_file.seek(start) # seek to region start 
chunk = mem_file.read(end - start) # read region contents 
# ... 

如果你知道的區域始終處於有序,您可以使用break代替continue(因爲休息的地區也會超出範圍)。

但我認爲最好的解決辦法就是try吧,並處理錯誤。還有其他一些原因,如seekread可能會失敗 - 例如,如果您正在查看的進程在到達之前取消映射某個區域,或者退出 - 並且您寧願跳過該錯誤並繼續執行,而不僅僅是退出, ?

所以:

if m.group(3) == 'r': # if this is a readable region 
    start = int(m.group(1), 16) 
    end = int(m.group(2), 16) 
    try: 
     mem_file.seek(start) # seek to region start 
     chunk = mem_file.read(end - start) # read region co 
    except Exception as e: 
     print('Skipping region {:#018x} because of error {}'.format(start, e)) 
     continue 
    mem_dump = open(working_dir+"/%s.bin"%pid, "ab") 
    # ... 
+0

剛剛嘗試了兩個,對於第一個我得到相同的錯誤,對於「可怕的黑客」我得到「IOError:[Errno 0] Erro」 – bsteo 2013-05-12 15:18:14

+0

順便說一句,如何才能跳到下一個進程,如果地址是'0xffffffffff600000L'而不只是退出我的腳本? – bsteo 2013-05-12 15:30:41

+0

@xtmtrx:讓我編輯答案來證明這一點。 – abarnert 2013-05-12 21:07:04

相關問題