SHARE
TWEET

xp_pe_patch

8bitbubsy Feb 11th, 2019 (edited) 64 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* xp_pe_patch - by 8bitbubsy - 2017-2019
  2. ** Changes a PE (EXE/DLL) binary's minimum required OS version to Windows XP
  3. ** I do NOT recommend using XP as your main OS these days, it's a really dumb idea.
  4. ** This was mostly for fun, and because I actually needed it at some point. */
  5. #include <windows.h>
  6. #include <imagehlp.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <stdint.h>
  11. #include <stdbool.h>
  12. #include <math.h>
  13.  
  14. // remember to link imagehlp.lib
  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, sizeof (NO_BACKUP_SWITCH)-1) == 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.         return false;
  199.     }
  200.  
  201.     free(fileBuf);
  202.     fclose(out);
  203.  
  204.     return true;
  205. }
  206.  
  207. static bool readAndCheckPEHeader(FILE *in)
  208. {
  209.     uint16_t *magic = (uint16_t *)&peHeader[0x18];
  210.  
  211.     if (fseek(in, 0x0000003C, SEEK_SET) != 0)                 return false;
  212.     if (fread(&peOffset, sizeof (int32_t), 1, in) != 1)       return false;
  213.     if (fseek(in, peOffset, SEEK_SET) != 0)                   return false;
  214.     if (fread(peHeader, 1, PE_READ_SIZE, in) != PE_READ_SIZE) return false;
  215.     if (*(uint32_t *)&peHeader[0x00] != 0x00004550)           return false; /* PE signature */
  216.     if (*(uint16_t *)&peHeader[0x14] < PE_READ_SIZE)          return false; /* opt. header size */
  217.     if (*magic != 0x010B && *magic != 0x020B)                 return false; /* PE type - 32-bit or 64-bit */
  218.  
  219.     return true;
  220. }
  221.  
  222. static bool setOSVersionInPEHeader(uint32_t version)
  223. {
  224.     uint32_t *osSystemVersion, *subSystemVersion;
  225.  
  226.     osSystemVersion  = (uint32_t *)(&peHeader[0x40]);
  227.     subSystemVersion = (uint32_t *)(&peHeader[0x48]);
  228.  
  229.     oldOsSystemVersion  = *osSystemVersion;
  230.     oldSubSystemVersion = *subSystemVersion;
  231.  
  232.     if (((*osSystemVersion & 0x0000FFFF) < 0x0005) && ((*subSystemVersion & 0x0000FFFF) < 0x0005))
  233.         return (false); /* min. required OS version is a version before XP  - don't do anything */
  234.  
  235.     /* do the patching */
  236.     if ((*osSystemVersion != SYSTEM_VER_WINXP) || (*subSystemVersion != SYSTEM_VER_WINXP))
  237.     {
  238.         *osSystemVersion  = version;
  239.         *subSystemVersion = version;
  240.  
  241.         return (true);
  242.     }
  243.  
  244.     /* min. requirement is already set to Windows XP - don't do anything */
  245.     return (false);
  246. }
  247.  
  248. static uint32_t getPEChecksum(char *filename)
  249. {
  250.     HANDLE hFile, hFileMapping;
  251.     PVOID pBaseAddress;
  252.     DWORD dwHeaderSum, dwCheckSum;
  253.     LARGE_INTEGER liSize;
  254.     PIMAGE_NT_HEADERS pNTHeaders;
  255.  
  256.     hFile = NULL;
  257.     hFileMapping = NULL;
  258.     pBaseAddress = NULL;
  259.     dwCheckSum = 0;
  260.  
  261.     hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  262.     if (hFile == NULL)
  263.         goto cleanUp;
  264.  
  265.     hFileMapping = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  266.     if (hFileMapping == NULL)
  267.         goto cleanUp;
  268.  
  269.     pBaseAddress = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
  270.     if (pBaseAddress == NULL)
  271.         goto cleanUp;
  272.  
  273.     if (GetFileSizeEx(hFile, &liSize) == FALSE)
  274.         goto cleanUp;
  275.  
  276.     pNTHeaders = CheckSumMappedFile(pBaseAddress, liSize.LowPart, &dwHeaderSum, &dwCheckSum);
  277.     if (pNTHeaders == NULL)
  278.         goto cleanUp;
  279.  
  280. cleanUp:
  281.     if (hFile != NULL) CloseHandle(hFile);
  282.     if (hFileMapping != NULL) CloseHandle(hFileMapping);
  283.     if (pBaseAddress != NULL) UnmapViewOfFile(pBaseAddress);
  284.  
  285.     return dwCheckSum;
  286. }
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