【问题标题】:How to get the global variable address of the executable program through pin and libelf.h如何通过pin和libelf.h获取可执行程序的全局变量地址
【发布时间】:2019-10-07 08:51:56
【问题描述】:

我想开发一个 pintool 来找出我的 C 程序的全局变量的地址。假设我有一个 C 程序,其中有一些全局指针变量。当我使用 pintool 运行相同的程序时,我希望通过 pintool 找到这些全局变量的地址。

我正在尝试通过 pin 获取全局变量的地址,但是我们 都知道 Pin 似乎没有提供这样的功能。根据文档:“符号对象仅提供有关应用程序中的函数符号的信息。有关其他类型符号(例如数据符号)的信息,必须由工具独立获取,libelf.h 似乎可以获取全局变量的地址,请帮助我并建议我如何才能做到这一点?

【问题讨论】:

    标签: global-variables elf intel-pin


    【解决方案1】:

    我本来想只做一个评论,但它有点太长了......

    每个定义的全局变量驻留在可执行文件中(更准确地说是在 .data 或 .bss 部分,取决于它们是否已初始化)。分配其他变量(在堆栈或堆上)。

    你甚至不需要符号来检查一个变量(给定它的地址)是否在一个可执行部分中:使用图像检测函数(IMG_xxx),循环这些部分(SEC_xxx)获取部分的基础和结尾,检查它是哪一个(.data 或 .bss)。您可以使用SEC_Type 获取带有 PIN 码的部分类型;一旦你有了一个地址,如果它位于 .bss 或 .data 中,那么你就有了一个全局变量。

    现在,如果您想要位于给定地址的变量的名称,它会更加复杂,并且正如 PIN 文档所述,您需要符号信息。我不知道 libelf 是否可以轻松做到这一点,但 libdwarf 可以。您还可以查看 llvm-dwarfdump 代码,该代码是开源的并且也能够做到这一点。


    注意:我在 Windows 上进行了实验(.data 部分),但在 Linux 上的输出应该有点相似。

    这是一个带有一个已知全局变量的小虚拟示例;未经优化编译:

    #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;
    }
    

    下面是使用全局变量的count函数部分的反汇编:

    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                          |
    

    对全局变量 std::cout 的反汇编:

    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 |
    

    注意3个地址:

    • 00007FF7077B10BE(读取)
    • 00007FF7077B10C6(写)
    • 00007FF7077B117A (std::cout)

    全局变量本身在:

    • 00007FF7077B5628

    这是 pintool 的源代码(注意:由于未知原因,我在使用 std::cout 时无法正确初始化 CRT,所以我改用 printf)。

    #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

    输出:

    [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.
    

    显然还有一些其他的被程序内部使用的全局变量显示出来了;但至少它应该让您了解如何在程序中跟踪全局变量。

    【讨论】:

    • 感谢您的回答,现在我知道我可以通过 SEC 获取全局变量的地址和大小,但我不知道如何获取 .bss 中的读写地址和.data
    • 参见源代码中的source/tools/ManualExamples/pinatrace.cpp 示例。它显示了如何获取读取或写入的地址。 INS_InsertCallIARG_MEMORYOP_EA 参数将为您提供内存地址。获得此地址后,只需检查它是否位于上述部分之一中。
    • span class="comcopy">sorry,我还没有实现,我用SEC来获取.bss和,数据的地址和大小,然后我只在这个范围内跟踪读/写,但总是没有全局变量. if(!strcmp(sec_name.c_str(),".bss") || !strcmp(sec_name.c_str(),".data") ){ADDRINT addr=SEC_Address(sec);USIZE size=SEC_Size(sec); if(global.count(addr)==0) global.insert(std_make_pair(addr,size));}
    • 我会尽量做一个完整的例子,至少在周末之前。
    • 感谢您的帮助。期待你的回复~
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-14
    • 1970-01-01
    • 2015-09-28
    相关资源
    最近更新 更多