Subversion Repositories filter_foundry

Compare Revisions

No changes between revisions

Regard whitespace Rev 275 → Rev 276

/trunk/CHANGELOG.md
1,10 → 1,11
# Changelog
 
## 1.7.0.7 [Work-In-Progress]
## 1.7.0.7 [08-Aug-2021]
- Standalone filters are now created in 32 and 64 bit. To make this work, you need to install FilterFoundry.8bf and FilterFoundry64.8bf in your plug-in directory.
- Security improvement: Filters which have been built using obfuscation "V3" or "V4" will now always be treated as protected plugin, even if the obfuscated code has been manipulated.
- Introduced obfuscation "V4" (more secure)
- Obfuscated "V1" and obfuscated "V2" filters can now be loaded again (as long as they aren't protected)
- Security improvement: Filters which have been built using obfuscation "V3" will now always be treated as protected plugin, even if the obfuscated code has been manipulated.
- Windows message box dialogs are now properly "modal" (they have the correct parent window handle), and therefore, they blink when you click at the parent window.
- Standalone filters are now created in 32 and 64 bit. To make this work, you need to install FilterFoundry.8bf and FilterFoundry64.8bf in your plug-in directory.
- The TPLT (template data) and build dialog resources are now deleted from standalone filters to save space.
 
## 1.7.0.6 [01-Aug-2021]
/trunk/Obfuscation.md
14,9 → 14,24
 
Defined in **ff.h**, implemented in **make.c**:
 
void obfusc(PARM_T* pparm);
void obfusc(PARM_T* pparm, unsigned int seed);
void deobfusc(PARM_T* pparm);
 
### Obfuscation "Version 4"
 
Introduced in **Filter Foundry 1.7.0.7** [08-Aug-2021]
 
It is not compiler-dependant, but different between every standalone filter.
 
The binary code of the 8BF file will be manipulated during building
in order to store the seed into the `deobfusc()` function.
This allows that 32 bit and 64 bit filters are "cross built".
 
Algorithm: XOR shift like in version 2, but the seed is individual for
each individual built standalone filter.
 
The value "4" will be stored at position 0x30 (this field is not used in the `PARM` resource).
 
### Obfuscation "Version 3"
 
Introduced in **Filter Foundry 1.7.0.5** [30-Jul-2021]
/trunk/README.md
6,7 → 6,7
Initially written by [Toby Thain](https://www.telegraphics.com.au/sw/) in 2003 - 2009, the development has been continued by [Daniel Marschall](https://www.daniel-marschall.de/) / [ViaThinkSoft](https://www.viathinksoft.de/) since 2018. Several advancements and improvements have been made, and a 64-bit Windows version was created.
 
 
### Windows version 1.7.0.6
### Windows version 1.7.0.7
 
Filter Foundry 1.7 comes with a 32-Bit Windows plugin (FilterFoundry.8bf, [Download here](https://www.viathinksoft.de/download/248/FilterFoundry.8bf)) and a 64-Bit Windows plugin (FilterFoundry64.8bf, [Download here](https://www.viathinksoft.de/download/249/FilterFoundry64.8bf)).
 
/trunk/TODO.md
5,12 → 5,14
Known bugs
----------
 
* 32/64 bit cross creation is not possible if obfuscation is compiler dependent! We need to make something different!
(Nothing here yet)
 
 
Minor priority stuff or ideas
-----------------------------
 
* When a filter is created obfuscated and you click "Make" again, should then be the "obfuscate" checkbox be checked again?
 
* The filter `r*(y&1)` looks horrible when you zoom out!
 
* Memory leak: `strdup()` and `my_strdup()` need `free()` !
/trunk/ff.h
88,6 → 88,7
//#define DEBUG
 
// from main.c
unsigned long get_parm_hash(PARM_T *parm);
void DoPrepare (FilterRecordPtr epb);
void DoStart (FilterRecordPtr epb);
OSErr DoContinue (FilterRecordPtr epb);
115,10 → 116,11
void evalpixel(unsigned char *outp,unsigned char *inp);
 
// from make.c
#define OBFUSC_V4_DEFAULT_SEED 0x52830517
unsigned long printablehash(unsigned long hash);
size_t fixpipl(PIPropertyList *pipl,size_t origsize,StringPtr title, long *event_id);
size_t aete_generate(void* aeteptr, PARM_T *pparm, long event_id);
void obfusc(PARM_T* pparm);
void obfusc(PARM_T* pparm, unsigned int seed);
void deobfusc(PARM_T* pparm);
 
// from loadfile_*.c
165,3 → 167,4
#endif /* _MSC_VER */
 
#endif /* INCLUDED_FF_H */
 
/trunk/load_mac.c
79,7 → 79,13
// then try plugin formats (Mac first, then Windows .8bf or .prm DLL)
}else if( (readok = readmacplugin(sfr,reason) || read8bfplugin(sfr,reason)) ){
if ((gdata->parm.cbSize != PARM_SIZE) && (gdata->parm.cbSize != PARM_SIZE_PREMIERE) && (gdata->parm.cbSize != PARM_SIG_MAC)) {
if (gdata->parm.unknown2 == 4) {
// Obfuscation V4 is protected, because FF>=1.7.0.5 combines protection and obfuscation
*reason = "The filter is protected.";
}
else {
*reason = "Incompatible obfuscation.";
}
return false; // Stop! We know the issue now.
}else if(gdata->parm.iProtected){
*reason = "The filter is protected.";
/trunk/load_win.c
91,7 → 91,13
if (hm = LoadLibraryEx(myp2cstrcpy(name,sfr->sfFile.name),NULL,LOAD_LIBRARY_AS_DATAFILE)) {
if (readPARMresource(hm,reason,READ_OBFUSC)) {
if ((gdata->parm.cbSize != PARM_SIZE) && (gdata->parm.cbSize != PARM_SIZE_PREMIERE) && (gdata->parm.cbSize != PARM_SIG_MAC)) {
if (gdata->parm.unknown2 == 4) {
// Obfuscation V4 is protected, because FF>=1.7.0.5 combines protection and obfuscation
*reason = _strdup("The filter is protected.");
}
else {
*reason = _strdup("Incompatible obfuscation.");
}
return false; // Stop! We know the issue now.
} else if (gdata->parm.iProtected) {
*reason = _strdup("The filter is protected.");
/trunk/main.c
64,17 → 64,17
DLLEXPORT MACPASCAL
void ENTRYPOINT(short selector,FilterRecordPtr pb,intptr_t *data,short *result);
 
unsigned long get_parm_hash(PARM_T parm) {
unsigned long get_parm_hash(PARM_T *parm) {
unsigned long hash;
int i;
 
hash = djb2((char*)parm.category);
hash += djb2((char*)parm.title);
hash += djb2((char*)parm.copyright);
hash += djb2((char*)parm.author);
for (i = 0; i < 4; i++) hash += hash += djb2((char*)parm.map[i]);
for (i = 0; i < 8; i++) hash += hash += djb2((char*)parm.ctl[i]);
for (i = 0; i < 4; i++) hash += hash += djb2((char*)parm.formula[i]);
hash = djb2((char*)parm->category);
hash += djb2((char*)parm->title);
hash += djb2((char*)parm->copyright);
hash += djb2((char*)parm->author);
for (i = 0; i < 4; i++) hash += hash += djb2((char*)parm->map[i]);
for (i = 0; i < 8; i++) hash += hash += djb2((char*)parm->ctl[i]);
for (i = 0; i < 4; i++) hash += hash += djb2((char*)parm->formula[i]);
 
return hash;
}
247,7 → 247,7
if (strlen(tempdir) > 0) strcat(tempdir, "/");
#endif
 
hash = (gdata->standalone) ? get_parm_hash(gdata->parm) : 0;
hash = (gdata->standalone) ? get_parm_hash(&gdata->parm) : 0;
sprintf(outfilename, "%sFilterFoundry%d.afs", tempdir, hash);
 
myc2pstrcpy(sfr.sfFile.name, outfilename);
345,7 → 345,7
if (strlen(tempdir) > 0) strcat(tempdir, "/");
#endif
 
hash = (isStandalone) ? get_parm_hash(gdata->parm) : 0;
hash = (isStandalone) ? get_parm_hash(&gdata->parm) : 0;
sprintf(outfilename, "%sFilterFoundry%d.afs", tempdir, hash);
 
myc2pstrcpy(sfr.sfFile.name, outfilename);
/trunk/make.c
460,30 → 460,34
return (*seed >> 16) & 0x7fff; /* Scale between 0 and RAND_MAX */
}
 
// TODO: obfusc() must be compiler independent again, otherwise the 32/64 cross-create won't work!
void _xorshift(unsigned char** p, uint32_t* x32, size_t num) {
size_t i;
unsigned char* x = *p;
for (i = 0; i < num; i++) {
// https://de.wikipedia.org/wiki/Xorshift
*x32 ^= *x32 << 13;
*x32 ^= *x32 >> 17;
*x32 ^= *x32 << 5;
*x++ ^= *x32;
}
*p = x;
}
 
void obfusc(PARM_T* pparm) {
void obfusc(PARM_T* pparm, unsigned int seed) {
unsigned char* p;
size_t i;
unsigned int seed;
size_t size, seed_position;
 
seed_position = offsetof(PARM_T, unknown2);
size = sizeof(PARM_T);
 
// Version 3 obfuscation
// Filter Foundry >= 1.7.0.5
// Version 4 obfuscation
// Filter Foundry >= 1.7.0.7
 
do {
seed = (unsigned int)time(0);
} while ((seed == 0x90E364A3/*V1*/) || (seed == 0xE2CFCA34/*V2*/));
srand(seed);
 
p = (unsigned char*)pparm;
for (i = 0; i < seed_position; i++) *p++ ^= rand();
*((unsigned int*)p) = seed; // seed is placed at this position. data will lost! (in deobfusc, it will be set to 0x00000000)
_xorshift(&p, &seed, seed_position);
*((unsigned int*)p) = 4; // Obfusc V4 info
p += 4;
for (i = 0; i < size - seed_position - 4; i++) *p++ ^= rand();
_xorshift(&p, &seed, size - seed_position - 4);
}
 
void deobfusc(PARM_T* pparm) {
516,6 → 520,26
*p++ ^= x32;
}
}
else if (seed == 4) {
// Version 4 obfuscation
// Filter Foundry >= 1.7.0.7
// Not compiler dependent, but individual for each build
// It is important that this code works for both x86 and x64 indepdently from the used compiler,
// otherwise, the cross-make x86/x64 won't work!
seed = OBFUSC_V4_DEFAULT_SEED; // this value will be manipulated during the building of each individual filter (see make_win.c)
p = (unsigned char*)pparm;
_xorshift(&p, &seed, seed_position);
p += 4; // obfusc info == 4
_xorshift(&p, &seed, size - seed_position - 4);
 
// Filter Foundry >= 1.7.0.5 builds combines obfuscation and protection
// when a standalone filter is built. Theoretically, you can un-protect a
// plugin, even if it is obfuscated, just by bit-flipping the LSB of byte 0x164.
// Therefore, we enforce that the plugin is protected!
// Note: We don't need to check PARM_T_PREMIERE, because only PARM_T
// can be obfuscated by FilterFoundry.
pparm->iProtected = 1;
}
else {
// Version 3 obfuscation
// Filter Foundry >= 1.7.0.5
/trunk/make_mac.c
106,7 → 106,7
if( !(e = PtrToHand(&gdata->parm,&h,sizeof(PARM_T))) ){
if(gdata->obfusc){
HLock(h);
obfusc((PARM_T*)*h);
obfusc((PARM_T*)*h, OBFUSC_V4_DEFAULT_SEED);
HUnlock(h);
parm_type = 'DATA';
parm_id = OBFUSCDATA_ID;
/trunk/make_win.c
52,7 → 52,7
char name[1024];
char description[1024];
size_t i;
int iname = 0;
size_t iname = 0;
int idescription = 0;
 
// Description
172,6 → 172,31
free(changeRequestStr);
}
 
int binary_replace_file(const char* filename, unsigned int search, unsigned int replace) {
unsigned int srecord = 0;
int found = 0;
 
FILE* fptr = fopen(filename, "rb+");
if (fptr == NULL) return -1;
 
while ((fread(&srecord, sizeof(srecord), 1, fptr) == 1))
{
if (srecord == search) {
srecord = replace;
fseek(fptr, -1*(long)sizeof(srecord), SEEK_CUR);
fwrite(&srecord, (int)sizeof(srecord), 1, fptr);
fseek(fptr, 0, SEEK_CUR); // important!
found++;
}
else {
fseek(fptr, -1*(long)(sizeof(srecord) - 1), SEEK_CUR);
}
}
fclose(fptr);
 
return found;
}
 
Boolean doresources(HMODULE srcmod,char *dstname, int bits){
HRSRC datarsrc,aetersrc,manifestsrc;
HGLOBAL datah,aeteh,hupdate,manifesth;
183,12 → 208,9
LPCTSTR parm_type;
int i,parm_id;
Boolean discard = true;
 
unsigned int obfuscseed = 0;
long event_id;
 
// if(!EnumResourceLanguages(srcmod,"PiPL",MAKEINTRESOURCE(16000),enumfunc,0))
// dbglasterror("EnumResourceLanguages");
 
if( (hupdate = _BeginUpdateResource(dstname,false)) ){
DBG("BeginUpdateResource OK");
if( (datarsrc = FindResource(srcmod,MAKEINTRESOURCE(16000),"TPLT"))
229,6 → 251,12
/* Generate 'aete' resource (contains names of the parameters for the "Actions" tab in Photoshop) */
aetesize = aete_generate(newaete, pparm, event_id);
 
if (gdata->obfusc) {
// Avoid that the same filter can generate with two seeds,
// otherwise the comparison would be much easier
obfuscseed = (unsigned int)get_parm_hash(pparm);
}
 
// ====== Change Pascal strings to C-Strings
 
/* convert to C strings for Windows PARM resource */
253,7 → 281,9
if(gdata->obfusc){
parm_type = RT_RCDATA;
parm_id = OBFUSCDATA_ID;
obfusc(pparm);
 
// Note: After we have finished updating the resources, we will write <obfuscseed> into the binary code of the 8BF file
obfusc(pparm, obfuscseed);
}else{
parm_type = "PARM";
parm_id = PARM_ID;
282,9 → 312,18
 
}else dbglasterror(_strdup("Find-, Load- or LockResource"));
 
// Here, the file will be saved
if(!_EndUpdateResource(hupdate,discard))
dbglasterror(_strdup("EndUpdateResource"));
 
if (gdata->obfusc) {
// We modify the binary code to replace the deobfuscate-seed from OBFUSC_V4_DEFAULT_SEED to obfuscseed
if (binary_replace_file(dstname, OBFUSC_V4_DEFAULT_SEED, obfuscseed) <= 0) {
dbg("binary_replace_file failed");
discard = true;
}
}
 
if(pparm) free(pparm);
if(newpipl) free(newpipl);
if(newaete) free(newaete);
296,11 → 335,11
BOOL remove_64_filename_prefix(char* dstname) {
// foobar.8bf => foobar.8bf
// foobar64.8bf => foobar.8bf
int i;
size_t i;
for (i = strlen(dstname); i > 2; i--) {
if (dstname[i] == '.') {
if ((dstname[i - 2] == '6') && (dstname[i - 1] == '4')) {
int tmp = strlen(dstname);
size_t tmp = strlen(dstname);
memcpy(&dstname[i - 2], &dstname[i], strlen(dstname) - i + 1);
dstname[tmp - 2] = 0;
return true;
312,10 → 351,10
 
BOOL add_64_filename_prefix(char* dstname) {
// foobar.8bf => foobar64.8bf
int i;
size_t i;
for (i = strlen(dstname); i > 2; i--) {
if (dstname[i] == '.') {
int tmp = strlen(dstname);
size_t tmp = strlen(dstname);
memcpy(&dstname[i + 2], &dstname[i], strlen(dstname) - i + 1);
dstname[i] = '6';
dstname[i + 1] = '4';
/trunk/manifest32.xml
5,7 → 5,7
<assemblyIdentity
name="Telegraphics.FilterFoundry"
processorArchitecture="x86"
version="1.7.0.6"
version="1.7.0.7"
type="win32"/>
<description>Filter Foundry</description>
<dependency>
/trunk/manifest64.xml
5,7 → 5,7
<assemblyIdentity
name="Telegraphics.FilterFoundry"
processorArchitecture="amd64"
version="1.7.0.6"
version="1.7.0.7"
type="win32"/>
<description>Filter Foundry</description>
<dependency>
/trunk/testcases/import/foundry17_32_op.8bf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/trunk/testcases/import/foundry17_64_op.8bf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/trunk/testcases/import/README.md
28,10 → 28,12
| Import FilterFoundry 1.7 for Windows x86 | .8bf | 0x2086 | foundry17_32.8bf | Watcom | Works |
| Import FF Obfuscated "V2" 1.7 for Windows x86 | .8bf | n/a | foundry17_32_o.8bf | Watcom | Works |
| Import FF Protected 1.7 for Windows x86 | .8bf | 0x2086 | foundry17_32_p.8bf | Watcom | Locked OK |
| Import FF Prot+Obfsc "V2" 1.7 for Windows x86 | .8bf | n/a | foundry17_32_op.8bf | Watcom | Locked OK |
| Import FF Prot+Obfsc "V2" 1.7 for Windows x86 | .8bf | n/a | foundry17_32_op2.8bf | Watcom | Locked OK |
| Import FF Prot+Obfsc "V3" 1.7 for Windows x86 | .8bf | n/a | foundry17_32_op3.8bf | Watcom | Locked/Incompat |
| Import FF Prot+Obfsc "V4" 1.7 for Windows x86 | .8bf | n/a | foundry17_32_op4.8bf | Watcom | Locked OK |
| Import FilterFoundry 1.7 for Windows x64 | .8bf | 0x2086 | foundry17_64.8bf | MSVC++ | Works |
| Import FF Obfuscated "V2" 1.7 for Windows x64 | .8bf | n/a | foundry17_64_o.8bf | MSVC++ | Works |
| Import FF Protected 1.7 for Windows x64 | .8bf | 0x2086 | foundry17_64_p.8bf | MSVC++ | Locked OK |
| Import FF Prot+Obfsc "V2" 1.7 for Windows x64 | .8bf | n/a | foundry17_64_op.8bf | MSVC++ | Locked OK |
| Import FF Prot+Obfsc "V2" 1.7 for Windows x64 | .8bf | n/a | foundry17_64_op2.8bf | MSVC++ | Locked OK |
| Import FF Prot+Obfsc "V3" 1.7 for Windows x64 | .8bf | n/a | foundry17_64_op3.8bf | MSVC++ | Locked/Incompat |
| Import FF Prot+Obfsc "V4" 1.7 for Windows x64 | .8bf | n/a | foundry17_64_op4.8bf | MSVC++ | Locked OK |
/trunk/testcases/import/foundry17_32_op2.8bf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/testcases/import/foundry17_32_op4.8bf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/testcases/import/foundry17_64_op2.8bf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/testcases/import/foundry17_64_op4.8bf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/version.h
32,8 → 32,8
 
#define plugInName "FilterFoundry"
 
#define VERSION_STR "1.7.0.6"
#define VERSION_NUM 1,7,0,6
#define VERSION_STR "1.7.0.7"
#define VERSION_NUM 1,7,0,7
 
#define VERS_RSRC VERSION_NUM,verUS,VERSION_STR,"Filter Foundry " VERSION_STR
 
42,7 → 42,7
#define PROJECT_URL "https://github.com/danielmarschall/filter_foundry"
 
/* formatted for Win32 VERSIONINFO resource */
#define VI_VERS_NUM 1,7,0,6
#define VI_VERS_NUM 1,7,0,7
#define VI_FLAGS 0 /* 0 for final, or any of VS_FF_DEBUG,VS_FF_PATCHED,VS_FF_PRERELEASE,VS_FF_PRIVATEBUILD,VS_FF_SPECIALBUILD */
#define VI_COMMENTS "Download the latest version here: " PROJECT_URL "\0" /* null terminated Comments field */
#define VI_COMPANY_NAME "ViaThinkSoft, Telegraphics Pty Ltd\0"