Search code examples
global-variableselfintel-pin

How to get the global variable address of the executable program through pin and libelf.h


I want to develop a pintool to find out the address of global variable of my C program.Suppose I have a C program in which I had some Global pointer variables. When I run the same program with pintool then I wish to find the address of those global variable through pintool.

I am trying to get the address of a global variable via pin,but we all know that Pin doesn't seem to provide such a funcionality. As per the documentation: "Symbol objects only provide information about the function symbols in the application. Information about other types of symbols (e.g. data symbols), must be obtained independently by the tool,libelf.h seems can get the address of global variable,please help me and suggest me how can I be able to do this?


Solution

  • I would have liked to do just a comment but it's a bit too long...

    Per definition global variables resides in the executable (more precisely in the .data or .bss section depending if they are initialized or not). The other variables are allocated (either on stack or heap).

    You don't even need symbols to check if a variable (given its address) is in one of the executable sections or not: use the image instrumentation functions (IMG_xxx), loop around the sections (SEC_xxx) get the base and end of the sections, check which one it is (.data or the .bss). You can get the type of the section with PIN using SEC_Type; once you have an address, if it lies inside .bss or .data, then you have a global variable.

    Now, if you want the name of the variable that lies at a given address, it's more complicated and as the PIN documentation states, you'll need symbolic information. I don't know if libelf can do that easily, but libdwarf can. You can also check at the llvm-dwarfdump code which is open source and able to do that also.


    note: I did the experimentation on Windows (.data section) but the output should be somewhat similar on Linux.

    Here's a small dummy example with one known global variable; compiled without optimization:

    #include <iostream>
    
    int global_counter; // global
    
    void count(const int i)
    {
        int local_counter = 0;  // local
    
        for(int j = 0; j < i; j++)
        {
            global_counter += 1;
            if(j % 2 == 0) {
                local_counter += 1;
            }
        }
    
        std::cout << "local counter: " << local_counter << std::endl;
    }
    
    
    int main(int argc, char** argv)
    {
        if(argc < 2) {
            return -1;
        }
    
        const auto i = std::atoi(argv[1]);
        if (i >= 0) {
            count(i);
    
            std::cout << "global counter: " << global_counter << std::endl;
        }
    
        return 0;
    }
    

    Here's the disassembly of the part the count function where the global variable is used:

    00007FF7077B10BE  | 8B | mov eax,dword ptr ds:[<global_counter>]                       | PinTestSimpleTarget.cpp:14
    00007FF7077B10C4  | FF | inc eax                                                       |
    00007FF7077B10C6  | 89 | mov dword ptr ds:[<global_counter>],eax                       |
    00007FF7077B10CC  | 8B | mov eax,dword ptr ss:[rsp+20]                                 | PinTestSimpleTarget.cpp:15
    00007FF7077B10D0  | 99 | cdq                                                           |
    00007FF7077B10D1  | 83 | and eax,1                                                     |
    00007FF7077B10D4  | 33 | xor eax,edx                                                   |
    00007FF7077B10D6  | 2B | sub eax,edx                                                   |
    00007FF7077B10D8  | 85 | test eax,eax                                                  |
    00007FF7077B10DA  | 75 | jne pintestsimpletarget.7FF7077B10E6                          |
    

    Disassembly of the std::cout on the global variable:

    00007FF7077B117A  | 8B | mov edx,dword ptr ds:[<global_counter>]                       |
    00007FF7077B1180  | 48 | mov rcx,rax                                                   | rax:$LN23
    00007FF7077B1183  | FF | call qword ptr ds:[<&??6?$basic_ostream@DU?$char_traits@D@std |
    

    Notice the 3 addresses:

    • 00007FF7077B10BE (read)
    • 00007FF7077B10C6 (write)
    • 00007FF7077B117A (std::cout)

    The global variable itself is at:

    • 00007FF7077B5628

    Here's the pintool source (note: for an unknown reason I couldn't get the CRT to correctly initialize when using std::cout so I resorted to use printf instead).

    #include "pin.H"
    
    typedef struct _BOUNDARIES
    {
        ADDRINT lowest_address;
        ADDRINT highest_address;
    
        std::string to_str() const
        {
            std::stringstream stream;
            stream << "Low Addr: " << std::hex << lowest_address <<
                "; High Addr: " << highest_address;
            return std::string(stream.str());
        }
    
        bool is_in_bounds(const ADDRINT addr) const
        {
            return addr >= lowest_address && addr < highest_address;
        }
    
    } BOUNDARIES;
    
    /* ================================================================== */
    // Global variables 
    /* ================================================================== */
    BOUNDARIES main_executable_boundaries;
    BOUNDARIES data_section_boundaries;
    
    
    /* ===================================================================== */
    // Utilities
    /* ===================================================================== */
    
    /*!
     *  Print out help message.
     */
    INT32 Usage()
    {
        //std::cout << "[PINTOOL] This tool display the addresses of global variables in the .data section " << std::endl;
        printf("[PINTOOL] This tool display the addresses of global variables in the .data section\n");
        return -1;
    }
    
    /* ===================================================================== */
    // Analysis routines
    /* ===================================================================== */
    
    // analysis for memory read
    VOID record_mem_read(ADDRINT ip, ADDRINT addr)
    {
        if(data_section_boundaries.is_in_bounds(addr))
        {
            printf("[PINTOOL] Read on a global variable (.data); Instruction addr: %p; Read addr: %p\n", ip, addr);
        }
    }
    
    // analysis for memory write
    VOID record_mem_write(VOID* ip, ADDRINT addr)
    {
        if (data_section_boundaries.is_in_bounds(addr))
        {
            printf("[PINTOOL] Write on a global variable (.data); Instruction addr: %p; Write addr: %p\n", ip, addr);
        }
    }
    
    /* ===================================================================== */
    // Instrumentation callbacks
    /* ===================================================================== */
    
    VOID instrument_instruction(INS ins, VOID *v)
    {
        // must be valid and within bounds of the main executable.
        if(!INS_Valid(ins) || !main_executable_boundaries.is_in_bounds(INS_Address(ins))) {
            return;
        }
    
        const UINT32 mem_operands = INS_MemoryOperandCount(ins);
    
        // Iterate over each memory operand of the instruction.
        for (UINT32 memOp = 0; memOp < mem_operands; memOp++)
        {
            if (INS_MemoryOperandIsRead(ins, memOp))
            {
                INS_InsertPredicatedCall(
                    ins, IPOINT_BEFORE, reinterpret_cast<AFUNPTR>(record_mem_read),
                    IARG_INST_PTR,
                    IARG_MEMORYOP_EA, memOp,
                    IARG_END);
            }
    
            if (INS_MemoryOperandIsWritten(ins, memOp))
            {
                INS_InsertPredicatedCall(
                    ins, IPOINT_BEFORE, reinterpret_cast<AFUNPTR>(record_mem_write),
                    IARG_INST_PTR,
                    IARG_MEMORYOP_EA, memOp,
                    IARG_END);
            }
        }
    }
    
    VOID image_load(IMG img, VOID* v)
    {
        printf("[PINTOOL] Loading image: %s; Image ID: %i\n",IMG_Name(img).c_str(), IMG_Id(img));
        if(IMG_IsMainExecutable(img)) {
            // register lowest and highest addresses to restrict the trace between those addresses.
            main_executable_boundaries.lowest_address = IMG_LowAddress(img);
            main_executable_boundaries.highest_address = IMG_HighAddress(img);
            printf("Main executable boundaries: %s\n", main_executable_boundaries.to_str().c_str());
    
            // cycle through all sections of the main executable.
            for (SEC sec = IMG_SecHead(img); SEC_Valid(sec); sec = SEC_Next(sec))
            {
                // get boundaries of the '.data' section
                if(SEC_Name(sec) == ".data") {
                    const auto sec_address = SEC_Address(sec);
                    data_section_boundaries.lowest_address = sec_address;
                    data_section_boundaries.highest_address = sec_address + SEC_Size(sec);                
                    printf("Data section boundaries: %s\n", data_section_boundaries.to_str().c_str());
                }
            }
        }
    }
    
    VOID image_unload(IMG img, VOID* v)
    {
        printf("[PINTOOL] Unloading image: %s\n", IMG_Name(img).c_str());
    }
    
    VOID fini(INT32 code, VOID *v)
    {
        printf("[PINTOOL] Instrumentation tear down.\n");
    }
    
    /* ===================================================================== */
    // Main
    /* ===================================================================== */
    
    int main(int argc, char *argv[])
    {
        //std::cerr << "[PINTOOL] Loading." << std::endl;
    
        // Initialize PIN library. Print help message if -h(elp) is specified
        // in the command line or the command line is invalid 
        if( PIN_Init(argc,argv) )
        {
            return Usage();
        }
    
        // Register Instruction to be called to instrument instructions
        INS_AddInstrumentFunction(instrument_instruction, nullptr);
    
        // Register ImageLoad to be called when an image is loaded
        IMG_AddInstrumentFunction(image_load, nullptr);
    
        // Register ImageUnload to be called when an image is unloaded
        IMG_AddUnloadFunction(image_unload, nullptr);
    
        // Register function to be called when the application exits
        PIN_AddFiniFunction(fini, nullptr);
    
        //std::cerr << "[PINTOOL] Starting instrumentation." << std::endl;
    
        // Start the program, never returns
        PIN_StartProgram();
    
        return 0;
    }
    

    • .\pin.exe -t MyPinTool.dll -- PinTestSimpleTarget.exe 6

    output:

    [PINTOOL] Loading image: G:\Appdata\CPP\PinTestSimpleTarget\x64\Release\PinTestSimpleTarget.exe; Image ID: 1
    Main executable boundaries: Low Addr: 7ff7077b0000; High Addr: 7ff7077b8fff
    Data section boundaries: Low Addr: 7ff7077b5000; High Addr: 7ff7077b5640
    [PINTOOL] Loading image: C:\WINDOWS\System32\KERNELBASE.dll; Image ID: 2
    [PINTOOL] Loading image: C:\WINDOWS\System32\KERNEL32.DLL; Image ID: 3
    [PINTOOL] Loading image: C:\WINDOWS\SYSTEM32\ntdll.dll; Image ID: 4
    [PINTOOL] Loading image: C:\WINDOWS\System32\ucrtbase.dll; Image ID: 5
    [PINTOOL] Loading image: C:\WINDOWS\SYSTEM32\VCRUNTIME140.dll; Image ID: 6
    [PINTOOL] Loading image: C:\WINDOWS\SYSTEM32\MSVCP140.dll; Image ID: 7
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1ed1; Read addr: 0x7ff7077b5008
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1f63; Write addr: 0x7ff7077b5000
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1cb6; Read addr: 0x7ff7077b55c0
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1cc7; Write addr: 0x7ff7077b55c0
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b2265; Write addr: 0x7ff7077b501c
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b2271; Write addr: 0x7ff7077b5018
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b22c0; Read addr: 0x7ff7077b5020
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b22c0; Write addr: 0x7ff7077b5020
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b2310; Read addr: 0x7ff7077b5624
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b233f; Write addr: 0x7ff7077b5624
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b234d; Write addr: 0x7ff7077b5018
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b2357; Write addr: 0x7ff7077b501c
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b238b; Read addr: 0x7ff7077b501c
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b2394; Write addr: 0x7ff7077b5018
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b239e; Write addr: 0x7ff7077b501c
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b23ad; Write addr: 0x7ff7077b5018
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b23b7; Write addr: 0x7ff7077b501c
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b23d2; Read addr: 0x7ff7077b5030
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1c97; Read addr: 0x7ff7077b55b8
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1c97; Write addr: 0x7ff7077b55b8
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1998; Read addr: 0x7ff7077b55b0
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b19ab; Write addr: 0x7ff7077b55b0
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1d02; Read addr: 0x7ff7077b55c1
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b23d2; Read addr: 0x7ff7077b5030
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1d4f; Write addr: 0x7ff7077b55c8
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1d57; Write addr: 0x7ff7077b55d8
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1d5e; Write addr: 0x7ff7077b55e0
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1d66; Write addr: 0x7ff7077b55f0
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1d6d; Write addr: 0x7ff7077b55c1
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1e76; Read addr: 0x7ff7077b55c8
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1fca; Read addr: 0x7ff7077b5014
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1fb5; Read addr: 0x7ff7077b5610
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1fb5; Write addr: 0x7ff7077b5610
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1fbe; Read addr: 0x7ff7077b5618
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1fbe; Write addr: 0x7ff7077b5618
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b19e9; Write addr: 0x7ff7077b55b0
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b23d2; Read addr: 0x7ff7077b5030
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1e37; Read addr: 0x7ff7077b55b8
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b1e37; Write addr: 0x7ff7077b55b8
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1a0c; Read addr: 0x7ff7077b5638
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1a38; Read addr: 0x7ff7077b5630
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b10be; Read addr: 0x7ff7077b5628
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b10c6; Write addr: 0x7ff7077b5628
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b10be; Read addr: 0x7ff7077b5628
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b10c6; Write addr: 0x7ff7077b5628
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b10be; Read addr: 0x7ff7077b5628
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b10c6; Write addr: 0x7ff7077b5628
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b10be; Read addr: 0x7ff7077b5628
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b10c6; Write addr: 0x7ff7077b5628
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b10be; Read addr: 0x7ff7077b5628
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b10c6; Write addr: 0x7ff7077b5628
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b10be; Read addr: 0x7ff7077b5628
    [PINTOOL] Write on a global variable (.data); Instruction addr: 0x7ff7077b10c6; Write addr: 0x7ff7077b5628
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b143d; Read addr: 0x7ff7077b5008
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1860; Read addr: 0x7ff7077b5008
    local counter: 3
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b143d; Read addr: 0x7ff7077b5008
    global counter: [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b1860; Read addr: 0x7ff7077b5008
    [PINTOOL] Read on a global variable (.data); Instruction addr: 0x7ff7077b117a; Read addr: 0x7ff7077b5628
    6
    [PINTOOL] Loading image: C:\WINDOWS\System32\kernel.appcore.dll; Image ID: 8
    [PINTOOL] Loading image: C:\WINDOWS\System32\msvcrt.dll; Image ID: 9
    [PINTOOL] Loading image: C:\WINDOWS\System32\RPCRT4.dll; Image ID: 10
    [PINTOOL] Unloading image: G:\Appdata\CPP\PinTestSimpleTarget\x64\Release\PinTestSimpleTarget.exe
    [PINTOOL] Unloading image: C:\WINDOWS\System32\KERNELBASE.dll
    [PINTOOL] Unloading image: C:\WINDOWS\System32\KERNEL32.DLL
    [PINTOOL] Unloading image: C:\WINDOWS\SYSTEM32\ntdll.dll
    [PINTOOL] Unloading image: C:\WINDOWS\System32\ucrtbase.dll
    [PINTOOL] Unloading image: C:\WINDOWS\SYSTEM32\VCRUNTIME140.dll
    [PINTOOL] Unloading image: C:\WINDOWS\SYSTEM32\MSVCP140.dll
    [PINTOOL] Unloading image: C:\WINDOWS\System32\kernel.appcore.dll
    [PINTOOL] Unloading image: C:\WINDOWS\System32\msvcrt.dll
    [PINTOOL] Unloading image: C:\WINDOWS\System32\RPCRT4.dll
    [PINTOOL] Instrumentation tear down.
    

    Obviously there are some other global variables used internally by the program which are displayed; but at least it should give you a good idea on how to track global variables in your program.