SHARE
TWEET

xp_pe_patch

8bitbubsy Feb 11th, 2019 (edited) 48 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. ** xp_pe_patch - by 8bitbubsy - 2017-2019
  3. ** Changes a PE (EXE/DLL) binary's minimum required OS version to Windows XP
  4. ** I do NOT recommend using XP as your main OS these days, it's a really dumb idea.
  5. ** This was mostly for fun, and because I actually needed it at some point.
  6. */
  7. #include <windows.h>
  8. #include <imagehlp.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include <stdint.h>
  13. #include <stdbool.h>
  14. #include <math.h>
  15.  
  16. #define PE_READ_SIZE 0x5C
  17. #define SYSTEM_VER_WINXP 0x00010005
  18. #define NO_BACKUP_SWITCH "-nb"
  19.  
  20. static uint8_t peHeader[PE_READ_SIZE];
  21. static uint32_t peOffset, oldOsSystemVersion, oldSubSystemVersion;
  22.  
  23. static bool makeBinaryBackup(char *origFilename, FILE *in);
  24. static bool readAndCheckPEHeader(FILE *in);
  25. static bool setOSVersionInPEHeader(uint32_t version);
  26. static uint32_t getPEChecksum(char *filename);
  27.  
  28. int main(int argc, char *argv[])
  29. {
  30.     bool makeBackupFlag, neededPatching;
  31.     uint16_t mzSig;
  32.     uint32_t newChecksum;
  33.     FILE *in, *out;
  34.  
  35.     makeBackupFlag = true;
  36.  
  37.     printf("xp_pe_patch - patches a PE binary's min. required OS to WinXP - by 8bitbubsy\n");
  38.     printf("============================================================================\n");
  39.  
  40.     if (argc < 2)
  41.     {
  42.         printf("Usage: xp_patch.exe <exe/dll file> [switches]\n\n");
  43.         printf("Switches:\n");
  44.         printf(" %s     Don't make .bak backup of original binary.\n", NO_BACKUP_SWITCH);
  45.         return (-1);
  46.     }
  47.  
  48.     if ((argc == 3) && (strncmp(argv[2], NO_BACKUP_SWITCH, strlen (NO_BACKUP_SWITCH)) == 0))
  49.         makeBackupFlag = false;
  50.  
  51.     in = fopen(argv[1], "rb");
  52.     if (in == NULL)
  53.     {
  54.         printf("ERROR: Can't open input file for reading! Is the file in use?\n");
  55.         return (1);
  56.     }
  57.  
  58.     if ((fread(&mzSig, sizeof (int16_t), 1, in) != 1) || (mzSig != 0x5A4D) || (readAndCheckPEHeader(in) == false))
  59.     {
  60.         printf("ERROR: Not a valid PE binary (or problems reading header)!\n");
  61.         fclose(in);
  62.         return (1);
  63.     }
  64.  
  65.     printf("Found PE header at offset 0x%08X.\n", peOffset);
  66.     *((uint32_t *)(&peHeader[0x58])) = 0; /* clear old PE checksum (set later) */
  67.  
  68.     neededPatching = setOSVersionInPEHeader(SYSTEM_VER_WINXP);
  69.  
  70.     if (makeBackupFlag)
  71.     {
  72.         if (!makeBinaryBackup(argv[1], in))
  73.         {
  74.             printf("ERROR: I/O error creating binary backup!\n");
  75.             fclose(in);
  76.             return (1);
  77.         }
  78.  
  79.         printf("Original binary was backed up.\n");
  80.     }
  81.  
  82.     out = fopen(argv[1], "r+b");
  83.     if (out == NULL)
  84.     {
  85.         printf("ERROR: Can't open file for writing! Is the file in use?\n");
  86.         return (1);
  87.     }
  88.  
  89.     if (fseek(out, peOffset, SEEK_SET) != 0)
  90.     {
  91.         printf("ERROR: I/O error seeking in output file!\n");
  92.         fclose(out);
  93.         return (1);
  94.     }
  95.  
  96.     if (fwrite(peHeader, 1, PE_READ_SIZE, out) != PE_READ_SIZE)
  97.     {
  98.         printf("ERROR: Error writing to file! The binary is probably corrupt now, sorry.\n");
  99.         fclose(out);
  100.         return (1);
  101.     }
  102.  
  103.     fclose(out);
  104.  
  105.     if (neededPatching)
  106.     {
  107.         printf("32-bit integer at offset 0x%08X changed from 0x%08X to 0x%08X.\n",
  108.             peOffset + 0x40, oldOsSystemVersion, SYSTEM_VER_WINXP);
  109.  
  110.         printf("32-bit integer at offset 0x%08X changed from 0x%08X to 0x%08X.\n",
  111.             peOffset + 0x48, oldSubSystemVersion, SYSTEM_VER_WINXP);
  112.     }
  113.     else
  114.     {
  115.         printf("No version patching was needed.\n");
  116.     }
  117.  
  118.     newChecksum = getPEChecksum(argv[1]);
  119.     if (newChecksum != 0)
  120.     {
  121.         *((uint32_t *)(&peHeader[0x58])) = newChecksum;
  122.  
  123.         out = fopen(argv[1], "r+b");
  124.         if (out == NULL)
  125.         {
  126.             printf("ERROR: Can't open file for writing! Is the file in use?\n");
  127.             return (1);
  128.         }
  129.  
  130.         if (fseek(out, peOffset, SEEK_SET) != 0)
  131.         {
  132.             printf("ERROR: I/O error seeking in output file!\n");
  133.             fclose(out);
  134.             return (1);
  135.         }
  136.  
  137.         if (fwrite(peHeader, 1, PE_READ_SIZE, out) != PE_READ_SIZE)
  138.         {
  139.             printf("ERROR: Error writing to file! The binary is probably corrupt now, sorry.\n");
  140.             fclose(out);
  141.             return (1);
  142.         }
  143.  
  144.         fclose(out);
  145.  
  146.         printf("Image checksum was calculated and set to 0x%08X.\n", newChecksum);
  147.     }
  148.  
  149.     return (0);
  150. }
  151.  
  152. static bool makeBinaryBackup(char *origFilename, FILE *in)
  153. {
  154.     char *fileNameBuf;
  155.     uint8_t *fileBuf;
  156.     uint32_t fileSize;
  157.     FILE *out;
  158.  
  159.     if ((origFilename == NULL) || (in == NULL))
  160.         return (false);
  161.  
  162.     fseek(in, 0, SEEK_END);
  163.     fileSize = ftell(in);
  164.     rewind(in);
  165.  
  166.     fileBuf = (uint8_t *)(malloc(fileSize));
  167.     if (fileBuf == NULL)
  168.         return (false);
  169.  
  170.     if (fread(fileBuf, 1, fileSize, in) != fileSize)
  171.     {
  172.         free(fileBuf);
  173.         return (false);
  174.     }
  175.  
  176.     fileNameBuf = (char *)(malloc(strlen(origFilename) + 4 + 1));
  177.     if (fileNameBuf == NULL)
  178.     {
  179.         free(fileBuf);
  180.         return (false);
  181.     }
  182.  
  183.     strcpy(fileNameBuf, origFilename);
  184.     strcat(fileNameBuf, ".bak");
  185.     out = fopen(fileNameBuf, "wb");
  186.     free(fileNameBuf);
  187.  
  188.     if (out == NULL)
  189.     {
  190.         free(fileBuf);
  191.         return (false);
  192.     }
  193.  
  194.     if (fwrite(fileBuf, 1, fileSize, out) != fileSize)
  195.     {
  196.         free(fileBuf);
  197.         fclose(out);
  198.  
  199.         return (false);
  200.     }
  201.  
  202.     free(fileBuf);
  203.     fclose(out);
  204.  
  205.     return (true);
  206. }
  207.  
  208. static bool readAndCheckPEHeader(FILE *in)
  209. {
  210.     uint16_t *magic;
  211.  
  212.     magic = (uint16_t *)(&peHeader[0x18]);
  213.  
  214.     if (fseek(in, 0x0000003C, SEEK_SET) != 0)                 return (false);
  215.     if (fread(&peOffset, sizeof (int32_t), 1, in) != 1)       return (false);
  216.     if (fseek(in, peOffset, SEEK_SET) != 0)                   return (false);
  217.     if (fread(peHeader, 1, PE_READ_SIZE, in) != PE_READ_SIZE) return (false);
  218.     if (*((uint32_t *)(&peHeader[0x00])) != 0x00004550)       return (false); /* PE signature */
  219.     if (*((uint16_t *)(&peHeader[0x14])) < PE_READ_SIZE)      return (false); /* opt. header size */
  220.     if ((*magic != 0x010B) && (*magic != 0x020B))             return (false); /* PE type - 32-bit or 64-bit */
  221.  
  222.     return (true);
  223. }
  224.  
  225. static bool setOSVersionInPEHeader(uint32_t version)
  226. {
  227.     uint32_t *osSystemVersion, *subSystemVersion;
  228.  
  229.     osSystemVersion  = (uint32_t *)(&peHeader[0x40]);
  230.     subSystemVersion = (uint32_t *)(&peHeader[0x48]);
  231.  
  232.     oldOsSystemVersion  = *osSystemVersion;
  233.     oldSubSystemVersion = *subSystemVersion;
  234.  
  235.     if (((*osSystemVersion & 0x0000FFFF) < 0x0005) && ((*subSystemVersion & 0x0000FFFF) < 0x0005))
  236.         return (false); /* min. required OS version is a version before XP  - don't do anything */
  237.  
  238.     /* do the patching */
  239.     if ((*osSystemVersion != SYSTEM_VER_WINXP) || (*subSystemVersion != SYSTEM_VER_WINXP))
  240.     {
  241.         *osSystemVersion  = version;
  242.         *subSystemVersion = version;
  243.  
  244.         return (true);
  245.     }
  246.  
  247.     /* min. requirement is already set to Windows XP - don't do anything */
  248.     return (false);
  249. }
  250.  
  251. static uint32_t getPEChecksum(char *filename)
  252. {
  253.     HANDLE hFile, hFileMapping;
  254.     PVOID pBaseAddress;
  255.     DWORD dwHeaderSum, dwCheckSum;
  256.     LARGE_INTEGER liSize;
  257.     PIMAGE_NT_HEADERS pNTHeaders;
  258.  
  259.     hFile        = NULL;
  260.     hFileMapping = NULL;
  261.     pBaseAddress = NULL;
  262.     dwCheckSum   = 0;
  263.  
  264.     hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  265.     if (hFile == NULL)
  266.         goto cleanUp;
  267.  
  268.     hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  269.     if (hFileMapping == NULL)
  270.         goto cleanUp;
  271.  
  272.     pBaseAddress = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
  273.     if (pBaseAddress == NULL)
  274.         goto cleanUp;
  275.  
  276.     if (GetFileSizeEx(hFile, &liSize) == FALSE)
  277.         goto cleanUp;
  278.  
  279.     pNTHeaders = CheckSumMappedFile(pBaseAddress, liSize.LowPart, &dwHeaderSum, &dwCheckSum);
  280.     if (pNTHeaders == NULL)
  281.         goto cleanUp;
  282.  
  283. cleanUp:
  284.     if (hFile        != NULL) CloseHandle(hFile);
  285.     if (hFileMapping != NULL) CloseHandle(hFileMapping);
  286.     if (pBaseAddress != NULL) UnmapViewOfFile(pBaseAddress);
  287.  
  288.     return (dwCheckSum);
  289. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top