О копировании dll-раздела в память
void
CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module)
{
int i, size;
unsigned char *codeBase = module->codeBase;
unsigned char *dest;
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
for (i=0; i<module->headers->FileHeader.NumberOfSections; i++, section++) {
if (section->SizeOfRawData == 0) {
// section doesn't contain data in the dll itself, but may define
// uninitialized data
size = old_headers->OptionalHeader.SectionAlignment;
if (size > 0) {
dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress,
size,
MEM_COMMIT,
PAGE_READWRITE);
section->Misc.PhysicalAddress = (DWORD) (POINTER_TYPE) dest;
memset(dest, 0, size);
}
// section is empty
continue;
}
// commit memory block and copy data from dll
dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress,
section->SizeOfRawData,
MEM_COMMIT,
PAGE_READWRITE);
memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData);
section->Misc.PhysicalAddress = (DWORD) (POINTER_TYPE) dest;
}
}
Я хочу загрузить файл DLL из памяти. И код выше был найден в http://www.joachim-bauch.de/tutorials/loading-a-dll-from-memory.
Я также обнаружил, что автор говорит, что: "Разделы без данных в файле (например, разделы данных для используемых переменных) имеют SizeOfRawData = 0, поэтому вы можете использовать SizeOfInitializedData или SizeOfUninitializedData для OptionalHeader. Какой из них должен быть выбран в зависимости от бита флаги IMAGE_SCN_CNT_INITIALIZED_DATA и IMAGE_SCN_CNT_UNINITIALIZED_DATA, которые могут быть установлены в характеристиках раздела."
Но я не могу понять, когда SizeOfRawData равен нулю, почему размер выделенной памяти равен SectionAlignment, ни SizeOfInitializedData, ни SizeOfUninitializedData.
1 ответ
Согласно спецификации Microsoft PE и COFF SizeOfRawData равен нулю, когда:
Если раздел содержит только неинициализированные данные, это поле (SizeOfRawData) должно быть нулевым.
(Как примечание стороны, это также верно, если раздел содержит только инициализированные данные, которые инициализированы в 0.)
SizeOfInitializedData или SizeOfUninitializedData нельзя использовать для каждого раздела, так как эти поля являются суммой всех инициализированных и неинициализированных разделов, если существует более одного раздела этого типа (цитируя спецификацию):
SizeOfInitializedData: размер инициализированного раздела данных или сумма всех таких разделов, если имеется несколько разделов данных.
SizeOfUninitializedData: размер секции неинициализированных данных (BSS) или сумма всех таких секций, если имеется несколько секций BSS.
Таким образом, если у вас есть более одного инициализированного или неинициализированного раздела, вы в конечном итоге выделите много для одного раздела, если будете использовать (соответственно) поля SizeOfInitializedData или SizeOfUninitializedData.
Это не может быть SectionAlignment (который обычно устанавливается на гранулярность распределения системы), потому что вы также в конечном итоге выделите недостаточно места для вашего раздела, если размер xection больше, чем гранулярность выделения (обычно 4Kibi или 4096). байт).
SectionAlignment: выравнивание (в байтах) разделов при их загрузке в память. Он должен быть больше или равен FileAlignment. По умолчанию используется размер страницы для архитектуры.
В качестве примера предположим, что у вас есть 2 раздела неинициализированных данных (SizeOfRawData = 0 для каждого раздела) по 8192 байта каждый. Если вы выделяете:
SizeOfUninitializedData: в конечном итоге вы выделите 8192 * 2 байта для каждого раздела, что слишком много.
SectionAlignment: вы в конечном итоге выделите 4096 (0x1000) байтов для каждого раздела, что недостаточно.
IMO, единственные поля, которые имеют отношение к вашему делу, это IMAGE_SECTION_HEADER.VirtualSize:
VirtualSize: общий размер раздела при загрузке в память. Если это значение больше, чем SizeOfRawData, раздел будет дополнен нулями. Это поле действительно только для исполняемых образов и должно быть установлено равным нулю для объектных файлов.
Обратите внимание, что поле VirtualSize не округлено (это точное количество байтов, необходимое в памяти без учета степени детализации страницы).
Таким образом, в случае, если у вас есть раздел с SizeOfRawData = 0, вы должны:
- Возьмите поле VirtualSize этого раздела
- Выделите результирующий размер с VirtualAlloc()
Вам не нужно округлять VirtualSize, потому что VirtualAlloc() позаботится о выделении следующей кратности гранулярности размера страницы (как указано в GetSystemInfo и поле SYSTEM_INFO.dwPageSize).