Большинство процессов Windows (* .exe) загружаются в (пользовательский режим) адрес памяти 0x00400000, это то, что мы называем «виртуальным адресом» (VA) - потому что они видны только каждому процессу и будут преобразованы в разные физические адреса ОС (видимые на уровне ядра / драйвера).
Например, возможный адрес физической памяти (видимый ЦП):
0x00300000 on physical memory has process A's main
0x00500000 on physical memory has process B's main
И ОС может иметь таблицу сопоставления:
process A's 0x00400000 (VA) = physical address 0x00300000
process B's 0x00400000 (VA) = physical address 0x00500000
Затем, когда вы попытаетесь прочитать 0x004000000 в процессе A, вы получите содержимое, которое находится в 0x00300000 физической памяти.
Что касается RVA, он просто разработан, чтобы облегчить перемещение. При загрузке перемещаемых модулей (например, DLL) система попытается вставить его в область памяти процесса. Таким образом, в макете файла он помещает «относительный» адрес, чтобы помочь вычислению.
Например, DLL C может иметь этот адрес:
RVA 0x00001000 DLL C's main entry
При загрузке в процесс A по базовому адресу 0x10000000 основной записью C становится
VA = 0x10000000 + 0x00001000 = 0x10001000
(if process A's VA 0x10000000 mapped to physical address was 0x30000000, then
C's main entry will be 0x30001000 for physical address).
При загрузке в процесс B по базовому адресу 0x32000000 основной записью C становится
VA = 0x32000000 + 0x00001000 = 0x32001000
(if process B's VA 0x32000000 mapped to physical address was 0x50000000, then
C's main entry will be 0x50001000 for physical address).
Обычно RVA в файлах изображений относится к базовому адресу процесса при загрузке в память, но некоторые RVA могут относиться к начальному адресу «раздела» в файлах изображений или объектных файлов (вы должны проверить подробности спецификации формата PE). ). Независимо от того, что RVA относится к «некоторому» базовому VA.
Подводя итог,
- Адрес физической памяти - это то, что процессор видит
- Виртуальный адрес (VA) по отношению к физическому адресу, на процесс (управляемый ОС)
- RVA относительно VA (базы файлов или разделов) для каждого файла (управляется компоновщиком и загрузчиком)
(редактировать) относительно нового вопроса когтя:
Значение RVA метода / переменной НЕ всегда является его смещением от начала файла. Они обычно относятся к некоторому виртуальному компьютеру, который может быть базовым адресом загрузки по умолчанию или базовым виртуальным компьютером раздела - поэтому я говорю, что вы должны проверить спецификацию PE для получения подробной информации.
Ваш инструмент PEView пытается отобразить RVA каждого байта для загрузки базового адреса. Поскольку секции начинаются на разных основаниях, RVA может стать другой при пересечении секций.
Что касается ваших догадок, они очень близки к правильным ответам:
Обычно мы не будем обсуждать «RVA» перед разделами, но заголовок PE будет по-прежнему загружаться до конца заголовков разделов. Разрыв между заголовком и телом раздела (если есть) не будет загружен. Вы можете проверить это отладчиками. Более того, когда между разделами есть некоторый промежуток, они могут быть не загружены.
Как я уже сказал, RVA просто «относительно некоторого VA», независимо от того, какой это VA (хотя, говоря о PE, VA обычно ссылается на базовый адрес нагрузки). Когда вы читаете спецификацию формата PE, вы можете найти «RVA», который относится к какому-то специальному адресу, такому как начальный адрес ресурса. RVA списка PEView от 0x1000 потому, что этот раздел начинается с 0x1000. Почему 0x1000? Поскольку компоновщик оставил 0x1000 байт для PE-заголовка, RVA начинается с 0x1000.
То, что вы пропустили, это понятие «секция» на стадии загрузки PE. PE может содержать несколько «разделов», каждый раздел отображается на новый начальный адрес VA. Например, это сбрасывается из win7 kernel32.dll:
# Name VirtSize RVA PhysSize Offset
1 .text 000C44C1 00001000 000C4600 00000800
2 .data 00000FEC 000C6000 00000E00 000C4E00
3 .rsrc 00000520 000C7000 00000600 000C5C00
4 .reloc 0000B098 000C8000 0000B200 000C6200
Существует невидимый заголовок "0 RVA = 0000, SIZE = 1000", который заставляет .text начинаться с RVA 1000. Секции должны быть непрерывными при загрузке в память (то есть, VA), поэтому их RVA является непрерывным. Однако, поскольку память распределяется по страницам, она будет кратна размеру страницы (4096 = 0x1000 байт). Вот почему секция № 2 начинается с 1000 + C5000 = C6000 (C5000 происходит от C44C1).
Чтобы обеспечить отображение памяти, эти разделы должны быть выровнены по некоторому размеру (размер выравнивания файла - определяется компоновщиком. В моем примере выше это 0x200 = 512 байт), который контролирует поле PhysSize. Смещение означает «смещение к началу физического файла PE».
Таким образом, заголовки занимают 0x800 байт файла (и 0x1000 при отображении в память), что является смещением раздела # 1. Затем, выровняв его данные (c44c1 байт), мы получим physsize C4600. C4600 + 800 = C4E00, что в точности соответствует смещению второй секции.
Хорошо, это относится ко всей загрузке PE, так что это может быть немного трудно понять ...
(редактировать) позвольте мне снова сделать новое простое резюме.
* * 1068
«RVA» в файлах DLL / EXE (формат PE) обычно относится к «загрузить базовый адрес в память» (но не всегда - вы должны прочитать спецификацию)
Формат PE содержит структуру отображения «раздел» для отображения физического содержимого файла в память. Таким образом, RVA на самом деле не относится к смещению файла.
Чтобы вычислить RVA некоторого байта, вы должны найти его смещение в разделе и добавить базу раздела.