Rev 507 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 507 | Rev 508 | ||
---|---|---|---|
1 | # Obfuscated filters |
1 | # Obfuscated filters |
2 | 2 | ||
3 | ## Resource location |
3 | ## Resource location |
4 | 4 | ||
5 | Obfuscated standalone filters: |
5 | Obfuscated standalone filters: |
6 | - Windows resource: OBFS\16\0 (previously RCDATA\16001\0) |
6 | - Windows resource: OBFS\16\0 (previously RCDATA\16001\0) |
7 | - MacOS resource: 'obFS' 16 (previously 'DATA' 16001) |
7 | - MacOS resource: 'obFS' 16 (previously 'DATA' 16001) |
8 | 8 | ||
9 | Normal standalone filters: |
9 | Normal standalone filters: |
10 | - Windows resource: PARM\16\0 (previously PARM\16000\0) |
10 | - Windows resource: PARM\16\0 (previously PARM\16000\0) |
11 | - MacOS resource: 'PARM' 16 (previously 'PARM' 16000) |
11 | - MacOS resource: 'PARM' 16 (previously 'PARM' 16000) |
12 | 12 | ||
13 | ## Implementation |
13 | ## Implementation |
14 | 14 | ||
15 | Defined in **ff.h**, implemented in **obfusc.c**: |
15 | Defined in **ff.h**, implemented in **obfusc.c**: |
16 | 16 | ||
17 | // Implements Obfusc V6. |
17 | // Implements Obfusc V7. |
18 | // Returns a seed that needs to be stored in the executable code. |
18 | // Returns a seed1 and seed2 which need to be stored in the executable code. |
19 | uint64_t obfusc(PARM_T* pparm); |
19 | obfusc(PARM_T* pparm, uint64_t* out_initial_seed, uint64_t* out_initial_seed2); |
20 | 20 | ||
21 | // In V1+V2: Seed is hardcoded |
21 | // In V1+V2: Seed is hardcoded |
22 | // In V3: Seed is in PARM (field "unknown2") |
22 | // In V3: Seed is in PARM (field "unknown2") |
23 | // In V4-V6: Seed is in the program code and will me modified with a binary search+replace |
23 | // In V4-V7: Seed is in the program code and will me modified with a binary search+replace |
24 | void deobfusc(PARM_T* pparm); |
24 | void deobfusc(PARM_T* pparm); |
25 | 25 | ||
- | 26 | ### Obfuscation "Version 7" |
|
- | 27 | ||
- | 28 | Introduced in **Filter Foundry 1.7.0.17** |
|
- | 29 | ||
- | 30 | Now, there are two 64-bit seeds: |
|
- | 31 | ||
- | 32 | Initial seed 1: `0x7416972a52830517` (is in the code segment) |
|
- | 33 | Initial seed 2: `0xEF87A2F13E1F2186` (is in the data segment) |
|
- | 34 | ||
- | 35 | First, XOR-Shift64 using seed 2, then ROL shift, then XOR-Shift32 like in Obfusc V6. |
|
- | 36 | ||
26 | ### Obfuscation "Version 6" |
37 | ### Obfuscation "Version 6" |
27 | 38 | ||
28 | Introduced in **Filter Foundry 1.7.0.10** |
39 | Introduced in **Filter Foundry 1.7.0.10** |
29 | 40 | ||
30 | First, the fields `unknown1`, `unknown2`, aned `unknown3` are set to 0. |
41 | First, the fields `unknown1`, `unknown2`, aned `unknown3` are set to 0. |
31 | 42 | ||
32 | A 64 bit seed will be generated. |
43 | A 64 bit seed will be generated. |
33 | On Windows, the seed is the ECMA 182 CRC64 checksum of the PARM. |
44 | On Windows, the seed is the ECMA 182 CRC64 checksum of the PARM. |
34 | On Macintosh, it stays at the default value `0x38AD972A52830517` (before 1.7.0.17) or |
45 | On Macintosh, it stays at the default value `0x38AD972A52830517` (before 1.7.0.17) or |
35 | `0x7416972a52830517` (beginning with 1.7.0.17). |
46 | `0x7416972a52830517` (beginning with 1.7.0.17). |
36 | (because the manipulation of the binary code is not implemented). |
47 | (because the manipulation of the binary code is not implemented). |
37 | 48 | ||
38 | Then, the CRC32b checksum of the PARM will be written to `unknown1`. |
49 | Then, the CRC32b checksum of the PARM will be written to `unknown1`. |
39 | 50 | ||
40 | The PARM will then be XORed with a random data stream of the lower 32 bits of the 64 bit seed. |
51 | The PARM will then be XORed with a random data stream of the lower 32 bits of the 64 bit seed. |
41 | The algorithm is the XORshift which was introcuced in obfuscation version 2. |
52 | The algorithm is the XORshift which was introcuced in obfuscation version 2. |
42 | Unlike obfuscation version 3-5, while generating and applying the random data |
53 | Unlike obfuscation version 3-5, while generating and applying the random data |
43 | stream, no bytes are skipped. |
54 | stream, no bytes are skipped. |
44 | 55 | ||
45 | After this, PARM will be XORed with the 64 bit seed, |
56 | After this, PARM will be XORed with the 64 bit seed, |
46 | which will be ROLed by 1 bit after each byte: |
57 | which will be ROLed by 1 bit after each byte: |
47 | 58 | ||
48 | uint64_t rol_u64(uint64_t value, uint64_t by) { |
59 | uint64_t rol_u64(uint64_t value, uint64_t by) { |
49 | return value << by | value >> (sizeof(uint64_t) * 8 - by); |
60 | return value << by | value >> (sizeof(uint64_t) * 8 - by); |
50 | } |
61 | } |
51 | 62 | ||
52 | The 64 bit seed is stored in the executable. |
63 | The 64 bit seed is stored in the executable. |
53 | 64 | ||
54 | The DWORD value `0x00000006` will be stored at field `unknown2` |
65 | The DWORD value `0x00000006` will be stored at field `unknown2` |
55 | (byte 0x30..0x33; the field is not used in the `PARM` resource). |
66 | (byte 0x30..0x33; the field is not used in the `PARM` resource). |
56 | 67 | ||
57 | During de-obfuscation, the program will check if the checksum in `unknown1` |
68 | During de-obfuscation, the program will check if the checksum in `unknown1` |
58 | matches. If it does not match, the data will be discarded. |
69 | matches. If it does not match, the data will be discarded. |
59 | 70 | ||
60 | ### Obfuscation "Version 5" |
71 | ### Obfuscation "Version 5" |
61 | 72 | ||
62 | Introduced in **Filter Foundry 1.7.0.8** |
73 | Introduced in **Filter Foundry 1.7.0.8** |
63 | 74 | ||
64 | Obfuscation version 5 is the same as version 4, but there is a constraint |
75 | Obfuscation version 5 is the same as version 4, but there is a constraint |
65 | that the seed must be equal to the CRC32b checksum of the deobfuscated PARM. |
76 | that the seed must be equal to the CRC32b checksum of the deobfuscated PARM. |
66 | This is done to check the integrity of the deobfuscation. |
77 | This is done to check the integrity of the deobfuscation. |
67 | 78 | ||
68 | Also, the xor-shifting is intentionally incompatible with version 4 |
79 | Also, the xor-shifting is intentionally incompatible with version 4 |
69 | (to avoid downgrade-attacks) by XORing the initial seed with 0xFFFFFFFF. |
80 | (to avoid downgrade-attacks) by XORing the initial seed with 0xFFFFFFFF. |
70 | 81 | ||
71 | The DWORD value `0x00000005` will be stored at field `unknown2` |
82 | The DWORD value `0x00000005` will be stored at field `unknown2` |
72 | (byte 0x30..0x33; the field is not used in the `PARM` resource). |
83 | (byte 0x30..0x33; the field is not used in the `PARM` resource). |
73 | 84 | ||
74 | While generating and applying the random data stream, the bytes |
85 | While generating and applying the random data stream, the bytes |
75 | 0x30..0x33 (the location where the version info is stored) are skipped, |
86 | 0x30..0x33 (the location where the version info is stored) are skipped, |
76 | like in version 3. |
87 | like in version 3. |
77 | 88 | ||
78 | ### Obfuscation "Version 4" |
89 | ### Obfuscation "Version 4" |
79 | 90 | ||
80 | Introduced in **Filter Foundry 1.7.0.7** |
91 | Introduced in **Filter Foundry 1.7.0.7** |
81 | 92 | ||
82 | It is not compiler-dependant, but different between every standalone filter. |
93 | It is not compiler-dependant, but different between every standalone filter. |
83 | 94 | ||
84 | Windows version: |
95 | Windows version: |
85 | The binary code of the 8BF file will be manipulated during building |
96 | The binary code of the 8BF file will be manipulated during building |
86 | to store the seed into the `deobfusc()` function. |
97 | to store the seed into the `deobfusc()` function. |
87 | The placeholder value is `OBFUSC_V4_DEFAULT_SEED 0x52830517` |
98 | The placeholder value is `OBFUSC_V4_DEFAULT_SEED 0x52830517` |
88 | This allows that 32-bit and 64-bit filters are "cross built". |
99 | This allows that 32-bit and 64-bit filters are "cross built". |
89 | 100 | ||
90 | (Theoretical) Macintosh version: |
101 | (Theoretical) Macintosh version: |
91 | Obfuscation and deobfuscation has the seed `0x52830517`, since the |
102 | Obfuscation and deobfuscation has the seed `0x52830517`, since the |
92 | manipulation of the binary code is not implemented. |
103 | manipulation of the binary code is not implemented. |
93 | 104 | ||
94 | Algorithm: XOR-Shift like in version 2, but the seed is individual for |
105 | Algorithm: XOR-Shift like in version 2, but the seed is individual for |
95 | each individual built standalone filter. |
106 | each individual built standalone filter. |
96 | 107 | ||
97 | The DWORD value `0x00000004` will be stored at field `unknown2` |
108 | The DWORD value `0x00000004` will be stored at field `unknown2` |
98 | (byte 0x30..0x33; the field is not used in the `PARM` resource). |
109 | (byte 0x30..0x33; the field is not used in the `PARM` resource). |
99 | 110 | ||
100 | While generating and applying the random data stream, the bytes |
111 | While generating and applying the random data stream, the bytes |
101 | 0x30..0x33 (the location where the version info is stored) are skipped, |
112 | 0x30..0x33 (the location where the version info is stored) are skipped, |
102 | like in version 3. |
113 | like in version 3. |
103 | 114 | ||
104 | ### Obfuscation "Version 3" |
115 | ### Obfuscation "Version 3" |
105 | 116 | ||
106 | Introduced in **Filter Foundry 1.7.0.5** |
117 | Introduced in **Filter Foundry 1.7.0.5** |
107 | 118 | ||
108 | A random seed is chosen and written to field `unknown2` (byte 0x30..0x33). |
119 | A random seed is chosen and written to field `unknown2` (byte 0x30..0x33). |
109 | 120 | ||
110 | Then, the `PARM` resource will be obfuscated by applying an XOR operation to a random data stream: |
121 | Then, the `PARM` resource will be obfuscated by applying an XOR operation to a random data stream: |
111 | 122 | ||
112 | unsigned char *p; |
123 | unsigned char *p; |
113 | *p++ ^= (int)(rand() * 1.0 / (RAND_MAX + 1) * 256); |
124 | *p++ ^= (int)(rand() * 1.0 / (RAND_MAX + 1) * 256); |
114 | 125 | ||
115 | Bytes 0x30..0x33 (the location where the seed is stored) are skipped. |
126 | Bytes 0x30..0x33 (the location where the seed is stored) are skipped. |
116 | 127 | ||
117 | The `rand()` operation is compiler-dependant, and therefore the resource cannot be exchanged between plugins. |
128 | The `rand()` operation is compiler-dependant, and therefore the resource cannot be exchanged between plugins. |
118 | 129 | ||
119 | 32 bit plugin is built with OpenWatcom (for Win95 compatibility) which has following formula: |
130 | 32 bit plugin is built with OpenWatcom (for Win95 compatibility) which has following formula: |
120 | 131 | ||
121 | int rand_openwatcom(unsigned int* seed) { |
132 | int rand_openwatcom(unsigned int* seed) { |
122 | *seed = *seed * 1103515245L + 12345L; |
133 | *seed = *seed * 1103515245L + 12345L; |
123 | return (*seed >> 16) & 0x7fff; /* Scale between 0 and RAND_MAX */ |
134 | return (*seed >> 16) & 0x7fff; /* Scale between 0 and RAND_MAX */ |
124 | } |
135 | } |
125 | 136 | ||
126 | 64 bit plugin is built with Visual C++ which has following formula: |
137 | 64 bit plugin is built with Visual C++ which has following formula: |
127 | 138 | ||
128 | int rand_msvcc(unsigned int* seed) { |
139 | int rand_msvcc(unsigned int* seed) { |
129 | *seed = *seed * 214013L + 2531011L; |
140 | *seed = *seed * 214013L + 2531011L; |
130 | return (*seed >> 16) & 0x7fff; /* Scale between 0 and RAND_MAX */ |
141 | return (*seed >> 16) & 0x7fff; /* Scale between 0 and RAND_MAX */ |
131 | } |
142 | } |
132 | 143 | ||
133 | ### Obfuscation "Version 2" |
144 | ### Obfuscation "Version 2" |
134 | 145 | ||
135 | Introduced in **Filter Foundry 1.7b1** |
146 | Introduced in **Filter Foundry 1.7b1** |
136 | 147 | ||
137 | It is compiler-independent! |
148 | It is compiler-independent! |
138 | 149 | ||
139 | Algorithm: [XOR-Shift](https://de.wikipedia.org/wiki/Xorshift "XOR-Shift") with hardcoded seed `0x95d4a68f`. |
150 | Algorithm: [XOR-Shift](https://de.wikipedia.org/wiki/Xorshift "XOR-Shift") with hardcoded seed `0x95d4a68f`. |
140 | 151 | ||
141 | x32 = 0x95d4a68f; |
152 | x32 = 0x95d4a68f; |
142 | for(i = size, p = pparm; i--;) { |
153 | for(i = size, p = pparm; i--;) { |
143 | x32 ^= x32 << 13; |
154 | x32 ^= x32 << 13; |
144 | x32 ^= x32 >> 17; |
155 | x32 ^= x32 >> 17; |
145 | x32 ^= x32 << 5; |
156 | x32 ^= x32 << 5; |
146 | *p++ ^= x32; |
157 | *p++ ^= x32; |
147 | } |
158 | } |
148 | 159 | ||
149 | ### Obfuscation "Version 1" |
160 | ### Obfuscation "Version 1" |
150 | 161 | ||
151 | Introduced in **Filter Foundry 1.4b8,9,10** |
162 | Introduced in **Filter Foundry 1.4b8,9,10** |
152 | 163 | ||
153 | It is compiler-dependant, and therefore the resource cannot be exchanged between plugins! |
164 | It is compiler-dependant, and therefore the resource cannot be exchanged between plugins! |
154 | 165 | ||
155 | Algorithm: XOR with `rand()`-stream with hardcoded seed `0xdc43df3c`. |
166 | Algorithm: XOR with `rand()`-stream with hardcoded seed `0xdc43df3c`. |
156 | 167 | ||
157 | srand(0xdc43df3c); |
168 | srand(0xdc43df3c); |
158 | for(i = size, p = pparm; i--;) { |
169 | for(i = size, p = pparm; i--;) { |
159 | *p++ ^= rand(); |
170 | *p++ ^= rand(); |
160 | } |
171 | } |
161 | 172 | ||
162 | The plugin is built with Visual C++ which has following formula: |
173 | The plugin is built with Visual C++ which has following formula: |
163 | 174 | ||
164 | int rand_msvcc(unsigned int* seed) { |
175 | int rand_msvcc(unsigned int* seed) { |
165 | *seed = *seed * 214013L + 2531011L; |
176 | *seed = *seed * 214013L + 2531011L; |
166 | return (*seed >> 16) & 0x7fff; /* Scale between 0 and RAND_MAX */ |
177 | return (*seed >> 16) & 0x7fff; /* Scale between 0 and RAND_MAX */ |
167 | } |
178 | } |
168 | 179 |