//------------------------------------------------ //--- 010 Editor v4.0.2 Script File // // File: Patchmaker.1sc // Authors: Didier Stevens // Version: 0.1 // Purpose: Generate a 010 script to patch a file based // on differences. The files must be the same size. // Category: Compare // History: // 0.1 2016-02-10 SweetScape Software: Updated header for repository submission. // 0.0.3 2013-04-11 D Stevens: add SHA-256 checking // 0.0.2 2013-03-29 D Stevens: refactoring & cleanup // 0.0.1 2013-03-28 D Stevens: start development with 010 Editor v4.0.2 // // Source code put in public domain by Didier Stevens, no Copyright // https://DidierStevens.com // Use at your own risk //------------------------------------------------ #define TITLE "patchmaker" #define BUFFER 0x10000 void PatchMaker(int iSelectedFile) { int iFileOutput; int64 iIter1; int64 iIter2; int64 iLastPosition; int iSize; uchar aucByte0[BUFFER]; uchar aucByte1[BUFFER]; string sSHA256Original; string sSHA256Patched; FileSelect(iSelectedFile); if (ChecksumAlgStr(CHECKSUM_SHA256, sSHA256Patched) < 0) { MessageBox(idOk, TITLE, "Error calculating SHA-256 of patched file."); return; } FileSelect(1 - iSelectedFile); if (ChecksumAlgStr(CHECKSUM_SHA256, sSHA256Original) < 0) { MessageBox(idOk, TITLE, "Error calculating SHA-256 of original file."); return; } iLastPosition = -1; iFileOutput = FileNew(); FileSelect(1 - iSelectedFile); FPrintf(iFileOutput, "// Generated by patchmaker.1sc on %s\n", GetCurrentDateTime("yyyy/MM/dd hh:mm:ss")); FPrintf(iFileOutput, "// Original file %s\n", GetFileName()); FileSelect(iSelectedFile); FPrintf(iFileOutput, "// Patched file %s\n", GetFileName()); FPrintf(iFileOutput, "// SHA-256 original file: %s\n", sSHA256Original); FPrintf(iFileOutput, "// SHA-256 patched file: %s\n", sSHA256Patched); FPrintf(iFileOutput, "// -----------------------------\n"); FPrintf(iFileOutput, "string sSHA256;\n"); FPrintf(iFileOutput, "if (ChecksumAlgStr(CHECKSUM_SHA256, sSHA256) < 0)\n"); FPrintf(iFileOutput, "{\n"); FPrintf(iFileOutput, " MessageBox(idOk, \"Patchmaker\", \"Error calculating SHA-256. Click OK to exit.\");\n"); FPrintf(iFileOutput, " Exit(0);\n"); FPrintf(iFileOutput, "}\n"); FPrintf(iFileOutput, "if (sSHA256 != \"%s\")\n", sSHA256Original); FPrintf(iFileOutput, " if (MessageBox(idYes | idNo, \"Patchmaker\", \"This file is different from the original. Do you want to proceed?\") == idNo)\n"); FPrintf(iFileOutput, " Exit(0);\n"); FPrintf(iFileOutput, "\n"); for (iIter1 = 0; iIter1 < FileSize(); iIter1 += BUFFER) { if (iIter1 + BUFFER > FileSize()) iSize = FileSize() - iIter1; else iSize = BUFFER; FileSelect(iSelectedFile); ReadBytes(aucByte0, iIter1, iSize); FileSelect(1 - iSelectedFile); ReadBytes(aucByte1, iIter1, iSize); if (Memcmp(aucByte0, aucByte1, iSize)) for (iIter2 = 0; iIter2 < iSize; iIter2++) if (aucByte0[iIter2] != aucByte1[iIter2]) { if (iLastPosition != -1 && iLastPosition < iIter1 + iIter2 - 1) FPrintf(iFileOutput, "\n"); FPrintf(iFileOutput, "WriteUByte(0x%08x, 0x%02x);\n", iIter1 + iIter2, aucByte0[iIter2]); iLastPosition = iIter1 + iIter2; } } FPrintf(iFileOutput, "// -----------------------------\n"); FileSelect(iFileOutput); } void Main(void) { int iSelectedFile; int iFileSize; if (2 != FileCount()) { MessageBox(idOk, TITLE, "Exactly 2 files must be open."); return; } iSelectedFile = GetFileNum(); iFileSize = FileSize(); FileSelect(1 - iSelectedFile); if (iFileSize != FileSize()) { MessageBox(idOk, TITLE, "The 2 files must have the same size."); return; } PatchMaker(iSelectedFile); } Main();