Subversion Repositories filter_foundry

Rev

Rev 380 | Rev 402 | 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
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
 
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++;
393 daniel-mar 131
        if (strlen(pparm->szAuthor) > 0) {
132
                tmp += mbstowcs(tmp, pparm->szAuthor, 100);
258 daniel-mar 133
        }
134
        else {
135
                tmp += mbstowcs(tmp, "\b", 100); // \b = remove
136
        }
137
        tmp++;
138
 
139
        tmp += mbstowcs(tmp, "LegalCopyright", 100);
140
        tmp++;
393 daniel-mar 141
        if (strlen(pparm->szCopyright) > 0) {
142
                tmp += mbstowcs(tmp, pparm->szCopyright, 100);
258 daniel-mar 143
        }
144
        else {
145
                tmp += mbstowcs(tmp, "\b", 100); // \b = remove
146
        }
147
        tmp++;
148
 
149
        tmp += mbstowcs(tmp, "FileDescription", 100);
150
        tmp++;
393 daniel-mar 151
        if (strlen(pparm->szTitle) > 0) {
152
                tmp += mbstowcs(tmp, pparm->szTitle, 100);
258 daniel-mar 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;
393 daniel-mar 181
 
280 daniel-mar 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;
393 daniel-mar 373
        char title[256];
258 daniel-mar 374
        LPCTSTR parm_type;
376 daniel-mar 375
        LPCSTR parm_id;
258 daniel-mar 376
        Boolean discard = true;
347 daniel-mar 377
        uint64_t obfuscseed = 0;
258 daniel-mar 378
        long event_id;
319 daniel-mar 379
        Boolean mustFreeSrcMod;
258 daniel-mar 380
 
345 daniel-mar 381
        memset(&dummy_oper, 0, sizeof(operdef_t));
382
        memset(&dummy_func, 0, sizeof(funcdef_t));
383
        memset(&dummy_symn, 0, sizeof(symndef_t));
384
 
319 daniel-mar 385
        if (srcmod == NULL) {
386
                srcmod = LoadLibraryEx(dstname, NULL, LOAD_LIBRARY_AS_DATAFILE);
387
                if (!srcmod) {
388
                        dbglasterror(_strdup("LoadLibraryEx"));
389
                        return false;
390
                }
391
                mustFreeSrcMod = true;
392
        }
393
        else {
394
                mustFreeSrcMod = false;
395
        }
396
 
258 daniel-mar 397
        if( (hupdate = _BeginUpdateResource(dstname,false)) ){
398
                DBG("BeginUpdateResource OK");
308 daniel-mar 399
                if( (datarsrc = FindResource(srcmod,MAKEINTRESOURCE(16000), "TPLT"))
258 daniel-mar 400
                        && (datah = LoadResource(srcmod,datarsrc))
401
                        && (datap = (Ptr)LockResource(datah))
402
                        && (aetersrc = FindResource(srcmod, MAKEINTRESOURCE(16000), "AETE"))
403
                        && (aeteh = LoadResource(srcmod, aetersrc))
404
                        && (aetep = (Ptr)LockResource(aeteh))
380 daniel-mar 405
                        && (manifestsrc = FindResource(srcmod, MAKEINTRESOURCE(1), "TPLT"))
258 daniel-mar 406
                        && (manifesth = LoadResource(srcmod, manifestsrc))
407
                        && (manifestp = (Ptr)LockResource(manifesth)) )
408
                {
324 daniel-mar 409
                        char* newmanifest;
410
                        int manifestsize = SizeofResource(srcmod, manifestsrc);
258 daniel-mar 411
 
324 daniel-mar 412
                        newmanifest = (char*)malloc(manifestsize + 4096/*+4KiB for name,description,etc.*/);
413
 
258 daniel-mar 414
                        DBG("loaded DATA, PiPL");
415
 
393 daniel-mar 416
                        strcpy(title,gdata->parm.szTitle);
258 daniel-mar 417
                        if(gdata->parm.popDialog)
393 daniel-mar 418
                                strcat(title,"...");
258 daniel-mar 419
 
420
                        origsize = SizeofResource(srcmod,datarsrc);
421
 
422
                        if( (newpipl = (Ptr)malloc(origsize+0x300))
423
                         && (newaete = (Ptr)malloc(4096))
424
                         && (pparm = (PARM_T*)malloc(sizeof(PARM_T))) )
425
                        {
426
                                // ====== Generate AETE and PIPL
427
 
428
                                /* add user-specified title and category to new PiPL */
429
                                memcpy(newpipl,datap,origsize);
430
                                /* note that Windows PiPLs have 2 byte version datum in front
431
                                   that isn't reflected in struct definition or Mac resource template: */
393 daniel-mar 432
                                piplsize = fixpipl((PIPropertyList*)(newpipl+2),origsize-2,&title[0], &event_id) + 2;
258 daniel-mar 433
 
434
                                /* set up the PARM resource with saved parameters */
435
                                memcpy(pparm,&gdata->parm,sizeof(PARM_T));
436
 
437
                                /* Generate 'aete' resource (contains names of the parameters for the "Actions" tab in Photoshop) */
438
                                aetesize = aete_generate(newaete, pparm, event_id);
439
 
324 daniel-mar 440
                                // ====== Create fitting manifest for the activation context
258 daniel-mar 441
 
324 daniel-mar 442
                                manifestp_copy = (char*)malloc(manifestsize + 1/*sz*/);
443
                                if (manifestp_copy != 0) {
444
                                        memcpy(manifestp_copy, manifestp, manifestsize); // copy manifestp to manifestp_copy, because manifestp is readonly
445
                                        manifestp_copy[manifestsize] = '\0'; // and add the null-terminating char, because domanifest() uses sprintf() on it
446
                                        manifestsize = domanifest(newmanifest, manifestp_copy, pparm, bits);
447
                                        free(manifestp_copy);
448
                                }
449
 
258 daniel-mar 450
                                // ====== Change version attributes
451
 
452
                                changeVersionInfo(dstname, pparm, hupdate);
453
 
454
                                // ====== Obfuscate pparm!
455
 
292 daniel-mar 456
                                if (gdata->obfusc) {
375 daniel-mar 457
                                        parm_type = OBFUSCDATA_TYPE_NEW;
458
                                        parm_id = OBFUSCDATA_ID_NEW;
276 daniel-mar 459
 
460
                                        // Note: After we have finished updating the resources, we will write <obfuscseed> into the binary code of the 8BF file
292 daniel-mar 461
                                        obfuscseed = obfusc(pparm);
258 daniel-mar 462
                                }else{
375 daniel-mar 463
                                        parm_type = PARM_TYPE;
464
                                        parm_id = PARM_ID_NEW;
258 daniel-mar 465
                                }
466
 
467
                                // ====== Save AETE, PIPL, Manifest and PARM/RCDATA
468
 
469
                                /* Attention: The resource we have found using FindResource() might have a different
470
                                   language than the resource we are saving (Neutral), so we might end up having
471
                                   multiple languages for the same resource. Therefore, the language "Neutral" was
472
                                   set in the Scripting.rc file for the resource AETE and PIPL.rc for the resources PIPL. */
274 daniel-mar 473
 
380 daniel-mar 474
                                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 475
                                        && _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
476
                                        && _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
477
                                        && _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
478
                                        && _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 479
//                                      && _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
308 daniel-mar 480
                                        && _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
393 daniel-mar 481
//                                      && (
482
//                                              // TODO: Sometimes, the cursors get ID 1,2,3 and somestimes 4,5,6. How to do it better?
483
//                                              // TODO: If we do this, we get "Internal error"
484
//                                              _UpdateResource(hupdate, RT_CURSOR, MAKEINTRESOURCE(3)/*QuestionHand*/, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0)
485
//                                              || _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 486
                                        && ((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 487
                                        && _UpdateResource(hupdate, "PIPL" /* note: caps!! */,MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),newpipl,(DWORD)piplsize)
258 daniel-mar 488
                                        && _UpdateResource(hupdate, "AETE" /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newaete, (DWORD)aetesize)
345 daniel-mar 489
                                        // 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.
490
                                        && (gdata->obfusc || _UpdateResource(hupdate, "OPER", MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_oper, sizeof(dummy_oper)))
491
                                        && (gdata->obfusc || _UpdateResource(hupdate, "FUNC", MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_func, sizeof(dummy_func)))
492
                                        && (gdata->obfusc || _UpdateResource(hupdate, "SYNM", MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_symn, sizeof(dummy_symn)))
258 daniel-mar 493
                                        && _UpdateResource(hupdate, RT_MANIFEST, MAKEINTRESOURCE(1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newmanifest, (DWORD)manifestsize)
376 daniel-mar 494
                                        && _UpdateResource(hupdate, parm_type,parm_id, MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),pparm,sizeof(PARM_T)) )
258 daniel-mar 495
                                {
496
                                        discard = false;
497
                                } else {
498
                                        dbglasterror(_strdup("UpdateResource"));
499
                                }
500
                        }
501
 
502
                }else dbglasterror(_strdup("Find-, Load- or LockResource"));
503
 
276 daniel-mar 504
                // Here, the file will be saved
319 daniel-mar 505
                if (mustFreeSrcMod) {
506
                        FreeLibrary(srcmod);
507
                }
508
                if (!_EndUpdateResource(hupdate, discard)) {
258 daniel-mar 509
                        dbglasterror(_strdup("EndUpdateResource"));
319 daniel-mar 510
                }
511
                else {
258 daniel-mar 512
 
319 daniel-mar 513
                        if (gdata->obfusc) {
347 daniel-mar 514
                                // We modify the binary code to replace the deobfuscate-seed from <cObfuscSeed> to <obfuscseed>
515
 
516
                                // First try with alignment "4" (this should be the usual case),
517
                                // and if that failed, try without alignment ("1").
518
                                // We only need to set maxamount to "1", because "const volatile" makes sure that
519
                                // the compiler won't place (inline) it at several locations in the code.
520
                                if ((binary_replace_file(dstname, cObfuscSeed, obfuscseed, /*align to 4*/1, /*maxamount=*/1) == 0) &&
521
                                        (binary_replace_file(dstname, cObfuscSeed, obfuscseed, /*align to 1*/0, /*maxamount=*/1) == 0))
522
                                {
319 daniel-mar 523
                                        dbg("binary_replace_file failed");
524
                                        discard = true;
525
                                }
276 daniel-mar 526
                        }
527
 
319 daniel-mar 528
                        update_pe_timestamp(dstname, time(0));
278 daniel-mar 529
 
319 daniel-mar 530
                        repair_pe_checksum(dstname);
531
                }
393 daniel-mar 532
 
258 daniel-mar 533
                if(pparm) free(pparm);
534
                if(newpipl) free(newpipl);
535
                if(newaete) free(newaete);
536
        }else
537
                dbglasterror(_strdup("BeginUpdateResource"));
538
        return !discard;
539
}
540
 
278 daniel-mar 541
Boolean remove_64_filename_prefix(char* dstname) {
274 daniel-mar 542
        // foobar.8bf => foobar.8bf
543
        // foobar64.8bf => foobar.8bf
276 daniel-mar 544
        size_t i;
274 daniel-mar 545
        for (i = strlen(dstname); i > 2; i--) {
546
                if (dstname[i] == '.') {
547
                        if ((dstname[i - 2] == '6') && (dstname[i - 1] == '4')) {
276 daniel-mar 548
                                size_t tmp = strlen(dstname);
274 daniel-mar 549
                                memcpy(&dstname[i - 2], &dstname[i], strlen(dstname) - i + 1);
550
                                dstname[tmp - 2] = 0;
551
                                return true;
552
                        }
553
                }
554
        }
555
        return false;
556
}
557
 
278 daniel-mar 558
Boolean add_64_filename_prefix(char* dstname) {
274 daniel-mar 559
        // foobar.8bf => foobar64.8bf
276 daniel-mar 560
        size_t i;
274 daniel-mar 561
        for (i = strlen(dstname); i > 2; i--) {
562
                if (dstname[i] == '.') {
276 daniel-mar 563
                        size_t tmp = strlen(dstname);
274 daniel-mar 564
                        memcpy(&dstname[i + 2], &dstname[i], strlen(dstname) - i + 1);
565
                        dstname[i] = '6';
566
                        dstname[i + 1] = '4';
567
                        dstname[tmp + 2] = 0;
568
                        return true;
569
                }
570
        }
571
        return false;
572
}
573
 
574
BOOL FileExists(LPCTSTR szPath) {
575
        DWORD dwAttrib = GetFileAttributes(szPath);
576
        return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
577
                !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
578
}
579
 
314 daniel-mar 580
Boolean extract_file(LPCTSTR lpType, LPCTSTR lpName, const char* outName) {
308 daniel-mar 581
        HGLOBAL datah;
582
        LPVOID datap;
583
        HRSRC datarsrc;
584
        size_t datalen;
585
 
586
        if ((datarsrc = FindResource((HMODULE)hDllInstance, lpName, lpType))
587
                && (datah = LoadResource((HMODULE)hDllInstance, datarsrc))
588
                && (datalen = SizeofResource((HMODULE)hDllInstance, datarsrc))
589
                && (datap = (Ptr)LockResource(datah))) {
590
 
591
                FILE* fp = fopen(outName, "wb+");
592
                if (fp == NULL) return false;
593
                if (fwrite(datap, 1, datalen, fp) != datalen) return false;
594
                if (fclose(fp)) return false;
595
 
596
                return true;
597
        }
598
        else {
599
                return false;
600
        }
601
}
602
 
357 daniel-mar 603
BOOL StripAuthenticode(const char* pszFileName) {
604
        HANDLE hFile = CreateFile(pszFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
364 daniel-mar 605
        if (hFile == INVALID_HANDLE_VALUE) {
606
                CloseHandle(hFile);
607
                return FALSE;
608
        }
609
        if (!_ImageRemoveCertificate(hFile, 0)) {
610
                CloseHandle(hFile);
611
                return FALSE;
612
        }
357 daniel-mar 613
        CloseHandle(hFile);
614
        return TRUE;
615
}
616
 
308 daniel-mar 617
OSErr do_make_standalone(char* dstname, int bits) {
274 daniel-mar 618
        Boolean res;
292 daniel-mar 619
        char err[MAX_PATH + 200];
620
 
274 daniel-mar 621
        //DeleteFile(dstname);
314 daniel-mar 622
        if (extract_file("TPLT", MAKEINTRESOURCE(1000 + bits), dstname)) {
360 daniel-mar 623
                // In case we did digitally sign the FilterFoundry plugin (which is currently not the case though),
624
                // we must now remove the signature, because the embedding of parameter data has invalidated it.
625
                // Do it before we manipulate anything, in order to avoid that there is an invalid binary (which might annoy AntiVirus software)
626
                StripAuthenticode(dstname);
627
 
628
                // Now do the resources
319 daniel-mar 629
                res = doresources(NULL, dstname, bits);
630
                if (!res) {
292 daniel-mar 631
                        DeleteFile(dstname);
319 daniel-mar 632
                        sprintf(err, "Could not create %d bit standalone plugin (doresources failed).", bits);
292 daniel-mar 633
                        alertuser(_strdup(&err[0]), _strdup(""));
274 daniel-mar 634
                }
635
        }
636
        else {
308 daniel-mar 637
                // 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 638
                res = false;
292 daniel-mar 639
                //DeleteFile(dstname);
308 daniel-mar 640
                sprintf(err, "Could not create %d bit standalone plugin (File extraction failed).", bits);
274 daniel-mar 641
                alertuser(_strdup(&err[0]), _strdup(""));
642
        }
643
 
644
        return res ? noErr : ioErr;
645
}
646
 
314 daniel-mar 647
Boolean check_unicows() {
648
        // Unicows.dll is required for Win9x to implement the BeginUpdateResource functionalities
649
 
650
        if (isWin32NT()) {
651
                // Modern Windows don't require UnicoWS
652
                return true;
653
        } else {
258 daniel-mar 654
                HMODULE hLib;
655
 
656
                hLib = LoadLibraryA("UNICOWS.DLL");
657
                if (!hLib) {
318 daniel-mar 658
                        char dstname[MAX_PATH + 1];
258 daniel-mar 659
 
314 daniel-mar 660
                        // Try to install UnicoWS automatically
318 daniel-mar 661
                        GetSystemDirectoryA(&dstname[0], MAX_PATH);
662
                        strcat(&dstname[0], "\\UNICOWS.DLL");
663
                        extract_file("DLL", "UNICOWS", &dstname[0]); // included in make_win.rc
279 daniel-mar 664
 
314 daniel-mar 665
                        hLib = LoadLibraryA("UNICOWS.DLL");
666
                        if (!hLib) {
667
                                // This should not happen
316 daniel-mar 668
                                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 669
 
314 daniel-mar 670
                                return false;
671
                        }
672
                        else {
673
                                FreeLibrary(hLib);
674
                                return true;
675
                        }
258 daniel-mar 676
                }
677
                else {
678
                        FreeLibrary(hLib);
314 daniel-mar 679
                        return true;
258 daniel-mar 680
                }
681
        }
314 daniel-mar 682
}
258 daniel-mar 683
 
314 daniel-mar 684
OSErr make_standalone(StandardFileReply *sfr){
685
        OSErr tmpErr, outErr;
686
        char dstname[MAX_PATH+1];
687
 
274 daniel-mar 688
        outErr = noErr;
314 daniel-mar 689
 
690
        check_unicows();
393 daniel-mar 691
 
308 daniel-mar 692
        // Make 32 bit:
693
        // Destfile = no64_or_32(chosenname)
274 daniel-mar 694
        myp2cstrcpy(dstname, sfr->sfFile.name);
695
        remove_64_filename_prefix(dstname);
308 daniel-mar 696
        tmpErr = do_make_standalone(&dstname[0], 32);
274 daniel-mar 697
        if (tmpErr != noErr)
698
                outErr = tmpErr;
699
        else
308 daniel-mar 700
                showmessage(_strdup("32 bit standalone filter was successfully created"));
274 daniel-mar 701
 
308 daniel-mar 702
        if (isWin32NT()) {
703
                // Make 64 bit:
704
                // Destfile = no64_or_32(chosenname) + 64
274 daniel-mar 705
                myp2cstrcpy(dstname, sfr->sfFile.name);
706
                remove_64_filename_prefix(dstname);
308 daniel-mar 707
                add_64_filename_prefix(dstname);
708
                tmpErr = do_make_standalone(&dstname[0], 64);
274 daniel-mar 709
                if (tmpErr != noErr)
710
                        outErr = tmpErr;
711
                else
308 daniel-mar 712
                        showmessage(_strdup("64 bit standalone filter was successfully created"));
277 daniel-mar 713
        }
279 daniel-mar 714
        else {
331 daniel-mar 715
                // Unicows.dll cannot edit resources of 64 bit DLLs. (Tested with UnicoWS 1.1.3790.0)
346 daniel-mar 716
                // On WinNT+, the normal Kernel function BeginUpdateResource can edit 64 bit DLLs, even in NT4.0 SP6
320 daniel-mar 717
                simplewarning(_strdup("Note: A 64 bit standalone filter cannot be created with your Windows version"));
279 daniel-mar 718
        }
274 daniel-mar 719
 
720
        return outErr;
258 daniel-mar 721
}
308 daniel-mar 722