| Formatted Hexadecimal Memory Dumper |
|
|
|
| Contributed by Rick Kelly | |
| 10 August 2002 | |
|
Rick gives us a handy script and detailed explanation on how to inspect memory contents by writing the contents of a specific address range to a text file with both the hexadecimal content and ASCII string values included.Formatted Hexadecimal Memory Dumper © 2002 Rick Kelly www.crooit.com Introduction For the developer working with Win32 structures or other random memory locations, there are times when visually inspecting memory contents may be necessary. Given a memory pointer and a length, our goal is to produce a standard text file that looks like: Memory Address=00EF90E8 Length=32 00EF90E8 0000 1C 02 00 00 41 00 6C 00 61 00 73 00 6B 00 61 00 ....A.l.a.s.k.a. 00EF90F8 0010 6E 00 20 00 53 00 74 00 61 00 6E 00 64 00 61 00 n. .S.t.a.n.d.a.Where we not only show the raw hexadecimal contents but a sanitized ASCII string value as well. Win32 API References The following Win32 API method is used to retrieve a value from memory and save it in a Paradox variable. Uses "kernel32.dll"
MoveFromMemory(
wDestination cPtr,
wSource cLong,
wLength cLong) cLong [stdcall "RtlMoveMemory"]
endUses
Overview A neat trick we will use takes advantage of how Intel® words and double-words are loaded and stored from low byte to high byte. For instance, a stored word or Type SmallInt with value 16 looks like x'1000'. We can fetch one byte from memory, store it in the first byte of a SmallInt and then use normal OPAL for further processing. Our method below will take a LongInt pointer and LongInt length, produce a normal text file with a specified name of the memory contents, and optionally, run the Windows Notepad program so we can see the results. method HexDump(liPointer LongInt,
liLength LongInt,
stFileName String,
loNotePad Logical)
var
siAny SmallInt
stHex String
stAny String
stASCII String
liMemory LongInt
ts TextStream
liSegments LongInt
liIndex LongInt
stAlias String
endVar
switch
case ts.open(stFileName,"NW") = False :
otherwise :
stHex = toHex(liPointer)
stAny = "Memory Address="
+ upper(stHex.substr(3,8))
+ " Length="
+ strval(liLength)
+ chr(13)
+ chr(10)
ts.writeLine(stAny)
;
; Calculate the number of 16 byte segments we are going to process
;
liSegments = longInt(ceil(liLength / 16.0))
;
; Loop through memory and decode
;
for liIndex from 1 to liSegments
stHex = toHex(liPointer)
stAny = upper(stHex.substr(3,8)) + " "
stHex = toHex((liIndex * 16) - 16)
stAny = stAny
+ upper(stHex.substr(7,4))
+ " "
stASCII = " "
for liMemory from liPointer to liPointer + iif(liLength < 16,liLength - 1,15)
siAny = 0
MoveFromMemory(siAny,liMemory,1)
stHex = toHex(siAny)
stAny = stAny
+ upper(stHex.substr(9,2))
+ " "
;
; Show only standard ASCII character set
;
switch
case siAny >= 32 and
siAny <= 126 :
stASCII = stASCII
+ chr(siAny)
otherwise :
stASCII = stASCII
+ "."
endSwitch
endFor
;
; If this is the last block and it is not
; an even multiple of 16, pad it with
; some spaces
;
switch
case liIndex <> liSegments :
case liLength >= 16 :
otherwise :
stAny = stAny
+ space((16 - liLength) * 3 + 3)
endSwitch
ts.writeLine(stAny + stASCII)
liPointer = liPointer + 16
liLength = liLength - 16
endFor
ts.close()
endSwitch
;
; Optional launch of Notepad
;
switch
case loNotePad = True :
;
; Check if alias was used
;
switch
case stFileName.substr(1,1) = ":" :
;
; Isolate Alias and get path
;
stFileName = stFileName.substr(2,stFileName.size() - 1)
siAny = stFileName.search(":")
stAlias = stFileName.substr(1,siAny - 1)
stFileName = getAliasPath(stAlias)
+ "\\"
+ stFileName.substr(siAny + 1,
stFileName.size() - siAny)
endSwitch
;
; Launch Notepad
;
execute("notepad.exe " + stFileName,No,ExeShowMaximized)
endSwitch
endMethod
Example The following script (download available here) will retrieve a Windows TimeZone structure and call HexDump. Uses "kernel32.dll"
MoveFromMemory(wDestination cPtr,
wSource cLong,
wLength cLong) cLong [stdcall "RtlMoveMemory"]
GlobalAlloc(wFlags cLong,
dwBytes cLong) cLong [stdcall]
GlobalFree(hMem cLong) cLong [stdcall]
GetTimeZoneInformation(wTZI cLong) cLong [stdcall]
endUses
method run(var eventInfo Event)
var
liPointer LongInt
liLength LongInt
liReturn LongInt
endVar
;
; TimeZone Structure
;
; + 0 = Bias
; + 4 = Standard Name (32 SmallInt values)
; + 68 = Standard Date Structure
; + 84 = Standard Bias
; + 88 = Daylight Name (32 SmallInt values)
; + 152 = Daylight Date Structure
; + 168 = Daylight Bias
;
; Total Length = 172 bytes
;
; Date Structure (all type SmallInt)
; Year,Month,Day of Week,Day,Hour,Minute,Second,Millisecond
;
liLength = 172
liPointer = GlobalAlloc(fromHex("0x40"),liLength)
;
; Retrieve Time Zone Structure
;
liReturn = GetTimeZoneInformation(liPointer)
HexDump(liPointer,liLength,":PRIV:__mdump.txt",True)
liReturn = GlobalFree(liPointer)
endMethod
|
| < Prev | Next > |
|---|





