Как я могу найти глобальные и стековые области процесса в Win32? - PullRequest
1 голос
/ 12 января 2010

Как я могу определить, какие области памяти процесса Win32 содержат глобальные данные и данные стека для каждого потока?

Ответы [ 3 ]

2 голосов
/ 13 января 2010

Нет API (который я знаю) для этого. Но если у вас есть DLL в процессе, вы получите уведомления DLL_PROCESS_ATTACH / DLL_THREAD_ATTACH в DllMain при создании каждого потока. Когда вы получите эти уведомления, вы можете записать идентификатор потока и адрес стекового объекта для этого потока, потому что вас вызовут в новом потоке. Поэтому сохраните идентификатор потока и адрес стека в некоторой таблице, которую вы создаете в то время. Не пытайтесь проделать большую работу в DllMain, просто запишите расположение стека и вернитесь.

Затем можно использовать VirtualQuery , чтобы превратить адрес переменной в каждом стеке потоков в виртуальный диапазон выделения, который должен дать вам базовый адрес стека (помните, что стеки растут из старших адресов на низкие адреса). Размер выделения по умолчанию для стека составляет 1 МБ, но он может быть переопределен переключателем компоновщика или создателем потока, но стек должен быть смежным. Так что вы получите от VirtualQuery полный стек на тот момент времени

Что касается местоположения кучи - для кучи может быть несколько расположений, но в целом, если вы хотите указать одно непрерывное местоположение кучи, используйте HeapAlloc , чтобы получить адрес объекта кучи, а затем VirtualQuery, чтобы определить диапазон страниц для этого раздела кучи.

В качестве альтернативы Вы можете использовать VirtualQuery в hModule для EXE и для каждой DLL. и тогда вы можете предположить, что все, что является чтением-записью, а не стеком или модулем, является частью кучи. Обратите внимание, что это будет верно в большинстве процессов, но может не быть истинным в некоторых процессах, поскольку приложение может напрямую вызывать VirtualAlloc или CreateFileMapping, что приводит к действительным указателям данных, которые не принадлежат ни стеку, ни куче. Используйте EnumProcessModules , чтобы получить список модулей, загруженных в процесс.

VirtualQuery в основном берет случайный адрес и возвращает базовый адрес коллекции страниц, которой принадлежит этот адрес, а также защиту страниц. Так что это хорошо для перехода от определенного указателя, который «тип» распределения.

1 голос
/ 12 мая 2010

Глобальные данные

Под «глобальным» я предполагаю, что вы имеете в виду все данные, которые не распределяются динамически с использованием new, malloc, HeapAlloc, VirtualAlloc и т. Д. - данные, которые вы можете объявить в исходном коде вне функций и вне определений классов.

Вы можете найти их, загрузив каждую DLL в виде PE-файла в программу чтения PE-файлов и определив расположение разделов .data и .bss (они могут иметь разные имена для разных компиляторов). Вы должны сделать это для каждой DLL. Это дает вам общие места для этих данных для каждой DLL. Затем, если у вас есть отладочная информация или файл с ошибками MAP, вы можете сопоставить адреса DLL с информацией отладочной информации / файла карты, чтобы получить имена и точное местоположение для каждой переменной.

Вы можете найти, что DLL формата PE поможет вам выполнить эту задачу намного проще, чем написание кода для запроса файла PE самостоятельно.

Стеки потоков

Перечислять потоки в приложении, используя ToolHelp32 (или библиотеку PSAPI, если в Windows NT 4). Для каждого потока получите контекст потока и прочитайте регистр ESP (RSP для x64). Теперь выполните VirtualQuery для адреса в регистре ESP / RSP, считанного из каждого контекста. Область 1 МБ (значение по умолчанию) вокруг этого адреса (начинается с mbi.AllocationBase и работает вверх 1 МБ) - это расположение в стеке. Обратите внимание, что размер стека не может быть 1 МБ, вы можете запросить это из PE-заголовка DLL / EXE, который запустил поток, если хотите.

РЕДАКТИРОВАТЬ , Исправить опечатку, где я поменял несколько регистров имен, спасибо @ interjay

1 голос
/ 12 января 2010

Взять адрес переменных, выделенных в интересующих вас областях памяти. То, что вы делаете с адресами, когда они у вас есть, - это совсем другой вопрос.

Вы также можете objdump -h (я думаю, это -h, может быть -x), чтобы перечислить адреса разделов, включая разделы данных.

...