Subversion Repositories filter_foundry

Rev

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