2

Problem

I have a struct of some type, say the DOS header at the beginning of a typical PE file:

/DOS/IMAGE_DOS_HEADER
pack(disabled)
Structure IMAGE_DOS_HEADER {
   0   char[2]   2   e_magic   "Magic number"
   2   word   2   e_cblp   "Bytes of last page"
   4   word   2   e_cp   "Pages in file"
   6   word   2   e_crlc   "Relocations"
   8   word   2   e_cparhdr   "Size of header in paragraphs"
   10   word   2   e_minalloc   "Minimum extra paragraphs needed"
   12   word   2   e_maxalloc   "Maximum extra paragraphs needed"
   14   word   2   e_ss   "Initial (relative) SS value"
   16   word   2   e_sp   "Initial SP value"
   18   word   2   e_csum   "Checksum"
   20   word   2   e_ip   "Initial IP value"
   22   word   2   e_cs   "Initial (relative) CS value"
   24   word   2   e_lfarlc   "File address of relocation table"
   26   word   2   e_ovno   "Overlay number"
   28   word[4]   8   e_res[4]   "Reserved words"
   36   word   2   e_oemid   "OEM identifier (for e_oeminfo)"
   38   word   2   e_oeminfo   "OEM information; e_oemid specific"
   40   word[10]   20   e_res2[10]   "Reserved words"
   60   dword   4   e_lfanew   "File address of new exe header"
   64   byte[64]   64   e_program   "Actual DOS program"
}
Size = 128   Actual Alignment = 1

at address 00400000 in memory that is initialized as part of the loader and has some fixed values. It's already defined as a struct in Ghidra, e.g. by some auto analysis.

enter image description here

Now I want to get the value of e.g. e_cp, the "Pages in file", in this case 3, ideally as a proper Ghidra datatype in case that is a pointer, address or some more complex datatype. Ideally I want to access it by the name "e_cp" and not by hardcoding the offset.

Attempts

getDataAt(currentProgram.imageBase + 4), returns null, etDataContaining(currentProgram.imageBase + 4) returns a DataDB object for the entire IMAGE_DOS_HEADER struct.

How can I get the actual value in memory at a known address, that is part of a struct?

5
  • >>> getDataContaining(currentProgram.imageBase).getComponentAt(4) dw 3h is that what you need ?
    – blabb
    Commented Jul 24, 2021 at 18:11
  • yes, this was pretty much what I needed, and had initially tried to find on the RE SE, but didn't find an existing question. In the process of writing up the question I had found the solution myself and posted the question and a self answer as is encouraged stackoverflow.com/help/self-answer Commented Jul 25, 2021 at 8:29
  • I read your self answer but wasn't sure what was the required end result ? what you were looking for so commented and answered btw .....dat.getAllStructures() will return an iterator you can cast any data as any structure using next() some thing like windbg (nt!_EPROCESS *) 0x1234
    – blabb
    Commented Jul 25, 2021 at 8:48
  • The core of the answer is .getComponentAt. it took me a while to realize that the method for the datatype and the data object are different. Commented Jul 26, 2021 at 15:39
  • I am not sure how dat.getAllStructures() would have helped me though. It seems easier to get the datatype of the data by using getDataContaining(currentProgram.imageBase).dataType Commented Jul 26, 2021 at 15:41

2 Answers 2

2

As i commented is this what you are looking for ?

>>> base = getDataContaining(currentProgram.imageBase)
>>> base
IMAGE_DOS_HEADER 
>>> for i in range (0,base.length,1):
...     print ( base.baseDataType.getComponentAt(i).toString() , base.getComponentAt(i))
... 
(u'  0  0  char[2]  2  e_magic  "Magic number"', char[2] "MZ")
(u'  0  0  char[2]  2  e_magic  "Magic number"', char[2] "MZ")
(u'  1  2  word  2  e_cblp  "Bytes of last page"', dw 90h)
(u'  1  2  word  2  e_cblp  "Bytes of last page"', dw 90h)
(u'  2  4  word  2  e_cp  "Pages in file"', dw 3h)
(u'  2  4  word  2  e_cp  "Pages in file"', dw 3h)
(u'  3  6  word  2  e_crlc  "Relocations"', dw 0h)
(u'  3  6  word  2  e_crlc  "Relocations"', dw 0h)
(u'  4  8  word  2  e_cparhdr  "Size of header in paragraphs"', dw 4h)
(u'  4  8  word  2  e_cparhdr  "Size of header in paragraphs"', dw 4h)
(u'  5  10  word  2  e_minalloc  "Minimum extra paragraphs needed"', dw 0h)
(u'  5  10  word  2  e_minalloc  "Minimum extra paragraphs needed"', dw 0h)
(u'  6  12  word  2  e_maxalloc  "Maximum extra paragraphs needed"', dw FFFFh)
(u'  6  12  word  2  e_maxalloc  "Maximum extra paragraphs needed"', dw FFFFh)
(u'  7  14  word  2  e_ss  "Initial (relative) SS value"', dw 0h)
(u'  7  14  word  2  e_ss  "Initial (relative) SS value"', dw 0h)
(u'  8  16  word  2  e_sp  "Initial SP value"', dw B8h)
(u'  8  16  word  2  e_sp  "Initial SP value"', dw B8h)
(u'  9  18  word  2  e_csum  "Checksum"', dw 0h)
(u'  9  18  word  2  e_csum  "Checksum"', dw 0h)
(u'  10  20  word  2  e_ip  "Initial IP value"', dw 0h)
(u'  10  20  word  2  e_ip  "Initial IP value"', dw 0h)
(u'  11  22  word  2  e_cs  "Initial (relative) CS value"', dw 0h)
(u'  11  22  word  2  e_cs  "Initial (relative) CS value"', dw 0h)
(u'  12  24  word  2  e_lfarlc  "File address of relocation table"', dw 40h)
(u'  12  24  word  2  e_lfarlc  "File address of relocation table"', dw 40h)
(u'  13  26  word  2  e_ovno  "Overlay number"', dw 0h)
(u'  13  26  word  2  e_ovno  "Overlay number"', dw 0h)
(u'  14  28  word[4]  8  e_res[4]  "Reserved words"', dw[4] )
(u'  14  28  word[4]  8  e_res[4]  "Reserved words"', dw[4] )
(u'  14  28  word[4]  8  e_res[4]  "Reserved words"', dw[4] )
(u'  14  28  word[4]  8  e_res[4]  "Reserved words"', dw[4] )
(u'  14  28  word[4]  8  e_res[4]  "Reserved words"', dw[4] )
(u'  14  28  word[4]  8  e_res[4]  "Reserved words"', dw[4] )
(u'  14  28  word[4]  8  e_res[4]  "Reserved words"', dw[4] )
(u'  14  28  word[4]  8  e_res[4]  "Reserved words"', dw[4] )
(u'  15  36  word  2  e_oemid  "OEM identifier (for e_oeminfo)"', dw 0h)
(u'  15  36  word  2  e_oemid  "OEM identifier (for e_oeminfo)"', dw 0h)
(u'  16  38  word  2  e_oeminfo  "OEM information; e_oemid specific"', dw 0h)
(u'  16  38  word  2  e_oeminfo  "OEM information; e_oemid specific"', dw 0h)
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  17  40  word[10]  20  e_res2[10]  "Reserved words"', dw[10] )
(u'  18  60  dword  4  e_lfanew  "File address of new exe header"', ddw 108h)
(u'  18  60  dword  4  e_lfanew  "File address of new exe header"', ddw 108h)
(u'  18  60  dword  4  e_lfanew  "File address of new exe header"', ddw 108h)
(u'  18  60  dword  4  e_lfanew  "File address of new exe header"', ddw 108h)
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
(u'  19  64  byte[64]  64  e_program  "Actual DOS program"', db[64] )
2

I want to get the value of e.g. e_cp, the "Pages in file", in this case 3, ideally as a proper Ghidra datatype in case that is a pointer, address or some more complex datatype

You have to access a member of a struct (or an array) with the getComponent method, e.g. in Kotlin code( easily changed to Python or Java):

var struct: DataDB = getDataAt(currentProgram.imageBase)
struct.getComponent(2)

this will return the value for the third (zero indexing) component of the IMAGE_DOS_HEADER struct: dw 3h

Ideally I want to access it by the name "e_cp" and not by hardcoding the offset.

There seems to be no direct way to access a struct my member name. The information about the member names, types and sizes is contained in struct.dataType if this is cast to Structure you can use getComponent (different method than above!):

import ghidra.program.model.data.Structure
var struct: Data = getDataAt(currentProgram.imageBase)
var structType: Structure = struct.dataType as Structure
structType.getComponent(2)

will result in a DataTypeComponent object rendered as: 2 4 word 2 e_cp "Pages in file".

This object has an attribute fieldName that contains the name "e_cp" of this member. You can use the structType.components attribute to find the field with your desired name, and then get the .ordinal attribute of the DataTypeComponent object to get the correct index to pass to struct.getComponent

For convenience and only in Kotlin you can define an Extension Method

operator fun Data.get(name: String): Data? {
    if (this.dataType is Structure){
        val s = (this.dataType as Structure)
        val idx = s.components.firstOrNull { it.fieldName == name }?.ordinal
        return idx?.let(this::getComponent)
    }
    return null
}

that allows Data objects to be indexed with a string, which will search the components for a field matching the passed string, and return the appropriate component:

In [1]: getDataAt(currentProgram.imageBase)["e_cp"]
Out[1]: dw 3h

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.