Subversion Repositories filter_foundry

Rev

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

Rev Author Line No. Line
258 daniel-mar 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
 
278 daniel-mar 23
#include <time.h>
24
 
258 daniel-mar 25
#include "file_compat.h"
26
#include "compat_string.h"
357 daniel-mar 27
#include "compat_win.h"
258 daniel-mar 28
#include "versioninfo_modify_win.h"
29
#include "version.h"
30
 
31
extern HINSTANCE hDllInstance;
32
 
402 daniel-mar 33
Boolean doresources(char *dstname, int bits);
258 daniel-mar 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
 
324 daniel-mar 54
int domanifest(char *newmanifest, char *manifestp, PARM_T* pparm, int bits) {
258 daniel-mar 55
        char name[1024];
56
        char description[1024];
57
        size_t i;
276 daniel-mar 58
        size_t iname = 0;
258 daniel-mar 59
        int idescription = 0;
60
 
61
        // Description
393 daniel-mar 62
        for (i = 0; i < strlen(pparm->szCategory); i++) {
63
                char c = pparm->szCategory[i];
258 daniel-mar 64
                if ((c != '<') && (c != '>')) {
65
                        description[idescription++] = c;
66
                }
67
        }
68
        description[idescription++] = ' ';
69
        description[idescription++] = '-';
70
        description[idescription++] = ' ';
393 daniel-mar 71
        for (i = 0; i < strlen(pparm->szTitle); i++) {
72
                char c = pparm->szTitle[i];
258 daniel-mar 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.");
393 daniel-mar 82
        for (i = 0; i < strlen(pparm->szCategory); i++) {
83
                char c = pparm->szCategory[i];
352 daniel-mar 84
                if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9'))) {
258 daniel-mar 85
                        name[iname++] = c;
86
                }
87
        }
88
        name[iname++] = '.';
393 daniel-mar 89
        for (i = 0; i < strlen(pparm->szTitle); i++) {
90
                char c = pparm->szTitle[i];
352 daniel-mar 91
                if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9'))) {
258 daniel-mar 92
                        name[iname++] = c;
93
                }
94
        }
95
        name[iname++] = '\0';
96
 
274 daniel-mar 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
        }
258 daniel-mar 103
}
104
 
416 daniel-mar 105
ULONG changeVersionInfo(char* dstname, HANDLE hUpdate, PARM_T* pparm, int bits) {
258 daniel-mar 106
        char* soleFilename;
107
        LPWSTR changeRequestStr, tmp;
416 daniel-mar 108
        ULONG dwError = NOERROR;
109
        HRSRC hResInfo;
110
        HGLOBAL hg;
111
        ULONG size;
112
        PVOID pv;
419 daniel-mar 113
        //BOOL fDiscard = TRUE;
258 daniel-mar 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++;
393 daniel-mar 137
        if (strlen(pparm->szAuthor) > 0) {
138
                tmp += mbstowcs(tmp, pparm->szAuthor, 100);
258 daniel-mar 139
        }
140
        else {
141
                tmp += mbstowcs(tmp, "\b", 100); // \b = remove
142
        }
143
        tmp++;
144
 
145
        tmp += mbstowcs(tmp, "LegalCopyright", 100);
146
        tmp++;
393 daniel-mar 147
        if (strlen(pparm->szCopyright) > 0) {
148
                tmp += mbstowcs(tmp, pparm->szCopyright, 100);
258 daniel-mar 149
        }
150
        else {
151
                tmp += mbstowcs(tmp, "\b", 100); // \b = remove
152
        }
153
        tmp++;
154
 
155
        tmp += mbstowcs(tmp, "FileDescription", 100);
156
        tmp++;
393 daniel-mar 157
        if (strlen(pparm->szTitle) > 0) {
158
                tmp += mbstowcs(tmp, pparm->szTitle, 100);
258 daniel-mar 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
 
416 daniel-mar 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
                                                {
419 daniel-mar 189
                                                        //fDiscard = FALSE;
416 daniel-mar 190
                                                }
419 daniel-mar 191
                                                else {
192
                                                        //dwError = GetLastError();
193
                                                }
416 daniel-mar 194
                                        }
419 daniel-mar 195
                                        LocalFree(pv);
416 daniel-mar 196
                                }
197
                        }
198
                }
258 daniel-mar 199
        }
200
 
201
        free(changeRequestStr);
416 daniel-mar 202
 
203
        return dwError;
258 daniel-mar 204
}
205
 
278 daniel-mar 206
Boolean update_pe_timestamp(const char* filename, time_t timestamp) {
280 daniel-mar 207
        size_t peoffset;
208
        FILE* fptr;
393 daniel-mar 209
 
280 daniel-mar 210
        fptr = fopen(filename, "rb+");
278 daniel-mar 211
        if (fptr == NULL) return false;
212
 
213
        fseek(fptr, 0x3C, SEEK_SET);
214
        fread(&peoffset, sizeof(peoffset), 1, fptr);
215
 
280 daniel-mar 216
        fseek(fptr, (long)peoffset + 8, SEEK_SET);
278 daniel-mar 217
        fwrite(&timestamp, sizeof(time_t), 1, fptr);
218
 
219
        fclose(fptr);
220
 
221
        return true;
222
}
223
 
347 daniel-mar 224
int binary_replace_file(const char* filename, uint64_t search, uint64_t replace, Boolean align, int maxamount) {
225
        uint64_t srecord = 0;
276 daniel-mar 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++;
347 daniel-mar 239
                        if (found == maxamount) break;
276 daniel-mar 240
                }
241
                else {
347 daniel-mar 242
                        if (!align) {
243
                                fseek(fptr, -1*(long)(sizeof(srecord) - 1), SEEK_CUR);
244
                        }
276 daniel-mar 245
                }
246
        }
247
        fclose(fptr);
248
 
249
        return found;
250
}
251
 
281 daniel-mar 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
 
345 daniel-mar 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
 
402 daniel-mar 388
Boolean doresources(char *dstname, int bits){
258 daniel-mar 389
        HRSRC datarsrc,aetersrc,manifestsrc;
390
        HGLOBAL datah,aeteh,hupdate,manifesth;
345 daniel-mar 391
 
392
        operdef_t dummy_oper;
393
        funcdef_t dummy_func;
394
        symndef_t dummy_symn;
395
 
258 daniel-mar 396
        Ptr newpipl = NULL, newaete = NULL;
397
        LPVOID datap, aetep, manifestp;
324 daniel-mar 398
        char* manifestp_copy;
258 daniel-mar 399
        PARM_T *pparm = NULL;
324 daniel-mar 400
        size_t piplsize,aetesize,origsize;
393 daniel-mar 401
        char title[256];
258 daniel-mar 402
        LPCTSTR parm_type;
376 daniel-mar 403
        LPCSTR parm_id;
258 daniel-mar 404
        Boolean discard = true;
347 daniel-mar 405
        uint64_t obfuscseed = 0;
258 daniel-mar 406
        long event_id;
407
 
345 daniel-mar 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
 
258 daniel-mar 412
        if( (hupdate = _BeginUpdateResource(dstname,false)) ){
413
                DBG("BeginUpdateResource OK");
402 daniel-mar 414
                if( (datarsrc = FindResource(hDllInstance,MAKEINTRESOURCE(16000 + bits), "TPLT"))
415
                        && (datah = LoadResource(hDllInstance,datarsrc))
258 daniel-mar 416
                        && (datap = (Ptr)LockResource(datah))
402 daniel-mar 417
                        && (aetersrc = FindResource(hDllInstance, MAKEINTRESOURCE(16000), "AETE"))
418
                        && (aeteh = LoadResource(hDllInstance, aetersrc))
258 daniel-mar 419
                        && (aetep = (Ptr)LockResource(aeteh))
402 daniel-mar 420
                        && (manifestsrc = FindResource(hDllInstance, MAKEINTRESOURCE(1), "TPLT"))
421
                        && (manifesth = LoadResource(hDllInstance, manifestsrc))
258 daniel-mar 422
                        && (manifestp = (Ptr)LockResource(manifesth)) )
423
                {
324 daniel-mar 424
                        char* newmanifest;
402 daniel-mar 425
                        int manifestsize = SizeofResource(hDllInstance, manifestsrc);
258 daniel-mar 426
 
324 daniel-mar 427
                        newmanifest = (char*)malloc(manifestsize + 4096/*+4KiB for name,description,etc.*/);
428
 
258 daniel-mar 429
                        DBG("loaded DATA, PiPL");
430
 
393 daniel-mar 431
                        strcpy(title,gdata->parm.szTitle);
258 daniel-mar 432
                        if(gdata->parm.popDialog)
393 daniel-mar 433
                                strcat(title,"...");
258 daniel-mar 434
 
402 daniel-mar 435
                        origsize = SizeofResource(hDllInstance,datarsrc);
258 daniel-mar 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: */
393 daniel-mar 447
                                piplsize = fixpipl((PIPropertyList*)(newpipl+2),origsize-2,&title[0], &event_id) + 2;
258 daniel-mar 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
 
324 daniel-mar 455
                                // ====== Create fitting manifest for the activation context
258 daniel-mar 456
 
324 daniel-mar 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
 
258 daniel-mar 465
                                // ====== Change version attributes
466
 
416 daniel-mar 467
                                if (changeVersionInfo(dstname, hupdate, pparm, bits) != NOERROR) {
468
                                        simplealert(_strdup("changeVersionInfo failed"));
469
                                }
258 daniel-mar 470
 
471
                                // ====== Obfuscate pparm!
472
 
292 daniel-mar 473
                                if (gdata->obfusc) {
375 daniel-mar 474
                                        parm_type = OBFUSCDATA_TYPE_NEW;
475
                                        parm_id = OBFUSCDATA_ID_NEW;
276 daniel-mar 476
 
477
                                        // Note: After we have finished updating the resources, we will write <obfuscseed> into the binary code of the 8BF file
292 daniel-mar 478
                                        obfuscseed = obfusc(pparm);
258 daniel-mar 479
                                }else{
375 daniel-mar 480
                                        parm_type = PARM_TYPE;
481
                                        parm_id = PARM_ID_NEW;
258 daniel-mar 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. */
274 daniel-mar 490
 
416 daniel-mar 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
308 daniel-mar 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
393 daniel-mar 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
402 daniel-mar 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
308 daniel-mar 499
                                        && _UpdateResource(hupdate, "PIPL" /* note: caps!! */,MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),newpipl,(DWORD)piplsize)
258 daniel-mar 500
                                        && _UpdateResource(hupdate, "AETE" /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newaete, (DWORD)aetesize)
345 daniel-mar 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)))
258 daniel-mar 505
                                        && _UpdateResource(hupdate, RT_MANIFEST, MAKEINTRESOURCE(1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newmanifest, (DWORD)manifestsize)
376 daniel-mar 506
                                        && _UpdateResource(hupdate, parm_type,parm_id, MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),pparm,sizeof(PARM_T)) )
258 daniel-mar 507
                                {
508
                                        discard = false;
509
                                } else {
510
                                        dbglasterror(_strdup("UpdateResource"));
511
                                }
512
                        }
513
 
416 daniel-mar 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>
258 daniel-mar 518
 
416 daniel-mar 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
                                }
258 daniel-mar 530
 
416 daniel-mar 531
                                update_pe_timestamp(dstname, time(0));
347 daniel-mar 532
 
416 daniel-mar 533
                                repair_pe_checksum(dstname);
534
                        }else dbglasterror(_strdup("EndUpdateResource"));
276 daniel-mar 535
 
416 daniel-mar 536
                }else dbglasterror(_strdup("Find-, Load- or LockResource"));
278 daniel-mar 537
 
258 daniel-mar 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
 
278 daniel-mar 546
Boolean remove_64_filename_prefix(char* dstname) {
274 daniel-mar 547
        // foobar.8bf => foobar.8bf
548
        // foobar64.8bf => foobar.8bf
276 daniel-mar 549
        size_t i;
274 daniel-mar 550
        for (i = strlen(dstname); i > 2; i--) {
551
                if (dstname[i] == '.') {
552
                        if ((dstname[i - 2] == '6') && (dstname[i - 1] == '4')) {
276 daniel-mar 553
                                size_t tmp = strlen(dstname);
274 daniel-mar 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
 
278 daniel-mar 563
Boolean add_64_filename_prefix(char* dstname) {
274 daniel-mar 564
        // foobar.8bf => foobar64.8bf
276 daniel-mar 565
        size_t i;
274 daniel-mar 566
        for (i = strlen(dstname); i > 2; i--) {
567
                if (dstname[i] == '.') {
276 daniel-mar 568
                        size_t tmp = strlen(dstname);
274 daniel-mar 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
 
314 daniel-mar 585
Boolean extract_file(LPCTSTR lpType, LPCTSTR lpName, const char* outName) {
308 daniel-mar 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
 
357 daniel-mar 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);
364 daniel-mar 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
        }
357 daniel-mar 618
        CloseHandle(hFile);
619
        return TRUE;
620
}
621
 
308 daniel-mar 622
OSErr do_make_standalone(char* dstname, int bits) {
274 daniel-mar 623
        Boolean res;
292 daniel-mar 624
        char err[MAX_PATH + 200];
625
 
274 daniel-mar 626
        //DeleteFile(dstname);
314 daniel-mar 627
        if (extract_file("TPLT", MAKEINTRESOURCE(1000 + bits), dstname)) {
360 daniel-mar 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
402 daniel-mar 634
                res = doresources(dstname, bits);
319 daniel-mar 635
                if (!res) {
292 daniel-mar 636
                        DeleteFile(dstname);
319 daniel-mar 637
                        sprintf(err, "Could not create %d bit standalone plugin (doresources failed).", bits);
292 daniel-mar 638
                        alertuser(_strdup(&err[0]), _strdup(""));
274 daniel-mar 639
                }
640
        }
641
        else {
308 daniel-mar 642
                // If you see this error, please make sure that you have called foundry_3264_mixer to include the 32/64 plugins as resource!
274 daniel-mar 643
                res = false;
292 daniel-mar 644
                //DeleteFile(dstname);
308 daniel-mar 645
                sprintf(err, "Could not create %d bit standalone plugin (File extraction failed).", bits);
274 daniel-mar 646
                alertuser(_strdup(&err[0]), _strdup(""));
647
        }
648
 
649
        return res ? noErr : ioErr;
650
}
651
 
314 daniel-mar 652
OSErr make_standalone(StandardFileReply *sfr){
653
        OSErr tmpErr, outErr;
654
        char dstname[MAX_PATH+1];
655
 
274 daniel-mar 656
        outErr = noErr;
314 daniel-mar 657
 
308 daniel-mar 658
        // Make 32 bit:
659
        // Destfile = no64_or_32(chosenname)
274 daniel-mar 660
        myp2cstrcpy(dstname, sfr->sfFile.name);
661
        remove_64_filename_prefix(dstname);
308 daniel-mar 662
        tmpErr = do_make_standalone(&dstname[0], 32);
274 daniel-mar 663
        if (tmpErr != noErr)
664
                outErr = tmpErr;
665
        else
308 daniel-mar 666
                showmessage(_strdup("32 bit standalone filter was successfully created"));
274 daniel-mar 667
 
402 daniel-mar 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"));
274 daniel-mar 678
 
679
        return outErr;
258 daniel-mar 680
}
308 daniel-mar 681