python - Hvorfor bruge integerstøbning på proceshåndtag objekt til 1. param af kernel32.TerminateProcess?

Indlæg af Hanne Mølgaard Plasc

Problem



ok, jeg gør nogle test på at dræbe Windows-proces ved hjælp af python-bindingen af ​​Windows-systemopkald, der er to metoder, jeg bruger, men de gør det anderledes, nogle detaljer forvirrer mig.


Første tilgang bruger win32api


import win32api,subprocess
proc = subprocess.Popen([ 'notepad' ])
win32api.TerminateProcess(proc.\_handle, -1)


anden tilgang bruger ctypes


import ctypes, subprocess
proc = subprocess.Popen([ 'notepad' ])
ctypes.windll.kernel32.TerminateProcess( proc.\_handle, -1 )


i den anden tilgang vil det ikke fungere, medmindre du heltal kaster proc.\_handlen som denne:


proc = subprocess.Popen([ 'notepad' ])
int\_handle = int(proc.\_handle)
ctypes.windll.kernel32.TerminateProcess(int\_handle, -1 )


dette int\_handle, formodentlig en slags proceshåndtag nummer, normalt værdier inden for 1-1000 på min maskine.
ved at inspicere proc.\_handle-objektet ved hjælp af disse indbyggede, fik jeg ikke nogen frygtelig nyttig information:


print "dir() of handle >>",dir(proc.\_handle)    # ['Close', 'Detach']
print "type() of handle >>",type(proc.\_handle)  # <type '\_subprocess\_handle'>


Sysinternals handle.exe gav også for meget info.


notepad.exe pid: 8688 HOSTuser
4: Event         
8: WaitCompletionPacket 
C: IoCompletion  
10: TpWorkerFactory 
14: IRTimer       
   ...


Mit spørgsmål:



  1. Hvad excatly er dette heltal gemt i int\_handle?

  2. Hvorfor kan det få håndtaget værdien at gøre et heltal casting på proc.\_handle objekt?

  3. og hvorfor passerer dette nummer til kernel32.TerminateProcess?


Bedste reference


Se MSDN-emnet på håndtag og objekter for at få overblik over de forskellige typer objekter i systemet, og hvordan håndtag bruges til at referere dem. Kernelgenstande som Process objekter findes i kernel adresserum. Bruger-tilstandsprogrammer kan ikke direkte referere til kernelager. I stedet har hver proces et kerneobjekt håndteringsbord, der kort håndterer værdier som 4, 8, 12 og så videre til kerneobjekter. For eksempel, når du ringer til CreateProcess, returnerer opkaldet håndtag til Process og dets primære Thread. Du kan også ringe OpenProcess eller OpenThread for at åbne et håndtag til en eksisterende proces eller tråd med ID. Ring CloseHandle for at lukke et håndtag, der ikke længere er nødvendigt. [40] [41] [42] [43] [44]


(Kernel File objekter, som fra at kalde CreateFile, henvises også til via håndtag. CPython bruger imidlertid C runtime'ens lave I/O-filbeskrivelser i stedet for f.eks. 0, 1, 2 og så videre, dvs. Unix/POSIX-fildeskriptorer. På Unix er alt en fil, mens alt i Windows er et objekt. C-kørselstiden opretholder en privat kortlægning af filbeskrivelser til Windows File håndtag. Andre objekttyper er ikke kortlagt til Unix-fildeskriptorer. Ved hjælp af de lave I/O-filbeskrivelser og C-standard I/O gøres det lettere at understøtte både Unix og Windows. Der er sagt at der er mindst en foreslået patch med det ambitiøse mål om at omskrive Python 3 's I/O-support på Windows til at bruge Windows API og File håndteres direkte.)





I Python 2 bruger subprocess en type \_subprocess\_handle på Windows til automatisk at lukke et håndtag, når det ikke længere er refereret. Denne type definerer en \_\_int\_\_ metode til at understøtte omregning af håndtagets værdi til et heltal, men det betyder ikke, at standardkonverteringskonvertering kun konverterer heltalsargumenter til C int værdier, hvilket er grunden til, at du skal bruge int(proc.\_handle).


Men ved hjælp af standard integer konverteringen er en fejltagelse. Du skal definere TerminateProcess.argtypes = (ctypes.c\_void\_p, ctypes.c\_uint). Selvom ægte kernehåndtag altid er i 32-bit-rækken, skal du også bruge en fake håndtag som (HANDLE)-1 (selv om det er et 64-bit system), som bruges til at referere til den aktuelle proces uden at skulle åbne et ægte håndtag. fuld pointer interval. På 64-bit systemer skal de øverste DWORD af real kernelhåndtag være nul, og for pseudohåndtag som (HANDLE)-1 skal den ikke-nul øverste DWORD bevares. I 2.x skriver ctypes ikke stakken hukommelse for argumenter, og ved hjælp af standard C int typen skriver kun den nederste DWORD af stakken QWORD. Til pålidelighed skal du enten manuelt indpakke argumenter som peger eller definere alle HANDLE type argumenter (inklusive HMODULE, HWND osv.) som en pegertype som ctypes.c\_void\_p eller wintypes.HANDLE.


Brug af ctypes.windll er også problematisk, da det caches DLL'er, hvilke cache-funktionspegere. Dette efterlader dit script eller modul til gavn for den globale stat og kan føre til modstridende argtypes, restype og errcheck definitioner. Det tillader heller ikke at aktivere den trådbeskyttede lagring til den sidste fejlværdi. Her er et eksempel ctypes definition, som er mere pålidelig:


import ctypes
from ctypes import wintypes

kernel32 = ctypes.WinDLL('kernel32', use\_last\_error=True)
kernel32.TerminateProcess.argtypes = (wintypes.HANDLE, wintypes.UINT)

if \_\_name\_\_ == '\_\_main\_\_':
    import subprocess

    p = subprocess.Popen('notepad')       
    if not kernel32.TerminateProcess(int(p.\_handle), 1):
        raise ctypes.WinError(ctypes.get\_last\_error())