Subversion Repositories filter_foundry

Rev

Rev 416 | Rev 425 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.     This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
  3.     Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
  4.     Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19. */
  20.  
  21. #include "ff.h"
  22.  
  23. #include <time.h>
  24.  
  25. #include "file_compat.h"
  26. #include "compat_string.h"
  27. #include "compat_win.h"
  28. #include "versioninfo_modify_win.h"
  29. #include "version.h"
  30.  
  31. extern HINSTANCE hDllInstance;
  32.  
  33. Boolean doresources(char *dstname, int bits);
  34.  
  35. void dbglasterror(char *func){
  36.         char s[0x100];
  37.  
  38.         strcpy(s,func);
  39.         strcat(s," failed: ");
  40.         FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),0,s+strlen(s),0x100,NULL );
  41.         dbg(s);
  42. }
  43.  
  44. /*
  45. BOOL CALLBACK enumfunc(HMODULE hModule,LPCTSTR lpszType,LPCTSTR lpszName,WORD wIDLanguage,LONG lParam){
  46.         char s[0x100];
  47.         sprintf(s,"EnumResourceLanguages callback: module=%#x type=%s name=%s lang=%d",
  48.                 hModule,lpszType,lpszName,wIDLanguage);
  49.         dbg(s);
  50.         return TRUE;
  51. }
  52. */
  53.  
  54. int domanifest(char *newmanifest, char *manifestp, PARM_T* pparm, int bits) {
  55.         char name[1024];
  56.         char description[1024];
  57.         size_t i;
  58.         size_t iname = 0;
  59.         int idescription = 0;
  60.  
  61.         // Description
  62.         for (i = 0; i < strlen(pparm->szCategory); i++) {
  63.                 char c = pparm->szCategory[i];
  64.                 if ((c != '<') && (c != '>')) {
  65.                         description[idescription++] = c;
  66.                 }
  67.         }
  68.         description[idescription++] = ' ';
  69.         description[idescription++] = '-';
  70.         description[idescription++] = ' ';
  71.         for (i = 0; i < strlen(pparm->szTitle); i++) {
  72.                 char c = pparm->szTitle[i];
  73.                 if ((c != '<') && (c != '>')) {
  74.                         description[idescription++] = c;
  75.                 }
  76.         }
  77.         description[idescription++] = '\0';
  78.  
  79.         // Name
  80.         strcpy(name, "Telegraphics.FilterFoundry.");
  81.         iname = strlen("Telegraphics.FilterFoundry.");
  82.         for (i = 0; i < strlen(pparm->szCategory); i++) {
  83.                 char c = pparm->szCategory[i];
  84.                 if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9'))) {
  85.                         name[iname++] = c;
  86.                 }
  87.         }
  88.         name[iname++] = '.';
  89.         for (i = 0; i < strlen(pparm->szTitle); i++) {
  90.                 char c = pparm->szTitle[i];
  91.                 if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9'))) {
  92.                         name[iname++] = c;
  93.                 }
  94.         }
  95.         name[iname++] = '\0';
  96.  
  97.         if (bits == 64) {
  98.                 return sprintf(newmanifest, manifestp, (char*)name, "amd64", VERSION_STR, (char*)description);
  99.         }
  100.         else {
  101.                 return sprintf(newmanifest, manifestp, (char*)name, "x86", VERSION_STR, (char*)description);
  102.         }
  103. }
  104.  
  105. ULONG changeVersionInfo(char* dstname, HANDLE hUpdate, PARM_T* pparm, int bits) {
  106.         char* soleFilename;
  107.         LPWSTR changeRequestStr, tmp;
  108.         ULONG dwError = NOERROR;
  109.         HRSRC hResInfo;
  110.         HGLOBAL hg;
  111.         ULONG size;
  112.         PVOID pv;
  113.         //BOOL fDiscard = TRUE;
  114.  
  115.         if (soleFilename = strrchr(dstname, '\\')) {
  116.                 ++soleFilename;
  117.         }
  118.         else {
  119.                 soleFilename = dstname;
  120.         }
  121.  
  122.         // Format of argument "PCWSTR changes" is "<name>\0<value>\0<name>\0<value>\0....."
  123.         // You can CHANGE values for any given name
  124.         // You can DELETE entries by setting the value to "\b" (0x08 backspace character)
  125.         // You cannot (yet) ADD entries.
  126.         changeRequestStr = (LPWSTR)malloc(6 * 2 * 100 + 1);
  127.  
  128.         tmp = changeRequestStr;
  129.  
  130.         tmp += mbstowcs(tmp, "Comments", 100);
  131.         tmp++;
  132.         tmp += mbstowcs(tmp, "Built using Filter Foundry " VERSION_STR, 100);
  133.         tmp++;
  134.  
  135.         tmp += mbstowcs(tmp, "CompanyName", 100);
  136.         tmp++;
  137.         if (strlen(pparm->szAuthor) > 0) {
  138.                 tmp += mbstowcs(tmp, pparm->szAuthor, 100);
  139.         }
  140.         else {
  141.                 tmp += mbstowcs(tmp, "\b", 100); // \b = remove
  142.         }
  143.         tmp++;
  144.  
  145.         tmp += mbstowcs(tmp, "LegalCopyright", 100);
  146.         tmp++;
  147.         if (strlen(pparm->szCopyright) > 0) {
  148.                 tmp += mbstowcs(tmp, pparm->szCopyright, 100);
  149.         }
  150.         else {
  151.                 tmp += mbstowcs(tmp, "\b", 100); // \b = remove
  152.         }
  153.         tmp++;
  154.  
  155.         tmp += mbstowcs(tmp, "FileDescription", 100);
  156.         tmp++;
  157.         if (strlen(pparm->szTitle) > 0) {
  158.                 tmp += mbstowcs(tmp, pparm->szTitle, 100);
  159.         }
  160.         else {
  161.                 tmp += mbstowcs(tmp, "Untitled filter", 100);
  162.         }
  163.         tmp++;
  164.  
  165.         tmp += mbstowcs(tmp, "OriginalFilename", 100);
  166.         tmp++;
  167.         tmp += mbstowcs(tmp, soleFilename, 100);
  168.         tmp++;
  169.  
  170.         tmp += mbstowcs(tmp, "License", 100);
  171.         tmp++;
  172.         tmp += mbstowcs(tmp, "\b", 100); // \b = remove, since filter is standalone and might have its own license
  173.         tmp++;
  174.  
  175.         tmp += mbstowcs(tmp, "", 1);
  176.  
  177.         if (hResInfo = FindResourceEx(hDllInstance, "TPLT", MAKEINTRESOURCE(3000 + bits), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)))
  178.         {
  179.                 if (hg = LoadResource(hDllInstance, hResInfo))
  180.                 {
  181.                         if (size = SizeofResource(hDllInstance, hResInfo))
  182.                         {
  183.                                 if (pv = LockResource(hg))
  184.                                 {
  185.                                         if (UpdateVersionRaw(pv, size, &pv, &size, changeRequestStr))
  186.                                         {
  187.                                                 if (_UpdateResource(hUpdate, RT_VERSION, MAKEINTRESOURCE(1), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), pv, size))
  188.                                                 {
  189.                                                         //fDiscard = FALSE;
  190.                                                 }
  191.                                                 else {
  192.                                                         //dwError = GetLastError();
  193.                                                 }
  194.                                         }
  195.                                         LocalFree(pv);
  196.                                 }
  197.                         }
  198.                 }
  199.         }
  200.  
  201.         free(changeRequestStr);
  202.  
  203.         return dwError;
  204. }
  205.  
  206. Boolean update_pe_timestamp(const char* filename, time_t timestamp) {
  207.         size_t peoffset;
  208.         FILE* fptr;
  209.  
  210.         fptr = fopen(filename, "rb+");
  211.         if (fptr == NULL) return false;
  212.  
  213.         fseek(fptr, 0x3C, SEEK_SET);
  214.         fread(&peoffset, sizeof(peoffset), 1, fptr);
  215.  
  216.         fseek(fptr, (long)peoffset + 8, SEEK_SET);
  217.         fwrite(&timestamp, sizeof(time_t), 1, fptr);
  218.  
  219.         fclose(fptr);
  220.  
  221.         return true;
  222. }
  223.  
  224. int binary_replace_file(const char* filename, uint64_t search, uint64_t replace, Boolean align, int maxamount) {
  225.         uint64_t srecord = 0;
  226.         int found = 0;
  227.  
  228.         FILE* fptr = fopen(filename, "rb+");
  229.         if (fptr == NULL) return -1;
  230.  
  231.         while ((fread(&srecord, sizeof(srecord), 1, fptr) == 1))
  232.         {
  233.                 if (srecord == search) {
  234.                         srecord = replace;
  235.                         fseek(fptr, -1*(long)sizeof(srecord), SEEK_CUR);
  236.                         fwrite(&srecord, (int)sizeof(srecord), 1, fptr);
  237.                         fseek(fptr, 0, SEEK_CUR); // important!
  238.                         found++;
  239.                         if (found == maxamount) break;
  240.                 }
  241.                 else {
  242.                         if (!align) {
  243.                                 fseek(fptr, -1*(long)(sizeof(srecord) - 1), SEEK_CUR);
  244.                         }
  245.                 }
  246.         }
  247.         fclose(fptr);
  248.  
  249.         return found;
  250. }
  251.  
  252. //DOS .EXE header
  253. struct image_dos_header
  254. {
  255.         uint16_t e_magic;                     // Magic number
  256.         uint16_t e_cblp;                      // Bytes on last page of file
  257.         uint16_t e_cp;                        // Pages in file
  258.         uint16_t e_crlc;                      // Relocations
  259.         uint16_t e_cparhdr;                   // Size of header in paragraphs
  260.         uint16_t e_minalloc;                  // Minimum extra paragraphs needed
  261.         uint16_t e_maxalloc;                  // Maximum extra paragraphs needed
  262.         uint16_t e_ss;                        // Initial (relative) SS value
  263.         uint16_t e_sp;                        // Initial SP value
  264.         uint16_t e_csum;                      // Checksum
  265.         uint16_t e_ip;                        // Initial IP value
  266.         uint16_t e_cs;                        // Initial (relative) CS value
  267.         uint16_t e_lfarlc;                    // File address of relocation table
  268.         uint16_t e_ovno;                      // Overlay number
  269.         uint16_t e_res[4];                    // Reserved words
  270.         uint16_t e_oemid;                     // OEM identifier (for e_oeminfo)
  271.         uint16_t e_oeminfo;                   // OEM information; e_oemid specific
  272.         uint16_t e_res2[10];                  // Reserved words
  273.         int32_t  e_lfanew;                    // File address of new exe header
  274. };
  275.  
  276. struct image_file_header
  277. {
  278.         uint16_t Machine;
  279.         uint16_t NumberOfSections;
  280.         uint32_t TimeDateStamp;
  281.         uint32_t PointerToSymbolTable;
  282.         uint32_t NumberOfSymbols;
  283.         uint16_t SizeOfOptionalHeader;
  284.         uint16_t Characteristics;
  285. };
  286.  
  287. uint32_t calculate_checksum(const char* filename) {
  288.         //Calculate checksum of image
  289.         // Taken from "PE Bliss" Cross-Platform Portable Executable C++ Library
  290.         // https://github.com/mrexodia/portable-executable-library/blob/master/pe_lib/pe_checksum.cpp
  291.         // Converted from C++ to C by Daniel Marschall
  292.  
  293.         FILE* fptr;
  294.         unsigned long long checksum = 0;
  295.         struct image_dos_header header;
  296.         size_t filesize;
  297.         unsigned long long top;
  298.         unsigned long pe_checksum_pos;
  299.         static const unsigned long checksum_pos_in_optional_headers = 64;
  300.         size_t i;
  301.  
  302.         fptr = fopen(filename, "rb");
  303.         if (fptr == NULL) return 0x00000000;
  304.  
  305.         //Read DOS header
  306.         fseek(fptr, 0, SEEK_SET);
  307.         fread(&header, sizeof(struct image_dos_header), 1, fptr);
  308.  
  309.         //Calculate PE checksum
  310.         fseek(fptr, 0, SEEK_SET);
  311.         top = 0xFFFFFFFF;
  312.         top++;
  313.  
  314.         //"CheckSum" field position in optional PE headers - it's always 64 for PE and PE+
  315.         //Calculate real PE headers "CheckSum" field position
  316.         //Sum is safe here
  317.         pe_checksum_pos = header.e_lfanew + sizeof(struct image_file_header) + sizeof(uint32_t) + checksum_pos_in_optional_headers;
  318.  
  319.         //Calculate checksum for each byte of file
  320.         fseek(fptr, 0L, SEEK_END);
  321.         filesize = ftell(fptr);
  322.         fseek(fptr, 0L, SEEK_SET);
  323.         for (i = 0; i < filesize; i += 4)
  324.         {
  325.                 unsigned long dw = 0;
  326.  
  327.                 //Read DWORD from file
  328.                 fread(&dw, sizeof(dw), 1, fptr);
  329.                 //Skip "CheckSum" DWORD
  330.                 if (i == pe_checksum_pos)
  331.                         continue;
  332.  
  333.                 //Calculate checksum
  334.                 checksum = (checksum & 0xffffffff) + dw + (checksum >> 32);
  335.                 if (checksum > top)
  336.                         checksum = (checksum & 0xffffffff) + (checksum >> 32);
  337.         }
  338.  
  339.         //Finish checksum
  340.         checksum = (checksum & 0xffff) + (checksum >> 16);
  341.         checksum = (checksum)+(checksum >> 16);
  342.         checksum = checksum & 0xffff;
  343.  
  344.         checksum += (unsigned long)(filesize);
  345.  
  346.         fclose(fptr);
  347.  
  348.         //Return checksum
  349.         return (uint32_t)checksum;
  350. }
  351.  
  352. Boolean repair_pe_checksum(const char* filename) {
  353.         size_t peoffset;
  354.         FILE* fptr;
  355.  
  356.         uint32_t checksum = calculate_checksum(filename);
  357.         //if (checksum == 0x00000000) return false;
  358.  
  359.         fptr = fopen(filename, "rb+");
  360.         if (fptr == NULL) return false;
  361.  
  362.         fseek(fptr, 0x3C, SEEK_SET);
  363.         fread(&peoffset, sizeof(peoffset), 1, fptr);
  364.  
  365.         fseek(fptr, (long)peoffset + 88, SEEK_SET);
  366.         fwrite(&checksum, sizeof(uint32_t), 1, fptr);
  367.  
  368.         fclose(fptr);
  369.  
  370.         return true;
  371. }
  372.  
  373. typedef struct {
  374.         char funcname[8];
  375.         uint16_t codelen;
  376. } operdef_t;
  377.  
  378. typedef struct {
  379.         char funcname[8];
  380.         uint16_t numparams;
  381. } funcdef_t;
  382.  
  383. typedef struct {
  384.         char funcname[8];
  385.         char referencename[8];
  386. } symndef_t;
  387.  
  388. Boolean doresources(char *dstname, int bits){
  389.         HRSRC datarsrc,aetersrc,manifestsrc;
  390.         HGLOBAL datah,aeteh,hupdate,manifesth;
  391.  
  392.         operdef_t dummy_oper;
  393.         funcdef_t dummy_func;
  394.         symndef_t dummy_symn;
  395.  
  396.         Ptr newpipl = NULL, newaete = NULL;
  397.         LPVOID datap, aetep, manifestp;
  398.         char* manifestp_copy;
  399.         PARM_T *pparm = NULL;
  400.         size_t piplsize,aetesize,origsize;
  401.         char title[256];
  402.         LPCTSTR parm_type;
  403.         LPCSTR parm_id;
  404.         Boolean discard = true;
  405.         uint64_t obfuscseed = 0;
  406.         long event_id;
  407.  
  408.         memset(&dummy_oper, 0, sizeof(operdef_t));
  409.         memset(&dummy_func, 0, sizeof(funcdef_t));
  410.         memset(&dummy_symn, 0, sizeof(symndef_t));
  411.  
  412.         if( (hupdate = _BeginUpdateResource(dstname,false)) ){
  413.                 DBG("BeginUpdateResource OK");
  414.                 if( (datarsrc = FindResource(hDllInstance,MAKEINTRESOURCE(16000 + bits), "TPLT"))
  415.                         && (datah = LoadResource(hDllInstance,datarsrc))
  416.                         && (datap = (Ptr)LockResource(datah))
  417.                         && (aetersrc = FindResource(hDllInstance, MAKEINTRESOURCE(16000), "AETE"))
  418.                         && (aeteh = LoadResource(hDllInstance, aetersrc))
  419.                         && (aetep = (Ptr)LockResource(aeteh))
  420.                         && (manifestsrc = FindResource(hDllInstance, MAKEINTRESOURCE(1), "TPLT"))
  421.                         && (manifesth = LoadResource(hDllInstance, manifestsrc))
  422.                         && (manifestp = (Ptr)LockResource(manifesth)) )
  423.                 {
  424.                         char* newmanifest;
  425.                         int manifestsize = SizeofResource(hDllInstance, manifestsrc);
  426.  
  427.                         newmanifest = (char*)malloc(manifestsize + 4096/*+4KiB for name,description,etc.*/);
  428.  
  429.                         DBG("loaded DATA, PiPL");
  430.  
  431.                         strcpy(title,gdata->parm.szTitle);
  432.                         if(gdata->parm.popDialog)
  433.                                 strcat(title,"...");
  434.  
  435.                         origsize = SizeofResource(hDllInstance,datarsrc);
  436.  
  437.                         if( (newpipl = (Ptr)malloc(origsize+0x300))
  438.                          && (newaete = (Ptr)malloc(4096))
  439.                          && (pparm = (PARM_T*)malloc(sizeof(PARM_T))) )
  440.                         {
  441.                                 // ====== Generate AETE and PIPL
  442.  
  443.                                 /* add user-specified title and category to new PiPL */
  444.                                 memcpy(newpipl,datap,origsize);
  445.                                 /* note that Windows PiPLs have 2 byte version datum in front
  446.                                    that isn't reflected in struct definition or Mac resource template: */
  447.                                 piplsize = fixpipl((PIPropertyList*)(newpipl+2),origsize-2,&title[0], &event_id) + 2;
  448.  
  449.                                 /* set up the PARM resource with saved parameters */
  450.                                 memcpy(pparm,&gdata->parm,sizeof(PARM_T));
  451.  
  452.                                 /* Generate 'aete' resource (contains names of the parameters for the "Actions" tab in Photoshop) */
  453.                                 aetesize = aete_generate(newaete, pparm, event_id);
  454.  
  455.                                 // ====== Create fitting manifest for the activation context
  456.  
  457.                                 manifestp_copy = (char*)malloc(manifestsize + 1/*sz*/);
  458.                                 if (manifestp_copy != 0) {
  459.                                         memcpy(manifestp_copy, manifestp, manifestsize); // copy manifestp to manifestp_copy, because manifestp is readonly
  460.                                         manifestp_copy[manifestsize] = '\0'; // and add the null-terminating char, because domanifest() uses sprintf() on it
  461.                                         manifestsize = domanifest(newmanifest, manifestp_copy, pparm, bits);
  462.                                         free(manifestp_copy);
  463.                                 }
  464.  
  465.                                 // ====== Change version attributes
  466.  
  467.                                 if (changeVersionInfo(dstname, hupdate, pparm, bits) != NOERROR) {
  468.                                         simplealert(_strdup("changeVersionInfo failed"));
  469.                                 }
  470.  
  471.                                 // ====== Obfuscate pparm!
  472.  
  473.                                 if (gdata->obfusc) {
  474.                                         parm_type = OBFUSCDATA_TYPE_NEW;
  475.                                         parm_id = OBFUSCDATA_ID_NEW;
  476.  
  477.                                         // Note: After we have finished updating the resources, we will write <obfuscseed> into the binary code of the 8BF file
  478.                                         obfuscseed = obfusc(pparm);
  479.                                 }else{
  480.                                         parm_type = PARM_TYPE;
  481.                                         parm_id = PARM_ID_NEW;
  482.                                 }
  483.  
  484.                                 // ====== Save AETE, PIPL, Manifest and PARM/RCDATA
  485.  
  486.                                 /* Attention: The resource we have found using FindResource() might have a different
  487.                                    language than the resource we are saving (Neutral), so we might end up having
  488.                                    multiple languages for the same resource. Therefore, the language "Neutral" was
  489.                                    set in the Scripting.rc file for the resource AETE and PIPL.rc for the resources PIPL. */
  490.  
  491.                                 if(
  492.                                            _UpdateResource(hupdate, RT_DIALOG, MAKEINTRESOURCE(ID_BUILDDLG), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL, 0) // clean up things we don't need in the standalone plugin
  493.                                         && _UpdateResource(hupdate, RT_DIALOG, MAKEINTRESOURCE(ID_MAINDLG), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL, 0) // clean up things we don't need in the standalone plugin
  494.                                         && _UpdateResource(hupdate, RT_GROUP_ICON, "CAUTION_ICO", MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
  495. //                                      && _UpdateResource(hupdate, RT_ICON, MAKEINTRESOURCE(1)/*Caution*/, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
  496.                                         && _UpdateResource(hupdate, RT_GROUP_CURSOR, "HAND_QUESTION", MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
  497.                                         // TODO: Removing the single resources don't work correctly. Sometimes the cursors are numbered 4,5,6 and sometimes 1,2,3 . Probably conflicts with icons
  498. //                                      && _UpdateResource(hupdate, RT_CURSOR, MAKEINTRESOURCE(3)/*QuestionHand*/, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
  499.                                         && _UpdateResource(hupdate, "PIPL" /* note: caps!! */,MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),newpipl,(DWORD)piplsize)
  500.                                         && _UpdateResource(hupdate, "AETE" /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newaete, (DWORD)aetesize)
  501.                                         // OPER and FUNC are written so that "Plugin Manager 2.1" thinks that this plugin is a Filter Factory plugin! SYNM is not important, though.
  502.                                         && (gdata->obfusc || _UpdateResource(hupdate, "OPER", MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_oper, sizeof(dummy_oper)))
  503.                                         && (gdata->obfusc || _UpdateResource(hupdate, "FUNC", MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_func, sizeof(dummy_func)))
  504.                                         && (gdata->obfusc || _UpdateResource(hupdate, "SYNM", MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_symn, sizeof(dummy_symn)))
  505.                                         && _UpdateResource(hupdate, RT_MANIFEST, MAKEINTRESOURCE(1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newmanifest, (DWORD)manifestsize)
  506.                                         && _UpdateResource(hupdate, parm_type,parm_id, MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),pparm,sizeof(PARM_T)) )
  507.                                 {
  508.                                         discard = false;
  509.                                 } else {
  510.                                         dbglasterror(_strdup("UpdateResource"));
  511.                                 }
  512.                         }
  513.  
  514.                         // Here, the file will be saved
  515.                         if (_EndUpdateResource(hupdate, discard)) {
  516.                                 if (gdata->obfusc) {
  517.                                         // We modify the binary code to replace the deobfuscate-seed from <cObfuscSeed> to <obfuscseed>
  518.  
  519.                                         // First try with alignment "4" (this should be the usual case),
  520.                                         // and if that failed, try without alignment ("1").
  521.                                         // We only need to set maxamount to "1", because "const volatile" makes sure that
  522.                                         // the compiler won't place (inline) it at several locations in the code.
  523.                                         if ((binary_replace_file(dstname, cObfuscSeed, obfuscseed, /*align to 4*/1, /*maxamount=*/1) == 0) &&
  524.                                                 (binary_replace_file(dstname, cObfuscSeed, obfuscseed, /*align to 1*/0, /*maxamount=*/1) == 0))
  525.                                         {
  526.                                                 dbg("binary_replace_file failed");
  527.                                                 discard = true;
  528.                                         }
  529.                                 }
  530.  
  531.                                 update_pe_timestamp(dstname, time(0));
  532.  
  533.                                 repair_pe_checksum(dstname);
  534.                         }else dbglasterror(_strdup("EndUpdateResource"));
  535.  
  536.                 }else dbglasterror(_strdup("Find-, Load- or LockResource"));
  537.  
  538.                 if(pparm) free(pparm);
  539.                 if(newpipl) free(newpipl);
  540.                 if(newaete) free(newaete);
  541.         }else
  542.                 dbglasterror(_strdup("BeginUpdateResource"));
  543.         return !discard;
  544. }
  545.  
  546. Boolean remove_64_filename_prefix(char* dstname) {
  547.         // foobar.8bf => foobar.8bf
  548.         // foobar64.8bf => foobar.8bf
  549.         size_t i;
  550.         for (i = strlen(dstname); i > 2; i--) {
  551.                 if (dstname[i] == '.') {
  552.                         if ((dstname[i - 2] == '6') && (dstname[i - 1] == '4')) {
  553.                                 size_t tmp = strlen(dstname);
  554.                                 memcpy(&dstname[i - 2], &dstname[i], strlen(dstname) - i + 1);
  555.                                 dstname[tmp - 2] = 0;
  556.                                 return true;
  557.                         }
  558.                 }
  559.         }
  560.         return false;
  561. }
  562.  
  563. Boolean add_64_filename_prefix(char* dstname) {
  564.         // foobar.8bf => foobar64.8bf
  565.         size_t i;
  566.         for (i = strlen(dstname); i > 2; i--) {
  567.                 if (dstname[i] == '.') {
  568.                         size_t tmp = strlen(dstname);
  569.                         memcpy(&dstname[i + 2], &dstname[i], strlen(dstname) - i + 1);
  570.                         dstname[i] = '6';
  571.                         dstname[i + 1] = '4';
  572.                         dstname[tmp + 2] = 0;
  573.                         return true;
  574.                 }
  575.         }
  576.         return false;
  577. }
  578.  
  579. BOOL FileExists(LPCTSTR szPath) {
  580.         DWORD dwAttrib = GetFileAttributes(szPath);
  581.         return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
  582.                 !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
  583. }
  584.  
  585. Boolean extract_file(LPCTSTR lpType, LPCTSTR lpName, const char* outName) {
  586.         HGLOBAL datah;
  587.         LPVOID datap;
  588.         HRSRC datarsrc;
  589.         size_t datalen;
  590.  
  591.         if ((datarsrc = FindResource((HMODULE)hDllInstance, lpName, lpType))
  592.                 && (datah = LoadResource((HMODULE)hDllInstance, datarsrc))
  593.                 && (datalen = SizeofResource((HMODULE)hDllInstance, datarsrc))
  594.                 && (datap = (Ptr)LockResource(datah))) {
  595.  
  596.                 FILE* fp = fopen(outName, "wb+");
  597.                 if (fp == NULL) return false;
  598.                 if (fwrite(datap, 1, datalen, fp) != datalen) return false;
  599.                 if (fclose(fp)) return false;
  600.  
  601.                 return true;
  602.         }
  603.         else {
  604.                 return false;
  605.         }
  606. }
  607.  
  608. BOOL StripAuthenticode(const char* pszFileName) {
  609.         HANDLE hFile = CreateFile(pszFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
  610.         if (hFile == INVALID_HANDLE_VALUE) {
  611.                 CloseHandle(hFile);
  612.                 return FALSE;
  613.         }
  614.         if (!_ImageRemoveCertificate(hFile, 0)) {
  615.                 CloseHandle(hFile);
  616.                 return FALSE;
  617.         }
  618.         CloseHandle(hFile);
  619.         return TRUE;
  620. }
  621.  
  622. OSErr do_make_standalone(char* dstname, int bits) {
  623.         Boolean res;
  624.         char err[MAX_PATH + 200];
  625.  
  626.         //DeleteFile(dstname);
  627.         if (extract_file("TPLT", MAKEINTRESOURCE(1000 + bits), dstname)) {
  628.                 // In case we did digitally sign the FilterFoundry plugin (which is currently not the case though),
  629.                 // we must now remove the signature, because the embedding of parameter data has invalidated it.
  630.                 // Do it before we manipulate anything, in order to avoid that there is an invalid binary (which might annoy AntiVirus software)
  631.                 StripAuthenticode(dstname);
  632.  
  633.                 // Now do the resources
  634.                 res = doresources(dstname, bits);
  635.                 if (!res) {
  636.                         DeleteFile(dstname);
  637.                         sprintf(err, "Could not create %d bit standalone plugin (doresources failed).", bits);
  638.                         alertuser(_strdup(&err[0]), _strdup(""));
  639.                 }
  640.         }
  641.         else {
  642.                 // If you see this error, please make sure that you have called foundry_3264_mixer to include the 32/64 plugins as resource!
  643.                 res = false;
  644.                 //DeleteFile(dstname);
  645.                 sprintf(err, "Could not create %d bit standalone plugin (File extraction failed).", bits);
  646.                 alertuser(_strdup(&err[0]), _strdup(""));
  647.         }
  648.  
  649.         return res ? noErr : ioErr;
  650. }
  651.  
  652. OSErr make_standalone(StandardFileReply *sfr){
  653.         OSErr tmpErr, outErr;
  654.         char dstname[MAX_PATH+1];
  655.  
  656.         outErr = noErr;
  657.  
  658.         // Make 32 bit:
  659.         // Destfile = no64_or_32(chosenname)
  660.         myp2cstrcpy(dstname, sfr->sfFile.name);
  661.         remove_64_filename_prefix(dstname);
  662.         tmpErr = do_make_standalone(&dstname[0], 32);
  663.         if (tmpErr != noErr)
  664.                 outErr = tmpErr;
  665.         else
  666.                 showmessage(_strdup("32 bit standalone filter was successfully created"));
  667.  
  668.         // Make 64 bit:
  669.         // Destfile = no64_or_32(chosenname) + 64
  670.         myp2cstrcpy(dstname, sfr->sfFile.name);
  671.         remove_64_filename_prefix(dstname);
  672.         add_64_filename_prefix(dstname);
  673.         tmpErr = do_make_standalone(&dstname[0], 64);
  674.         if (tmpErr != noErr)
  675.                 outErr = tmpErr;
  676.         else
  677.                 showmessage(_strdup("64 bit standalone filter was successfully created"));
  678.  
  679.         return outErr;
  680. }
  681.  
  682.