Есть ли способ найти адреса разделов кода (.data, .text, et c) во время выполнения? - PullRequest
1 голос
/ 02 февраля 2020

Я хочу написать некоторый код, который будет печатать адреса и длины каждого из разделов кода в своем собственном процессе при запуске. Есть простой способ сделать это? Я знаю, что относительно легко найти расположение таких функций, как main, используя код, такой как void* main_address = main;, но я хочу найти такие разделы, как .data и .text, и я не знаю, смогу ли я сделать то же самое с ними, когда я компиляции. Я пишу этот эксперимент на Windows системе и компилирую для архитектуры x86. Я знаю небольшую сборку x86, если это необходимо для решения. Буду очень признателен за любую помощь или совет. Спасибо!

Ответы [ 3 ]

3 голосов
/ 02 февраля 2020

Это зависит от используемого компилятора. Это будет о g cc & binutils.

  1. Найдите скрипт компоновщика вашего проекта. Сценарий компоновщика обычно имеет расширение .ld. Если нет линкерного скрипта, ваш проект использует скрипт по умолчанию. Чтобы увидеть скрипт компоновщика по умолчанию, вам нужно передать `-Wl, -verbose. Вы увидите много информации, но мы ищем что-то вроде этого (это мое):
/* Default linker script, for normal executables */
/* Copyright (C) 2014 Free Software Foundation, Inc.
   Copying and distribution of this script, with or without modification,
   are permitted in any medium without royalty provided the copyright
   notice and this notice are preserved.  */
OUTPUT_FORMAT(pei-i386)
SEARCH_DIR("/mingw/mingw32/lib"); SEARCH_DIR("/mingw/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
SECTIONS
{
  /* Make the virtual address and file offset synced if the alignment is
     lower than the target page size. */
  . = SIZEOF_HEADERS;
  . = ALIGN(__section_alignment__);
  .text  __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) :
  {
     *(.init)
    *(.text)
    *(SORT(.text$*))
     *(.text.*)
     *(.gnu.linkonce.t.*)
    *(.glue_7t)
    *(.glue_7)
     ___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
            LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*));  LONG (0);
     ___DTOR_LIST__ = .; __DTOR_LIST__ = . ;
            LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*));  LONG (0);
     *(.fini)
    /* ??? Why is .gcc_exc here?  */
     *(.gcc_exc)
    PROVIDE (etext = .);
    PROVIDE (_etext = .);
     *(.gcc_except_table)
  }
  /* The Cygwin32 library uses a section to avoid copying certain data
     on fork.  This used to be named ".data".  The linker used
     to include this between __data_start__ and __data_end__, but that
     breaks building the cygwin32 dll.  Instead, we name the section
     ".data_cygwin_nocopy" and explicitly include it after __data_end__. */
  .data BLOCK(__section_alignment__) :
  {
    __data_start__ = . ;
    *(.data)
    *(.data2)
    *(SORT(.data$*))
    *(.jcr)
    __data_end__ = . ;
    *(.data_cygwin_nocopy)
  }
  .rdata BLOCK(__section_alignment__) :
  {
    *(.rdata)
             *(SORT(.rdata$*))
    __rt_psrelocs_start = .;
    *(.rdata_runtime_pseudo_reloc)
    __rt_psrelocs_end = .;
  }
  __rt_psrelocs_size = __rt_psrelocs_end - __rt_psrelocs_start;
  ___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
  __RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
  ___RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;
  __RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;
  .eh_frame BLOCK(__section_alignment__) :
  {
    *(.eh_frame*)
  }
  .pdata BLOCK(__section_alignment__) :
  {
    *(.pdata)
  }
  .bss BLOCK(__section_alignment__) :
  {
    __bss_start__ = . ;
    *(.bss)
    *(COMMON)
    __bss_end__ = . ;
  }
  .edata BLOCK(__section_alignment__) :
  {
    *(.edata)
  }
  /DISCARD/ :
  {
    *(.debug$S)
    *(.debug$T)
    *(.debug$F)
    *(.drectve)
     *(.note.GNU-stack)
     *(.gnu.lto_*)
  }
  .idata BLOCK(__section_alignment__) :
  {
    /* This cannot currently be handled with grouped sections.
    See pe.em:sort_sections.  */
    SORT(*)(.idata$2)
    SORT(*)(.idata$3)
    /* These zeroes mark the end of the import list.  */
    LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
    SORT(*)(.idata$4)
    __IAT_start__ = .;
    SORT(*)(.idata$5)
    __IAT_end__ = .;
    SORT(*)(.idata$6)
    SORT(*)(.idata$7)
  }
  .CRT BLOCK(__section_alignment__) :
  {
    ___crt_xc_start__ = . ;
    *(SORT(.CRT$XC*))  /* C initialization */
    ___crt_xc_end__ = . ;
    ___crt_xi_start__ = . ;
    *(SORT(.CRT$XI*))  /* C++ initialization */
    ___crt_xi_end__ = . ;
    ___crt_xl_start__ = . ;
    *(SORT(.CRT$XL*))  /* TLS callbacks */
    /* ___crt_xl_end__ is defined in the TLS Directory support code */
    ___crt_xp_start__ = . ;
    *(SORT(.CRT$XP*))  /* Pre-termination */
    ___crt_xp_end__ = . ;
    ___crt_xt_start__ = . ;
    *(SORT(.CRT$XT*))  /* Termination */
    ___crt_xt_end__ = . ;
  }
  /* Windows TLS expects .tls$AAA to be at the start and .tls$ZZZ to be
     at the end of section.  This is important because _tls_start MUST
     be at the beginning of the section to enable SECREL32 relocations with TLS
     data.  */
  .tls BLOCK(__section_alignment__) :
  {
    ___tls_start__ = . ;
    *(.tls$AAA)
    *(.tls)
    *(.tls$)
    *(SORT(.tls$*))
    *(.tls$ZZZ)
    ___tls_end__ = . ;
  }
  .endjunk BLOCK(__section_alignment__) :
  {
    /* end is deprecated, don't use it */
    PROVIDE (end = .);
    PROVIDE ( _end = .);
     __end__ = .;
  }
  .rsrc BLOCK(__section_alignment__) : SUBALIGN(4)
  {
    *(.rsrc)
    *(.rsrc$*)
  }
  .reloc BLOCK(__section_alignment__) :
  {
    *(.reloc)
  }
  .stab BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.stab)
  }
  .stabstr BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.stabstr)
  }
  /* DWARF debug sections.
     Symbols in the DWARF debugging sections are relative to the beginning
     of the section.  Unlike other targets that fake this by putting the
     section VMA at 0, the PE format will not allow it.  */
  /* DWARF 1.1 and DWARF 2.  */
  .debug_aranges BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_aranges)
  }
  .zdebug_aranges BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_aranges)
  }
  .debug_pubnames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_pubnames)
  }
  .zdebug_pubnames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_pubnames)
  }
  .debug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_pubtypes)
  }
  .zdebug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_pubtypes)
  }
  /* DWARF 2.  */
  .debug_info BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_info .gnu.linkonce.wi.*)
  }
  .zdebug_info BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_info .zdebug.gnu.linkonce.wi.*)
  }
  .debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_abbrev)
  }
  .zdebug_abbrev BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_abbrev)
  }
  .debug_line BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_line)
  }
  .zdebug_line BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_line)
  }
  .debug_frame BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_frame*)
  }
  .zdebug_frame BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_frame*)
  }
  .debug_str BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_str)
  }
  .zdebug_str BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_str)
  }
  .debug_loc BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_loc)
  }
  .zdebug_loc BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_loc)
  }
  .debug_macinfo BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_macinfo)
  }
  .zdebug_macinfo BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_macinfo)
  }
  /* SGI/MIPS DWARF 2 extensions.  */
  .debug_weaknames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_weaknames)
  }
  .zdebug_weaknames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_weaknames)
  }
  .debug_funcnames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_funcnames)
  }
  .zdebug_funcnames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_funcnames)
  }
  .debug_typenames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_typenames)
  }
  .zdebug_typenames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_typenames)
  }
  .debug_varnames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_varnames)
  }
  .zdebug_varnames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_varnames)
  }
  .debug_macro BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_macro)
  }
  .zdebug_macro BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_macro)
  }
  /* DWARF 3.  */
  .debug_ranges BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_ranges)
  }
  .zdebug_ranges BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_ranges)
  }
  /* DWARF 4.  */
  .debug_types BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_types .gnu.linkonce.wt.*)
  }
  .zdebug_types BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.zdebug_types .gnu.linkonce.wt.*)
  }
}

Скопируйте и вставьте его в текстовый файл (расширение .ld поможет вам или другие люди понимают, что делает этот файл).

Как мы видим, в разделе .text есть два символа в en, но в начале нет символа. Мы можем сами добавить этот символ

  .text  __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) :
  {
     .__text_start__ = .;
     *(.init)

Юо нужно передать -Tpath_to_your_ld_file компоновщику

, затем в файле. c мы сможем проверить его:

extern char _text_start__, etext, _data_start__, _data_end__, _bss_start__, _bss_end__;

int main()
{
    printf("Text start: %p  Text end: %p\n", (void *)&_text_start__, (void *)&etext);
    printf("Data start: %p  Data end: %p\n", (void *)&_data_start__, (void *)&_data_end__);
    printf("BSS start: %p  BSS end: %p\n", (void *)&_bss_start__, (void *)&_bss_end__);
}

на моем компьютере это:

Text start: 00401000  Text end: 00408FF4
Data start: 00409000  Data end: 0040902C
BSS start: 0040D000  BSS end: 0040DA34
3 голосов
/ 02 февраля 2020

просто пройти мимо PIMAGE_SECTION_HEADER s

void DumpSections()
{
    //PIMAGE_NT_HEADERS pinth = (PIMAGE_NT_HEADERS)((PBYTE)&__ImageBase + reinterpret_cast<PIMAGE_DOS_HEADER>(&__ImageBase)->e_lfanew);
    if (PIMAGE_NT_HEADERS pinth = RtlImageNtHeader(&__ImageBase))
    {
        if (ULONG NumberOfSections = pinth->FileHeader.NumberOfSections)
        {
            PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinth);

            do 
            {
                DbgPrint("%p %08x %.8s\n", (PBYTE)&__ImageBase + pish->VirtualAddress, pish->Misc.VirtualSize, pish->Name);
            } while (pish++, --NumberOfSections);
        }
    }
}
1 голос
/ 02 февраля 2020

Я не знаю Windows соглашений, но если это похоже на Linux, ваш компилятор, ассемблер или компоновщик может определить символ для начала раздела. (Используйте nm или аналогичный инструмент для выгрузки таблицы символов из .obj или .exe.)

Если это так, extern const char that_symbol[] определит переменную C с потенциально совпадающим именем. Тогда, конечно, вы можете просто использовать адрес that_symbol. (Примечание: не const char *that_symbol; в памяти не хранится указатель. Вы определяете переменную stati c, для которой address - это нужный адрес. Не читайте значение этой переменной.)

Используйте GNU C extern char foo[] asm("real_name"), если необходимо, для обхода начальных подчеркиваний или используйте имя символа asm, которое включает . или что-то, что C не позволяет. https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html Это, конечно, расширение GNU.


См. @ P__J __ * для полной Windows реализации того, что этот ответ я предлагал , включая скрипт компоновщика GNU binutils, чтобы добавить недостающие символы для начала / конца некоторых разделов, которые инструментальная цепочка не определяет самостоятельно. В качестве имени C используется extern char вместо extern char[], поэтому вы всегда должны использовать &name для получения адреса символа. Но фундаментальная идея определения C extern глобалов, имеющих адрес, который вы хотите, именно то, что я предлагал.

...