Subversion Repositories filter_foundry

Rev

Rev 508 | Rev 510 | Go to most recent revision | Details | Compare with Previous | 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
503 daniel-mar 4
    Copyright (C) 2018-2022 Daniel Marschall, ViaThinkSoft
292 daniel-mar 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
 
24
#include "ff.h"
25
 
506 daniel-mar 26
// Random seed for obfuscation "17 05 83 52 2a 97 16 74"
27
// During the standalone-make process, this value will be changed by manipulating the 8BF file.
28
// Therefore, the 32/64 bit 8BF files *MUST* contain the key contiguous and preferrpreferablyibly 4-aligned
29
// Why do I use GetObfuscSeed?
30
// 1. Because I prefer the key in side code segment so that it is better hidden than if it was in a data segment.
31
// 2. Since the code segment is closer to the 8BF file start, the search+replace of the key is faster
32
// Please also note:
33
// The 8BF file *MUST* only contain the seed A SINGLE TIME
34
// (In the Non-Standalone filter actually 3 times, because we have 2 resourced containing the 32/64 template DLLs)
35
#if defined(__WATCOMC__)
36
        uint64_t GetObfuscSeed() {
37
                // Due to "volatile", this value will only exist a single time in the binary file.
38
                // This char array will result in contiguous chars in OpenWatcom.
39
                // In MSVC++, the array will be built using several "mov ..." OP codes.
40
                volatile char seed[8] = { '\x17', '\x05', '\x83', '\x52', '\x2a', '\x97', '\x16', '\x74' };
41
                return (uint64_t)seed;
42
        }
43
#elif defined(_MSC_VER)
44
        #ifdef _WIN64
45
        // Note: For MSVCC 64-bit, neither making the method volatile, nor including a volatile variable did avoid inlining.
46
        // so we use __declspec(noinline)
47
        __declspec(noinline) uint64_t GetObfuscSeed() {
48
                // TODO: Not 4-byte aligned! (both variants)
49
                //volatile uint64_t seed = 0x7416972a52830517ull;
50
                //return seed;
51
                return 0x7416972a52830517ull;
52
        }
53
        #else
54
        __declspec(noinline) uint64_t GetObfuscSeed() {
55
                //volatile int test = 0;
56
                uint64_t* addr = NULL;
57
                __asm {
58
                        mov eax, seed // Doesn't work in OpenWatcom
59
                        mov addr, eax
60
                        jmp end
61
                        align 4 // Doesn't work in OpenWatcom
62
                        seed:
63
                                _emit 0x17 // Doesn't work in OpenWatcom
64
                                _emit 0x05
65
                                _emit 0x83
66
                                _emit 0x52
67
                                _emit 0x2A
68
                                _emit 0x97
69
                                _emit 0x16
70
                                _emit 0x74
71
                                /*
72
                                pop ss
73
                                add eax, 0x972a5283
74
                                push ss
75
                                jz seed
76
                                */
77
                        end:
78
                }
79
                return addr == NULL ? 0 : *addr;
80
        }
81
        #endif
82
#else
83
        // Unfortunately, with this compiler, we the value needs to be in the .data segment...
84
        // Due to "const volatile", this value will only exist a single time in the binary file.
508 daniel-mar 85
        const volatile uint64_t obfusc_seed = 0x7416972a52830517ull;
506 daniel-mar 86
        uint64_t GetObfuscSeed() {
508 daniel-mar 87
                return obfusc_seed;
506 daniel-mar 88
        }
89
#endif
292 daniel-mar 90
 
508 daniel-mar 91
// Random seed #2 for obfuscation "86 21 1f 3e f1 a2 87 ef"
92
// Lies in the data segment. Same rules like for the random seed #1.
93
const volatile uint64_t obfusc_seed2 = 0xef87a2f13e1f2186ull;
94
#ifdef _MSC_VER
95
__declspec(noinline)
96
#endif
97
uint64_t GetObfuscSeed2() {
98
        // Additional seed for Obfusc V7. It is always in the data segment,
99
        // while obfusc seed 1 is in the code segment (if the compiler allows it)
100
        return obfusc_seed2;
101
}
102
 
292 daniel-mar 103
int rand_msvcc(unsigned int* seed) {
104
        *seed = *seed * 214013L + 2531011L;
105
        return (*seed >> 16) & 0x7fff; /* Scale between 0 and RAND_MAX */
106
}
107
 
108
int rand_openwatcom(unsigned int* seed) {
109
        // https://github.com/open-watcom/open-watcom-v2/blob/master/bld/clib/math/c/rand.c
110
        *seed = *seed * 1103515245L + 12345L;
111
        return (*seed >> 16) & 0x7fff; /* Scale between 0 and RAND_MAX */
112
}
113
 
293 daniel-mar 114
void xorshift(unsigned char** p, uint32_t* x32, size_t num) {
292 daniel-mar 115
        size_t i;
116
        unsigned char* x = *p;
117
        for (i = 0; i < num; i++) {
118
                // https://de.wikipedia.org/wiki/Xorshift
119
                *x32 ^= *x32 << 13;
120
                *x32 ^= *x32 >> 17;
121
                *x32 ^= *x32 << 5;
122
                *x++ ^= *x32;
123
        }
124
        *p = x;
125
}
126
 
508 daniel-mar 127
void xorshift64(unsigned char** p, uint64_t* x64, size_t num) {
128
        // https://de.wikipedia.org/wiki/Xorshift
129
        size_t i;
130
        unsigned char* x = *p;
131
        for (i = 0; i < num; i++) {
132
                *x64 ^= *x64 << 13;
133
                *x64 ^= *x64 >> 7;
134
                *x64 ^= *x64 << 17;
135
                *x++ ^= *x64;
136
        }
137
        *p = x;
138
}
139
 
348 daniel-mar 140
#ifndef CHAR_BIT
141
#define CHAR_BIT 8
142
#endif
143
 
144
uint64_t rol_u64(uint64_t value, uint64_t by) {
509 daniel-mar 145
        return value << by | value >> ((uint64_t)sizeof(uint64_t) * CHAR_BIT - by);
348 daniel-mar 146
}
147
 
148
void rolshift(unsigned char** p, uint64_t* x64, size_t num) {
149
        size_t i;
150
        unsigned char* x = *p;
151
        for (i = 0; i < num; i++) {
152
                *x++ ^= *x64;
153
                *x64 = rol_u64(*x64, 1);
154
        }
155
        *p = x;
156
}
157
 
311 daniel-mar 158
uint32_t crc32b(char *data, int nLength) {
159
        int i, j, k;
318 daniel-mar 160
        uint32_t crc, mask;
161
        char byte;
311 daniel-mar 162
 
163
        i = 0;
164
        crc = 0xFFFFFFFF;
165
 
166
        for(k=0;k<nLength;k++) {
167
                byte = data[k];
168
                crc = crc ^ byte;
169
                for (j = 7; j >= 0; j--) {
318 daniel-mar 170
                        mask = (-1) * (crc & 1);
311 daniel-mar 171
                        crc = (crc >> 1) ^ (0xEDB88320 & mask);
172
                }
173
                i++;
174
        }
175
        return ~crc;
176
}
177
 
349 daniel-mar 178
static const uint64_t crc64_tab[256] = {
179
        0x0000000000000000ULL, 0x42F0E1EBA9EA3693ULL, 0x85E1C3D753D46D26ULL,
180
        0xC711223CFA3E5BB5ULL, 0x493366450E42ECDFULL, 0x0BC387AEA7A8DA4CULL,
181
        0xCCD2A5925D9681F9ULL, 0x8E224479F47CB76AULL, 0x9266CC8A1C85D9BEULL,
182
        0xD0962D61B56FEF2DULL, 0x17870F5D4F51B498ULL, 0x5577EEB6E6BB820BULL,
183
        0xDB55AACF12C73561ULL, 0x99A54B24BB2D03F2ULL, 0x5EB4691841135847ULL,
184
        0x1C4488F3E8F96ED4ULL, 0x663D78FF90E185EFULL, 0x24CD9914390BB37CULL,
185
        0xE3DCBB28C335E8C9ULL, 0xA12C5AC36ADFDE5AULL, 0x2F0E1EBA9EA36930ULL,
186
        0x6DFEFF5137495FA3ULL, 0xAAEFDD6DCD770416ULL, 0xE81F3C86649D3285ULL,
187
        0xF45BB4758C645C51ULL, 0xB6AB559E258E6AC2ULL, 0x71BA77A2DFB03177ULL,
188
        0x334A9649765A07E4ULL, 0xBD68D2308226B08EULL, 0xFF9833DB2BCC861DULL,
189
        0x388911E7D1F2DDA8ULL, 0x7A79F00C7818EB3BULL, 0xCC7AF1FF21C30BDEULL,
190
        0x8E8A101488293D4DULL, 0x499B3228721766F8ULL, 0x0B6BD3C3DBFD506BULL,
191
        0x854997BA2F81E701ULL, 0xC7B97651866BD192ULL, 0x00A8546D7C558A27ULL,
192
        0x4258B586D5BFBCB4ULL, 0x5E1C3D753D46D260ULL, 0x1CECDC9E94ACE4F3ULL,
193
        0xDBFDFEA26E92BF46ULL, 0x990D1F49C77889D5ULL, 0x172F5B3033043EBFULL,
194
        0x55DFBADB9AEE082CULL, 0x92CE98E760D05399ULL, 0xD03E790CC93A650AULL,
195
        0xAA478900B1228E31ULL, 0xE8B768EB18C8B8A2ULL, 0x2FA64AD7E2F6E317ULL,
196
        0x6D56AB3C4B1CD584ULL, 0xE374EF45BF6062EEULL, 0xA1840EAE168A547DULL,
197
        0x66952C92ECB40FC8ULL, 0x2465CD79455E395BULL, 0x3821458AADA7578FULL,
198
        0x7AD1A461044D611CULL, 0xBDC0865DFE733AA9ULL, 0xFF3067B657990C3AULL,
199
        0x711223CFA3E5BB50ULL, 0x33E2C2240A0F8DC3ULL, 0xF4F3E018F031D676ULL,
200
        0xB60301F359DBE0E5ULL, 0xDA050215EA6C212FULL, 0x98F5E3FE438617BCULL,
201
        0x5FE4C1C2B9B84C09ULL, 0x1D14202910527A9AULL, 0x93366450E42ECDF0ULL,
202
        0xD1C685BB4DC4FB63ULL, 0x16D7A787B7FAA0D6ULL, 0x5427466C1E109645ULL,
203
        0x4863CE9FF6E9F891ULL, 0x0A932F745F03CE02ULL, 0xCD820D48A53D95B7ULL,
204
        0x8F72ECA30CD7A324ULL, 0x0150A8DAF8AB144EULL, 0x43A04931514122DDULL,
205
        0x84B16B0DAB7F7968ULL, 0xC6418AE602954FFBULL, 0xBC387AEA7A8DA4C0ULL,
206
        0xFEC89B01D3679253ULL, 0x39D9B93D2959C9E6ULL, 0x7B2958D680B3FF75ULL,
207
        0xF50B1CAF74CF481FULL, 0xB7FBFD44DD257E8CULL, 0x70EADF78271B2539ULL,
208
        0x321A3E938EF113AAULL, 0x2E5EB66066087D7EULL, 0x6CAE578BCFE24BEDULL,
209
        0xABBF75B735DC1058ULL, 0xE94F945C9C3626CBULL, 0x676DD025684A91A1ULL,
210
        0x259D31CEC1A0A732ULL, 0xE28C13F23B9EFC87ULL, 0xA07CF2199274CA14ULL,
211
        0x167FF3EACBAF2AF1ULL, 0x548F120162451C62ULL, 0x939E303D987B47D7ULL,
212
        0xD16ED1D631917144ULL, 0x5F4C95AFC5EDC62EULL, 0x1DBC74446C07F0BDULL,
213
        0xDAAD56789639AB08ULL, 0x985DB7933FD39D9BULL, 0x84193F60D72AF34FULL,
214
        0xC6E9DE8B7EC0C5DCULL, 0x01F8FCB784FE9E69ULL, 0x43081D5C2D14A8FAULL,
215
        0xCD2A5925D9681F90ULL, 0x8FDAB8CE70822903ULL, 0x48CB9AF28ABC72B6ULL,
216
        0x0A3B7B1923564425ULL, 0x70428B155B4EAF1EULL, 0x32B26AFEF2A4998DULL,
217
        0xF5A348C2089AC238ULL, 0xB753A929A170F4ABULL, 0x3971ED50550C43C1ULL,
218
        0x7B810CBBFCE67552ULL, 0xBC902E8706D82EE7ULL, 0xFE60CF6CAF321874ULL,
219
        0xE224479F47CB76A0ULL, 0xA0D4A674EE214033ULL, 0x67C58448141F1B86ULL,
220
        0x253565A3BDF52D15ULL, 0xAB1721DA49899A7FULL, 0xE9E7C031E063ACECULL,
221
        0x2EF6E20D1A5DF759ULL, 0x6C0603E6B3B7C1CAULL, 0xF6FAE5C07D3274CDULL,
222
        0xB40A042BD4D8425EULL, 0x731B26172EE619EBULL, 0x31EBC7FC870C2F78ULL,
223
        0xBFC9838573709812ULL, 0xFD39626EDA9AAE81ULL, 0x3A28405220A4F534ULL,
224
        0x78D8A1B9894EC3A7ULL, 0x649C294A61B7AD73ULL, 0x266CC8A1C85D9BE0ULL,
225
        0xE17DEA9D3263C055ULL, 0xA38D0B769B89F6C6ULL, 0x2DAF4F0F6FF541ACULL,
226
        0x6F5FAEE4C61F773FULL, 0xA84E8CD83C212C8AULL, 0xEABE6D3395CB1A19ULL,
227
        0x90C79D3FEDD3F122ULL, 0xD2377CD44439C7B1ULL, 0x15265EE8BE079C04ULL,
228
        0x57D6BF0317EDAA97ULL, 0xD9F4FB7AE3911DFDULL, 0x9B041A914A7B2B6EULL,
229
        0x5C1538ADB04570DBULL, 0x1EE5D94619AF4648ULL, 0x02A151B5F156289CULL,
230
        0x4051B05E58BC1E0FULL, 0x87409262A28245BAULL, 0xC5B073890B687329ULL,
231
        0x4B9237F0FF14C443ULL, 0x0962D61B56FEF2D0ULL, 0xCE73F427ACC0A965ULL,
232
        0x8C8315CC052A9FF6ULL, 0x3A80143F5CF17F13ULL, 0x7870F5D4F51B4980ULL,
233
        0xBF61D7E80F251235ULL, 0xFD913603A6CF24A6ULL, 0x73B3727A52B393CCULL,
234
        0x31439391FB59A55FULL, 0xF652B1AD0167FEEAULL, 0xB4A25046A88DC879ULL,
235
        0xA8E6D8B54074A6ADULL, 0xEA16395EE99E903EULL, 0x2D071B6213A0CB8BULL,
236
        0x6FF7FA89BA4AFD18ULL, 0xE1D5BEF04E364A72ULL, 0xA3255F1BE7DC7CE1ULL,
237
        0x64347D271DE22754ULL, 0x26C49CCCB40811C7ULL, 0x5CBD6CC0CC10FAFCULL,
238
        0x1E4D8D2B65FACC6FULL, 0xD95CAF179FC497DAULL, 0x9BAC4EFC362EA149ULL,
239
        0x158E0A85C2521623ULL, 0x577EEB6E6BB820B0ULL, 0x906FC95291867B05ULL,
240
        0xD29F28B9386C4D96ULL, 0xCEDBA04AD0952342ULL, 0x8C2B41A1797F15D1ULL,
241
        0x4B3A639D83414E64ULL, 0x09CA82762AAB78F7ULL, 0x87E8C60FDED7CF9DULL,
242
        0xC51827E4773DF90EULL, 0x020905D88D03A2BBULL, 0x40F9E43324E99428ULL,
243
        0x2CFFE7D5975E55E2ULL, 0x6E0F063E3EB46371ULL, 0xA91E2402C48A38C4ULL,
244
        0xEBEEC5E96D600E57ULL, 0x65CC8190991CB93DULL, 0x273C607B30F68FAEULL,
245
        0xE02D4247CAC8D41BULL, 0xA2DDA3AC6322E288ULL, 0xBE992B5F8BDB8C5CULL,
246
        0xFC69CAB42231BACFULL, 0x3B78E888D80FE17AULL, 0x7988096371E5D7E9ULL,
247
        0xF7AA4D1A85996083ULL, 0xB55AACF12C735610ULL, 0x724B8ECDD64D0DA5ULL,
248
        0x30BB6F267FA73B36ULL, 0x4AC29F2A07BFD00DULL, 0x08327EC1AE55E69EULL,
249
        0xCF235CFD546BBD2BULL, 0x8DD3BD16FD818BB8ULL, 0x03F1F96F09FD3CD2ULL,
250
        0x41011884A0170A41ULL, 0x86103AB85A2951F4ULL, 0xC4E0DB53F3C36767ULL,
251
        0xD8A453A01B3A09B3ULL, 0x9A54B24BB2D03F20ULL, 0x5D45907748EE6495ULL,
252
        0x1FB5719CE1045206ULL, 0x919735E51578E56CULL, 0xD367D40EBC92D3FFULL,
253
        0x1476F63246AC884AULL, 0x568617D9EF46BED9ULL, 0xE085162AB69D5E3CULL,
254
        0xA275F7C11F7768AFULL, 0x6564D5FDE549331AULL, 0x279434164CA30589ULL,
255
        0xA9B6706FB8DFB2E3ULL, 0xEB46918411358470ULL, 0x2C57B3B8EB0BDFC5ULL,
256
        0x6EA7525342E1E956ULL, 0x72E3DAA0AA188782ULL, 0x30133B4B03F2B111ULL,
257
        0xF7021977F9CCEAA4ULL, 0xB5F2F89C5026DC37ULL, 0x3BD0BCE5A45A6B5DULL,
258
        0x79205D0E0DB05DCEULL, 0xBE317F32F78E067BULL, 0xFCC19ED95E6430E8ULL,
259
        0x86B86ED5267CDBD3ULL, 0xC4488F3E8F96ED40ULL, 0x0359AD0275A8B6F5ULL,
260
        0x41A94CE9DC428066ULL, 0xCF8B0890283E370CULL, 0x8D7BE97B81D4019FULL,
261
        0x4A6ACB477BEA5A2AULL, 0x089A2AACD2006CB9ULL, 0x14DEA25F3AF9026DULL,
262
        0x562E43B4931334FEULL, 0x913F6188692D6F4BULL, 0xD3CF8063C0C759D8ULL,
263
        0x5DEDC41A34BBEEB2ULL, 0x1F1D25F19D51D821ULL, 0xD80C07CD676F8394ULL,
264
        0x9AFCE626CE85B507ULL
265
};
266
 
267
/*
268
 * ECMA 182 CRC64, taken from https://searchcode.com/file/68313281/lib/crc64.c/
269
 */
270
uint64_t crc64(const unsigned char* data, size_t len)
271
{
272
        uint64_t crc = 0;
273
 
274
        while (len--) {
275
                int i = ((int)(crc >> 56) ^ *data++) & 0xFF;
276
                crc = crc64_tab[i] ^ (crc << 8);
277
        }
278
 
279
        return crc;
280
}
281
 
352 daniel-mar 282
 
283
int obfuscation_version(PARM_T* pparm) {
284
        uint32_t obfusc_info = pparm->unknown2;
285
 
507 daniel-mar 286
        if (obfusc_info == 0x00000001) { // 01 00 00 00
287
                // Photoshop FilterFactory default initialization of field "unknown2" (no obfuscation)
352 daniel-mar 288
                return 0;
289
        }
507 daniel-mar 290
        else if (obfusc_info == 0x00000000) { // 00 00 00 00
291
                // Premiere FilterFactory default initialization of field "unknown1" (no obfuscation)
292
                // (Premiere Field "unknown1" has the offset of Photoshop's "unknown2" field)
352 daniel-mar 293
                return 0;
294
        }
295
        else if (obfusc_info == 0x90E364A3) { // A3 64 E3 90
296
                // Version 1 obfuscation (Filter Foundry 1.4b8,9,10)
297
                return 1;
298
        }
299
        else if (obfusc_info == 0xE2CFCA34) { // 34 CA CF E2
300
                // Version 2 obfuscation (Filter Foundry 1.7b1)
301
                return 2;
302
        }
303
        else if ((obfusc_info >= 4) && (obfusc_info <= 0xFF)) { // xx 00 00 00
304
                // Version 4 obfuscation (Filter Foundry 1.7.0.7)
305
                // Version 5 obfuscation (Filter Foundry 1.7.0.8)
306
                // Version 6 obfuscation (Filter Foundry 1.7.0.10)
508 daniel-mar 307
                // Version 7 obfuscation (Filter Foundry 1.7.0.17)
308
                // Future: Version 8, ... 255
352 daniel-mar 309
                return obfusc_info;
310
        }
311
        else {
312
                // Version 3 obfuscation (Filter Foundry 1.7.0.5)
313
                // obfusc_info is the srand() seed and is equal to the time(0) build timestamp
314
                return 3;
315
        }
316
}
317
 
508 daniel-mar 318
void obfusc(PARM_T* pparm, uint64_t* out_initial_seed, uint64_t* out_initial_seed2) {
319
        // Version 7 obfuscation (Introduced in Filter Foundry 1.7.0.17)
292 daniel-mar 320
 
321
        unsigned char* p;
508 daniel-mar 322
        uint64_t initial_seed, initial_seed2, rolseed;
350 daniel-mar 323
        uint32_t xorseed;
508 daniel-mar 324
        uint64_t xorseed2;
347 daniel-mar 325
 
292 daniel-mar 326
#ifdef MAC_ENV
347 daniel-mar 327
        // Currently, make_mac.c does not implement modifying the executable code (TODO),
328
        // so we will use the default initial_seed!
506 daniel-mar 329
        initial_seed = GetObfuscSeed();
508 daniel-mar 330
        initial_seed2 = GetObfuscSeed2();
292 daniel-mar 331
#else
347 daniel-mar 332
        // Give always the same seed if the parameters are the same. No random values.
333
        // This initial seed will be returned and built into the executable code by make_win.c
508 daniel-mar 334
        pparm->unknown1 = 0;
335
        pparm->unknown2 = 0;
336
        pparm->unknown3 = 0;
350 daniel-mar 337
        initial_seed = crc64((unsigned char*)pparm, sizeof(PARM_T));
508 daniel-mar 338
        pparm->unknown3 = crc32b((char*)pparm, sizeof(PARM_T)); // make sure that the second seed is different
339
        pparm->unknown2 = crc32b((char*)pparm, sizeof(PARM_T)); // make sure that the second seed is different
340
        pparm->unknown1 = crc32b((char*)pparm, sizeof(PARM_T)); // make sure that the second seed is different
341
        initial_seed2 = crc64((unsigned char*)pparm, sizeof(PARM_T));
292 daniel-mar 342
#endif
343
 
508 daniel-mar 344
        // AFTER unknown1-3 have been set to 0 (again), calculate the checksum!
345
        pparm->unknown1 = 0;
346
        pparm->unknown2 = 0;
347
        pparm->unknown3 = 0;
347 daniel-mar 348
        pparm->unknown1 = crc32b((char*)pparm, sizeof(PARM_T));
309 daniel-mar 349
 
350 daniel-mar 350
        xorseed = initial_seed & 0xFFFFFFFF;
292 daniel-mar 351
        p = (unsigned char*)pparm;
350 daniel-mar 352
        xorshift(&p, &xorseed, sizeof(PARM_T));
292 daniel-mar 353
 
348 daniel-mar 354
        rolseed = initial_seed;
347 daniel-mar 355
        p = (unsigned char*)pparm;
348 daniel-mar 356
        rolshift(&p, &rolseed, sizeof(PARM_T));
347 daniel-mar 357
 
508 daniel-mar 358
        xorseed2 = initial_seed2;
359
        p = (unsigned char*)pparm;
360
        xorshift64(&p, &xorseed2, sizeof(PARM_T));
347 daniel-mar 361
 
508 daniel-mar 362
        pparm->unknown2 = 7; // obfusc version
363
 
364
        *out_initial_seed = initial_seed;
365
        *out_initial_seed2 = initial_seed2;
292 daniel-mar 366
}
367
 
368
void deobfusc(PARM_T* pparm) {
309 daniel-mar 369
        uint32_t obfusc_version;
292 daniel-mar 370
        size_t size = sizeof(PARM_T);
371
 
293 daniel-mar 372
        obfusc_version = obfuscation_version(pparm);
292 daniel-mar 373
 
374
        switch (obfusc_version) {
375
                case 0:
376
                        // no obfuscation
377
                        return;
378
                case 1: {
379
                        // Version 1 obfuscation (Filter Foundry 1.4b8,9,10)
380
                        // Filter built with VC++ (official release by Toby Thain)
381
 
382
                        unsigned char* p;
383
                        size_t i;
309 daniel-mar 384
                        uint32_t seed;
292 daniel-mar 385
 
386
                        seed = 0xdc43df3c;
387
 
388
                        for (i = size, p = (unsigned char*)pparm; i--;) {
389
                                *p++ ^= rand_msvcc(&seed);
390
                        }
391
                        break;
392
                }
393
                case 2: {
394
                        // Version 2 obfuscation (Filter Foundry 1.7b1)
395
                        // Compiler independent
396
 
397
                        unsigned char* p;
398
                        size_t i;
309 daniel-mar 399
                        uint32_t seed;
292 daniel-mar 400
 
401
                        seed = 0x95d4a68f;
402
 
403
                        for (i = size, p = (unsigned char*)pparm; i--;) {
404
                                seed ^= seed << 13;
405
                                seed ^= seed >> 17;
406
                                seed ^= seed << 5;
407
                                *p++ ^= seed;
408
                        }
409
                        break;
410
                }
411
                case 3: {
412
                        // Version 3 obfuscation (Filter Foundry 1.7.0.5)
413
                        // NO loading of other implementation supported, but that doesn't matter since
414
                        // obfuscation and protection is combined in Filter Factory >= 1.7.0.5.
415
                        // Using rand() is more secure, because it differs from compiler to compiler, so
416
                        // it is harder to read a protected 8BF plugin.
417
                        // Note that rand() in combination with srand() is deterministic, so it is safe
418
                        // to use it: https://stackoverflow.com/questions/55438293/does-rand-function-in-c-follows-non-determinstc-algorithm
419
                        // Note: 32-Bit FF is built using OpenWatcom (to support Win95), while 64-Bit FF is built using Microsoft Visual C++
420
 
421
                        unsigned char* p;
422
                        size_t i;
309 daniel-mar 423
                        uint32_t seed;
292 daniel-mar 424
                        size_t seed_position;
425
 
426
                        seed = pparm->unknown2;
427
                        seed_position = offsetof(PARM_T, unknown2); // = offsetof(PARM_T_PREMIERE, unknown1)
428
 
429
                        srand(seed);
329 daniel-mar 430
 
292 daniel-mar 431
                        p = (unsigned char*)pparm;
351 daniel-mar 432
                        for (i = 0; i < seed_position; i++) {
433
                                *p++ ^= (int)(rand() * 1.0 / ((double)RAND_MAX + 1) * 256);
434
                        }
309 daniel-mar 435
                        *((uint32_t*)p) = 0; // here was the seed. Fill it with 0x00000000
507 daniel-mar 436
                        p += 4; // jump to the next DWORD
351 daniel-mar 437
                        for (i = 0; i < size - seed_position - 4; i++) {
438
                                *p++ ^= (int)(rand() * 1.0 / ((double)RAND_MAX + 1) * 256);
439
                        }
329 daniel-mar 440
 
292 daniel-mar 441
                        break;
442
                }
443
                case 4:
444
                case 5: {
445
                        // Version 4 obfuscation (Filter Foundry 1.7.0.7)
446
                        // Version 5 obfuscation (Filter Foundry 1.7.0.8)
489 daniel-mar 447
                        // Not compiler dependent, but individual for each standalone filter
292 daniel-mar 448
                        // It is important that this code works for both x86 and x64 indepdently from the used compiler,
449
                        // otherwise, the cross-make x86/x64 won't work!
450
                        // Version 5 contains a seed requirement (checksum).
451
 
452
                        unsigned char* p;
453
                        size_t seed_position;
309 daniel-mar 454
                        uint32_t seed, initial_seed;
292 daniel-mar 455
 
506 daniel-mar 456
                        initial_seed = GetObfuscSeed() & 0xFFFFFFFF; // this value will be manipulated during the building of each individual filter (see make_win.c)
309 daniel-mar 457
 
458
                        seed = initial_seed;
292 daniel-mar 459
                        seed_position = offsetof(PARM_T, unknown2); // = offsetof(PARM_T_PREMIERE, unknown1)
460
 
309 daniel-mar 461
                        if (obfusc_version == 5) {
462
                                // make v4 and v5 intentionally incompatible to avoid a downgrade-attack
463
                                seed ^= 0xFFFFFFFF;
464
                        }
465
 
292 daniel-mar 466
                        p = (unsigned char*)pparm;
293 daniel-mar 467
                        xorshift(&p, &seed, seed_position);
507 daniel-mar 468
                        *((uint32_t*)p) = 0; // here was the version info (4 or 5). Fill it with 0x00000000
469
                        p += 4; // jump to the next DWORD
293 daniel-mar 470
                        xorshift(&p, &seed, size - seed_position - 4);
292 daniel-mar 471
 
472
                        if (obfusc_version == 5) {
318 daniel-mar 473
                                pparm->unknown2 = 0; // make sure crc32b matches always
347 daniel-mar 474
                                if (crc32b((char*)pparm, sizeof(PARM_T)) != initial_seed) {
292 daniel-mar 475
                                        // Integrity check failed!
309 daniel-mar 476
                                        memset(pparm, 0, sizeof(PARM_T)); // invalidate everything
292 daniel-mar 477
                                }
478
                        }
479
 
480
                        break;
481
                }
509 daniel-mar 482
                case 6:
483
                case 7: {
347 daniel-mar 484
                        // Version 6 obfuscation (Filter Foundry 1.7.0.10)
509 daniel-mar 485
                        // Version 7 obfuscation (Filter Foundry 1.7.0.17)
489 daniel-mar 486
                        // Not compiler dependent, but individual for each standalone filter
347 daniel-mar 487
                        // It is important that this code works for both x86 and x64 indepdently from the used compiler,
488
                        // otherwise, the cross-make x86/x64 won't work!
489
 
490
                        unsigned char* p;
350 daniel-mar 491
                        uint32_t xorseed, checksum;
348 daniel-mar 492
                        uint64_t initial_seed, rolseed;
503 daniel-mar 493
 
506 daniel-mar 494
                        initial_seed = GetObfuscSeed(); // this value will be manipulated during the building of each individual filter (see make_win.c)
347 daniel-mar 495
 
509 daniel-mar 496
                        if (obfusc_version >= 7) {
497
                                uint64_t xorseed2, initial_seed2;
498
                                initial_seed2 = GetObfuscSeed2(); // this value will be manipulated during the building of each individual filter (see make_win.c)
499
                                xorseed2 = initial_seed2;
500
                                p = (unsigned char*)pparm;
501
                                xorshift64(&p, &xorseed2, sizeof(PARM_T));
347 daniel-mar 502
                        }
503
 
508 daniel-mar 504
                        rolseed = initial_seed;
505
                        p = (unsigned char*)pparm;
506
                        rolshift(&p, &rolseed, sizeof(PARM_T));
507
 
508
                        xorseed = initial_seed & 0xFFFFFFFF;
509
                        p = (unsigned char*)pparm;
510
                        xorshift(&p, &xorseed, sizeof(PARM_T));
511
 
512
                        checksum = pparm->unknown1;
513
 
514
                        pparm->unknown1 = 0;
515
                        pparm->unknown2 = 0;
516
                        pparm->unknown3 = 0;
517
 
518
                        if (checksum != crc32b((char*)pparm, sizeof(PARM_T))) {
519
                                // Integrity check failed!
520
                                memset(pparm, 0, sizeof(PARM_T)); // invalidate everything
521
                        }
522
 
523
                        break;
524
                }
292 daniel-mar 525
                default: {
526
                        // Obfuscation version unexpected!
309 daniel-mar 527
                        memset(pparm, 0, sizeof(PARM_T)); // invalidate everything
311 daniel-mar 528
 
529
                        // If "return" is present: Calling function will receive an invalid cbSize value, hence showing "incompatible obfuscation"
530
                        // If "return" is not present: Then the code below will set a correct cbSize and iProtect flag if obfusc_version>=3, which will raise the error "filter is protected"
531
                        return;
292 daniel-mar 532
                }
533
        }
534
 
309 daniel-mar 535
        if ((pparm->cbSize != PARM_SIZE) &&
351 daniel-mar 536
                (pparm->cbSize != PARM_SIZE_PREMIERE) &&
309 daniel-mar 537
                (pparm->cbSize != PARM_SIG_MAC)) {
538
                memset(pparm, 0, sizeof(PARM_T)); // invalidate everything
539
        }
503 daniel-mar 540
 
292 daniel-mar 541
        if (obfusc_version >= 3) {
489 daniel-mar 542
                // Filter Foundry >= 1.7.0.5 combines obfuscation and protection
292 daniel-mar 543
                // when a standalone filter is built. Theoretically, you can un-protect a
544
                // plugin, even if it is obfuscated, just by bit-flipping the LSB of byte 0x164.
545
                // Therefore, we enforce that the plugin is protected!
546
                pparm->iProtected = 1;
547
 
548
                // Furthermore, if obfuscation 3+ failed (since the seed is individual for each 8BF file),
293 daniel-mar 549
                // we still want that load_*.c is able to detect pparm->iProtected instead
550
                // of throwing the error "Incompatible obfuscation".
292 daniel-mar 551
                pparm->cbSize = PARM_SIZE;
408 daniel-mar 552
                pparm->standalone = 1;
292 daniel-mar 553
        }
312 daniel-mar 554
 
555
        if (obfusc_version >= 1) {
556
                // information was lost due to obfuscation. Make sure it is zero.
557
                pparm->unknown2 = 0;
558
        }
351 daniel-mar 559
 
560
        if (obfusc_version >= 6) {
561
                // information was lost due to checksum. Make sure it is zero.
562
                pparm->unknown1 = 0;
563
        }
292 daniel-mar 564
}