8 /** DEFINES *******************************************************************/
10 #define PATCH_BUFFER_SIZE 4096 /* Maximum size of a patch */
11 #define PATCH_BUFFER_MAGIC "\xde\xad\xbe\xef MaGiC MaRk "
12 #define SIZEOF_PATCH_BUFFER_MAGIC (sizeof (PATCH_BUFFER_MAGIC) - 1)
14 /** TYPES *********************************************************************/
16 typedef struct _PatchedByte
18 int offset
; /*!< File offset of the patched byte. */
19 unsigned char expected
; /*!< Expected (original) value of the byte. */
20 unsigned char patched
; /*!< Patched (new) value for the byte. */
23 typedef struct _PatchedFile
25 const char *name
; /*!< Name of the file to be patched. */
26 int fileSize
; /*!< Size of the file in bytes. */
27 int patchCount
; /*!< Number of patches for the file. */
28 PatchedByte
*patches
; /*!< Patches for the file. */
33 const char *name
; /*!< Name of the patch. */
34 int fileCount
; /*!< Number of files in the patch. */
35 PatchedFile
*files
; /*!< Files for the patch. */
38 /** FUNCTION PROTOTYPES *******************************************************/
40 static void printUsage();
42 /** GLOBALS *******************************************************************/
44 static Patch m_patch
= { NULL
, 0, NULL
};
45 static int m_argc
= 0;
46 static char **m_argv
= NULL
;
48 /* patch buffer where we put the patch info into */
49 static unsigned char m_patchBuffer
[SIZEOF_PATCH_BUFFER_MAGIC
+ PATCH_BUFFER_SIZE
] =
52 /** HELPER FUNCTIONS **********************************************************/
55 loadFile(const char *fileName
, int *fileSize_
)
63 f
= fopen(fileName
, "rb");
66 printf("Couldn't open file %s for reading!\n", fileName
);
71 if (fstat(fileno(f
), &sb
) < 0)
74 printf("Couldn't get size of file %s!\n", fileName
);
77 fileSize
= sb
.st_size
;
84 printf("Couldn't allocate %d bytes for file %s!\n", fileSize
, fileName
);
88 if (fread(p
, fileSize
, 1, f
) != 1)
92 printf("Couldn't read file %s into memory!\n", fileName
);
99 *fileSize_
= fileSize
;
105 saveFile(const char *fileName
, void *file
, int fileSize
)
110 f
= fopen(fileName
, "wb");
113 printf("Couldn't open file %s for writing!\n", fileName
);
118 if (fwrite(file
, fileSize
, 1, f
) != 1)
121 printf("Couldn't write file %s!\n", fileName
);
133 PatchedFile
*patchedFile
,
134 const char *originalFileName
)
136 const char *patchedFileName
= patchedFile
->name
;
137 unsigned char *origChunk
, *patchedChunk
;
138 int origSize
, patchedSize
, i
, patchCount
;
139 PatchedByte
*patches
= NULL
;
140 int patchesArrayCount
= 0;
142 /* Load both files */
143 origChunk
= loadFile(originalFileName
, &origSize
);
144 if (origChunk
== NULL
)
146 patchedChunk
= loadFile(patchedFileName
, &patchedSize
);
147 if (patchedChunk
== NULL
)
152 if (origSize
!= patchedSize
)
156 printf("File size of %s and %s differs (%d != %d)\n",
157 originalFileName
, patchedFileName
,
158 origSize
, patchedSize
);
162 /* Compare the files and record any differences */
163 printf("Comparing %s to %s", originalFileName
, patchedFileName
);
164 for (i
= 0, patchCount
= 0; i
< origSize
; i
++)
166 if (origChunk
[i
] != patchedChunk
[i
])
170 /* Resize patches array if needed */
171 if (patchesArrayCount
< patchCount
)
173 PatchedByte
*newPatches
;
174 newPatches
= realloc(patches
, patchCount
* sizeof (PatchedByte
));
175 if (newPatches
== NULL
)
181 printf("\nOut of memory (tried to allocated %d bytes)\n",
182 patchCount
* sizeof (PatchedByte
));
185 patches
= newPatches
;
188 /* Fill in patch info */
189 patches
[patchCount
- 1].offset
= i
;
190 patches
[patchCount
- 1].expected
= origChunk
[i
];
191 patches
[patchCount
- 1].patched
= patchedChunk
[i
];
193 if ((i
% (origSize
/ 40)) == 0)
196 printf(" %d changed bytes found.\n", patchCount
);
198 /* Unload the files */
202 /* Save patch info */
203 patchedFile
->fileSize
= patchedSize
;
204 patchedFile
->patchCount
= patchCount
;
205 patchedFile
->patches
= patches
;
212 outputPatch(const char *outputFileName
)
214 unsigned char *patchExe
, *patchBuffer
;
215 int i
, size
, patchExeSize
, patchSize
, stringSize
, stringOffset
, patchOffset
;
219 printf("Putting patch into %s...\n", outputFileName
);
221 /* Calculate size of the patch */
222 patchSize
= sizeof (Patch
) + sizeof (PatchedFile
) * m_patch
.fileCount
;
223 stringSize
= strlen(m_patch
.name
) + 1;
224 for (i
= 0; i
< m_patch
.fileCount
; i
++)
226 stringSize
+= strlen(m_patch
.files
[i
].name
) + 1;
227 patchSize
+= sizeof (PatchedByte
) * m_patch
.files
[i
].patchCount
;
229 if ((stringSize
+ patchSize
) > PATCH_BUFFER_SIZE
)
231 printf("Patch is too big - %d bytes maximum, %d bytes needed\n",
232 PATCH_BUFFER_SIZE
, stringSize
+ patchSize
);
236 /* Load patch.exe file into memory... */
237 patchExe
= loadFile(m_argv
[0], &patchExeSize
);
238 if (patchExe
== NULL
)
243 /* Try to find the magic mark for the patch buffer */
244 for (i
= 0; i
< (patchExeSize
- SIZEOF_PATCH_BUFFER_MAGIC
); i
++)
246 if (memcmp(patchExe
+ i
, m_patchBuffer
, SIZEOF_PATCH_BUFFER_MAGIC
) == 0)
248 patchBuffer
= patchExe
+ i
+ SIZEOF_PATCH_BUFFER_MAGIC
;
253 if (!(i
< (patchExeSize
- SIZEOF_PATCH_BUFFER_MAGIC
)))
256 printf("Couldn't find patch buffer magic in file %s - this shouldn't happen!!!\n", m_argv
[0]);
260 /* Pack patch together and replace string pointers by offsets */
261 patch
= (Patch
*)patchBuffer
;
262 files
= (PatchedFile
*)(patchBuffer
+ sizeof (Patch
));
263 patchOffset
= sizeof (Patch
) + sizeof (PatchedFile
) * m_patch
.fileCount
;
264 stringOffset
= patchSize
;
266 patch
->fileCount
= m_patch
.fileCount
;
267 patch
->files
= (PatchedFile
*)sizeof (Patch
);
269 patch
->name
= (const char *)stringOffset
;
270 strcpy(patchBuffer
+ stringOffset
, m_patch
.name
);
271 stringOffset
+= strlen(m_patch
.name
) + 1;
273 for (i
= 0; i
< m_patch
.fileCount
; i
++)
275 files
[i
].fileSize
= m_patch
.files
[i
].fileSize
;
276 files
[i
].patchCount
= m_patch
.files
[i
].patchCount
;
278 files
[i
].name
= (const char *)stringOffset
;
279 strcpy(patchBuffer
+ stringOffset
, m_patch
.files
[i
].name
);
280 stringOffset
+= strlen(m_patch
.files
[i
].name
) + 1;
282 size
= files
[i
].patchCount
* sizeof (PatchedByte
);
283 files
[i
].patches
= (PatchedByte
*)patchOffset
;
284 memcpy(patchBuffer
+ patchOffset
, m_patch
.files
[i
].patches
, size
);
287 size
= patchSize
+ stringSize
;
288 memset(patchBuffer
+ size
, 0, PATCH_BUFFER_SIZE
- size
);
291 if (saveFile(outputFileName
, patchExe
, patchExeSize
) < 0)
298 printf("Patch saved!\n");
310 p
= m_patchBuffer
+ SIZEOF_PATCH_BUFFER_MAGIC
;
313 if (patch
->name
== NULL
)
318 m_patch
.name
= p
+ (int)patch
->name
;
319 m_patch
.fileCount
= patch
->fileCount
;
320 m_patch
.files
= (PatchedFile
*)(p
+ (int)patch
->files
);
322 for (i
= 0; i
< m_patch
.fileCount
; i
++)
324 m_patch
.files
[i
].name
= p
+ (int)m_patch
.files
[i
].name
;
325 m_patch
.files
[i
].patches
= (PatchedByte
*)(p
+ (int)m_patch
.files
[i
].patches
);
328 printf("Patch %s loaded...\n", m_patch
.name
);
333 /** MAIN FUNCTIONS ************************************************************/
339 const char *outputFileName
;
341 /* Check argument count */
342 if (m_argc
< 6 || (m_argc
% 2) != 0)
348 outputFileName
= m_argv
[3];
349 m_patch
.name
= m_argv
[2];
351 /* Allocate PatchedFiles array */
352 m_patch
.fileCount
= (m_argc
- 4) / 2;
353 m_patch
.files
= malloc(m_patch
.fileCount
* sizeof (PatchedFile
));
354 if (m_patch
.files
== NULL
)
356 printf("Out of memory!\n");
359 memset(m_patch
.files
, 0, m_patch
.fileCount
* sizeof (PatchedFile
));
361 /* Compare original to patched files and fill m_patch.files array */
362 for (i
= 0; i
< m_patch
.fileCount
; i
++)
364 m_patch
.files
[i
].name
= m_argv
[4 + (i
* 2) + 1];
365 status
= compareFiles(m_patch
.files
+ i
, m_argv
[4 + (i
* 2) + 0]);
368 for (i
= 0; i
< m_patch
.fileCount
; i
++)
370 if (m_patch
.files
[i
].patches
!= NULL
)
371 free(m_patch
.files
[i
].patches
);
374 m_patch
.files
= NULL
;
375 m_patch
.fileCount
= 0;
381 return outputPatch(outputFileName
);
388 int c
, i
, j
, fileSize
, makeBackup
;
391 const char *fileName
;
392 char buffer
[MAX_PATH
];
395 if (m_argc
> 1 && strcmp(m_argv
[1], "-d") != 0)
404 printf("This executable doesn't contain a patch, use -c to create one.\n");
411 printf("Patch name: %s\n", m_patch
.name
);
412 printf("File count: %d\n", m_patch
.fileCount
);
413 for (i
= 0; i
< m_patch
.fileCount
; i
++)
415 printf("----------------------\n"
417 "File size: %d bytes\n",
418 m_patch
.files
[i
].name
, m_patch
.files
[i
].fileSize
);
419 printf("Patch count: %d\n", m_patch
.files
[i
].patchCount
);
420 for (j
= 0; j
< m_patch
.files
[i
].patchCount
; j
++)
422 printf(" Offset 0x%x 0x%02x -> 0x%02x\n",
423 m_patch
.files
[i
].patches
[j
].offset
,
424 m_patch
.files
[i
].patches
[j
].expected
,
425 m_patch
.files
[i
].patches
[j
].patched
);
432 printf("Applying patch...\n");
433 for (i
= 0; i
< m_patch
.fileCount
; i
++)
435 /* Load original file */
436 fileName
= m_patch
.files
[i
].name
;
437 applyPatch_retry_file
:
438 file
= loadFile(fileName
, &fileSize
);
441 printf("File %s not found! ", fileName
);
442 applyPatch_file_open_error
:
443 printf("(S)kip, (R)etry, (A)bort, (M)anually enter filename");
448 while (c
!= 's' && c
!= 'r' && c
!= 'a' && c
!= 'm');
456 goto applyPatch_retry_file
;
464 if (fgets(buffer
, sizeof (buffer
), stdin
) == NULL
)
466 printf("fgets() failed!\n");
469 p
= strchr(buffer
, '\r');
472 p
= strchr(buffer
, '\n');
477 goto applyPatch_retry_file
;
481 /* Check file size */
482 if (fileSize
!= m_patch
.files
[i
].fileSize
)
485 printf("File %s has unexpected filesize of %d bytes (%d bytes expected)\n",
486 fileName
, fileSize
, m_patch
.files
[i
].fileSize
);
487 if (fileName
!= m_patch
.files
[i
].name
) /* manually entered filename */
489 goto applyPatch_file_open_error
;
495 printf("Do you want to make a backup of %s? (Y)es, (N)o, (A)bort", fileName
);
500 while (c
!= 'y' && c
!= 'n' && c
!= 'a');
504 char buffer
[MAX_PATH
];
505 snprintf(buffer
, MAX_PATH
, "%s.bak", fileName
);
506 buffer
[MAX_PATH
-1] = '\0';
508 if (access(buffer
, 0) >= 0) /* file exists */
510 printf("File %s already exists, overwrite? (Y)es, (N)o, (A)bort", buffer
);
515 while (c
!= 'y' && c
!= 'n' && c
!= 'a');
525 if (makeBackup
&& saveFile(buffer
, file
, fileSize
) < 0)
538 for (j
= 0; j
< m_patch
.files
[i
].patchCount
; j
++)
540 int offset
= m_patch
.files
[i
].patches
[j
].offset
;
541 if (file
[offset
] != m_patch
.files
[i
].patches
[j
].expected
)
543 printf("Unexpected value in file %s at offset 0x%x: expected = 0x%02x, found = 0x%02x\n",
544 fileName
, offset
, m_patch
.files
[i
].patches
[j
].expected
, file
[offset
]);
548 file
[offset
] = m_patch
.files
[i
].patches
[j
].patched
;
552 if (saveFile(fileName
, file
, fileSize
) < 0)
560 printf("Patch applied sucessfully!\n");
571 "%s -c - Create patch\n"
572 "%s -d - Dump patch\n"
575 "A patch can be created like this:\n"
576 "%s -c \"patch name\" output.exe file1.orig file1.patched[ file2.orig file2.patched[ ...]]\n",
577 m_argv
[0], m_argv
[0], m_argv
[0], m_argv
[0]);
589 if (argc
>= 2 && (strcmp(argv
[1], "-h") == 0 || strcmp(argv
[1], "--help") == 0))
594 else if (argc
>= 2 && argv
[1][0] == '-')
596 if (strcmp(argv
[1], "-c") == 0)
598 return createPatch();
600 else if (strcmp(argv
[1], "-d") == 0)
606 printf("Unknown option: %s\n"
607 "Use -h for help.\n",