Subversion Repositories filter_foundry

Rev

Rev 329 | 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 uint64_t cObfuscSeed = 0x38AD972A52830517L;
  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. uint64_t obfusc(PARM_T* pparm) {
  108.         // Version 6 obfuscation (Introduced in Filter Foundry 1.7.0.10)
  109.  
  110.         unsigned char* p;
  111.         uint32_t seed1, seed2;
  112.  
  113. #ifdef MAC_ENV
  114.         // Currently, make_mac.c does not implement modifying the executable code (TODO),
  115.         // so we will use the default initial_seed!
  116.         uint64_t initial_seed = cObfuscSeed;
  117.         seed1 = cObfuscSeed & 0xFFFFFFFF;
  118.         seed2 = cObfuscSeed >> 32;
  119. #else
  120.         // Give always the same seed if the parameters are the same. No random values.
  121.         // This initial seed will be returned and built into the executable code by make_win.c
  122.         seed1 = get_parm_hash(pparm);
  123.         seed2 = crc32b((char*)pparm, sizeof(PARM_T));
  124.         uint64_t initial_seed = ((uint64_t)seed2 << 32) + seed1;
  125. #endif
  126.  
  127.         pparm->unknown1 = 0;
  128.         pparm->unknown2 = 0;
  129.         pparm->unknown3 = 0;
  130.  
  131.         // AFTER unknown1-3 have been set to 0, calculate the checksum!
  132.         pparm->unknown1 = crc32b((char*)pparm, sizeof(PARM_T));
  133.  
  134.         seed1 = initial_seed & 0xFFFFFFFF;
  135.         p = (unsigned char*)pparm;
  136.         xorshift(&p, &seed1, sizeof(PARM_T));
  137.  
  138.         seed2 = initial_seed >> 32;
  139.         p = (unsigned char*)pparm;
  140.         xorshift(&p, &seed2, sizeof(PARM_T));
  141.  
  142.         pparm->unknown2 = 6; // obfusc version
  143.  
  144.         return initial_seed;
  145. }
  146.  
  147. void deobfusc(PARM_T* pparm) {
  148.         uint32_t obfusc_version;
  149.         size_t size = sizeof(PARM_T);
  150.  
  151.         obfusc_version = obfuscation_version(pparm);
  152.  
  153.         switch (obfusc_version) {
  154.                 case 0:
  155.                         // no obfuscation
  156.                         return;
  157.                 case 1: {
  158.                         // Version 1 obfuscation (Filter Foundry 1.4b8,9,10)
  159.                         // Filter built with VC++ (official release by Toby Thain)
  160.  
  161.                         unsigned char* p;
  162.                         size_t i;
  163.                         uint32_t seed;
  164.  
  165.                         seed = 0xdc43df3c;
  166.  
  167.                         for (i = size, p = (unsigned char*)pparm; i--;) {
  168.                                 *p++ ^= rand_msvcc(&seed);
  169.                         }
  170.                         break;
  171.                 }
  172.                 case 2: {
  173.                         // Version 2 obfuscation (Filter Foundry 1.7b1)
  174.                         // Compiler independent
  175.  
  176.                         unsigned char* p;
  177.                         size_t i;
  178.                         uint32_t seed;
  179.  
  180.                         seed = 0x95d4a68f;
  181.  
  182.                         for (i = size, p = (unsigned char*)pparm; i--;) {
  183.                                 seed ^= seed << 13;
  184.                                 seed ^= seed >> 17;
  185.                                 seed ^= seed << 5;
  186.                                 *p++ ^= seed;
  187.                         }
  188.                         break;
  189.                 }
  190.                 case 3: {
  191.                         // Version 3 obfuscation (Filter Foundry 1.7.0.5)
  192.                         // NO loading of other implementation supported, but that doesn't matter since
  193.                         // obfuscation and protection is combined in Filter Factory >= 1.7.0.5.
  194.                         // Using rand() is more secure, because it differs from compiler to compiler, so
  195.                         // it is harder to read a protected 8BF plugin.
  196.                         // Note that rand() in combination with srand() is deterministic, so it is safe
  197.                         // to use it: https://stackoverflow.com/questions/55438293/does-rand-function-in-c-follows-non-determinstc-algorithm
  198.                         // Note: 32-Bit FF is built using OpenWatcom (to support Win95), while 64-Bit FF is built using Microsoft Visual C++
  199.  
  200.                         unsigned char* p;
  201.                         size_t i;
  202.                         uint32_t seed;
  203.                         size_t seed_position;
  204.  
  205.                         seed = pparm->unknown2;
  206.                         seed_position = offsetof(PARM_T, unknown2); // = offsetof(PARM_T_PREMIERE, unknown1)
  207.  
  208.                         srand(seed);
  209.  
  210.                         p = (unsigned char*)pparm;
  211.                         for (i = 0; i < seed_position; i++) *p++ ^= (int)(rand() * 1.0 / ((double)RAND_MAX + 1) * 256);
  212.                         *((uint32_t*)p) = 0; // here was the seed. Fill it with 0x00000000
  213.                         p += 4;
  214.                         for (i = 0; i < size - seed_position - 4; i++) *p++ ^= (int)(rand() * 1.0 / ((double)RAND_MAX + 1) * 256);
  215.  
  216.                         break;
  217.                 }
  218.                 case 4:
  219.                 case 5: {
  220.                         // Version 4 obfuscation (Filter Foundry 1.7.0.7)
  221.                         // Version 5 obfuscation (Filter Foundry 1.7.0.8)
  222.                         // Not compiler dependent, but individual for each build
  223.                         // It is important that this code works for both x86 and x64 indepdently from the used compiler,
  224.                         // otherwise, the cross-make x86/x64 won't work!
  225.                         // Version 5 contains a seed requirement (checksum).
  226.  
  227.                         unsigned char* p;
  228.                         size_t seed_position;
  229.                         uint32_t seed, initial_seed;
  230.  
  231.                         initial_seed = cObfuscSeed & 0xFFFFFFFF; // this value will be manipulated during the building of each individual filter (see make_win.c)
  232.  
  233.                         seed = initial_seed;
  234.                         seed_position = offsetof(PARM_T, unknown2); // = offsetof(PARM_T_PREMIERE, unknown1)
  235.  
  236.                         if (obfusc_version == 5) {
  237.                                 // make v4 and v5 intentionally incompatible to avoid a downgrade-attack
  238.                                 seed ^= 0xFFFFFFFF;
  239.                         }
  240.  
  241.                         p = (unsigned char*)pparm;
  242.                         xorshift(&p, &seed, seed_position);
  243.                         *((uint32_t*)p) = 0; // here was the version info. Fill it with 0x00000000
  244.                         p += 4; // obfusc info was 4 or 5
  245.                         xorshift(&p, &seed, size - seed_position - 4);
  246.  
  247.                         if (obfusc_version == 5) {
  248.                                 pparm->unknown2 = 0; // make sure crc32b matches always
  249.                                 if (crc32b((char*)pparm, sizeof(PARM_T)) != initial_seed) {
  250.                                         // Integrity check failed!
  251.                                         memset(pparm, 0, sizeof(PARM_T)); // invalidate everything
  252.                                 }
  253.                         }
  254.  
  255.                         break;
  256.                 }
  257.                 case 6: {
  258.                         // Version 6 obfuscation (Filter Foundry 1.7.0.10)
  259.                         // Not compiler dependent, but individual for each build
  260.                         // It is important that this code works for both x86 and x64 indepdently from the used compiler,
  261.                         // otherwise, the cross-make x86/x64 won't work!
  262.  
  263.                         unsigned char* p;
  264.                         uint32_t seed1, seed2, checksum;
  265.                         uint64_t initial_seed = cObfuscSeed; // this value will be manipulated during the building of each individual filter (see make_win.c)
  266.  
  267.                         seed2 = initial_seed >> 32;
  268.                         p = (unsigned char*)pparm;
  269.                         xorshift(&p, &seed2, sizeof(PARM_T));
  270.  
  271.                         seed1 = initial_seed & 0xFFFFFFFF;
  272.                         p = (unsigned char*)pparm;
  273.                         xorshift(&p, &seed1, sizeof(PARM_T));
  274.  
  275.                         checksum = pparm->unknown1;
  276.  
  277.                         pparm->unknown1 = 0;
  278.                         pparm->unknown2 = 0;
  279.                         pparm->unknown3 = 0;
  280.  
  281.                         if (checksum != crc32b((char*)pparm, sizeof(PARM_T))) {
  282.                                 // Integrity check failed!
  283.                                 memset(pparm, 0, sizeof(PARM_T)); // invalidate everything
  284.                         }
  285.  
  286.                         break;
  287.                 }
  288.                 default: {
  289.                         // Obfuscation version unexpected!
  290.                         memset(pparm, 0, sizeof(PARM_T)); // invalidate everything
  291.  
  292.                         // If "return" is present: Calling function will receive an invalid cbSize value, hence showing "incompatible obfuscation"
  293.                         // 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"
  294.                         return;
  295.                 }
  296.         }
  297.  
  298.         if ((pparm->cbSize != PARM_SIZE) &&
  299.                 //(pparm->cbSize != PARM_SIZE_PREMIERE) &&
  300.                 (pparm->cbSize != PARM_SIG_MAC)) {
  301.                 memset(pparm, 0, sizeof(PARM_T)); // invalidate everything
  302.         }
  303.                
  304.         if (obfusc_version >= 3) {
  305.                 // Filter Foundry >= 1.7.0.5 builds combines obfuscation and protection
  306.                 // when a standalone filter is built. Theoretically, you can un-protect a
  307.                 // plugin, even if it is obfuscated, just by bit-flipping the LSB of byte 0x164.
  308.                 // Therefore, we enforce that the plugin is protected!
  309.                 pparm->iProtected = 1;
  310.  
  311.                 // Furthermore, if obfuscation 3+ failed (since the seed is individual for each 8BF file),
  312.                 // we still want that load_*.c is able to detect pparm->iProtected instead
  313.                 // of throwing the error "Incompatible obfuscation".
  314.                 pparm->cbSize = PARM_SIZE;
  315.         }
  316.  
  317.         if (obfusc_version >= 1) {
  318.                 // information was lost due to obfuscation. Make sure it is zero.
  319.                 pparm->unknown2 = 0;
  320.         }
  321. }
  322.