Nawiązując do artykułu Jak napisać prosty patch? i komentarzy @ img (hi mate), prezentuję bardziej rozbudowaną wersję patchera z całą gamą sprawdzania potencjalnych błędów. Jeśli zauważycie więcej potencjalnych kłopotów – piszcie w komentarzach (sam jestem ciekaw, co jeszcze może pójść nie tak w jak się wydaje prostej operacji).
#define UNICODE #include <windows.h> #include <Sfc.h> // zalacz biblioteke SFC.lib (mechanizm ochrony plikow systemowych WFP / WRP) #pragma comment(lib, "sfc") int main() { // pelna sciezka pliku do spatchowania const wchar_t * wszFilePath = L"C:\\plik.exe"; // bajty, ktore zostana zapisane do pliku const BYTE cPatch[] = { 0xAA, 0xBB, 0xCC }; // offset, pod ktorym zostana zapisane powyzsze bajty const DWORD dwPatchRawOffset = 0x1234; // rozmiar pliku DWORD dwFileSize = 0; // ilosc zapisanych bajtow w pliku (parametr dla funkcji WriteFile) DWORD dwWritten = 0; // kod bledu z funkcji zapisu do pliku WriteFile BOOL bWriteFileResult = FALSE; // sprawdz czy plik ma atrybuty read only lub znajduje sie na nosniku jak np. DVD DWORD dwFileAttributes = GetFileAttributes(wszFilePath); // czy udalo sie odczytac atrybuty? if (dwFileAttributes == INVALID_FILE_ATTRIBUTES) { MessageBox(NULL, L"Nie mozna odczytac atrybutow pliku (plik nie istnieje?)!", L"Blad", MB_ICONERROR); return 1; } // czy plik ma atrybuty tylko do odczytu? if ( (dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0) { MessageBox(NULL, L"Wybrany plik nie ma praw do zapisu (lub znajduje sie na takim nosniku jak np. DVD)!", L"Blad", MB_ICONERROR); return 2; } // czy plik jest chronionym plikiem systemowym? if (SfcIsFileProtected(NULL, wszFilePath) == TRUE) { MessageBox(NULL, L"Wybrany plik jest chronionym plikiem systemowym i automatycznie zostanie odtworzony po zmianie przez system Windows!", L"Blad", MB_ICONERROR); return 3; } // otworz plik wejsciowy w trybie do zapisu (flaga GENERIC_WRITE) HANDLE hFile = CreateFile(wszFilePath, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // jesli nie udalo sie otworzyc pliku - wyswietl komunikat i zakoncz if (hFile == INVALID_HANDLE_VALUE) { MessageBox(NULL, L"Nie udalo sie otworzyc pliku wejsciowego!", L"Blad", MB_ICONERROR); return 4; } // pobierz rozmiar pliku dwFileSize = GetFileSize(hFile, NULL); // czy plik jest pusty? if (dwFileSize == 0) { CloseHandle(hFile); MessageBox(NULL, L"Plik jest pusty (0 bajtow)!", L"Blad", MB_ICONERROR); return 5; } // czy wskaznik pliku, gdzie ma byc spatchowany przekracza rozmiar pliku? if ( (dwPatchRawOffset + sizeof(cPatch)) > dwFileSize) { CloseHandle(hFile); MessageBox(NULL, L"Wskaznik do spatchowania znajduje sie poza rozmiarem pliku!", L"Blad", MB_ICONERROR); return 6; } // ustaw wskaznik pliku na offsecie (raw offset), // gdzie zostana zapisane zmodyfikowane bajty if (SetFilePointer(hFile, dwPatchRawOffset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { CloseHandle(hFile); MessageBox(NULL, L"Nie udalo sie ustawic wskaznika do spatchowania w wybranym pliku!", L"Blad", MB_ICONERROR); return 7; } // pod wskazanym adresem zapisz bajty z tablicy cPatch bWriteFileResult = WriteFile(hFile, cPatch, sizeof(cPatch), &dwWritten, NULL); // czy udalo sie zapisac do pliku? if (bWriteFileResult == FALSE) { CloseHandle(hFile); MessageBox(NULL, L"Wystapil blad zapisu do pliku!", L"Blad", MB_ICONERROR); return 8; } // czy zapisane zostaly wszystkie bajty patcha? if (dwWritten != sizeof(cPatch)) { CloseHandle(hFile); MessageBox(NULL, L"Nie udalo sie zapisac wszystkich bajtow!", L"Blad", MB_ICONERROR); return 9; } // zapisz wyniki na dysk if (FlushFileBuffers(hFile) == FALSE) { CloseHandle(hFile); MessageBox(NULL, L"Nie udalo sie zapisac zmian na dysk!", L"Blad", MB_ICONERROR); return 10; } // zamknij plik CloseHandle(hFile); MessageBox(NULL, L"Plik zostal pomyslnie zmodyfikowany", L"Informacja", MB_ICONINFORMATION); return 0; }
Źródła w języku angielskim zostały także opublikowane na https://github.com/PELock/Patch-File-Example