You are not logged in. You can browse in the PowerBASIC Community, but you must click Login (top right) before you can post. If this is your first visit, check out the FAQ or Sign Up.
Steve Hutchesson, you may be the person to answer this but all feedback is welcome! How do programs such as ProcDump dump modules from memory to disk? Is this an accomplishable task in PB, and are there any examples of this nature?
I rephrase my question - I'll pay for somebody to write me the source code to dump process modules from memory to disk. Normally i like coding everything myself but there are some things i dont think i'd be able to achieve in a reasonable timeframe due to the research id have to put in beforehand
perhaps there should be a Jobs forum for questions like this? If anybody is interested, could they please reply here or mail to [email protected]
Thankyou!
Following is a rather crude technique for getting a loaded PE image from
another process. It allocates a buffer that is much larger than the
expected loaded image size which is filled with a single character. I have
done it this way to avoid reading the section data from the PE header as
it can be destroyed by various protection schemes.
It reads from hex 400000 (&H400000) which is the normal start address and
continues to read until the OS denies access to any further read.
You then search the buffer for the first occurrence of a long repeat of
the fill character which gives you the end of the loaded image.
Point a non loaded disk file name at the function and write the return
string to disk and you have a raw PE memory dump. NOTE that it will not
run in this form.
This function is valid for Win95b and it uses documented access but with
the endless changes in 32 bit windows, there is no garrantee that it will
run on either NT4 or WIN2K.
'##########################################################################
FUNCTION GetPEimage(fname$,ByVal LoadAdr as DWORD) as STRING
LOCAL hMem as DWORD
LOCAL bRead as DWORD
LOCAL EndIm as DWORD
LOCAL hProc as DWORD
LOCAL bSize as DWORD
LOCAL fl as DWORD
LOCAL pi as PROCESS_INFORMATION
LOCAL si as STARTUPINFO
LOCAL buffer$
Open fname$ for Binary as #1
fl = lof(1)
Get$ #1,1000, a$
If instr(a$,"PE"+chr$(0,0)) = 0 Then
MessageBox hWnd,"Cannot find PE signature in header", _
"Not PE file",%MB_OK
FUNCTION = ""
Exit FUNCTION
End If
Close #1
rvP& = CreateProcess(ByVal StrPtr(fname$), _
ByVal %NULL, _
ByVal %NULL, _
ByVal %NULL, _
%FALSE, _
%DETACHED_PROCESS, _
ByVal %NULL, _
ByVal %NULL, _
ByVal VarPtr(si), _
ByVal VarPtr(pi))
hProc = OpenProcess(%PROCESS_VM_READ,%TRUE,pi.dwProcessId)
bSize = fl * 6
buffer$ = string$(bSize,"x")
If LoadAdr = 0 Then
LoadAdr = &H400000 ' default 4 meg load address
End If
hMem = ReadProcessMemory(hProc,LoadAdr,ByVal StrPtr(buffer$), _
bSize,ByVal VarPtr(bRead))
EndIm = instr(buffer$,"xxxxxxxxxxxx") ' locate the end of the buffer
! dec EndIm
CloseHandle hProc
FUNCTION = left$(buffer$,EndIm)
END FUNCTION
' #########################################################################
Steve, youre sure I cant buy you a drink or anything?
Your "rather crude" technique works SUPERBLY under Windows NT (havent tested 95/98, but i dont see why they wouldnt work after success on NT and you developing it under 98)
Its unfortunate I can't dump processes that are already running, but this is still a huge step forward in my learning! Thankyou very very much
Drinks on me (!)
I just got an answer from one of the authors of ProcdumpNT, it reconstructs
the sections in a PE file directly from the disk file so the process of
overwriting the PE header does not effect its capacity to get a complete PE
image.
It is in fact the only way to do it unless the unpacker wants to try a
heuristic technique of reading the complete image and calculating where the
addresses start.
Glenfiddich it is ! (- ive still got half a bottle )
im in Perth by the way - good luck with the games, i hope it doesn't invade your suburb
I have one final question regarding processes/memory before I can carry on fluently with the rest of my project. I am trying to determine the base address... you are defaulting to &H400000, but I am trying to determine this value the proper way, however that may be
This is what ive got... it compiles, but i dont think im calling things right... (is this the right call to make to determine base address?)
naturally i am calling it after using OpenProcess, and parsing the handle over to NtQueryInformationProcess
[code]
DECLARE FUNCTION QueryInformationProcess LIB "ntdll.dll" ALIAS "NtQueryInformationProcess" (BYVAL ProcessHandle AS LONG, BYVAL inProcInfoClass AS LONG, BYVAL pBuffer AS ANY, PROCLENGTH AS LONG) AS LONG
FUNCTION QUERYBASEADDRESS() AS LONG
DIM xRes AS LONG
DIM iProc AS PROCESS_BASIC_INFORMATION
DIM oProc AS PROCESS_BASIC_INFORMATION
DIM xLen AS LONG
xLen = 255
DIM xMyInfo AS ProcessBasicInformation
xInfoType = xMyInfo
xRes = QueryInformationProcess(BYVAL hProc, BYVAL xInfoType, BYVAL VARPTR(iProc), xLen)
END FUNCTION
there is an example with C++ source at http://msdn.microsoft.com/library/pe...7/hood0197.htm and i am
sure this is the solution (at least under NT), but Im having a lot of
trouble converting C++ to PB ,as i dont write in C/C++ .. can you embed C in PB code? (i read on one forum here that you could, but i was only aware of basic and asm?), or is someone wise and kind enough to translate it to PB?
The only safe way to get the starting address in an EXE file is to read
it from the disk file and even this is subject to possible change.
The hInstance passed to an EXE file is the address of the beginning of
the PE image so in your own EXE files, dumping the PE image to disk is
easy, just read from hInstance for as much as you need.
I have yet to find a PE EXE that has a different load address to &H400000
and any that I have tried to rebase will not run but the capacity exists
so it is worth chasing what you are after.
The API you are using is not available in win9x and my MSDN does not have
it either so I don't have any way of testing what it will return.
I have had to write my own set of PE image headers from my MASM include
file to get a reliable set of structures to work on PE files and this
gives reasonably straight forward access to the information stored in the
different headers in a PE file.
the example you posted while very interesting is very long and
does not correctly retrieve the base address of the open process.
i don't have the time to translate it pb at the moment - however
i posted some code a little while ago for a rebase utility which
correctly retrieves the base address of a executable/dll.
extract what you need from the code and look at semen's code which
shows how to retrieve all running processes - this will get you
the processes' handles.
Below is the include file that I am using to work on PE files. I have
slightly renamed the structures so that the names do not clash with the
ones in the standard include file with PB6. This is are a straight port
from my MASM32 include file and it tests OK in PowerBASIC.
I will try and post some decent reference material on PE files, there
is a reasonably good text file by LUEVELSMEYER and a very comprehensive
PDF file called WINF10.PDF but neither seems to be readily available on
the Internet at the moment.
For dumping a PE image, probably the only safe way is to get the header
information from the disk file as it can be modified by the application.
I have not had a chance to have a look at Semen code but I just had a
quick look at the code posted by Florent for rebasing DLLs which is very
good and this stuff, particularly the imagehlp.dll functions should be
very useful to you.
' ************************************
' Structures for PE file manipulation
' ************************************
%IMAGE_SIZEOF_SECTION_HEADER = 40
' ---------------------------------
' original name "IMAGE_DOS_HEADER"
' ---------------------------------
TYPE IMAGE_DOS_HDR
e_magic as WORD
e_cblp as WORD
e_cp as WORD
e_crlc as WORD
e_cparhdr as WORD
e_minalloc as WORD
e_maxalloc as WORD
e_ss as WORD
e_sp as WORD
e_csum as WORD
e_ip as WORD
e_cs as WORD
e_lfarlc as WORD
e_ovno as WORD
e_res(3) as WORD ' 4 member WORD array
e_oemid as WORD
e_oeminfo as WORD
e_res2(9) as WORD ' 10 member WORD array
e_lfanew as LONG
END TYPE
' ----------------------------------
' original name "IMAGE_FILE_HEADER"
' ----------------------------------
TYPE IMAGE_FILE_HDR
Machine as WORD
NumberOfSections as WORD
TimeDateStamp as DWORD
PointerToSymbolTable as DWORD
NumberOfSymbols as DWORD
SizeOfOptionalHeader as WORD
Characteristics as WORD
END TYPE
' --------------------------------------
' original name "IMAGE_DATA_DIRECTORY"
' --------------------------------------
TYPE IMAGE_DATA_DIR
VirtualAddress as DWORD
isize as DWORD
END TYPE
' --------------------------------------
' original name "IMAGE_OPTIONAL_HEADER32"
' --------------------------------------
TYPE IMAGE_OPTIONAL_HDR
Magic as WORD
MajorLinkerVersion as BYTE
MinorLinkerVersion as BYTE
SizeOfCode as DWORD
SizeOfInitializedData as DWORD
SizeOfUninitializedData as DWORD
AddressOfEntryPoint as DWORD
BaseOfCode as DWORD
BaseOfData as DWORD
ImageBase as DWORD
SectionAlignment as DWORD
FileAlignment as DWORD
MajorOperatingSystemVersion as WORD
MinorOperatingSystemVersion as WORD
MajorImageVersion as WORD
MinorImageVersion as WORD
MajorSubsystemVersion as WORD
MinorSubsystemVersion as WORD
Win32VersionValue as DWORD
SizeOfImage as DWORD
SizeOfHeaders as DWORD
CheckSum as DWORD
Subsystem as WORD
DllCharacteristics as WORD
SizeOfStackReserve as DWORD
SizeOfStackCommit as DWORD
SizeOfHeapReserve as DWORD
SizeOfHeapCommit as DWORD
LoaderFlags as DWORD
NumberOfRvaAndSizes as DWORD
DataDirectory(15) as IMAGE_DATA_DIR ' 16 member array of structures
END TYPE
' ---------------------------------
' original name "IMAGE_NT_HEADERS"
' ---------------------------------
TYPE IMAGE_NT_HDR
Signature as DWORD
FileHeader as IMAGE_FILE_HDR
OptionalHeader as IMAGE_OPTIONAL_HDR
END TYPE
' ---------------------------------------
' original name "IMAGE_EXPORT_DIRECTORY"
' ---------------------------------------
TYPE IMAGE_EXPORT_DIR
Characteristics as DWORD
TimeDateStamp as DWORD
MajorVersion as WORD
MinorVersion as WORD
nName as DWORD
nBase as DWORD
NumberOfFunctions as DWORD
NumberOfNames as DWORD
AddressOfFunctions as DWORD
AddressOfNames as DWORD
AddressOfNameOrdinals as DWORD
END TYPE
UNION MISC
PhysicalAddress as DWORD
VirtualSize as DWORD
END UNION
' ---------------------------------------
' original name "IMAGE_SECTION_HEADER"
' ---------------------------------------
TYPE IMAGE_SECTION_HDR
Name1 as STRING * 8
Property as MISC
VirtualAddress as DWORD
SizeOfRawData as DWORD
PointerToRawData as DWORD
PointerToRelocations as DWORD
PointerToLinenumbers as DWORD
NumberOfRelocations as WORD
NumberOfLinenumbers as WORD
Characteristics as DWORD
END TYPE
very interesting info - I used the pe_map.exe to dump
hello.exe and got a nice informative report. I'll study
the LUEVESMEYER source as soon as I have time.
I read pe.txt which is very informative. I very much liked the
section where he shows making hello.exe executable. Can you
run Hello.exe on your system? On mine, NT 4.0 SP6 I get a
critical error message box telling me hello.exe is not a valid
NT application.
Cheers
Florent
[This message has been edited by Florent Heyworth (edited September 10, 2000).]
It did not run here either on win95b, incorrent alignment so I had a look
at it in a hex editor and it does not have a valid MZ header. I think both
NT4 and 9x will not run a file with an invalid MZ header or that is aligned
below 512 bytes.
From my experience, the smallest I have been able to get a valid PE file
is 1024 bytes with a test piece in MASM. It normally builds at 1536 bytes
but by merging the 2 sections with the /MERGE linker option, it drops in
size by a single 512 byte alignment.
Also thanks for posting the rebase code, it will be very useful.
Steve and Florent, thanks very much for your help! It is much appreciated as i am swimming in deep water here and Im not wearing floaties
Im getting closer to what I want to do (which is just dump a processes main module to a file), and its working on some , but not others...
Steve i modified the example you supplied up the top so that it can dump from an already-running process rather than having to start one up (parsing the process id)
Code:
FUNCTION GetPEimage(ProcID AS LONG, BYVAL LoadAdr AS DWORD) AS STRING
LOCAL hMem AS DWORD
LOCAL bRead AS DWORD
LOCAL EndIm AS DWORD
LOCAL hProc AS DWORD
LOCAL bSize AS DWORD
LOCAL tSize AS DWORD
LOCAL fl AS DWORD
LOCAL pi AS PROCESS_INFORMATION
LOCAL si AS STARTUPINFO
LOCAL buffer$
LOCAL hWnd AS LONG
hProc = OpenProcess(%PROCESS_VM_READ,%TRUE,ProcID)
bSize = 2000000 'almost 2 megs to dump
tbuffer$ = " "
buffer$ = STRING$(bSize,"x")
IF LoadAdr = 0 THEN
LoadAdr = &H400000 'default 4 meg load address
END IF
hMem = ReadProcessMemory(hProc,LoadAdr,BYVAL STRPTR(buffer$),bSize,BYVAL VARPTR(bRead))
EndIm = INSTR(buffer$,"xxxxxxxxxxxx") 'locate the end of the buffer
! dec EndIm
CloseHandle hProc
FUNCTION = LEFT$(buffer$,EndIm)
END FUNCTION
so that part is basically working perfectly on Windows 95, 98, NT , _AND_ 2000 so Steve I am over the moon that you have helped me get that far
but I am getting a headache from this base address issue. Im assuming that the reason it can only dump some processes and not all is because the base address isnt the default
I also tried scanning for the string "This program" (eg. for "This program cannot run in DOS") starting at 1 and working my way up to 256mb yet was unable to locate it even in processes such as Notepad. Scanning in that way should have worked with a process such as Notepad, i would've thought? even if it wouldn't work with an exe that has been "header-munted" by Steve's other example
getting there!
thought this may be of interest while you were mentioning smallest exe files ... http://ntsecurity.nu/toolbox/tini/
It is a remote access trojan server that is a standalone total exe of 3072 bytes. It works on 95, 98, NT, and 2000, and gives anyone who connects to it (tcp 7777) a command prompt - now thats fat-free programming
Steve or Florent or anyone! have you had any luck in getting all processes to dump ok? im still only able to get a few to dump! would this be because the base address may not be &H400000 ? i can only dump about one in five processes though, so that doesnt seem to be it?
There can be a number of reasons, 400000h works on most PE EXE files but
it will not work on a DLL, they are dynamically loaded by the operating
system loader at different addresses in the application's address space
depending on the address range available. From memory, there is an API
call designed to get a DLL starting address (Module handle).
There are of course a number of tricks used as both anti-debugging and
anti-hacking measures that will stop a successful image dump. Another
consideration is that from memory, this process cannot be used on non-PE
files. The original function I posted was designed to work on programs
started with CreateProcess and it seems to do the job on the PE EXE files
that I have used it with but for serious image analysis, I have mainly
seen guys using SICE for NT with an add-on called Icedump.
Set a breakpoint at the program entry point then dump the PE image. There
are specialised techniques to defeat this method but there are as many
trick around it.
Steve, I just realised that you do your work on 95/98 and not NT as I do - I finally was able to try your code on a 98 box tonight and it works perfectly for ALL the processes that I tried, so youre code is spot on ! ! im puzzled why it's only able to dump a minority of NT/2K processes though :/, but some is better than none
Again, many thanks for all your help with this issue Steve, ive learnt a lot from your postings and should be able to go on from this!
Steve, I can now successfully dump in NT/2K! ... the secret was to use the AttachThreadInput API first! I would not have been able to discover that if it wasn't for your help, so I return today stoked that I can at least partially return your kind favour.
Many thanks again!
PS. Upgrade to NT! <grin>
We process personal data about users of our site, through the use of cookies and other technologies, to deliver our services, and to analyze site activity. For additional details, refer to our Privacy Policy.
By clicking "I AGREE" below, you agree to our Privacy Policy and our personal data processing and cookie practices as described therein. You also acknowledge that this forum may be hosted outside your country and you consent to the collection, storage, and processing of your data in the country where this forum is hosted.
Comment