Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 03.11.2013, 04:00   #1
Alexey_68
Пользователь
 
Регистрация: 01.03.2013
Сообщений: 39
По умолчанию Запуск PE

Привет All.
Тема довольно "избитая", но всё же...
Имеется массив байт (исполняемый файл) который храниться в программе.
После резервирования и выделения памяти я копирую его по адресу который мне выделяет система (в моём случае 0х00390000), мне необходимо запустить его.
Во многих статьях описывается -
парсим заголовок, считываем информацию о секциях и т.п.
С форматом pe знаком, не пойму только куда мы "парсим" и.т.п., а вообще если кто может, то объясните момент более доходчиво, буду рад ссылкам и примерам.
Алексей.
Alexey_68 вне форума Ответить с цитированием
Старый 04.11.2013, 00:49   #2
Son Of Pain
Участник клуба
 
Регистрация: 23.12.2010
Сообщений: 1,129
По умолчанию

Сначала нужно взять из заголовка таблицу секций. У каждой секции есть relative virtual address, если прибавить к нему image base - получаем адрес в памяти, в который эту секцию нужно запихнуть. Если запихнуть не получается (нужная область памяти занята твоим кодом, например) - выделяешь память по другому адресу, считаешь разницу между "желаемым" и "полученным" адресами и правишь relocations для этой секции соответственно. Если из кода при линковке релокейшны выпилили - случится облом. Тогда придется переносить твой код куда-то в другое место, чтобы освободить нужные адреса.

После этого нужно проставить получившемуся образу импорты. Пройтись по таблице, подгрузить нужные дллки, взять из них адреса функций и вписать в iat.

Для большинства стандартных случаев этого будет достаточно. Если что-то непонятно - спрашивай, попробую развернуть подробнее )
Son Of Pain вне форума Ответить с цитированием
Старый 04.11.2013, 04:55   #3
Alexey_68
Пользователь
 
Регистрация: 01.03.2013
Сообщений: 39
По умолчанию

Спасибо большое за помощь, как раз это я и не мог понять, а именно - куда именно размещать, т.е. получается мы размещаем PE согласно всех его настроек которые описаны в pe заголовке и optional header'e так?
Если я правильно понимаю, то сначала прочитали "значение" и записали (скопировали memcpy) в то место памяти в котором он должен находится согласно его настроек.
А как происходит сам запуск когда файл полностью скопирован в память?
Пробовал вот этот код, на консольном приложении работает (причём в той же консоли которую запускаю), но в нём нет настройки таблицы импорта:
Код:
void RunFromMemory(char* pImage,char* pPath)
{
    DWORD dwWritten = 0;
    DWORD dwHeader = 0; 
    DWORD dwImageSize = 0;
    DWORD dwSectionCount = 0;
    DWORD dwSectionSize = 0;
    DWORD firstSection = 0;
    DWORD previousProtection = 0;
    DWORD jmpSize = 0;

    IMAGE_NT_HEADERS INH;
    IMAGE_DOS_HEADER IDH;
    IMAGE_SECTION_HEADER Sections[1000];

    PROCESS_INFORMATION peProcessInformation;
    STARTUPINFO peStartUpInformation;
    CONTEXT pContext;

    char* pMemory;
    char* pFile;
    memcpy(&IDH,pImage,sizeof(IDH));
    memcpy(&INH,(void*)((DWORD)pImage+IDH.e_lfanew),sizeof(INH));

    dwImageSize = INH.OptionalHeader.SizeOfImage;
    pMemory = (char*)malloc(dwImageSize);
    memset(pMemory,0,dwImageSize);
    pFile = pMemory;

    dwHeader = INH.OptionalHeader.SizeOfHeaders;
    firstSection = (DWORD)(((DWORD)pImage+IDH.e_lfanew) + sizeof(IMAGE_NT_HEADERS));
    memcpy(Sections,(char*)(firstSection),sizeof(IMAGE_SECTION_HEADER)*INH.FileHeader.NumberOfSections);

    memcpy(pFile,pImage,dwHeader);

    if((INH.OptionalHeader.SizeOfHeaders % INH.OptionalHeader.SectionAlignment)==0)
    {
        jmpSize = INH.OptionalHeader.SizeOfHeaders;
    }
    else
    {
        jmpSize = INH.OptionalHeader.SizeOfHeaders / INH.OptionalHeader.SectionAlignment;
        jmpSize += 1;
        jmpSize *= INH.OptionalHeader.SectionAlignment;
    }

    pFile = (char*)((DWORD)pFile + jmpSize);

    for(dwSectionCount = 0; dwSectionCount < INH.FileHeader.NumberOfSections; dwSectionCount++)
    {
        jmpSize = 0;
        dwSectionSize = Sections[dwSectionCount].SizeOfRawData;
        memcpy(pFile,(char*)(pImage + Sections[dwSectionCount].PointerToRawData),dwSectionSize);

        if((Sections[dwSectionCount].Misc.VirtualSize % INH.OptionalHeader.SectionAlignment)==0)
        {
            jmpSize = Sections[dwSectionCount].Misc.VirtualSize;
        }
        else
        {
            jmpSize = Sections[dwSectionCount].Misc.VirtualSize / INH.OptionalHeader.SectionAlignment;
            jmpSize += 1;
            jmpSize *= INH.OptionalHeader.SectionAlignment;
        }
        pFile = (char*)((DWORD)pFile + jmpSize);
    }


    memset(&peStartUpInformation,0,sizeof(STARTUPINFO));
    memset(&peProcessInformation,0,sizeof(PROCESS_INFORMATION));
    memset(&pContext,0,sizeof(CONTEXT));

    peStartUpInformation.cb = sizeof(peStartUpInformation);
    if(CreateProcess(NULL,pPath,&secAttrib,NULL, -1,CREATE_SUSPENDED,NULL,NULL,&peStartUpInformation,&peProcessInformation))
    {
        pContext.ContextFlags = CONTEXT_FULL;
        GetThreadContext(peProcessInformation.hThread,&pContext);
        VirtualProtectEx(peProcessInformation.hProcess,(void*)((DWORD)INH.OptionalHeader.ImageBase),dwImageSize,PAGE_EXECUTE_READWRITE,&previousProtection);
        WriteProcessMemory(peProcessInformation.hProcess,(void*)((DWORD)INH.OptionalHeader.ImageBase),pMemory,dwImageSize,&dwWritten);
        WriteProcessMemory(peProcessInformation.hProcess,(void*)((DWORD)pContext.Ebx + 8),&INH.OptionalHeader.ImageBase,4,&dwWritten);
        pContext.Eax = INH.OptionalHeader.ImageBase + INH.OptionalHeader.AddressOfEntryPoint;
        SetThreadContext(peProcessInformation.hThread,&pContext);
        VirtualProtectEx(peProcessInformation.hProcess,(void*)((DWORD)INH.OptionalHeader.ImageBase),dwImageSize,previousProtection,0);
        ResumeThread(peProcessInformation.hThread);
    }
    free(pMemory);
}
и его запуск:
Код:
if (((hRes = FindResource(hMod, "resname", RT_RCDATA)) != NULL)
	&& ((hGlob = LoadResource(hMod, hRes)) != NULL)
	&& ((lpbArray = LockResource(hGlob)) != NULL))
{
	dwSize = SizeofResource(hMod, hRes);
	lpMemory = (char*)malloc (dwSize);
	memset(lpMemory,0,dwSize);
	memcpy (lpMemory, lpbArray, dwSize);
	system("pause");
	RunFromMemory(lpMemory,"test.exe");
}
что можно использовать из этого кода (если можно)?
Alexey_68 вне форума Ответить с цитированием
Старый 04.11.2013, 21:24   #4
Son Of Pain
Участник клуба
 
Регистрация: 23.12.2010
Сообщений: 1,129
По умолчанию

Во-первых здесь
Код:
memcpy(pFile,(char*)(pImage + Sections[dwSectionCount].PointerToRawData),dwSectionSize);
ты при копировании секций игнорируешь их virtual address.

Дальше надо бы проследить, чтобы в адресном пространстве процесса была зарезервирована память для всех секций (VirtualAlloc), и проставить каждой секции соответствующие права доступа (read/write/execute/что там еще).

Ну и импорты отрезолвить, да.

А для запуска достаточно в контексте в регистр eip записать адрес entrypoint, если грузишь все это в другой процесс. Ну или просто jmp сделать, если в свой же.
Son Of Pain вне форума Ответить с цитированием
Старый 04.11.2013, 21:34   #5
Alexey_68
Пользователь
 
Регистрация: 01.03.2013
Сообщений: 39
По умолчанию

Son Of Pain благодарю за помощь и сразу вопрос:
>>ты при копировании секций игнорируешь их virtual address.
а как надо?
>>чтобы в адресном пространстве процесса была зарезервирована память для всех секций
пока не знаю как это осуществить...
вот исходник рабочий, но при запуске не отображаются надписи на кнопках, в чём там может быть проблема?
http://rghost.ru/49934369

Последний раз редактировалось Alexey_68; 04.11.2013 в 21:37.
Alexey_68 вне форума Ответить с цитированием
Старый 04.11.2013, 22:13   #6
Son Of Pain
Участник клуба
 
Регистрация: 23.12.2010
Сообщений: 1,129
По умолчанию

Цитата:
Сообщение от Alexey_68 Посмотреть сообщение
сразу вопрос:
>>ты при копировании секций игнорируешь их virtual address.
а как надо?
У каждой секции в таблице есть поле virtual address. Прибавляем к нему image base и получаем адрес, по которому она должна лежать. т. е. между секциями в памяти могут быть дырки, а ты кладешь все секции рядом в памяти. Просто в первом параметре memcpy напиши image base + section.virtual address )

Цитата:
>>чтобы в адресном пространстве процесса была зарезервирована память для всех секций
пока не знаю как это осуществить...
Просто в цикле VirtualAllocEx и VirtualProtectEx для каждой секции с соответствующими параметрами.
Son Of Pain вне форума Ответить с цитированием
Старый 04.11.2013, 22:29   #7
Alexey_68
Пользователь
 
Регистрация: 01.03.2013
Сообщений: 39
По умолчанию

for(dwSectionCount = 0; dwSectionCount < INH.FileHeader.NumberOfSections; dwSectionCount++)
{
jmpSize = 0;
dwSectionSize = Sections[dwSectionCount].SizeOfRawData;
memcpy(pFile,(char*)(pImage + Sections[dwSectionCount].VirtualAddress),dwSectionSize);
VirtualAlloc((char*)INH.OptionalHea der.ImageBase+Sections[dwSectionCount].VirtualAddress, dwSectionSize, MEM_COMMIT, PAGE_READWRITE);
так?
>>Просто в цикле VirtualAllocEx и VirtualProtectEx для каждой секции с соответствующими параметрами.
память выделять MEM_COMMIT?

Последний раз редактировалось Alexey_68; 04.11.2013 в 23:00.
Alexey_68 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
запуск программы SAMOUCHKA Общие вопросы по Java, Java SE, Kotlin 29 23.01.2013 16:05
Запуск процесса Express Yourself Общие вопросы .NET 2 05.12.2012 20:33
запуск windows kasya Свободное общение 12 02.06.2011 08:48
ЗАпуск Волк Общие вопросы Delphi 1 15.05.2011 13:53
запуск kalin Общие вопросы Delphi 8 02.03.2007 05:27