1

さて、あなたはctypesそこにすべての教祖...

1秒間に100回メモリアドレスを読み取るPythonスクリプトがあります。このメモリアドレスに格納されている値は、符号なし整数を表します。この値は時間の経過とともに増加します。残念ながら、2 ^ 8、2 ^ 16、または2 ^ 24を渡すと、ReadProcessMemory呼び出しはより大きな整数を取得するのに十分なバイトを読み取りません。実際、最初の読み取り後に正しいバイト数を読み取っていないように見えます。

コードスニペットは次のとおりです。

from time import sleep
from ctypes import *
from struct import *
pid = 0x0D50
op = windll.kernel32.OpenProcess
rpm = windll.kernel32.ReadProcessMemory
ch = windll.kernel32.CloseHandle
PAA = 0x1F0FFF
addy = 0x38D53368
ph = op(PAA,False,int(pid)) #program handle
lastvalue = 0
while True:
   datadummy = b'.'*4
   buff = c_char_p(datadummy)
   bufferSize = (len(buff.value))
   bytesRead = c_ulong(0)

   if rpm(ph,addy,buff,bufferSize,byref(bytesRead)):
       value = unpack('I',datadummy)[0]
       if lastvalue != value:
           print value
           print bytesRead
           lastvalue = value
   sleep(.01)

そして、出力は次のようになります。

191
c_ulong(4L) ////Here it got 4 bytes like I expected
211
c_ulong(1L) ////But here it only got 1 byte.?? It should be reading 4 bytes everytime
231
c_ulong(1L) 
251
c_ulong(1L)
15           ////This value is incorrect, because it only reads 1 byte. (should be 271)
c_ulong(1L)

私には、前の呼び出しで読み取る必要のあるバイト数だけを読み取っているように見えます...

どうすればこれを修正できますか?

4

2 に答える 2

4

この式により、モジュールのコードオブジェクトにb'.'*4定数が作成されました。この定数は、不変であることが想定'....'されていることを除いて、Pythonの他の定数と同様のオブジェクトです。ctypesを使用してその仮定に違反しました。例えば:

>>> from ctypes import *
>>> def f():
...   s = b'.'*4
...   buf = c_char_p(s)
...   memset(buf, 0, 1)
... 
>>> f.__code__.co_consts
(None, '.', 4, 0, 1, '....')
>>> c_char_p(f.__code__.co_consts[5]).value
'....'

>>> f() # set the first character to "\x00"
>>> f.__code__.co_consts
(None, '.', 4, 0, 1, '\x00...')
>>> c_char_p(f.__code__.co_consts[5]).value
''

value記述子はc_char_p、バッファがnullで終了する文字列であることを想定しています。最初のバイトが0に変更された状態でvalue、空の文字列を返します。ここで、リトルエンディアンとしてパックされた191の値を見てくださいunsigned long

>>> import struct
>>> struct.pack("<L", 191)
'\xbf\x00\x00\x00'

bufferSizeそれが2回目のパスで1になった理由を説明するはずです。

文字列がインターンされていた場合は、インタプリタをクラッシュさせるか、使用できなくする可能性があります。モジュール、クラス、関数、属性、および変数の名前と同様に、CPythonAPI内で使用されるほとんどの文字列はインターンされています。例えば:

>>> from ctypes import *
>>> import numbers
>>> s = 'numbers'
>>> b = c_char_p(s)
>>> r = memset(b, 100, 1)
>>> s
'dumbers'

>>> numbers.Number
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'numbers' is not defined

>>> globals()[s].Number
<class 'numbers.Number'>

create_string_buffercharは、 1回のパスで配列を作成および設定するための便利な関数です。

>>> b1 = create_string_buffer('test1')
>>> type(b1)
<class 'ctypes.c_char_Array_6'>
>>> b1.value
'test1'

>>> b2 = (c_char * 6)()
>>> b2.value = 'test2'
>>> type(b2)
<class 'ctypes.c_char_Array_6'>
>>> b2.value
'test2'
>>> b2.raw
'test2\x00'

unsigned long代わりに、への参照を渡すこともできます。

value = c_ulong() 
bytesRead = c_ulong()
rpm(ph, addy, byref(value), sizeof(value), byref(bytesRead))

不変性の仮定に違反する別の例。256未満の整数はキャッシュされます。つまり、それらを使用するコードは常に同じオブジェクトのセットを参照します。したがって、それらの1つを変更すると、システム全体に影響します。

>>> offset = sizeof(c_size_t)*2
>>> addr = id(200) + offset
>>> n = c_int.from_address(addr)
>>> n
c_long(200)
>>> n.value = 2000000
>>> 
>>> 200 + 1
2000001
于 2013-03-13T09:22:09.620 に答える
0

さて、私はそれを理解しました。試したctypes.create_string_buffer(init_or_size[, size])ものの代わりに使う必要がありました。c_char_p

作業コード:

from time import sleep
from ctypes import *
from struct import *
pid = 0x0D50
op = windll.kernel32.OpenProcess
rpm = windll.kernel32.ReadProcessMemory
ch = windll.kernel32.CloseHandle
PAA = 0x1F0FFF
addy = 0x543A88F0
ph = op(PAA,False,int(pid)) #program handle
lastvalue = 0
while True:

   buff = create_string_buffer(4)
   bufferSize = (sizeof(buff))
   bytesRead = c_ulong(0)

   if rpm(ph,addy,buff,bufferSize,byref(bytesRead)):
       value = unpack('I',buff)[0]
       if lastvalue != value:
           print value
           print bytesRead
           lastvalue = value
   sleep(.01)
于 2013-03-12T20:03:27.677 に答える