Subversion Repositories filter_foundry

Rev

Rev 292 | Rev 311 | 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 obfuscation_version(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 >= 4) && (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, ... 255
  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.         // Windows:   Version 5 obfuscation (Introduced in Filter Foundry 1.7.0.8)
  90.         // Macintosh: Version 4 obfuscation (Introduced in Filter Foundry 1.7.0.7)
  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.         // For Mac, we use obfuscation version 4, because the placing the seed into the produced executable code is not implemented in Mac!
  99.         // (It needs to be implemented in make_mac.c)
  100.         initial_seed = OBFUSC_V4_DEFAULT_SEED;
  101.         obfusc_version = 4;
  102. #else
  103.         // In obfuscation version 5, the seed is also the checksum. It will be verified at deobfusc()!
  104.         initial_seed = (unsigned int)get_parm_hash(pparm);
  105.         obfusc_version = 5;
  106. #endif
  107.  
  108.         seed_position = offsetof(PARM_T, unknown2);
  109.         size = sizeof(PARM_T);
  110.         seed = initial_seed;
  111.  
  112.         p = (unsigned char*)pparm;
  113.         xorshift(&p, &seed, seed_position);
  114.         *((unsigned int*)p) = obfusc_version;
  115.         p += 4;
  116.         xorshift(&p, &seed, size - seed_position - 4);
  117.  
  118.         return initial_seed;
  119. }
  120.  
  121. void deobfusc(PARM_T* pparm) {
  122.         unsigned int obfusc_version;
  123.         size_t size = sizeof(PARM_T);
  124.  
  125.         obfusc_version = obfuscation_version(pparm);
  126.  
  127.         switch (obfusc_version) {
  128.                 case 0:
  129.                         // no obfuscation
  130.                         return;
  131.                 case 1: {
  132.                         // Version 1 obfuscation (Filter Foundry 1.4b8,9,10)
  133.                         // Filter built with VC++ (official release by Toby Thain)
  134.  
  135.                         unsigned char* p;
  136.                         size_t i;
  137.                         unsigned int seed;
  138.  
  139.                         seed = 0xdc43df3c;
  140.  
  141.                         for (i = size, p = (unsigned char*)pparm; i--;) {
  142.                                 *p++ ^= rand_msvcc(&seed);
  143.                         }
  144.                         break;
  145.                 }
  146.                 case 2: {
  147.                         // Version 2 obfuscation (Filter Foundry 1.7b1)
  148.                         // Compiler independent
  149.  
  150.                         unsigned char* p;
  151.                         size_t i;
  152.                         unsigned int seed;
  153.  
  154.                         seed = 0x95d4a68f;
  155.  
  156.                         for (i = size, p = (unsigned char*)pparm; i--;) {
  157.                                 seed ^= seed << 13;
  158.                                 seed ^= seed >> 17;
  159.                                 seed ^= seed << 5;
  160.                                 *p++ ^= seed;
  161.                         }
  162.                         break;
  163.                 }
  164.                 case 3: {
  165.                         // Version 3 obfuscation (Filter Foundry 1.7.0.5)
  166.                         // NO loading of other implementation supported, but that doesn't matter since
  167.                         // obfuscation and protection is combined in Filter Factory >= 1.7.0.5.
  168.                         // Using rand() is more secure, because it differs from compiler to compiler, so
  169.                         // it is harder to read a protected 8BF plugin.
  170.                         // Note that rand() in combination with srand() is deterministic, so it is safe
  171.                         // to use it: https://stackoverflow.com/questions/55438293/does-rand-function-in-c-follows-non-determinstc-algorithm
  172.                         // Note: 32-Bit FF is built using OpenWatcom (to support Win95), while 64-Bit FF is built using Microsoft Visual C++
  173.  
  174.                         unsigned char* p;
  175.                         size_t i;
  176.                         unsigned int seed;
  177.                         size_t seed_position;
  178.  
  179.                         seed = pparm->unknown2;
  180.                         seed_position = offsetof(PARM_T, unknown2); // = offsetof(PARM_T_PREMIERE, unknown1)
  181.  
  182.                         srand(seed);
  183.                         p = (unsigned char*)pparm;
  184.                         for (i = 0; i < seed_position; i++) *p++ ^= rand();
  185.                         *((unsigned int*)p) = 0; // here was the seed. Fill it with 0x00000000
  186.                         p += 4;
  187.                         for (i = 0; i < size - seed_position - 4; i++) *p++ ^= rand();
  188.                         break;
  189.                 }
  190.                 case 4:
  191.                 case 5: {
  192.                         // Version 4 obfuscation (Filter Foundry 1.7.0.7)
  193.                         // Version 5 obfuscation (Filter Foundry 1.7.0.8)
  194.                         // Not compiler dependent, but individual for each build
  195.                         // It is important that this code works for both x86 and x64 indepdently from the used compiler,
  196.                         // otherwise, the cross-make x86/x64 won't work!
  197.                         // Version 5 contains a seed requirement (checksum).
  198.  
  199.                         unsigned char* p;
  200.                         size_t seed_position;
  201.                         uint32_t seed;
  202.  
  203.                         seed = cObfuscV4Seed; // this value will be manipulated during the building of each individual filter (see make_win.c)
  204.                         seed_position = offsetof(PARM_T, unknown2); // = offsetof(PARM_T_PREMIERE, unknown1)
  205.  
  206.                         p = (unsigned char*)pparm;
  207.                         xorshift(&p, &seed, seed_position);
  208.                         p += 4; // obfusc info == 4
  209.                         xorshift(&p, &seed, size - seed_position - 4);
  210.  
  211.                         if (obfusc_version == 5) {
  212.                                 if ((unsigned int)get_parm_hash(pparm) != seed) {
  213.                                         // Integrity check failed!
  214.                                         memset(pparm, 0, sizeof(PARM_T)); // invalidate everything, forcing error "incompatible obfuscation"
  215.                                         return;
  216.                                 }
  217.                         }
  218.  
  219.                         break;
  220.                 }
  221.                 default: {
  222.                         // Obfuscation version unexpected!
  223.                         memset(pparm, 0, sizeof(PARM_T)); // invalidate everything, forcing error "incompatible obfuscation"
  224.                         return;
  225.                 }
  226.         }
  227.  
  228.         if (obfusc_version >= 3) {
  229.                 // Filter Foundry >= 1.7.0.5 builds combines obfuscation and protection
  230.                 // when a standalone filter is built. Theoretically, you can un-protect a
  231.                 // plugin, even if it is obfuscated, just by bit-flipping the LSB of byte 0x164.
  232.                 // Therefore, we enforce that the plugin is protected!
  233.                 pparm->iProtected = 1;
  234.  
  235.                 // Furthermore, if obfuscation 3+ failed (since the seed is individual for each 8BF file),
  236.                 // we still want that load_*.c is able to detect pparm->iProtected instead
  237.                 // of throwing the error "Incompatible obfuscation".
  238.                 pparm->cbSize = PARM_SIZE;
  239.         }
  240. }
  241.