Subversion Repositories filter_foundry

Rev

Rev 293 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
292 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 <stddef.h>
22
#include <stdint.h>
23
#include <assert.h>
24
#include <time.h>
25
 
26
#include "ff.h"
27
 
28
const volatile uint32_t cObfuscV4Seed = 0x52830517; // this value will be manipulated during the building of each individual filter (see make_win.c)
29
 
30
int rand_msvcc(unsigned int* seed) {
31
        *seed = *seed * 214013L + 2531011L;
32
        return (*seed >> 16) & 0x7fff; /* Scale between 0 and RAND_MAX */
33
}
34
 
35
int rand_openwatcom(unsigned int* seed) {
36
        // https://github.com/open-watcom/open-watcom-v2/blob/master/bld/clib/math/c/rand.c
37
        *seed = *seed * 1103515245L + 12345L;
38
        return (*seed >> 16) & 0x7fff; /* Scale between 0 and RAND_MAX */
39
}
40
 
41
void _xorshift(unsigned char** p, uint32_t* x32, size_t num) {
42
        size_t i;
43
        unsigned char* x = *p;
44
        for (i = 0; i < num; i++) {
45
                // https://de.wikipedia.org/wiki/Xorshift
46
                *x32 ^= *x32 << 13;
47
                *x32 ^= *x32 >> 17;
48
                *x32 ^= *x32 << 5;
49
                *x++ ^= *x32;
50
        }
51
        *p = x;
52
}
53
 
54
int obfuscationVersion(PARM_T* pparm) {
55
        unsigned int obfusc_info = pparm->unknown2;
56
 
57
        if (obfusc_info == 0x00000000) { // 00 00 00 00
58
                // Photoshop FilterFactory default initialization
59
                // (no obfuscation)
60
                return 0;
61
        }
62
        else if (obfusc_info == 0x00000001) { // 01 00 00 00
63
                // Premiere FilterFactory default initialization
64
                // (no obfuscation)
65
                return 0;
66
        }
67
        else if (obfusc_info == 0x90E364A3) { // A3 64 E3 90
68
                // Version 1 obfuscation (Filter Foundry 1.4b8,9,10)
69
                return 1;
70
        }
71
        else if (obfusc_info == 0xE2CFCA34) { // 34 CA CF E2
72
                // Version 2 obfuscation (Filter Foundry 1.7b1)
73
                return 2;
74
        }
75
        else if (obfusc_info <= 0xFF) { // xx 00 00 00
76
                // Version 4 obfuscation (Filter Foundry 1.7.0.7)
77
                // Version 5 obfuscation (Filter Foundry 1.7.0.8)
78
                // Future: Version 6, 7, 8, ...
79
                return obfusc_info;
80
        }
81
        else {
82
                // Version 3 obfuscation (Filter Foundry 1.7.0.5)
83
                // obfusc_info is the srand() seed and is equal to the time(0) build timestamp
84
                return 3;
85
        }
86
}
87
 
88
unsigned int obfusc(PARM_T* pparm) {
89
        // Version 5 obfuscation
90
        // Introduced in Filter Foundry 1.7.0.8
91
 
92
        unsigned char* p;
93
        size_t size, seed_position;
94
        unsigned int seed, initial_seed;
95
        unsigned int obfusc_version;
96
 
97
#ifdef MAC_ENV
98
        // placing the seed in the executable code is not implemented in Mac!
99
        seed = OBFUSC_V4_DEFAULT_SEED;
100
        obfusc_version = 4; // does not feature a integrity check
101
#else
102
        seed = (unsigned int)get_parm_hash(pparm); // Attention: deobfusc() will verify that it matches!
103
        obfusc_version = 5; // does not feature a integrity check
104
#endif
105
 
106
        seed_position = offsetof(PARM_T, unknown2);
107
        size = sizeof(PARM_T);
108
        initial_seed = seed;
109
 
110
        p = (unsigned char*)pparm;
111
        _xorshift(&p, &seed, seed_position);
112
        *((unsigned int*)p) = obfusc_version;
113
        p += 4;
114
        _xorshift(&p, &seed, size - seed_position - 4);
115
 
116
        return initial_seed;
117
}
118
 
119
void deobfusc(PARM_T* pparm) {
120
        unsigned int obfusc_version;
121
        size_t size = sizeof(PARM_T);
122
 
123
        obfusc_version = obfuscationVersion(pparm);
124
 
125
        switch (obfusc_version) {
126
                case 0:
127
                        // no obfuscation
128
                        return;
129
                case 1: {
130
                        // Version 1 obfuscation (Filter Foundry 1.4b8,9,10)
131
                        // Filter built with VC++ (official release by Toby Thain)
132
 
133
                        unsigned char* p;
134
                        size_t i;
135
                        unsigned int seed;
136
 
137
                        seed = 0xdc43df3c;
138
 
139
                        for (i = size, p = (unsigned char*)pparm; i--;) {
140
                                *p++ ^= rand_msvcc(&seed);
141
                        }
142
                        break;
143
                }
144
                case 2: {
145
                        // Version 2 obfuscation (Filter Foundry 1.7b1)
146
                        // Compiler independent
147
 
148
                        unsigned char* p;
149
                        size_t i;
150
                        unsigned int seed;
151
 
152
                        seed = 0x95d4a68f;
153
 
154
                        for (i = size, p = (unsigned char*)pparm; i--;) {
155
                                seed ^= seed << 13;
156
                                seed ^= seed >> 17;
157
                                seed ^= seed << 5;
158
                                *p++ ^= seed;
159
                        }
160
                        break;
161
                }
162
                case 3: {
163
                        // Version 3 obfuscation (Filter Foundry 1.7.0.5)
164
                        // NO loading of other implementation supported, but that doesn't matter since
165
                        // obfuscation and protection is combined in Filter Factory >= 1.7.0.5.
166
                        // Using rand() is more secure, because it differs from compiler to compiler, so
167
                        // it is harder to read a protected 8BF plugin.
168
                        // Note that rand() in combination with srand() is deterministic, so it is safe
169
                        // to use it: https://stackoverflow.com/questions/55438293/does-rand-function-in-c-follows-non-determinstc-algorithm
170
                        // Note: 32-Bit FF is built using OpenWatcom (to support Win95), while 64-Bit FF is built using Microsoft Visual C++
171
 
172
                        unsigned char* p;
173
                        size_t i;
174
                        unsigned int seed;
175
                        size_t seed_position;
176
 
177
                        seed = pparm->unknown2;
178
                        seed_position = offsetof(PARM_T, unknown2); // = offsetof(PARM_T_PREMIERE, unknown1)
179
 
180
                        srand(seed);
181
                        p = (unsigned char*)pparm;
182
                        for (i = 0; i < seed_position; i++) *p++ ^= rand();
183
                        *((unsigned int*)p) = 0; // here was the seed. Fill it with 0x00000000
184
                        p += 4;
185
                        for (i = 0; i < size - seed_position - 4; i++) *p++ ^= rand();
186
                        break;
187
                }
188
                case 4:
189
                case 5: {
190
                        // Version 4 obfuscation (Filter Foundry 1.7.0.7)
191
                        // Version 5 obfuscation (Filter Foundry 1.7.0.8)
192
                        // Not compiler dependent, but individual for each build
193
                        // It is important that this code works for both x86 and x64 indepdently from the used compiler,
194
                        // otherwise, the cross-make x86/x64 won't work!
195
                        // Version 5 contains a seed requirement (checksum).
196
 
197
                        unsigned char* p;
198
                        size_t seed_position;
199
                        uint32_t seed;
200
 
201
                        seed = cObfuscV4Seed; // this value will be manipulated during the building of each individual filter (see make_win.c)
202
                        seed_position = offsetof(PARM_T, unknown2); // = offsetof(PARM_T_PREMIERE, unknown1)
203
 
204
                        p = (unsigned char*)pparm;
205
                        _xorshift(&p, &seed, seed_position);
206
                        p += 4; // obfusc info == 4
207
                        _xorshift(&p, &seed, size - seed_position - 4);
208
 
209
                        if (obfusc_version == 5) {
210
                                if ((unsigned int)get_parm_hash(pparm) != seed) {
211
                                        // Integrity check failed!
212
                                        pparm->cbSize = 0xFFFFFFFF; // invalidate!
213
                                }
214
                        }
215
 
216
                        break;
217
                }
218
                default: {
219
                        // Obfuscation version unexpected!
220
                        pparm->cbSize = 0xFFFFFFFF; // invalidate!
221
                }
222
        }
223
 
224
        if (obfusc_version >= 3) {
225
                // Filter Foundry >= 1.7.0.5 builds combines obfuscation and protection
226
                // when a standalone filter is built. Theoretically, you can un-protect a
227
                // plugin, even if it is obfuscated, just by bit-flipping the LSB of byte 0x164.
228
                // Therefore, we enforce that the plugin is protected!
229
                pparm->iProtected = 1;
230
 
231
                // Furthermore, if obfuscation 3+ failed (since the seed is individual for each 8BF file),
232
                // we still want that load_win.c is able to detect pparm->iProtected instead
233
                // of throwing the error "Incompatible obfuscation"
234
                pparm->cbSize = PARM_SIZE;
235
        }
236
}