Subversion Repositories filter_foundry

Rev

Rev 293 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  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. }
  237.