How to write self-modifying executables

uunet!bria!mike uunet!bria!mike
Sun Jan 20 10:08:27 AEST 1991


In article <72651 at bu.edu.bu.edu> bucsf.bu.edu!jdubb (jay dubb) writes:
>   I am going to write a self-modifying executable (along the lines of
>what Mie Bria talked about in article 822: have an executable contain
>a time/date string which it can modify and use, to stop working past a
>certain date).

I've never been known as "Mie Bria" before. :-)

Since a few people have asked me about this (in mail, etc.) on how to go
about modifying an image, I'll provide some sample code.  THe basic idea
is this: the user executes a program; within this program is a static
string that contains some unique characters, followed by a date stamp.
The program then overlays itself (using exec()) with a small program who's
job it is to validate the image.  This small program searches for this
stamp, checks to see if it is valid, and updates the stamp.  If the image
is not valid, it marks it as invalid (therefore, setting the clock forward
again won't let the sneaky user get by) and terminates.  If the image is
valid, then it overlays itself with the original image, and the program
executes normally.

The reason that two programs are used is because UNIX will lock the image
during execution so that you cannot alter it; the multiple exec's get
around this problem.  Note that when you first execute the program from
the command line, argv[0] contains the name of the program; when the
security program re-execs the program, argv[0] is empty, thereby letting
the program know that the security program fired it up.

Obviously, any C programmer with a modicum of skill could get around
this, but it would put a damper on the run-of-the-mill user.

No flaming please ... the code may not be beautiful, but then again, it
sorta works (for me at least :-)

---[ cut here and call it "program.c" ]--------------------------------------

/*	program.c	a sample program */

#include <stdio.h>

char	stamp[16] = "XfuG00000000000";

main(argc,argv)
int 	argc;
char	*argv[];
{
	if ( strlen(argv[0]) > 0 )
		execlp("security","security",argv[0],NULL);

	printf("My stamp is %s\n",&stamp[4]);
	exit(0);
}

---[ cut here and call it "security.c" ]-------------------------------------

/*	@(#)security.c	1.1	stamp an image with the current date

	this program takes one argument, which is the name of an image
	that has a predefined "marker" (in this case, "DATE") which is
	followed by a date specification and checks that date against
	a possible "clock rollback"

	if stamp detects a rollback, it exits with an error status;
	otherwise, it proceeds to re-exec the image that started it
*/

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>

char	*target = "XfuG";

main(argc,argv)
int argc;
char *argv[];
{
	if ( argc != 2 )
		exit(1);

	if ( patch(argv[1]) == 0 )
		execlp(argv[1],"",NULL);
}

patch(file)
char	*file;
{
long	loc = 0L, count = 0L, bytes = 0L;
int	fd;
char	*block, *buf, *ptr;

	if ( (block = (char *)malloc(32768)) == NULL )
		return(1);
	buf = block;

	if ( (fd = open(file,O_RDWR)) == -1 ) 
		return(1);

	ptr = target;

	while ( read(fd,buf,32768) != 0 ) {
		loc = 0;
		while ( loc != 32768 ) {
			++bytes;
			if ( *buf == *ptr ) {
				if ( *++ptr == 0 ) {
					alter(fd,bytes);
					close(fd);
					free(block);
					return(0);
					}
				}
			else
				ptr = target;
			++loc;
			++buf;
			}
		buf = block;
		}

	close(fd);
	free(block);
	return(1);
}

alter(fd,off)
int	fd;
long	off;
{
char	stamp[12];
long	when, now;

	lseek(fd,off,SEEK_SET);
	read(fd,stamp,12);

	if ( strcmp(stamp,"INVALID") == 0 ) {
		fprintf(stderr,"This program has been disabled!\n");
		exit(1);
		}

	when = atol(stamp);
	time(&now);
	lseek(fd,-12,SEEK_CUR);

	if ( now < when ) {
		fprintf(stderr,"A security violation has occurred.\n");
		strcpy(stamp,"INVALID");
		write(fd,stamp,12);
		exit(1);
		}

	sprintf(stamp,"%ld",now);
	write(fd,stamp,12);
}

---[ end of example ]--------------------------------------------------------

Compile both programs in the current working directory, make sure that
your PATH includes the current directory, and that the 'program' image
is read/writable.  Enter the command:

	$ program

Then try setting the clock back, execute 'program' again.  Then set the
clock forwards to the real time, and execute 'program' again.

To actually make this usuable, you will have to resolve the search path,
and do a few other things, but at least I got you started...
-- 
Michael Stefanik, Systems Engineer (JOAT), Briareus Corporation
UUCP: ...!uunet!bria!mike
--
technoignorami (tek'no-ig'no-ram`i) a group of individuals that are constantly
found to be saying things like "Well, it works on my DOS machine ..."



More information about the Comp.unix.programmer mailing list