-
Notifications
You must be signed in to change notification settings - Fork 27
/
obfuscation-tricks.txt
414 lines (282 loc) · 7 KB
/
obfuscation-tricks.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
A primer on some C obfuscation tricks.
Typedef abuse:
1) normal expected form:
typedef signed int my_int;
2) abuse it by:
signed int typedef my_int;
int typedef signed my_int;
3) or since int is default type, one can do:
typedef my_int;
Array abuse:
char x[];
int index;
x[index] is *(x+index)
index[x] is legal C and equivalent too
Literal string abuse, like above in principle
int index = 0;
printf("%c\n", index["MyString"]);
4) Abuse unexpected results:
#include <stdio.h>
#define X (-2147483648)
int foo(void) { return -X; }
int main(void)
{
printf("%d\n", foo());
}
"-2147483648 is positive. This is because 2147483648 cannot fit in the type int,
so (following the ISO C rules) its data type is unsigned long int. Negating this
value yields 2147483648 again."
5) Surprising math:
int x = 0xfffe+0x0001;
looks like 2 hex constants, but in fact it is not.
6) Abuse the pre-processor
#define A case _COUNTER_: n = (__COUNTER__ - 1) & 0xfffff;break;
#define B A A A A A A A A A A A A A A A A
#define C B B B B B B B B B B B B B B B B
#define D C C C C C C C C C C C C C C C C
#define E D D D D D D D D D D D D D D D D
#define F E E E E E E E E E E E E E E E E
main(){ int n = 0; for (;;) switch(n) { F } }
7) indirection on function pointers with comments..
(**/**/**/**/**/**/**write)(1, "Hello World\n", 12);
8) Do confusing things:
unsigned char count = 1;
printf("%d %d\n", 0 == sizeof(count = 2, count++), count);
9) Make it hard to be traced:
#include <unistd.h>
#include <sys/ptrace.h>
#include <signal.h>
#include <setjmp.h>
sigjmp_buf e;
void h(int sig) { siglongjmp(e, 1); }
int main(void)
{
signal(SIGTRAP, h);
if (sigsetjmp(e, 0) != 1)
while (1)__asm__("int3");
if (!ptrace(PTRACE_TRACEME, 0, 1, 0))
write(1, "gdb or strace me\n", 17);
return 0;
}
10) insert URLs for fun:
int main(int argc, char *argv[])
{
http://smackerelofopinion.blogspot.co.uk/search/label/C
return 0;
}
11) URL comments ;-)
Useful background reading:
http://www.se.rit.edu/~tabeec/RIT_441/Resources_files/How%20To%20Write%20Unmaintainable%20Code.pdf
12) Fun with predefined values (yep, this compiles)
int main(){ return linux > unix; }
13) Break code over lines. Makes it hard to grep
ret\
urn 0;
14) Make macros with ( { ; imbalancing to make it more confusing
#define P printf(
#define X );}
main() {
P("Hello World" X
15) Use gcc alternate digraphs for fun!
Digraph: <% %> <: :> %: %:%:
Punctuator: { } [ ] # ##
16) Use macro definitions of numbers in roman numerals (and make them wrong to confuse reader)
#define XII (10+3)
17) use offputting variable names, eg;
float Not, And, Or;
double Int8;
int _, __, o, O; Oo, Oo, OO, oo;
so you end up with code like:
while (!Not & And != (Or | 2))...
18) Shove all variables into one array
don't have lots of ints; just have one array of ints and
reference these using:
x[0], 1[x], *(x+4), *(8+x).. etc
19) Use cpp pasting ## and stringification for fun and laughs
20) Abuse switch and while;
void sw(int s)
{
switch (s) while (0) {
case 0:
printf("zero\n");
continue;
case 1:
printf("one\n");
continue;
case 2:
printf("two\n");
continue;
default:
printf("something else\n");
continue;
}
}
21) Use confusing coding idioms:
Replace:
if (c)
x = v;
else
y = v;
With:
*(c ? &x : &y) = v;
22) don't use loops, abuse goto, setjmp, longjmp, recursion
make it confusing, don't make it obvious
23) use a smart algorithms
make it so smart that it is hard to figure out
what the code is really doing
24) Abuse sizeof
int foo(const int i)
{
char x[i];
return sizeof x;
}
int
main(void)
{
printf("%d\n", foo(-1));
}
25)
A void function that returns void(!)
void a (void) { }
void b (void) { return a(); };
26) Make it look different, format code into pictures
Example:
#include <stdio.h>
#include <stdlib.h>
#define K continue
#define t /*|+$-*/9
#define _l /*+$*/25
#define s/*&|+*/0xD
#define _/*&|+*/0xC
#define _o/*|+$-*/2
#define _1/*|+$-*/3
#define _0/*|+$*/16
#define J/*&|*/case
char typedef signed
B;typedef H;H main(
){B I['F'],V=0,E[]=
{s,0,s,31,t,1,s,111
,_,t,-3,_,s,50,_l,-
1,t,1,s,0x48>>2,_l,
-2,_,_1,5,_o,s,0,_1
,-8,s,0,s,-65,t,75,
s,100,_,t,8,_,_1,-5
,s,82,t,32,s,111,s,
20,_l,-2,t,7,_,_1,5
,_o,s,0,_1,-8,s,0,\
_0,};B*P=E;while(P)
{B L=*P,l=*(P+1),U=
I[V-1],A=(L>>2)&1,C
=(V-(1-A)),i;switch
(L)while(0){J _l:i=
l>0?U>>l:U<<-l;K;J\
t:i=U+l;K;J _:i=U;
K;J s:i=l;K;J _o:
putchar(U);K;J _1:
P+=U?0:l;K;J _0:e\
xit(0);}C[I]=(L&8)?
i:I[C];P+=(L&1)+1;V
+=A-((L&2)>>1);}re\
turn/*c.i.king*/0;}
26) Doing nothing
({_:&&_;});
({});
({;});
switch (0);
27) abusing __VA_ARGS__
One can pass an entire function body into a macro using __VA_ARGS__
#define F(f, ...) f __VA_ARGS__
F(void foo(void) { printf("foo\n"); })
28) Turn array to a pointer using +
foo(&array[0]);
instead use:
foo(+array);
29)
int x = 1;
foo(&x);
use:
foo( (int[]){1} );
30) Zero'ing
a ^= a;
a = '-'-'-';
31) Variable names:
char broiled;
double burger;
short cake;
float icecream;
long story;
signed sincerely;
static electricity;
auto mechanic;
volatile substance;
register electorat;
unsigned autobiography;
void *gazing_back;
char witness;
const*able;
union dues {};
31) Precendence rules abuse:
#include <stdio.h>
int main(void) { int array[] = {1, 2, 3}; int *p = &array[1]; printf("%d\n", -1[p]); }
-1[p] is -(*(1 + p)) and not *(-1 + p)
32) Make simple expressions more complex
u8 val;
tricky simple
if (val && ~val) if (val)
break; break;
33) Fun ways to increment:
i-=-1;
34) Yes/No?
return (char *[]){"No", "Yes"}[!!x];
35) Use local typedefs to confuse:
int x(int y)
{
return y;
}
int main(void)
{
printf("%d\n", (x)(257));
typedef char x;
printf("%d\n", (x)(257));
}
36) Unconstifying a const char * pointer without casting
const char *foo = "foo";
char *bar = strchr(foo, *foo);
37) Macro confusion with keywords
#define for(x) while(0)
int main(void)
{
int i;
for (i = 0; i < 100; i++) {
printf("%d\n", i);
}
}
38) Use lesser used syntax:
void what(char s[static volatile restrict 0])
{
printf("%s\n", s);
}
main()
{
what("foo");
}
39) Abuse +, -, ++, --
int a = 1, b = 2, c = 3;
int d = a+++-b+++-c;
40) A stupid for(;;)
while ((*(int[]){1})--)
41) ternary type conversions:
see: http://smackerelofopinion.blogspot.com/2021/04/c-ternary-operator-gotcha-type.html
#include <stdlib.h>
#include <stdio.h>
long int ternary(int a, unsigned int x)
{
return a ? a : x;
}
int main(void)
{
printf("%ld\n", ternary(-1, 0));
return 0;
}
42)
0x80000000 == -0x80000000 is true