I have a binary that loads a DAT section as code (calls ((code **) DAT_something)(0, 2)), and I'd like to be able to disassemble the DAT_something data region. Currently, when looking at the DAT_something region, the data type is undefined (everything is filled with ??s), and I do not know how to mark the section as shellcode. Right click > Disassemble also fails, because the memory is "uninitialized". How would I go about disassembling this shellcode?

  • Does the column next to the address display a question mark followed by the actual bytes at the address or is it only a question mark? Question mark followed by a known byte indicates that the data is known but a datatype is not. In my experience, you can hit d to disassemble in this case. Sounds like you can't. Jul 1, 2023 at 2:29
  • If you have a question mark followed by a known byte, maybe you can't disassemble because the area of code bytes isn't big enough for your opcode or you aren't disassembling a valid opcode. Jul 1, 2023 at 2:32
  • @MatthewTingum Both columns are filled with question marks. Hitting d does nothing, right clicking and pressing "Disassemble" shows the "uninitialized memory" message.
    – 0x150
    Jul 1, 2023 at 13:08

1 Answer 1


This sounds like an artificial section for externs. Let's say you have extern char buffer[256]. You compile to an object which doesn't care about externs because you're not linking or you somehow do link but ignore unresolved extern errors. Your elf knows the symbol name and the datatype of the symbol but not much else about the external dependency. Ghidra will recognize this, create an artifical block, and move on about it's day.

Why does the artificial block exist? Why doesn't it end up in a relocation table with got and got.plt entries? This is because the external data is not relocatable. The linker has no notion of how to access this data. It wasn't present when linked.

We can test this with a small example.

#include <stdio.h>

extern char extern_string[256];

int main(int argc, char **argv) {
    printf("%s\n", extern_string);
    return 0;

Then compile with:

gcc -c main.c

You're left with main.o. When I throw main.o in Ghidra, I find the following:

                             // EXTERNAL 
                             // NOTE: This block is artificial and allows ELF Relocations 
                             // ram:00101000-ram:0010100f
                             extern_string                                   XREF[1]:     main:0010000f(*)  
        00101000                 ??         ??
        00101001                 ??         ??
        00101002                 ??         ??
        00101003                 ??         ??
        00101004                 ??         ??
        00101005                 ??         ??
        00101006                 ??         ??
        00101007                 ??         ??

8 bytes from the extern so it must be looking for a pointer on my x86_64 machine. Perhaps a better example could demonstrate a larger area.

The point is, I never linked this with anything that would explain where extern_string is. Ghidra knows that it exists but simply can't locate it. Ghidra gives us a placeholder to say as much.

I wish I could give an example that demonstrates a larger artificial block. I feel like that would provide a more complete answer. Unfortunately I don't know how to generate that.

  • This does look similar to what I encountered, although I don't know if that comment was there. Thanks!
    – 0x150
    Jul 5, 2023 at 8:16

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.