Subversion Repositories filter_foundry

Rev

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