SHARE
TWEET

xp_pe_patch

8bitbubsy Jan 11th, 2017 (edited) 173 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. ** xp_pe_patch - by 8bitbubsy - 2017
  3. ** Changes a PE (EXE/DLL) binary's minimum required OS version to Windows XP.
  4. ** I do NOT recommend supporting XP in 2017, but people complain, so why not...
  5. */
  6.  
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <stdint.h>
  11. #include <stdbool.h>
  12.  
  13. #define PE_READ_SIZE 0x4C
  14. #define SYSTEM_VER_WINXP 0x00010005
  15. #define NO_BACKUP_SWITCH "-nb"
  16.  
  17. static uint8_t peHeader[PE_READ_SIZE];
  18. static uint32_t peOffset, oldOsSystemVersion, oldSubSystemVersion;
  19.  
  20. static uint8_t makeBinaryBackup(char *origFilename, FILE *in);
  21. static int8_t readAndCheckPEHeader(FILE *in);
  22. static uint8_t setOSVersionInPEHeader(uint32_t version);
  23.  
  24. int main(int argc, char *argv[])
  25. {
  26.     uint8_t makeBackupFlag;
  27.     uint16_t mzSig;
  28.     FILE *in, *out;
  29.  
  30.     makeBackupFlag = true;
  31.  
  32.     printf("xp_pe_patch - patches a PE binary's min. required OS to WinXP - by 8bitbubsy\n");
  33.     printf("============================================================================\n");
  34.  
  35.     if (argc < 2)
  36.     {
  37.         printf("Usage: xp_patch.exe <exe/dll file> [switches]\n\n");
  38.         printf("Switches:\n");
  39.         printf(" %s     Don't make .bak backup of original binary.\n", NO_BACKUP_SWITCH);
  40.         return (-1);
  41.     }
  42.  
  43.     if ((argc == 3) && (strncmp(argv[2], NO_BACKUP_SWITCH, strlen (NO_BACKUP_SWITCH)) == 0))
  44.         makeBackupFlag = false;
  45.  
  46.     in = fopen(argv[1], "rb");
  47.     if (in == NULL)
  48.     {
  49.         printf("ERROR: Can't open input file for reading! Is the file in use?\n");
  50.         return (1);
  51.     }
  52.  
  53.     if ((fread(&mzSig, sizeof (int16_t), 1, in) != 1) || (mzSig != 0x5A4D) || (readAndCheckPEHeader(in) == false))
  54.     {
  55.         printf("ERROR: Not a valid PE binary (or problems reading header)!\n");
  56.         fclose(in);
  57.         return (1);
  58.     }
  59.  
  60.     printf("Found PE header at offset 0x%08X.\n", peOffset);
  61.  
  62.     if (setOSVersionInPEHeader(SYSTEM_VER_WINXP) == false)
  63.     {
  64.         printf("ERROR: The file doesn't need patching! Minimum OS <= XP.\n");
  65.         fclose(in);
  66.         return (1);
  67.     }
  68.  
  69.     if (makeBackupFlag == true)
  70.     {
  71.         if (makeBinaryBackup(argv[1], in) == false)
  72.         {
  73.             printf("ERROR: I/O error creating binary backup!\n");
  74.             fclose(in);
  75.             return (1);
  76.         }
  77.  
  78.         printf("Original binary was backed up.\n");
  79.     }
  80.  
  81.     fclose(in);
  82.  
  83.     out = fopen(argv[1], "r+b");
  84.     if (out == NULL)
  85.     {
  86.         printf("ERROR: Can't open file for writing! Is the file in use?\n");
  87.         return (1);
  88.     }
  89.  
  90.     if (fseek(out, peOffset, SEEK_SET) != 0)
  91.     {
  92.         printf("ERROR: I/O error seeking in output file!\n");
  93.         fclose(out);
  94.         return (1);
  95.     }
  96.  
  97.     if (fwrite(peHeader, 1, PE_READ_SIZE, out) != PE_READ_SIZE)
  98.     {
  99.         printf("ERROR: Error writing to file! The binary is probably corrupt now, sorry.\n");
  100.         fclose(out);
  101.         return (1);
  102.     }
  103.  
  104.     printf("32-bit integer at offset 0x%08X changed from 0x%08X to 0x%08X.\n",
  105.         peOffset + 0x40, oldOsSystemVersion, SYSTEM_VER_WINXP);
  106.  
  107.     printf("32-bit integer at offset 0x%08X changed from 0x%08X to 0x%08X.\n",
  108.         peOffset + 0x48, oldSubSystemVersion, SYSTEM_VER_WINXP);
  109.  
  110.     printf("Patching done!\n");
  111.  
  112.     fclose(out);
  113.     return (0);
  114. }
  115.  
  116. static uint8_t makeBinaryBackup(char *origFilename, FILE *in)
  117. {
  118.     char *fileNameBuf;
  119.     uint8_t *fileBuf;
  120.     uint32_t fileSize;
  121.     FILE *out;
  122.  
  123.     if ((origFilename == NULL) || (in == NULL))
  124.         return (false);
  125.  
  126.     fseek(in, 0, SEEK_END);
  127.     fileSize = ftell(in);
  128.     rewind(in);
  129.  
  130.     fileBuf = (uint8_t *)(malloc(fileSize));
  131.     if (fileBuf == NULL)
  132.         return (false);
  133.  
  134.     if (fread(fileBuf, 1, fileSize, in) != fileSize)
  135.     {
  136.         free(fileBuf);
  137.         return (false);
  138.     }
  139.  
  140.     fileNameBuf = (char *)(malloc(strlen(origFilename) + 4 + 1));
  141.     if (fileNameBuf == NULL)
  142.     {
  143.         free(fileBuf);
  144.         return (false);
  145.     }
  146.  
  147.     strcpy(fileNameBuf, origFilename);
  148.     strcat(fileNameBuf, ".bak");
  149.     out = fopen(fileNameBuf, "wb");
  150.     free(fileNameBuf);
  151.  
  152.     if (out == NULL)
  153.     {
  154.         free(fileBuf);
  155.         return (false);
  156.     }
  157.  
  158.     if (fwrite(fileBuf, 1, fileSize, out) != fileSize)
  159.     {
  160.         free(fileBuf);
  161.         fclose(out);
  162.  
  163.         return (false);
  164.     }
  165.  
  166.     free(fileBuf);
  167.     fclose(out);
  168.  
  169.     return (true);
  170. }
  171.  
  172. static int8_t readAndCheckPEHeader(FILE *in)
  173. {
  174.     uint16_t *magic;
  175.  
  176.     magic = (uint16_t *)(&peHeader[0x18]);
  177.  
  178.     if (fseek(in, 0x0000003C, SEEK_SET) != 0)                 return (false);
  179.     if (fread(&peOffset, sizeof (int32_t), 1, in) != 1)       return (false);
  180.     if (fseek(in, peOffset, SEEK_SET) != 0)                   return (false);
  181.     if (fread(peHeader, 1, PE_READ_SIZE, in) != PE_READ_SIZE) return (false);
  182.     if (*((uint32_t *)(&peHeader[0x00])) != 0x00004550)       return (false); /* PE signature */
  183.     if (*((uint16_t *)(&peHeader[0x14])) < 52)                return (false); /* opt. header size */
  184.     if ((*magic != 0x010B) && (*magic != 0x020B))             return (false); /* PE type - 32-bit or 64-bit */
  185.  
  186.     return (true);
  187. }
  188.  
  189. static uint8_t setOSVersionInPEHeader(uint32_t version)
  190. {
  191.     uint32_t *osSystemVersion, *subSystemVersion;
  192.  
  193.     osSystemVersion  = (uint32_t *)(&peHeader[0x40]);
  194.     subSystemVersion = (uint32_t *)(&peHeader[0x48]);
  195.  
  196.     if (((*osSystemVersion & 0x0000FFFF) < 0x0005) && ((*subSystemVersion & 0x0000FFFF) < 0x0005))
  197.         return (false); /* min. required OS version is a version before XP  - don't do anything */
  198.  
  199.     if ((*osSystemVersion != SYSTEM_VER_WINXP) || (*subSystemVersion != SYSTEM_VER_WINXP))
  200.     {
  201.         /* do the patching */
  202.         oldOsSystemVersion  = *osSystemVersion;
  203.         oldSubSystemVersion = *subSystemVersion;
  204.  
  205.         *osSystemVersion  = version;
  206.         *subSystemVersion = version;
  207.  
  208.         return (true);
  209.     }
  210.  
  211.     /* min. requirement is already set to Windows XP - don't do anything */
  212.     return (false);
  213. }
RAW Paste Data
Want to get better at C?
Learn to code C in 2017
Pastebin PRO Summer Special!
Get 40% OFF on Pastebin PRO accounts!
Top