First you may have to add tigress.h
to the top of every file.
Tigress is a whole-program transformer. Essentially, this means that Tigress accepts a single C file as input. This is so that we can do whole-program analysis and transformations. For example, the EncodeData transformation has to perform a whole program alias analysis to avoid generating the wrong code, and the Inline transformation -- of course -- needs the code of a function in order to expand it inline.
What this is that, for typical programs that consist of multiple C files, before we can actually perform any Tigress transormations, we must first merge the files together.
There are many ways to merge a program. If you're writing your program from
scratch and know you will be obfuscating it, it makes sense to write it in
such a way that merging becomes easy. This has other advantages such as
improving the compiler's ability to optimize. It's not hard to do this,
simply make sure that all global identifiers are unique! For example, if
you have a C module foo.c/.h
you should give every C object
(functions, variiables, structs, enums, etc.) the prefix foo_
.
Then merging might be no harder than this:
> cat *.h *.c > merged.c
Merging C programs is a fairly common problem and many people have tried to write their own automatic mergers. Searching for "amalgamate" on github yields several hits:
A number of projects have found that advantageous to distribute their code as a single merged file
rather than a large collection of .c/.h
files. Examples include:
Tigress comes with its own merger. If your project has multiple files you'd call
the merger before applying any obfuscating transformations. This will merge
together all the .h
files that your program depends on, including
all the system .h
files. Note that this implies that the resulting
merged file is no longer portable.
Earlier versions of Tigress (prior to Version 4) had a separate merge program, called tigress-merge. This is no longer needed.
For more complex merging scenarios, see the CIL information page about merging.;
Here's a simple case where we're just merging two files together, to prepare for subsequent Tigress transformations:
> cat file1.c
struct foo;
extern struct foo *global;
> cat file2.c
struct bar {
int x;
struct bar *next;
};
extern struct bar *global;
struct foo {
int y;
};
extern struct foo another;
int main() {
}
> tigress file1.c file2.c --out=full.c
> gcc full.c
Here's a slightly more complex case:
> cat f1.h
struct f1_struct {int a;};
void f1_func(struct f1_struct x);
> cat f1.c
void f1_func(struct f1_struct x) {
x.a = 10;
}
> cat f2.h
struct f2_struct {int a;};
void f2_func(struct f2_struct x);
> cat f2.c
void f2_func(struct f2_struct x) {
x.a = 10;
}
> cat m.c
int main() {
struct f1_struct x;
struct f2_struct y;
f1_func(x);
f2_func(y);
}
Let's merge the files together into full.c
:
> tigress f1.c f2.c m.c --out=full.c
> gcc full.c
And now we can obfuscate the merged file using Tigress' Merge
transform (which merges functions, not files, of course!):
> tigress --Transform=Merge \
--Functions=f1_func,f2_func \
--MergeName=merged \
--out=obf.c full.c
> gcc obf.c
And this is what the resulting program looks like:
void merged(void *tigressRetVal , struct f1_struct x__0 , struct f2_struct x__1 ,
int whichBlock__2 ) {
if (whichBlock__2 == 0) {
x__0.a = 10;
return;
} else
if (whichBlock__2 == 1) {
x__1.a = 10;
return;
} else {
}
}
int main( ) {
struct f1_struct x ;
struct f2_struct y ;
merged(0, x, y, 0);
merged(0, x, y, 1);
}
Miniweb is a small web server.
To get the Tigress merger to work, we have to fix a few things. This is pretty common when you merge a program that was not designed to be merged!
First you may have to add tigress.h
to the top of every file.
Then, let's get rid of a bug:
> gsed -i 's/mwBuildHttpHeader/mwBuildHttpHeaderXXX/' httphandler.c
Now we can call Tigress to merge, and then obfuscate:
> tigress --out=miniweb-merge.c \
httppil.c \
http.c \
httpxml.c \
httphandler.c \
httppost.c \
httpauth.c \
miniweb.c
> gcc -o miniweb-merge.exe miniweb-merge.c
> tigress \
--Transform=Virtualize \
--Functions=mwInitParam \
--out=miniweb-merge-obf.c miniweb-merge.c
> gcc miniweb-merge-obf.c -o miniweb-merge-obf.exe
SQLite is an example of a
project that contains its own source code merge routine
(sqlite/tool/mksqlite3c.tcl
). If you want to obfuscate
SQLite you should definitely use their own merged sources, rather
than merge with the Tigress! However, purely as an exercise, we can
merge the raw SQLite sources using Tigress.
As usual, some initial fixes are necessary: remove the two files src/sqlite3recover.h
and src/geopoly.c
. Then go ahead and merge:
tigress \
-D__USE_XOPEN2K -D__USE_GNU -D_GNU_SOURCE \
-DSQLITE_ENABLE_MATH_FUNCTIONS \
-DSQLITE_THREADSAFE=1 \
-DNDEBUG \
-D_HAVE_SQLITE_CONFIG_H \
-DBUILD_sqlite \
-I./src \
-I/usr/local/include \
-DSQLITE_HAVE_ZLIB=1 \
-DSQLITE_DQS=0 \
-DSQLITE_ENABLE_FTS4 \
-DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_EXPLAIN_COMMENTS \
-DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION \
-DSQLITE_ENABLE_STMTVTAB \
-DSQLITE_ENABLE_DBPAGE_VTAB \
-DSQLITE_ENABLE_DBSTAT_VTAB \
-DSQLITE_ENABLE_BYTECODE_VTAB \
-DSQLITE_ENABLE_OFFSET_SQL_FUNC \
-DSQLITE_STRICT_SUBTYPE=1 \
src/*.c \
--out=merged.c
DoomGeneric is one of the many versions of the Doom game. Here is how we merge the sources:
> tigress \
dummy.c am_map.c doomdef.c doomstat.c dstrings.c d_event.c d_items.c \
d_iwad.c d_loop.c d_main.c d_mode.c d_net.c f_finale.c f_wipe.c g_game.c \
hu_lib.c hu_stuff.c info.c i_cdmus.c i_endoom.c i_joystick.c i_scale.c \
i_sound.c i_system.c i_timer.c memio.c m_argv.c m_bbox.c m_cheat.c \
m_config.c m_controls.c m_fixed.c m_menu.c m_misc.c m_random.c p_ceilng.c \
p_doors.c p_enemy.c p_floor.c p_inter.c p_lights.c p_map.c p_maputl.c \
p_mobj.c p_plats.c p_pspr.c p_saveg.c p_setup.c p_sight.c p_spec.c \
p_switch.c p_telept.c p_tick.c p_user.c r_bsp.c r_data.c r_draw.c \
r_main.c r_plane.c r_segs.c r_sky.c r_things.c sha1.c sounds.c statdump.c \
st_lib.c st_stuff.c s_sound.c tables.c v_video.c wi_stuff.c w_checksum.c \
w_file.c w_main.c w_wad.c z_zone.c w_file_stdc.c i_input.c i_video.c \
doomgeneric.c doomgeneric_xlib.c \
--out=one_doom.c
And now we can obfuscate (using the Tigress Ident
transormation which
does nothing!), compile, and play:
> tigress \
--Transform=Ident
--out=one_doom.obf.c \
one_doom.c
> gcc -o generic ./one_doom.obf.c -lm -lc -lX11 -Wl,-Map,doomgeneric.map
"The GNU Core Utilities are the basic file, shell and text
manipulation utilities of the GNU operating system." A number of academic papers use these programs
for evaluate purposes (whether this is a good idea or not is another question), so it make sense to be
able to merge them. Here is how to merge the who
utility:
Get the CoreUtils sources:
> git clone git://git.sv.gnu.org/coreutils
Run this command to get submodules and set up configuration:
> ./bootstrap
Configure the programs you want (here who
):
> ./configure --enable-install-program=who --enable-no-install-program=chroot,hostid,timeout,nice,\
users,pinky,stty,df,stdbuf,b2sum,base64,base32,basenc,basename,cat,chcon,chgrp,chmod,chown,cksum,\
comm,cp,csplit,cut,date,dd,dir,dirname,dircolors,du,echo,env,expand,expr,factor,false,fmt,fold,ginstall,\
groups,head,id,join,kill,link,ln,logname,ls,md5sum,mkdir,mkfifo,mknod,mktemp,mv,nl,nproc,nohup,numfmt,od,\
paste,pathchk,pr,printenv,printf,ptx,pwd,readlink,realpath,rm,rmdir,runcon,seq,sha1sum,sha224sum,sha256sum,\
sha384sum,sha512sum,shred,shuf,sleep,sort,split,stat,sum,sync,tac,tail,tee,test,touch,tr,true,truncate,tsort,\
tty,uname,unexpand,uniq,unlink,uptime,vdir,wc,whoami,yes
Run make
and then hit ctrl-C
./lib/configmake.h (and presumably) other files that are necessary.
Merge:
> tigress -I ./lib -I./src src/who.c --out=/tmp/who.c
Compile and run:
> gcc -I. -I./lib -Ilib -I./lib -Isrc -I./src -g -O2 -MT src/who.o -MD -MP -MF $depbase.Tpo -c -o src/who.o /tmp/who.c
> gcc -g -O2 -Wl,--as-needed -o src/who src/who.o src/libver.a lib/libcoreutils.a lib/libcoreutils.a -ldl
> src/who
collberg pts/0 2024-11-20 01:06 (100.11.0.0)