Моей конечной целью было получить список имен DLL из статической таблицы данных импорта.
Я подумал, что могу сделать что-то вроде:auto data_dirs = p_loaded_image->FileHeader->OptionalHeader.DataDirectory;
А затем каким-то образом перебрать этот список адресов, а затем таким образом получить имена DLL; что-то такое.
Итак, для детских шагов я просто пытался проверить, могу ли я сопоставить значения для p_loaded_image->FileHeader->OptionalHeader.SizeOfStackCommit;
с эквивалентом ручного указателя-математики. Кажется, я не могу сделать это без Access Violation
исключений, которые, кажется, подтверждают, что я делаю это неправильно.
Что я сделал не так и как конкретно сделать так, чтобы мой математический запрос указателя соответствовал фактически возвращаемому API загруженного изображения для получения того же значения SizeOfStackCommit
? Если вы сможете многому меня научить, я надеюсь, что смогу продвинуться дальше текущего этапа моей WIP по поиску имен DLL.
В целях экономии времени, если ваш компилятор поддерживает std::experimental::filesystem
, вы можете начать с комментария // Skip to here
, чтобы избежать всей консоли и стандартного шаблона проверки файлов, в противном случае вам нужно будет заглушить его или изменить на что-то более подходящее для старых спецификаций C++.
#include "Windows.h"
#include "Imagehlp.h"
#include "tchar.h"
#include "stdio.h"
#include "stdlib.h"
#include <string>
#include <vector>
#include <experimental\filesystem>
// All hard-coded values taken directly from latest PE/COFF .docx Documentation from MS:
// => http://go.microsoft.com/fwlink/p/?linkid=84140
const int MAGIC_32_NUM = 0x10b;
const int MAGIC_64_NUM = 0x20b;
// These two require C++17 || If needed, replace with older valid file-verification.
namespace fs = std::experimental::filesystem;
bool verify_loaded_file(std::string);
int _tmain(int argc, _TCHAR* argv[])
{
std::string image_to_load;
if (argc == 2) {
image_to_load = argv[1];
}
else {
printf("A valid path to a loadable image needs to be your only command-line parameter for %s", argv[0]);
return -1;
}
bool validFile = verify_loaded_file(image_to_load);
if (!validFile) {
printf("A valid file path of a DLL or EXE needs to be your only command-line parameter for %s", argv[0]);
return -1;
}
auto filesystem_image = fs::absolute(fs::path(image_to_load));
std::string image_directory = filesystem_image.parent_path().string();
std::string image_name = filesystem_image.stem().string();
std::string image_name_and_extension = image_name + filesystem_image.extension().string();
bool is64bit, is32bit = false;
// To use MapAndLoad, you need to manually include Imagehlp.lib in your project.
// The Imagehlp.h header alone does not suffice.
LOADED_IMAGE loaded_image = { 0 };
LOADED_IMAGE * p_loaded_image = &loaded_image;
bool image_loaded = MapAndLoad(image_name_and_extension.c_str(), image_directory.c_str(), p_loaded_image, FALSE, TRUE);
int error_check = GetLastError();
if (!image_loaded) {
printf("Something went wrong when trying to load %s0 with error code %s1", image_to_load.c_str(), error_check);
UnMapAndLoad(p_loaded_image);
return -1;
}
int magic_number = loaded_image.FileHeader->OptionalHeader.Magic;
if (magic_number == MAGIC_32_NUM) { is32bit = true; }
else if (magic_number == MAGIC_64_NUM) { is64bit = true; }
else {
printf("The magic number from the optional header wasn't detected as 32-bit or 64-bit\n");
printf("Check Windows System Error Code: %s\n", magic_number);
UnMapAndLoad(p_loaded_image);
return -1;
}
// Skip to here
UCHAR * module_base_address = p_loaded_image->MappedAddress;
size_t coverted_base_address = size_t(module_base_address);
size_t windows_optional_header_offset;
if (is64bit) { windows_optional_header_offset = size_t(24); }
else { windows_optional_header_offset = size_t(28); }
size_t data_directory_optional_header_offset;
if (is64bit) { data_directory_optional_header_offset = size_t(112); }
else { data_directory_optional_header_offset = size_t(96); }
size_t size_stack_commit_offset;
if (is64bit) { size_stack_commit_offset = size_t(80); }
else { size_stack_commit_offset = size_t(76); }
// The commented out line below breaks with Access Violations, as does the line following it:
// auto sum_for_size_stack = size_t(coverted_base_address + size_stack_commit_offset);
auto sum_for_size_stack = size_t(coverted_base_address +
windows_optional_header_offset +
data_directory_optional_header_offset +
size_stack_commit_offset);
auto direct_access_size_stack = p_loaded_image->FileHeader->OptionalHeader.SizeOfStackCommit;
DWORD64 * addy = &direct_access_size_stack;
printf("Direct: %s\n", direct_access_size_stack);
printf("Pointer-Math: %s\n", sum_for_size_stack);
UnMapAndLoad(p_loaded_image);
return 0;
}
//
bool verify_loaded_file(std::string file_to_verify)
{
if (fs::exists(file_to_verify))
{
size_t extension_query = file_to_verify.find(".dll", 0);
if (extension_query == std::string::npos)
{
extension_query = file_to_verify.find(".DLL", 0);
if (extension_query == std::string::npos)
{
extension_query = file_to_verify.find(".exe", 0);
if (extension_query == std::string::npos)
{
extension_query = file_to_verify.find(".EXE", 0);
}
else { return true; }
if (extension_query != std::string::npos) { return true; }
}
else { return true; }
}
else { return true; }
}
return false;
}
Последняя документация по формату PE-файла для Windows представлена здесь, в приложении к техническому документу, в котором содержится его .docx
: http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
Обновление 1:
У меня есть мой чистый арифметический обход указателя, работающий прямо до моей конечной цели. Чтобы добраться до этого момента, мне потребовалось удалить два уровня сложности.
Не возитесь с загрузкой изображения с помощью специальных API, так как я пытаюсь получить статическую информацию об импорте; решение для этого состояло в том, чтобы загрузить EXE в вектор символов, чтобы сделать его снимок в памяти.
Забудьте о слишком сложном звучании RVA, если вам необходимо его использовать. Просто используйте Byte Offsets для заголовков PE. В разделах вам нужно использовать RVA. Просто считайте, что адрес элемента 0 для вектора символов является вашим базовым адресом, для которого вычисляются все RVA. docx также сообщает вам, когда использовать смещение по сравнению с фактическим адресом, что полезно знать. Проверьте мой добавленный ответ, где я кратко рассказываю об использовании RVA для получения таблицы импорта.
Моя программа все еще не делает то, что я хочу, но, по крайней мере, у меня есть суть арифметики указателей, соответствующая средствам доступа к указателям, что и было целью этого вопроса.
Я думаю, что мои оставшиеся блокираторы связаны с тем, какие структуры загружать данными и где. Вы можете собрать и запустить мою суть WIP на компьютере с Win10 или обновить значение ph_file
должно быть какой-либо другой локально установленной 64-битной программой в вашей ОС, желательно без раздела .idata
. Наличие раздела .idata
не гарантируется даже при импорте библиотек DLL. Например, в Calculator.exe его нет.
Обновление 2:
Я получил некоторую помощь в отладке и, наконец, заработал. Код POC, так что почти ничего не подчищено и не оптимизировано, но он функционален. Проверено на двоичных файлах x86/win32 и x64. Суть здесь.
size_t
:coverted_base_address
иsize_stack_commit_offset
, чтобы убедиться, что вы получаете те значения, которые должны были ожидать? То же самое можно сказать и о следующей строке кода. - person Francis Cugler   schedule 03.05.2017CreateToolhelp32Snapshot
звучит отлично! Является ли это программным аварийным дампом или даже лучше/дополнительной информацией? Хотел бы я знать об этом раньше... - person kayleeFrye_onDeck   schedule 04.05.2017converted_base_address
и добавление серии смещений не дает адреса значенияSizeOfStackCommit
. Добавление толькоsize_stack_commit_offset
кconverted_base_address
тоже не помогает, поэтому у меня проблема с математикой указателей. Я выгрузил переменные конца выполнения в виде списка: -нос-знает/b08a188665c3fd3d78d04a0ec6ce89c0. Я добавил еще одну строку для тестирования,DWORD64 * addy = &direct_access_size_stack;
- person kayleeFrye_onDeck   schedule 04.05.2017auto
, чтобы захватить все частиp_loaded_image
, а также выгрузил их в суть. Это должно помочь пролить свет на возможные проблемы с перекрестными ссылками/смещением: /знает-нос/11dcdc481a8196a931c710b7ad160f9c - person kayleeFrye_onDeck   schedule 04.05.2017FileHeader
находится в начале сопоставленного раздела (0x000001560cd90000), но это не так. Туда помещается заглушка DOS, а в этом заголовке находится относительное расположение (0x000001560cd90100)FileHeader
. - person Ben Voigt   schedule 04.05.2017addy
ничего не значит, это адрес локальной переменной, содержащей копию ваших данных. Вы хотели&p_loaded_image->FileHeader->OptionalHeader.SizeOfStackCommit
- person Ben Voigt   schedule 04.05.2017windows_optional_header_offset
неверен. Это не должно быть БОЛЬШЕ для 32-разрядных, чем для 64-разрядных, и я думаю, что на самом деле это константа, которая не зависит от архитектуры. Глядя на определение структуры, я думаю, что у вас есть переменные 4x2 байта и переменные 3x4 байта, всегоwindows_optional_header_offset=20
. - person Ben Voigt   schedule 04.05.2017IMAGE_OPTIONAL_HEADER
до поляImageBase
. Это не имеет ничего общего с поиском начала необязательного заголовка. - person Ben Voigt   schedule 04.05.20173.4 Optional Header (Image Only)
- есть ли какой-то способ, не упомянутый на этом снимке экрана, о том, как его получить? i.imgur.com/xzzvnq3.png - person kayleeFrye_onDeck   schedule 04.05.2017winnt.h
тоже не помешал! - person kayleeFrye_onDeck   schedule 23.05.2017