如何通过pin和libelf.h获取可执行程序的全局变量地址

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

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

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

我本来只想发表评论,但有点太长了...

根据定义,全局变量驻留在可执行文件中(更准确地说,驻留在 .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.

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