Home arrow Articles arrow Paradox Programming arrow Formatted Hexadecimal Memory Dumper
11 October 2008
 
 
Formatted Hexadecimal Memory Dumper PDF Print E-mail
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 >
 
Top! Top!