Страницы

Поиск по вопросам

понедельник, 9 марта 2020 г.

Узнать относительный адрес внутри проекции PE-файла

#cpp #winapi #pe


Есть один известный крэкми. После его изучения оказывается, что для его взлома достаточно
пропатчить два байта по адресу 40138B (забить условный переход NOP'ами) и два байта
по адресу 401243 (прописать там безусловный переход). Я хочу написать программу, которая
делает это автоматически.

#include 
#include 
#include 
#include 

enum {OK, CANT_OPEN};

int patch (TCHAR* fname)
{
    char first_patch[2]  = {0x90, 0x90};    // NOP NOP
    char second_patch[2] = {0xEB, 0x07};    // JMP 40124C
    HANDLE hFile = CreateFile(fname,
                              FILE_ALL_ACCESS, NULL,
                              NULL, OPEN_EXISTING,
                              FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        return CANT_OPEN;

    int SizeFile  = GetFileSize(hFile, NULL);
    HANDLE MhFile = CreateFileMapping(hFile, 0, PAGE_READWRITE, 0, SizeFile, 0);
    HANDLE View   = MapViewOfFile(MhFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);

    UnmapViewOfFile(View);
    CloseHandle(hFile);
    CloseHandle(MhFile);
    return OK;
}

int main (int argc, char *argv[])
{
    TCHAR* default_fname = "CRACKME.EXE";

    if (argc > 1)
    {
        default_fname = argv[1];
    }

    patch(default_fname);

    std::cout << default_fname << std::endl;
    return 0;
}


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

Как в этой проекции найти адреса типа 40138B и 401243? Где можно посмотреть теорию
и примеры по редактированию PE-файлов?

Далее пишу хрень, можно не читать.
Успешно напечатал сигнатуру MZ, это значит, что при помощи View можно заполнять структуры
заголовков, используя, возможно, для выравнивания макросы Криса Касперски.

char M = *((char *) View);
char Z = *((char *) View + 1);
std::cout << M << Z << std::endl;


Проверка того, что заголовок дос успешно загружен. Потом добавлю код для отлавливания
возможных ошибок.

unsigned myRVAtoRAW(HANDLE pe_image, unsigned rva)
{
    IMAGE_DOS_HEADER dos_header;
    std::memcpy(reinterpret_cast(&dos_header), pe_image, sizeof(dos_header));

    std::cout << (dos_header.e_magic == 'ZM') << std::endl;
    return 0;
}

    


Ответы

Ответ 1



Можно пойти двумя путями: Разобраться и написать самому. Тогда рекомендую почитать статью: Разработка функций RvaToRaw и RawToRva. Либо воспользоваться функций из известной dbghelp.dll. Я бы посоветовал разобраться, благо это не сложно. Также следует отметить знаменитую статью Об упаковщиках в последний раз: Часть первая - теоретическая

Ответ 2



Что касаемо патчинга: int main() { HWND hWnd = FindWindow(0, "Calculator"); if(hWnd == 0){ MessageBox(0, "Error cannot find window.", "Error", MB_OK|MB_ICONERROR); } else { DWORD proccess_ID; GetWindowThreadProcessId(hWnd, &proccess_ID); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, proccess_ID); if(!hProcess){ MessageBox(0, "Could not open the process!", "Error!", MB_OK|MB_ICONERROR); } else { DWORD newdatasize = sizeof(newdata); if(WriteProcessMemory(hProcess, (LPVOID)0x40138B , "0x90", newdatasize, NULL)){ MessageBox(NULL, "WriteProcessMemory worked.", "Success", MB_OK + MB_ICONINFORMATION); } else { MessageBox(NULL, "Error cannot WriteProcessMemory!", "Error", MB_OK + MB_ICONERROR); } CloseHandle(hProcess); } } return 0; } Адреса искать по паттерну(уникальной сигнатуре), сделать ее можно в любом отладчике

Комментариев нет:

Отправить комментарий