A simple example of how to dump the executable image of a process or module/DLL from memory.
Some "process dumpers" try to dump the entire image in one go, for example ...
ReadProcessMemory (BYVAL hProc, BYVAL me32.ModBaseAddr, BYVAL STRPTR(sBuf), BYVAL me32.ModBaseSize, lBytesRead)
That works most of the time, but sometimes it will fail, as MSDN's ReadProcessMemory documentation states: "The entire area to be read must be accessible, and if it is not accessible, the function fails."
The solution is to simply read the image one page at a time -- GetSystemInfo(SYSTEM_INFO) ... SYSTEM_INFO.dwPageSize
Some "process dumpers" try to dump the entire image in one go, for example ...
ReadProcessMemory (BYVAL hProc, BYVAL me32.ModBaseAddr, BYVAL STRPTR(sBuf), BYVAL me32.ModBaseSize, lBytesRead)
That works most of the time, but sometimes it will fail, as MSDN's ReadProcessMemory documentation states: "The entire area to be read must be accessible, and if it is not accessible, the function fails."
The solution is to simply read the image one page at a time -- GetSystemInfo(SYSTEM_INFO) ... SYSTEM_INFO.dwPageSize
Code:
#COMPILE EXE #INCLUDE "win32api.inc" #INCLUDE "tlhelp32.inc" FUNCTION DumpModule (BYVAL dwPID AS DWORD, szModule AS ASCIIZ, sBuf AS STRING) AS DWORD '// Returns LEN(sBuf) if success, 0 if failed LOCAL hModuleSnap AS DWORD, me32 AS MODULEENTRY32, lResult AS LONG, szLModule AS ASCIIZ * %MAX_PATH, lBytesRead AS DWORD LOCAL dwBase AS DWORD, dwSize AS DWORD, lpSystemInfo AS SYSTEM_INFO, dwOffset AS DWORD, hProc AS DWORD, i AS DWORD GetSystemInfo lpSystemInfo szLModule = LCASE$(szModule) '// Now try to locate the base address and size of the target module hModuleSnap = CreateToolhelp32Snapshot(%TH32CS_SNAPMODULE, dwPID) IF hModuleSnap <> %INVALID_HANDLE_VALUE THEN me32.dwSize = SIZEOF(MODULEENTRY32) lResult = Module32First (hModuleSnap, me32) WHILE lResult IF LCASE$(me32.szExePath) = szLModule THEN dwBase = me32.ModBaseAddr dwSize = me32.ModBaseSize EXIT END IF lResult = Module32Next (hModuleSnap, me32) WEND CloseHandle hModuleSnap END IF IF dwBase = 0 THEN MSGBOX "Couldn't locate module in target process", %MB_ICONERROR + %MB_OK, "Error" EXIT FUNCTION END IF '// Now open the target process IF dwPID = GetCurrentProcessId THEN hProc = GetCurrentProcess ELSE hProc = OpenProcess(%PROCESS_VM_READ, %FALSE, dwPID) IF hProc = 0 THEN MSGBOX "OpenProcess failed", %MB_ICONERROR + %MB_OK, "Error" EXIT FUNCTION END IF END IF '// Read the memory one page at a time sBuf = STRING$(me32.ModBaseSize + lpSystemInfo.dwPageSize, 0) FOR i = 1 TO (me32.ModBaseSize \ lpSystemInfo.dwPageSize) + 1 ReadProcessMemory (BYVAL hProc, BYVAL me32.ModBaseAddr + dwOffset, BYVAL STRPTR(sBuf) + dwOffset, BYVAL lpSystemInfo.dwPageSize, lBytesRead) dwOffset = dwOffset + lpSystemInfo.dwPageSize NEXT sBuf = LEFT$(sBuf, me32.ModBaseSize) FUNCTION = LEN(sBuf) END FUNCTION FUNCTION PBMAIN () AS LONG '// Dump a module (szModule) from a process (dwPID) into string buffer (sBuf) LOCAL dwPID AS DWORD, sBuf AS STRING, szModule AS ASCIIZ * %MAX_PATH dwPID = GetCurrentProcessID '// PID of target process GetModuleFilename(BYVAL GetModuleHandle(BYVAL 0), szModule, SIZEOF(szModule)) '// Module filename in target process IF DumpModule(BYVAL dwPID, szModule, sBuf) > 0 THEN MSGBOX "Success. First two bytes = " & LEFT$(sBuf,2) '// should be "MZ" ELSE MSGBOX "Failed" END IF '// Save the buffer to disk LOCAL hFile AS DWORD: hFile = FREEFILE OPEN szModule & "-dumped.dat" FOR BINARY ACCESS WRITE LOCK SHARED AS #hFile PUT #hFile, 1, sBuf CLOSE #hFile END FUNCTION