Subversion Repositories filter_foundry

Rev

Rev 376 | Rev 393 | 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
 
274 daniel-mar 33
Boolean doresources(HMODULE srcmod,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
62
        for (i = 0; i < strlen((char*)pparm->category); i++) {
63
                char c = pparm->category[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((char*)pparm->title); i++) {
72
                char c = pparm->title[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((char*)pparm->category); i++) {
83
                char c = pparm->category[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++] = '.';
89
        for (i = 0; i < strlen((char*)pparm->title); i++) {
90
                char c = pparm->title[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
 
105
void changeVersionInfo(char* dstname, PARM_T* pparm, HGLOBAL hupdate) {
106
        char* soleFilename;
107
        LPWSTR changeRequestStr, tmp;
108
 
109
        if (soleFilename = strrchr(dstname, '\\')) {
110
                ++soleFilename;
111
        }
112
        else {
113
                soleFilename = dstname;
114
        }
115
 
116
        // Format of argument "PCWSTR changes" is "<name>\0<value>\0<name>\0<value>\0....."
117
        // You can CHANGE values for any given name
118
        // You can DELETE entries by setting the value to "\b" (0x08 backspace character)
119
        // You cannot (yet) ADD entries.
120
        changeRequestStr = (LPWSTR)malloc(6 * 2 * 100 + 1);
121
 
122
        tmp = changeRequestStr;
123
 
124
        tmp += mbstowcs(tmp, "Comments", 100);
125
        tmp++;
126
        tmp += mbstowcs(tmp, "Built using Filter Foundry " VERSION_STR, 100);
127
        tmp++;
128
 
129
        tmp += mbstowcs(tmp, "CompanyName", 100);
130
        tmp++;
131
        if (strlen((char*)pparm->author) > 0) {
132
                tmp += mbstowcs(tmp, (char*)pparm->author, 100);
133
        }
134
        else {
135
                tmp += mbstowcs(tmp, "\b", 100); // \b = remove
136
        }
137
        tmp++;
138
 
139
        tmp += mbstowcs(tmp, "LegalCopyright", 100);
140
        tmp++;
141
        if (strlen((char*)pparm->copyright) > 0) {
142
                tmp += mbstowcs(tmp, (char*)pparm->copyright, 100);
143
        }
144
        else {
145
                tmp += mbstowcs(tmp, "\b", 100); // \b = remove
146
        }
147
        tmp++;
148
 
149
        tmp += mbstowcs(tmp, "FileDescription", 100);
150
        tmp++;
151
        if (strlen((char*)pparm->title) > 0) {
152
                tmp += mbstowcs(tmp, (char*)pparm->title, 100);
153
        }
154
        else {
155
                tmp += mbstowcs(tmp, "Untitled filter", 100);
156
        }
157
        tmp++;
158
 
159
        tmp += mbstowcs(tmp, "OriginalFilename", 100);
160
        tmp++;
161
        tmp += mbstowcs(tmp, soleFilename, 100);
162
        tmp++;
163
 
164
        tmp += mbstowcs(tmp, "License", 100);
165
        tmp++;
166
        tmp += mbstowcs(tmp, "\b", 100); // \b = remove, since filter is standalone and might have its own license
167
        tmp++;
168
 
169
        tmp += mbstowcs(tmp, "", 1);
170
 
171
        if (UpdateVersionInfoWithHandle(dstname, hupdate, changeRequestStr) != NOERROR) {
315 daniel-mar 172
                simplealert(_strdup("UpdateVersionInfoWithHandle failed"));
258 daniel-mar 173
        }
174
 
175
        free(changeRequestStr);
176
}
177
 
278 daniel-mar 178
Boolean update_pe_timestamp(const char* filename, time_t timestamp) {
280 daniel-mar 179
        size_t peoffset;
180
        FILE* fptr;
181
 
182
        fptr = fopen(filename, "rb+");
278 daniel-mar 183
        if (fptr == NULL) return false;
184
 
185
        fseek(fptr, 0x3C, SEEK_SET);
186
        fread(&peoffset, sizeof(peoffset), 1, fptr);
187
 
280 daniel-mar 188
        fseek(fptr, (long)peoffset + 8, SEEK_SET);
278 daniel-mar 189
        fwrite(&timestamp, sizeof(time_t), 1, fptr);
190
 
191
        fclose(fptr);
192
 
193
        return true;
194
}
195
 
347 daniel-mar 196
int binary_replace_file(const char* filename, uint64_t search, uint64_t replace, Boolean align, int maxamount) {
197
        uint64_t srecord = 0;
276 daniel-mar 198
        int found = 0;
199
 
200
        FILE* fptr = fopen(filename, "rb+");
201
        if (fptr == NULL) return -1;
202
 
203
        while ((fread(&srecord, sizeof(srecord), 1, fptr) == 1))
204
        {
205
                if (srecord == search) {
206
                        srecord = replace;
207
                        fseek(fptr, -1*(long)sizeof(srecord), SEEK_CUR);
208
                        fwrite(&srecord, (int)sizeof(srecord), 1, fptr);
209
                        fseek(fptr, 0, SEEK_CUR); // important!
210
                        found++;
347 daniel-mar 211
                        if (found == maxamount) break;
276 daniel-mar 212
                }
213
                else {
347 daniel-mar 214
                        if (!align) {
215
                                fseek(fptr, -1*(long)(sizeof(srecord) - 1), SEEK_CUR);
216
                        }
276 daniel-mar 217
                }
218
        }
219
        fclose(fptr);
220
 
221
        return found;
222
}
223
 
281 daniel-mar 224
//DOS .EXE header
225
struct image_dos_header
226
{
227
        uint16_t e_magic;                     // Magic number
228
        uint16_t e_cblp;                      // Bytes on last page of file
229
        uint16_t e_cp;                        // Pages in file
230
        uint16_t e_crlc;                      // Relocations
231
        uint16_t e_cparhdr;                   // Size of header in paragraphs
232
        uint16_t e_minalloc;                  // Minimum extra paragraphs needed
233
        uint16_t e_maxalloc;                  // Maximum extra paragraphs needed
234
        uint16_t e_ss;                        // Initial (relative) SS value
235
        uint16_t e_sp;                        // Initial SP value
236
        uint16_t e_csum;                      // Checksum
237
        uint16_t e_ip;                        // Initial IP value
238
        uint16_t e_cs;                        // Initial (relative) CS value
239
        uint16_t e_lfarlc;                    // File address of relocation table
240
        uint16_t e_ovno;                      // Overlay number
241
        uint16_t e_res[4];                    // Reserved words
242
        uint16_t e_oemid;                     // OEM identifier (for e_oeminfo)
243
        uint16_t e_oeminfo;                   // OEM information; e_oemid specific
244
        uint16_t e_res2[10];                  // Reserved words
245
        int32_t  e_lfanew;                    // File address of new exe header
246
};
247
 
248
struct image_file_header
249
{
250
        uint16_t Machine;
251
        uint16_t NumberOfSections;
252
        uint32_t TimeDateStamp;
253
        uint32_t PointerToSymbolTable;
254
        uint32_t NumberOfSymbols;
255
        uint16_t SizeOfOptionalHeader;
256
        uint16_t Characteristics;
257
};
258
 
259
uint32_t calculate_checksum(const char* filename) {
260
        //Calculate checksum of image
261
        // Taken from "PE Bliss" Cross-Platform Portable Executable C++ Library
262
        // https://github.com/mrexodia/portable-executable-library/blob/master/pe_lib/pe_checksum.cpp
263
        // Converted from C++ to C by Daniel Marschall
264
 
265
        FILE* fptr;
266
        unsigned long long checksum = 0;
267
        struct image_dos_header header;
268
        size_t filesize;
269
        unsigned long long top;
270
        unsigned long pe_checksum_pos;
271
        static const unsigned long checksum_pos_in_optional_headers = 64;
272
        size_t i;
273
 
274
        fptr = fopen(filename, "rb");
275
        if (fptr == NULL) return 0x00000000;
276
 
277
        //Read DOS header
278
        fseek(fptr, 0, SEEK_SET);
279
        fread(&header, sizeof(struct image_dos_header), 1, fptr);
280
 
281
        //Calculate PE checksum
282
        fseek(fptr, 0, SEEK_SET);
283
        top = 0xFFFFFFFF;
284
        top++;
285
 
286
        //"CheckSum" field position in optional PE headers - it's always 64 for PE and PE+
287
        //Calculate real PE headers "CheckSum" field position
288
        //Sum is safe here
289
        pe_checksum_pos = header.e_lfanew + sizeof(struct image_file_header) + sizeof(uint32_t) + checksum_pos_in_optional_headers;
290
 
291
        //Calculate checksum for each byte of file
292
        fseek(fptr, 0L, SEEK_END);
293
        filesize = ftell(fptr);
294
        fseek(fptr, 0L, SEEK_SET);
295
        for (i = 0; i < filesize; i += 4)
296
        {
297
                unsigned long dw = 0;
298
 
299
                //Read DWORD from file
300
                fread(&dw, sizeof(dw), 1, fptr);
301
                //Skip "CheckSum" DWORD
302
                if (i == pe_checksum_pos)
303
                        continue;
304
 
305
                //Calculate checksum
306
                checksum = (checksum & 0xffffffff) + dw + (checksum >> 32);
307
                if (checksum > top)
308
                        checksum = (checksum & 0xffffffff) + (checksum >> 32);
309
        }
310
 
311
        //Finish checksum
312
        checksum = (checksum & 0xffff) + (checksum >> 16);
313
        checksum = (checksum)+(checksum >> 16);
314
        checksum = checksum & 0xffff;
315
 
316
        checksum += (unsigned long)(filesize);
317
 
318
        fclose(fptr);
319
 
320
        //Return checksum
321
        return (uint32_t)checksum;
322
}
323
 
324
Boolean repair_pe_checksum(const char* filename) {
325
        size_t peoffset;
326
        FILE* fptr;
327
 
328
        uint32_t checksum = calculate_checksum(filename);
329
        //if (checksum == 0x00000000) return false;
330
 
331
        fptr = fopen(filename, "rb+");
332
        if (fptr == NULL) return false;
333
 
334
        fseek(fptr, 0x3C, SEEK_SET);
335
        fread(&peoffset, sizeof(peoffset), 1, fptr);
336
 
337
        fseek(fptr, (long)peoffset + 88, SEEK_SET);
338
        fwrite(&checksum, sizeof(uint32_t), 1, fptr);
339
 
340
        fclose(fptr);
341
 
342
        return true;
343
}
344
 
345 daniel-mar 345
typedef struct {
346
        char funcname[8];
347
        uint16_t codelen;
348
} operdef_t;
349
 
350
typedef struct {
351
        char funcname[8];
352
        uint16_t numparams;
353
} funcdef_t;
354
 
355
typedef struct {
356
        char funcname[8];
357
        char referencename[8];
358
} symndef_t;
359
 
274 daniel-mar 360
Boolean doresources(HMODULE srcmod,char *dstname, int bits){
258 daniel-mar 361
        HRSRC datarsrc,aetersrc,manifestsrc;
362
        HGLOBAL datah,aeteh,hupdate,manifesth;
345 daniel-mar 363
 
364
        operdef_t dummy_oper;
365
        funcdef_t dummy_func;
366
        symndef_t dummy_symn;
367
 
258 daniel-mar 368
        Ptr newpipl = NULL, newaete = NULL;
369
        LPVOID datap, aetep, manifestp;
324 daniel-mar 370
        char* manifestp_copy;
258 daniel-mar 371
        PARM_T *pparm = NULL;
324 daniel-mar 372
        size_t piplsize,aetesize,origsize;
258 daniel-mar 373
        Str255 title;
374
        LPCTSTR parm_type;
376 daniel-mar 375
        int i;
376
        LPCSTR parm_id;
258 daniel-mar 377
        Boolean discard = true;
347 daniel-mar 378
        uint64_t obfuscseed = 0;
258 daniel-mar 379
        long event_id;
319 daniel-mar 380
        Boolean mustFreeSrcMod;
258 daniel-mar 381
 
345 daniel-mar 382
        memset(&dummy_oper, 0, sizeof(operdef_t));
383
        memset(&dummy_func, 0, sizeof(funcdef_t));
384
        memset(&dummy_symn, 0, sizeof(symndef_t));
385
 
319 daniel-mar 386
        if (srcmod == NULL) {
387
                srcmod = LoadLibraryEx(dstname, NULL, LOAD_LIBRARY_AS_DATAFILE);
388
                if (!srcmod) {
389
                        dbglasterror(_strdup("LoadLibraryEx"));
390
                        return false;
391
                }
392
                mustFreeSrcMod = true;
393
        }
394
        else {
395
                mustFreeSrcMod = false;
396
        }
397
 
258 daniel-mar 398
        if( (hupdate = _BeginUpdateResource(dstname,false)) ){
399
                DBG("BeginUpdateResource OK");
308 daniel-mar 400
                if( (datarsrc = FindResource(srcmod,MAKEINTRESOURCE(16000), "TPLT"))
258 daniel-mar 401
                        && (datah = LoadResource(srcmod,datarsrc))
402
                        && (datap = (Ptr)LockResource(datah))
403
                        && (aetersrc = FindResource(srcmod, MAKEINTRESOURCE(16000), "AETE"))
404
                        && (aeteh = LoadResource(srcmod, aetersrc))
405
                        && (aetep = (Ptr)LockResource(aeteh))
380 daniel-mar 406
                        && (manifestsrc = FindResource(srcmod, MAKEINTRESOURCE(1), "TPLT"))
258 daniel-mar 407
                        && (manifesth = LoadResource(srcmod, manifestsrc))
408
                        && (manifestp = (Ptr)LockResource(manifesth)) )
409
                {
324 daniel-mar 410
                        char* newmanifest;
411
                        int manifestsize = SizeofResource(srcmod, manifestsrc);
258 daniel-mar 412
 
324 daniel-mar 413
                        newmanifest = (char*)malloc(manifestsize + 4096/*+4KiB for name,description,etc.*/);
414
 
258 daniel-mar 415
                        DBG("loaded DATA, PiPL");
416
 
417
                        PLstrcpy(title,gdata->parm.title);
418
                        if(gdata->parm.popDialog)
419
                                PLstrcat(title,(StringPtr)"\003...");
420
 
421
                        origsize = SizeofResource(srcmod,datarsrc);
422
 
423
                        if( (newpipl = (Ptr)malloc(origsize+0x300))
424
                         && (newaete = (Ptr)malloc(4096))
425
                         && (pparm = (PARM_T*)malloc(sizeof(PARM_T))) )
426
                        {
427
                                // ====== Generate AETE and PIPL
428
 
429
                                /* add user-specified title and category to new PiPL */
430
                                memcpy(newpipl,datap,origsize);
431
                                /* note that Windows PiPLs have 2 byte version datum in front
432
                                   that isn't reflected in struct definition or Mac resource template: */
433
                                piplsize = fixpipl((PIPropertyList*)(newpipl+2),origsize-2,title, &event_id) + 2;
434
 
435
                                /* set up the PARM resource with saved parameters */
436
                                memcpy(pparm,&gdata->parm,sizeof(PARM_T));
437
 
438
                                /* Generate 'aete' resource (contains names of the parameters for the "Actions" tab in Photoshop) */
439
                                aetesize = aete_generate(newaete, pparm, event_id);
440
 
441
                                // ====== Change Pascal strings to C-Strings
442
 
443
                                /* convert to C strings for Windows PARM resource */
444
                                // Don't do it before aete_generate, because they need Pascal strings
445
                                myp2cstr(pparm->category);
446
                                myp2cstr(pparm->title);
447
                                myp2cstr(pparm->copyright);
448
                                myp2cstr(pparm->author);
449
                                for (i = 0; i < 4; ++i)
450
                                        myp2cstr(pparm->map[i]);
451
                                for (i = 0; i < 8; ++i)
452
                                        myp2cstr(pparm->ctl[i]);
453
 
324 daniel-mar 454
                                // ====== Create fitting manifest for the activation context
258 daniel-mar 455
 
324 daniel-mar 456
                                manifestp_copy = (char*)malloc(manifestsize + 1/*sz*/);
457
                                if (manifestp_copy != 0) {
458
                                        memcpy(manifestp_copy, manifestp, manifestsize); // copy manifestp to manifestp_copy, because manifestp is readonly
459
                                        manifestp_copy[manifestsize] = '\0'; // and add the null-terminating char, because domanifest() uses sprintf() on it
460
                                        manifestsize = domanifest(newmanifest, manifestp_copy, pparm, bits);
461
                                        free(manifestp_copy);
462
                                }
463
 
258 daniel-mar 464
                                // ====== Change version attributes
465
 
466
                                changeVersionInfo(dstname, pparm, hupdate);
467
 
468
                                // ====== Obfuscate pparm!
469
 
292 daniel-mar 470
                                if (gdata->obfusc) {
375 daniel-mar 471
                                        parm_type = OBFUSCDATA_TYPE_NEW;
472
                                        parm_id = OBFUSCDATA_ID_NEW;
276 daniel-mar 473
 
474
                                        // Note: After we have finished updating the resources, we will write <obfuscseed> into the binary code of the 8BF file
292 daniel-mar 475
                                        obfuscseed = obfusc(pparm);
258 daniel-mar 476
                                }else{
375 daniel-mar 477
                                        parm_type = PARM_TYPE;
478
                                        parm_id = PARM_ID_NEW;
258 daniel-mar 479
                                }
480
 
481
                                // ====== Save AETE, PIPL, Manifest and PARM/RCDATA
482
 
483
                                /* Attention: The resource we have found using FindResource() might have a different
484
                                   language than the resource we are saving (Neutral), so we might end up having
485
                                   multiple languages for the same resource. Therefore, the language "Neutral" was
486
                                   set in the Scripting.rc file for the resource AETE and PIPL.rc for the resources PIPL. */
274 daniel-mar 487
 
380 daniel-mar 488
                                if(_UpdateResource(hupdate, "TPLT" /* note: caps!! */, MAKEINTRESOURCE(1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0)  // clean up things we don't need in the standalone plugin
308 daniel-mar 489
                                        && _UpdateResource(hupdate, "TPLT" /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
490
                                        && _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
491
                                        && _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
492
                                        && _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
493
                                        && _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
494
                                        && _UpdateResource(hupdate, RT_GROUP_CURSOR, MAKEINTRESOURCE(IDC_FF_HAND_QUESTION), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
495
                                        && _UpdateResource(hupdate, RT_CURSOR, MAKEINTRESOURCE(6)/*QuestionHand*/, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
331 daniel-mar 496
                                        && ((bits != 32) || _UpdateResource(hupdate, "DLL", "UNICOWS", MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0)) // clean up things we don't need in the standalone plugin
308 daniel-mar 497
                                        && _UpdateResource(hupdate, "PIPL" /* note: caps!! */,MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),newpipl,(DWORD)piplsize)
258 daniel-mar 498
                                        && _UpdateResource(hupdate, "AETE" /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newaete, (DWORD)aetesize)
345 daniel-mar 499
                                        // 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.
500
                                        && (gdata->obfusc || _UpdateResource(hupdate, "OPER", MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_oper, sizeof(dummy_oper)))
501
                                        && (gdata->obfusc || _UpdateResource(hupdate, "FUNC", MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_func, sizeof(dummy_func)))
502
                                        && (gdata->obfusc || _UpdateResource(hupdate, "SYNM", MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_symn, sizeof(dummy_symn)))
258 daniel-mar 503
                                        && _UpdateResource(hupdate, RT_MANIFEST, MAKEINTRESOURCE(1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newmanifest, (DWORD)manifestsize)
376 daniel-mar 504
                                        && _UpdateResource(hupdate, parm_type,parm_id, MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),pparm,sizeof(PARM_T)) )
258 daniel-mar 505
                                {
506
                                        discard = false;
507
                                } else {
508
                                        dbglasterror(_strdup("UpdateResource"));
509
                                }
510
                        }
511
 
512
                }else dbglasterror(_strdup("Find-, Load- or LockResource"));
513
 
276 daniel-mar 514
                // Here, the file will be saved
319 daniel-mar 515
                if (mustFreeSrcMod) {
516
                        FreeLibrary(srcmod);
517
                }
518
                if (!_EndUpdateResource(hupdate, discard)) {
258 daniel-mar 519
                        dbglasterror(_strdup("EndUpdateResource"));
319 daniel-mar 520
                }
521
                else {
258 daniel-mar 522
 
319 daniel-mar 523
                        if (gdata->obfusc) {
347 daniel-mar 524
                                // We modify the binary code to replace the deobfuscate-seed from <cObfuscSeed> to <obfuscseed>
525
 
526
                                // First try with alignment "4" (this should be the usual case),
527
                                // and if that failed, try without alignment ("1").
528
                                // We only need to set maxamount to "1", because "const volatile" makes sure that
529
                                // the compiler won't place (inline) it at several locations in the code.
530
                                if ((binary_replace_file(dstname, cObfuscSeed, obfuscseed, /*align to 4*/1, /*maxamount=*/1) == 0) &&
531
                                        (binary_replace_file(dstname, cObfuscSeed, obfuscseed, /*align to 1*/0, /*maxamount=*/1) == 0))
532
                                {
319 daniel-mar 533
                                        dbg("binary_replace_file failed");
534
                                        discard = true;
535
                                }
276 daniel-mar 536
                        }
537
 
319 daniel-mar 538
                        update_pe_timestamp(dstname, time(0));
278 daniel-mar 539
 
319 daniel-mar 540
                        repair_pe_checksum(dstname);
541
                }
542
 
258 daniel-mar 543
                if(pparm) free(pparm);
544
                if(newpipl) free(newpipl);
545
                if(newaete) free(newaete);
546
        }else
547
                dbglasterror(_strdup("BeginUpdateResource"));
548
        return !discard;
549
}
550
 
278 daniel-mar 551
Boolean remove_64_filename_prefix(char* dstname) {
274 daniel-mar 552
        // foobar.8bf => foobar.8bf
553
        // foobar64.8bf => foobar.8bf
276 daniel-mar 554
        size_t i;
274 daniel-mar 555
        for (i = strlen(dstname); i > 2; i--) {
556
                if (dstname[i] == '.') {
557
                        if ((dstname[i - 2] == '6') && (dstname[i - 1] == '4')) {
276 daniel-mar 558
                                size_t tmp = strlen(dstname);
274 daniel-mar 559
                                memcpy(&dstname[i - 2], &dstname[i], strlen(dstname) - i + 1);
560
                                dstname[tmp - 2] = 0;
561
                                return true;
562
                        }
563
                }
564
        }
565
        return false;
566
}
567
 
278 daniel-mar 568
Boolean add_64_filename_prefix(char* dstname) {
274 daniel-mar 569
        // foobar.8bf => foobar64.8bf
276 daniel-mar 570
        size_t i;
274 daniel-mar 571
        for (i = strlen(dstname); i > 2; i--) {
572
                if (dstname[i] == '.') {
276 daniel-mar 573
                        size_t tmp = strlen(dstname);
274 daniel-mar 574
                        memcpy(&dstname[i + 2], &dstname[i], strlen(dstname) - i + 1);
575
                        dstname[i] = '6';
576
                        dstname[i + 1] = '4';
577
                        dstname[tmp + 2] = 0;
578
                        return true;
579
                }
580
        }
581
        return false;
582
}
583
 
584
BOOL FileExists(LPCTSTR szPath) {
585
        DWORD dwAttrib = GetFileAttributes(szPath);
586
        return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
587
                !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
588
}
589
 
314 daniel-mar 590
Boolean extract_file(LPCTSTR lpType, LPCTSTR lpName, const char* outName) {
308 daniel-mar 591
        HGLOBAL datah;
592
        LPVOID datap;
593
        HRSRC datarsrc;
594
        size_t datalen;
595
 
596
        if ((datarsrc = FindResource((HMODULE)hDllInstance, lpName, lpType))
597
                && (datah = LoadResource((HMODULE)hDllInstance, datarsrc))
598
                && (datalen = SizeofResource((HMODULE)hDllInstance, datarsrc))
599
                && (datap = (Ptr)LockResource(datah))) {
600
 
601
                FILE* fp = fopen(outName, "wb+");
602
                if (fp == NULL) return false;
603
                if (fwrite(datap, 1, datalen, fp) != datalen) return false;
604
                if (fclose(fp)) return false;
605
 
606
                return true;
607
        }
608
        else {
609
                return false;
610
        }
611
}
612
 
357 daniel-mar 613
BOOL StripAuthenticode(const char* pszFileName) {
614
        HANDLE hFile = CreateFile(pszFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
364 daniel-mar 615
        if (hFile == INVALID_HANDLE_VALUE) {
616
                CloseHandle(hFile);
617
                return FALSE;
618
        }
619
        if (!_ImageRemoveCertificate(hFile, 0)) {
620
                CloseHandle(hFile);
621
                return FALSE;
622
        }
357 daniel-mar 623
        CloseHandle(hFile);
624
        return TRUE;
625
}
626
 
308 daniel-mar 627
OSErr do_make_standalone(char* dstname, int bits) {
274 daniel-mar 628
        Boolean res;
292 daniel-mar 629
        char err[MAX_PATH + 200];
630
 
274 daniel-mar 631
        //DeleteFile(dstname);
314 daniel-mar 632
        if (extract_file("TPLT", MAKEINTRESOURCE(1000 + bits), dstname)) {
360 daniel-mar 633
                // In case we did digitally sign the FilterFoundry plugin (which is currently not the case though),
634
                // we must now remove the signature, because the embedding of parameter data has invalidated it.
635
                // Do it before we manipulate anything, in order to avoid that there is an invalid binary (which might annoy AntiVirus software)
636
                StripAuthenticode(dstname);
637
 
638
                // Now do the resources
319 daniel-mar 639
                res = doresources(NULL, dstname, bits);
640
                if (!res) {
292 daniel-mar 641
                        DeleteFile(dstname);
319 daniel-mar 642
                        sprintf(err, "Could not create %d bit standalone plugin (doresources failed).", bits);
292 daniel-mar 643
                        alertuser(_strdup(&err[0]), _strdup(""));
274 daniel-mar 644
                }
645
        }
646
        else {
308 daniel-mar 647
                // 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 648
                res = false;
292 daniel-mar 649
                //DeleteFile(dstname);
308 daniel-mar 650
                sprintf(err, "Could not create %d bit standalone plugin (File extraction failed).", bits);
274 daniel-mar 651
                alertuser(_strdup(&err[0]), _strdup(""));
652
        }
653
 
654
        return res ? noErr : ioErr;
655
}
656
 
314 daniel-mar 657
Boolean check_unicows() {
658
        // Unicows.dll is required for Win9x to implement the BeginUpdateResource functionalities
659
 
660
        if (isWin32NT()) {
661
                // Modern Windows don't require UnicoWS
662
                return true;
663
        } else {
258 daniel-mar 664
                HMODULE hLib;
665
 
666
                hLib = LoadLibraryA("UNICOWS.DLL");
667
                if (!hLib) {
318 daniel-mar 668
                        char dstname[MAX_PATH + 1];
258 daniel-mar 669
 
314 daniel-mar 670
                        // Try to install UnicoWS automatically
318 daniel-mar 671
                        GetSystemDirectoryA(&dstname[0], MAX_PATH);
672
                        strcat(&dstname[0], "\\UNICOWS.DLL");
673
                        extract_file("DLL", "UNICOWS", &dstname[0]); // included in make_win.rc
279 daniel-mar 674
 
314 daniel-mar 675
                        hLib = LoadLibraryA("UNICOWS.DLL");
676
                        if (!hLib) {
677
                                // This should not happen
316 daniel-mar 678
                                simplealert(_strdup("To build standalone plugins using this version of\nWindows, you need to install UNICOWS.DLL\n\nPlease download it from the Internet\nand place it into your system directory"));
258 daniel-mar 679
 
314 daniel-mar 680
                                return false;
681
                        }
682
                        else {
683
                                FreeLibrary(hLib);
684
                                return true;
685
                        }
258 daniel-mar 686
                }
687
                else {
688
                        FreeLibrary(hLib);
314 daniel-mar 689
                        return true;
258 daniel-mar 690
                }
691
        }
314 daniel-mar 692
}
258 daniel-mar 693
 
314 daniel-mar 694
OSErr make_standalone(StandardFileReply *sfr){
695
        OSErr tmpErr, outErr;
696
        char dstname[MAX_PATH+1];
697
 
274 daniel-mar 698
        outErr = noErr;
314 daniel-mar 699
 
700
        check_unicows();
308 daniel-mar 701
 
702
        // Make 32 bit:
703
        // Destfile = no64_or_32(chosenname)
274 daniel-mar 704
        myp2cstrcpy(dstname, sfr->sfFile.name);
705
        remove_64_filename_prefix(dstname);
308 daniel-mar 706
        tmpErr = do_make_standalone(&dstname[0], 32);
274 daniel-mar 707
        if (tmpErr != noErr)
708
                outErr = tmpErr;
709
        else
308 daniel-mar 710
                showmessage(_strdup("32 bit standalone filter was successfully created"));
274 daniel-mar 711
 
308 daniel-mar 712
        if (isWin32NT()) {
713
                // Make 64 bit:
714
                // Destfile = no64_or_32(chosenname) + 64
274 daniel-mar 715
                myp2cstrcpy(dstname, sfr->sfFile.name);
716
                remove_64_filename_prefix(dstname);
308 daniel-mar 717
                add_64_filename_prefix(dstname);
718
                tmpErr = do_make_standalone(&dstname[0], 64);
274 daniel-mar 719
                if (tmpErr != noErr)
720
                        outErr = tmpErr;
721
                else
308 daniel-mar 722
                        showmessage(_strdup("64 bit standalone filter was successfully created"));
277 daniel-mar 723
        }
279 daniel-mar 724
        else {
331 daniel-mar 725
                // Unicows.dll cannot edit resources of 64 bit DLLs. (Tested with UnicoWS 1.1.3790.0)
346 daniel-mar 726
                // On WinNT+, the normal Kernel function BeginUpdateResource can edit 64 bit DLLs, even in NT4.0 SP6
320 daniel-mar 727
                simplewarning(_strdup("Note: A 64 bit standalone filter cannot be created with your Windows version"));
279 daniel-mar 728
        }
274 daniel-mar 729
 
730
        return outErr;
258 daniel-mar 731
}
308 daniel-mar 732