6

I have a block of code that works great in 32bit, and I'm trying to make it work in 64bit as well. When running the process, the sizeof(structure) seems to be returning invalid options, and the structure isn't being populated properly for 64bit. What do I need to do to make this function in 64bit?

from ctypes import *
from ctypes.wintypes import *
import sys


# const variable
# Establish rights and basic options needed for all process declartion / iteration
TH32CS_SNAPPROCESS = 2
STANDARD_RIGHTS_REQUIRED = 0x000F0000
SYNCHRONIZE = 0x00100000
PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF)
TH32CS_SNAPMODULE = 0x00000008
TH32CS_SNAPTHREAD = 0x00000004

#class MODULEENTRY32(Structure):
#    _fields_ = [ ( 'dwSize' , DWORD ) , 
#                ( 'th32ModuleID' , DWORD ),
#                ( 'th32ProcessID' , DWORD ),
#                ( 'GlblcntUsage' , DWORD ),
#                ( 'ProccntUsage' , DWORD ) ,
#                ( 'modBaseAddr' , LONG ) ,
#                ( 'modBaseSize' , DWORD ) , 
#                ( 'hModule' , HMODULE ) ,
#                ( 'szModule' , c_char * 256 ),
#                ( 'szExePath' , c_char * 260 ) ]


class MODULEENTRY32(Structure):
    _fields_ = [ ( 'dwSize' , c_long ) , 
                ( 'th32ModuleID' , c_long ),
                ( 'th32ProcessID' , c_long ),
                ( 'GlblcntUsage' , c_long ),
                ( 'ProccntUsage' , c_long ) ,
                ( 'modBaseAddr' , c_long ) ,
                ( 'modBaseSize' , c_long ) , 
                ( 'hModule' , c_void_p ) ,
                ( 'szModule' , c_char * 256 ),
                ( 'szExePath' , c_char * 260 ) ]


CreateToolhelp32Snapshot= windll.kernel32.CreateToolhelp32Snapshot
Process32First = windll.kernel32.Process32First
Process32Next = windll.kernel32.Process32Next
Module32First = windll.kernel32.Module32First
Module32Next = windll.kernel32.Module32Next
GetLastError = windll.kernel32.GetLastError
OpenProcess = windll.kernel32.OpenProcess
GetPriorityClass = windll.kernel32.GetPriorityClass
CloseHandle = windll.kernel32.CloseHandle


try:
    ProcessID=22052
    hModuleSnap = DWORD
    me32 = MODULEENTRY32()
    me32.dwSize = sizeof( MODULEENTRY32 )
    #me32.dwSize = 5000
    hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, ProcessID )
    ret = Module32First( hModuleSnap, pointer(me32) )
    if ret == 0 :
        print 'ListProcessModules() Error on Module32First[%d]' % GetLastError()
        CloseHandle( hModuleSnap )
    global PROGMainBase
    PROGMainBase=False
    while ret :
        print me32.dwSize
        print me32.th32ModuleID
        print me32.th32ProcessID
        print me32.GlblcntUsage
        print me32.ProccntUsage
        print me32.modBaseAddr
        print me32.modBaseSize
        print me32.hModule
        print me32.szModule
        print me32.szExePath
        ret = Module32Next( hModuleSnap , pointer(me32) )
    CloseHandle( hModuleSnap )



except:
    print "Error in ListProcessModules"
hochl
  • 12,524
  • 10
  • 53
  • 87
lephino
  • 127
  • 2
  • 8
  • The commented out version looks more correct to me. Why don't you use it? – Niklas B. Mar 19 '12 at 00:26
  • I tried it, still doesn't enummerate in 64bit python, and sizeof ( ) is only returning 124, when in order for the command to run, it needs to be a much larger value. – lephino Mar 19 '12 at 00:47
  • I can't reproduce this, with the first definition I get `sizeof(MODULEENTRY32) == 560` on Win64, which seems plausable. – Niklas B. Mar 19 '12 at 01:01
  • you're correct,c:\Python27>c:\Python2764bit\python.exe c:\proc_list64.py Size of dwSize: 560 ListProcessModules() Error on Module32First[87] – lephino Mar 19 '12 at 02:19
  • hard code it with dwSize = a large number like 1000, the process will run and enumerate, but won't put any of the names in for szexe or szmodule – lephino Mar 19 '12 at 02:20
  • I know something is off in the structure for x64, I'm just not sure what. – lephino Mar 19 '12 at 02:21
  • I don't think it has anything to do with x64, but maybe you need to use the Unicode version of the structure? – Niklas B. Mar 19 '12 at 02:26
  • 1
    Why would the structure function properly on 32bit? I posted a similar problem,http://stackoverflow.com/questions/9755766/does-pythons-ctypes-c-char-work-for-windows-64, which turned out to be a structure difference on x64. – lephino Mar 19 '12 at 02:36
  • 1
    In that case, why didn't you look at http://msdn.microsoft.com/en-us/library/windows/desktop/ms684225(v=vs.85).aspx in the first place? And where did you get your wrong definition of `MODULEENTRY32`?! Try using a pointer for `modBaseAddr`. – Niklas B. Mar 19 '12 at 02:50
  • the commented out one I pulled from msdn, the wrong one came from different recipes I've stumbled across, most notability, an open source project "pymem". I'll give a pointer a test in modBaseAddr. – lephino Mar 19 '12 at 03:28
  • modBaseAddr POINTER(ULONG) did the trick. Want to put it in an answer so I can give you credit for it? – lephino Mar 19 '12 at 03:31

1 Answers1

7

Try using the correct definition:

class MODULEENTRY32(Structure):
    _fields_ = [( 'dwSize' , DWORD ) , 
                ( 'th32ModuleID' , DWORD ),
                ( 'th32ProcessID' , DWORD ),
                ( 'GlblcntUsage' , DWORD ),
                ( 'ProccntUsage' , DWORD ) ,
                ( 'modBaseAddr' , POINTER(BYTE) ) ,
                ( 'modBaseSize' , DWORD ) , 
                ( 'hModule' , HMODULE ) ,
                ( 'szModule' , c_char * 256 ),
                ( 'szExePath' , c_char * 260 ) ]
Niklas B.
  • 92,950
  • 18
  • 194
  • 224
  • 1
    I know this question is old and you may not remember this anymore, but how do you get the modBaseAddr back into an integer/hex value? It returns from the enumeration as `<__main__.LP_c_byte object at 0x00000000023C9348>` which is obviously due to it being a `POINTER(BYTE)` type, but I am unsure of how to convert from this value. – adam b Sep 21 '15 at 18:21
  • You could get it back to hex with `hex(ctypes.addressof(me32.modBaseAddr.contents))` however you'll get same result as if you'd have `('modBaseAddr' , LONG),` and read it as `hex(me32.modBaseAddr)` just like OP tried. – Filip Młynarski Apr 04 '21 at 18:02