9 /** DEFINES *******************************************************************/
11 #define PATCH_BUFFER_SIZE 4096 /* Maximum size of a patch */
12 #define PATCH_BUFFER_MAGIC "\xde\xad\xbe\xef MaGiC MaRk "
13 #define SIZEOF_PATCH_BUFFER_MAGIC (sizeof (PATCH_BUFFER_MAGIC) - 1)
15 /** TYPES *********************************************************************/
17 typedef struct _PatchedByte
19 uintptr_t offset
; /*!< File offset of the patched byte. */
20 unsigned char expected
; /*!< Expected (original) value of the byte. */
21 unsigned char patched
; /*!< Patched (new) value for the byte. */
24 typedef struct _PatchedFile
26 const char *name
; /*!< Name of the file to be patched. */
27 size_t fileSize
; /*!< Size of the file in bytes. */
28 int patchCount
; /*!< Number of patches for the file. */
29 PatchedByte
*patches
; /*!< Patches for the file. */
34 const char *name
; /*!< Name of the patch. */
35 int fileCount
; /*!< Number of files in the patch. */
36 PatchedFile
*files
; /*!< Files for the patch. */
39 /** FUNCTION PROTOTYPES *******************************************************/
41 static void printUsage();
43 /** GLOBALS *******************************************************************/
45 static Patch m_patch
= { NULL
, 0, NULL
};
46 static int m_argc
= 0;
47 static char **m_argv
= NULL
;
49 /* patch buffer where we put the patch info into */
50 static char m_patchBuffer
[SIZEOF_PATCH_BUFFER_MAGIC
+ PATCH_BUFFER_SIZE
] =
53 /** HELPER FUNCTIONS **********************************************************/
56 loadFile(const char *fileName
, size_t *fileSize_
)
64 f
= fopen(fileName
, "rb");
67 printf("Couldn't open file %s for reading!\n", fileName
);
72 if (fstat(_fileno(f
), &sb
) < 0)
75 printf("Couldn't get size of file %s!\n", fileName
);
78 fileSize
= sb
.st_size
;
85 printf("Couldn't allocate %Id bytes for file %s!\n", fileSize
, fileName
);
89 if (fread(p
, fileSize
, 1, f
) != 1)
93 printf("Couldn't read file %s into memory!\n", fileName
);
100 *fileSize_
= fileSize
;
106 saveFile(const char *fileName
, void *file
, size_t fileSize
)
111 f
= fopen(fileName
, "wb");
114 printf("Couldn't open file %s for writing!\n", fileName
);
119 if (fwrite(file
, fileSize
, 1, f
) != 1)
122 printf("Couldn't write file %s!\n", fileName
);
134 PatchedFile
*patchedFile
,
135 const char *originalFileName
)
137 const char *patchedFileName
= patchedFile
->name
;
138 unsigned char *origChunk
, *patchedChunk
;
139 size_t origSize
, patchedSize
;
141 PatchedByte
*patches
= NULL
;
142 int patchesArrayCount
= 0;
144 /* Load both files */
145 origChunk
= loadFile(originalFileName
, &origSize
);
146 if (origChunk
== NULL
)
148 patchedChunk
= loadFile(patchedFileName
, &patchedSize
);
149 if (patchedChunk
== NULL
)
154 if (origSize
!= patchedSize
)
158 printf("File size of %s and %s differs (%Iu != %Iu)\n",
159 originalFileName
, patchedFileName
,
160 origSize
, patchedSize
);
164 /* Compare the files and record any differences */
165 printf("Comparing %s to %s", originalFileName
, patchedFileName
);
166 for (i
= 0, patchCount
= 0; i
< origSize
; i
++)
168 if (origChunk
[i
] != patchedChunk
[i
])
172 /* Resize patches array if needed */
173 if (patchesArrayCount
< patchCount
)
175 PatchedByte
*newPatches
;
176 newPatches
= realloc(patches
, patchCount
* sizeof (PatchedByte
));
177 if (newPatches
== NULL
)
183 printf("\nOut of memory (tried to allocated %Id bytes)\n",
184 patchCount
* sizeof (PatchedByte
));
187 patches
= newPatches
;
190 /* Fill in patch info */
191 patches
[patchCount
- 1].offset
= i
;
192 patches
[patchCount
- 1].expected
= origChunk
[i
];
193 patches
[patchCount
- 1].patched
= patchedChunk
[i
];
195 if ((i
% (origSize
/ 40)) == 0)
198 printf(" %d changed bytes found.\n", patchCount
);
200 /* Unload the files */
204 /* Save patch info */
205 patchedFile
->fileSize
= patchedSize
;
206 patchedFile
->patchCount
= patchCount
;
207 patchedFile
->patches
= patches
;
214 outputPatch(const char *outputFileName
)
216 char *patchExe
, *patchBuffer
= NULL
;
217 size_t i
, size
, patchExeSize
, patchSize
, stringSize
, stringOffset
, patchOffset
;
221 printf("Putting patch into %s...\n", outputFileName
);
223 /* Calculate size of the patch */
224 patchSize
= sizeof (Patch
) + sizeof (PatchedFile
) * m_patch
.fileCount
;
225 stringSize
= strlen(m_patch
.name
) + 1;
226 for (i
= 0; i
< m_patch
.fileCount
; i
++)
228 stringSize
+= strlen(m_patch
.files
[i
].name
) + 1;
229 patchSize
+= sizeof (PatchedByte
) * m_patch
.files
[i
].patchCount
;
231 if ((stringSize
+ patchSize
) > PATCH_BUFFER_SIZE
)
233 printf("Patch is too big - %u bytes maximum, %Iu bytes needed\n",
234 PATCH_BUFFER_SIZE
, stringSize
+ patchSize
);
238 /* Load patch.exe file into memory... */
239 patchExe
= loadFile(m_argv
[0], &patchExeSize
);
240 if (patchExe
== NULL
)
245 /* Try to find the magic mark for the patch buffer */
246 for (i
= 0; i
< (patchExeSize
- SIZEOF_PATCH_BUFFER_MAGIC
); i
++)
248 if (memcmp(patchExe
+ i
, m_patchBuffer
, SIZEOF_PATCH_BUFFER_MAGIC
) == 0)
250 patchBuffer
= patchExe
+ i
+ SIZEOF_PATCH_BUFFER_MAGIC
;
255 if (!(i
< (patchExeSize
- SIZEOF_PATCH_BUFFER_MAGIC
)))
258 printf("Couldn't find patch buffer magic in file %s - this shouldn't happen!!!\n", m_argv
[0]);
262 /* Pack patch together and replace string pointers by offsets */
263 patch
= (Patch
*)patchBuffer
;
264 files
= (PatchedFile
*)(patchBuffer
+ sizeof (Patch
));
265 patchOffset
= sizeof (Patch
) + sizeof (PatchedFile
) * m_patch
.fileCount
;
266 stringOffset
= patchSize
;
268 patch
->fileCount
= m_patch
.fileCount
;
269 patch
->files
= (PatchedFile
*)sizeof (Patch
);
271 patch
->name
= (const char *)stringOffset
;
272 strcpy(patchBuffer
+ stringOffset
, m_patch
.name
);
273 stringOffset
+= strlen(m_patch
.name
) + 1;
275 for (i
= 0; i
< m_patch
.fileCount
; i
++)
277 files
[i
].fileSize
= m_patch
.files
[i
].fileSize
;
278 files
[i
].patchCount
= m_patch
.files
[i
].patchCount
;
280 files
[i
].name
= (const char *)stringOffset
;
281 strcpy(patchBuffer
+ stringOffset
, m_patch
.files
[i
].name
);
282 stringOffset
+= strlen(m_patch
.files
[i
].name
) + 1;
284 size
= files
[i
].patchCount
* sizeof (PatchedByte
);
285 files
[i
].patches
= (PatchedByte
*)patchOffset
;
286 memcpy(patchBuffer
+ patchOffset
, m_patch
.files
[i
].patches
, size
);
289 size
= patchSize
+ stringSize
;
290 memset(patchBuffer
+ size
, 0, PATCH_BUFFER_SIZE
- size
);
293 if (saveFile(outputFileName
, patchExe
, patchExeSize
) < 0)
300 printf("Patch saved!\n");
312 p
= m_patchBuffer
+ SIZEOF_PATCH_BUFFER_MAGIC
;
315 if (patch
->name
== NULL
)
320 m_patch
.name
= p
+ (intptr_t)patch
->name
;
321 m_patch
.fileCount
= patch
->fileCount
;
322 m_patch
.files
= (PatchedFile
*)(p
+ (intptr_t)patch
->files
);
324 for (i
= 0; i
< m_patch
.fileCount
; i
++)
326 m_patch
.files
[i
].name
= p
+ (intptr_t)m_patch
.files
[i
].name
;
327 m_patch
.files
[i
].patches
= (PatchedByte
*)(p
+ (intptr_t)m_patch
.files
[i
].patches
);
330 printf("Patch %s loaded...\n", m_patch
.name
);
335 /** MAIN FUNCTIONS ************************************************************/
341 const char *outputFileName
;
343 /* Check argument count */
344 if (m_argc
< 6 || (m_argc
% 2) != 0)
350 outputFileName
= m_argv
[3];
351 m_patch
.name
= m_argv
[2];
353 /* Allocate PatchedFiles array */
354 m_patch
.fileCount
= (m_argc
- 4) / 2;
355 m_patch
.files
= malloc(m_patch
.fileCount
* sizeof (PatchedFile
));
356 if (m_patch
.files
== NULL
)
358 printf("Out of memory!\n");
361 memset(m_patch
.files
, 0, m_patch
.fileCount
* sizeof (PatchedFile
));
363 /* Compare original to patched files and fill m_patch.files array */
364 for (i
= 0; i
< m_patch
.fileCount
; i
++)
366 m_patch
.files
[i
].name
= m_argv
[4 + (i
* 2) + 1];
367 status
= compareFiles(m_patch
.files
+ i
, m_argv
[4 + (i
* 2) + 0]);
370 for (i
= 0; i
< m_patch
.fileCount
; i
++)
372 if (m_patch
.files
[i
].patches
!= NULL
)
373 free(m_patch
.files
[i
].patches
);
376 m_patch
.files
= NULL
;
377 m_patch
.fileCount
= 0;
383 return outputPatch(outputFileName
);
390 int c
, i
, j
, makeBackup
;
394 const char *fileName
;
395 char buffer
[MAX_PATH
];
398 if (m_argc
> 1 && strcmp(m_argv
[1], "-d") != 0)
407 printf("This executable doesn't contain a patch, use -c to create one.\n");
414 printf("Patch name: %s\n", m_patch
.name
);
415 printf("File count: %d\n", m_patch
.fileCount
);
416 for (i
= 0; i
< m_patch
.fileCount
; i
++)
418 printf("----------------------\n"
420 "File size: %Id bytes\n",
421 m_patch
.files
[i
].name
, m_patch
.files
[i
].fileSize
);
422 printf("Patch count: %d\n", m_patch
.files
[i
].patchCount
);
423 for (j
= 0; j
< m_patch
.files
[i
].patchCount
; j
++)
425 printf(" Offset 0x%Ix 0x%02x -> 0x%02x\n",
426 m_patch
.files
[i
].patches
[j
].offset
,
427 m_patch
.files
[i
].patches
[j
].expected
,
428 m_patch
.files
[i
].patches
[j
].patched
);
435 printf("Applying patch...\n");
436 for (i
= 0; i
< m_patch
.fileCount
; i
++)
438 /* Load original file */
439 fileName
= m_patch
.files
[i
].name
;
440 applyPatch_retry_file
:
441 file
= loadFile(fileName
, &fileSize
);
444 printf("File %s not found! ", fileName
);
445 applyPatch_file_open_error
:
446 printf("(S)kip, (R)etry, (A)bort, (M)anually enter filename");
451 while (c
!= 's' && c
!= 'r' && c
!= 'a' && c
!= 'm');
459 goto applyPatch_retry_file
;
467 if (fgets(buffer
, sizeof (buffer
), stdin
) == NULL
)
469 printf("fgets() failed!\n");
472 p
= strchr(buffer
, '\r');
475 p
= strchr(buffer
, '\n');
480 goto applyPatch_retry_file
;
484 /* Check file size */
485 if (fileSize
!= m_patch
.files
[i
].fileSize
)
488 printf("File %s has unexpected filesize of %Id bytes (%Id bytes expected)\n",
489 fileName
, fileSize
, m_patch
.files
[i
].fileSize
);
490 if (fileName
!= m_patch
.files
[i
].name
) /* manually entered filename */
492 goto applyPatch_file_open_error
;
498 printf("Do you want to make a backup of %s? (Y)es, (N)o, (A)bort", fileName
);
503 while (c
!= 'y' && c
!= 'n' && c
!= 'a');
507 char buffer
[MAX_PATH
];
508 _snprintf(buffer
, MAX_PATH
, "%s.bak", fileName
);
509 buffer
[MAX_PATH
-1] = '\0';
511 if (_access(buffer
, 0) >= 0) /* file exists */
513 printf("File %s already exists, overwrite? (Y)es, (N)o, (A)bort", buffer
);
518 while (c
!= 'y' && c
!= 'n' && c
!= 'a');
528 if (makeBackup
&& saveFile(buffer
, file
, fileSize
) < 0)
541 for (j
= 0; j
< m_patch
.files
[i
].patchCount
; j
++)
543 int offset
= m_patch
.files
[i
].patches
[j
].offset
;
544 if (file
[offset
] != m_patch
.files
[i
].patches
[j
].expected
)
546 printf("Unexpected value in file %s at offset 0x%x: expected = 0x%02x, found = 0x%02x\n",
547 fileName
, offset
, m_patch
.files
[i
].patches
[j
].expected
, file
[offset
]);
551 file
[offset
] = m_patch
.files
[i
].patches
[j
].patched
;
555 if (saveFile(fileName
, file
, fileSize
) < 0)
563 printf("Patch applied sucessfully!\n");
574 "%s -c - Create patch\n"
575 "%s -d - Dump patch\n"
578 "A patch can be created like this:\n"
579 "%s -c \"patch name\" output.exe file1.orig file1.patched[ file2.orig file2.patched[ ...]]\n",
580 m_argv
[0], m_argv
[0], m_argv
[0], m_argv
[0]);
592 if (argc
>= 2 && (strcmp(argv
[1], "-h") == 0 || strcmp(argv
[1], "--help") == 0))
597 else if (argc
>= 2 && argv
[1][0] == '-')
599 if (strcmp(argv
[1], "-c") == 0)
601 return createPatch();
603 else if (strcmp(argv
[1], "-d") == 0)
609 printf("Unknown option: %s\n"
610 "Use -h for help.\n",