188 lines
5.7 KiB
Plaintext
188 lines
5.7 KiB
Plaintext
-----BEGIN PGP SIGNED MESSAGE-----
|
|
|
|
Article Written for Crisnews
|
|
By: Michael Stowe
|
|
|
|
|
|
|
|
"Self-Protecting Executables" -- by Michael Stowe
|
|
|
|
Files which protect themselves are probably one of the most
|
|
effective weapons against virus spreading. A self-protecting
|
|
file is a file which tests itself when starting up and refuses to
|
|
run if it has been altered in any way. Often, self-protecting
|
|
files will provide the first clue that a virus infection has
|
|
occurred.
|
|
|
|
This article presents simple C source code which may be used in
|
|
any program to provide a program with an effective technique for
|
|
sensing its own integrity.
|
|
|
|
There are two components to the protection scheme; a standalone
|
|
program which determines an .EXE or .COM file's signature, and
|
|
"brands" the file with the signature, and a module to be compiled
|
|
into the executable file that verifies this signature.
|
|
|
|
First, the branding program. It uses a very simple checksum
|
|
technique to generate a signature. As you can see from the code,
|
|
it simply xor's each byte with its position in the file and
|
|
appends the total to the end. The code follows:
|
|
|
|
#include <stdio.h>
|
|
|
|
unsigned long int file_brand(char *name)
|
|
{
|
|
FILE *fin;
|
|
register c;
|
|
register long accum=0;
|
|
register long count=0;
|
|
int error=0;
|
|
|
|
if ((fin=fopen(name, "rb+"))==NULL) {
|
|
perror(name);
|
|
return ERROR;
|
|
}
|
|
while ((c=getc(fin))!=EOF) {
|
|
accum+=c^count++;
|
|
}
|
|
|
|
fseek(fin, 0, SEEK_END);
|
|
|
|
fwrite(&accum, sizeof(long), 1, fin);
|
|
|
|
if (ferror(fin)) {
|
|
perror(name);
|
|
error = -1;
|
|
}
|
|
|
|
fclose(fin);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
void main(int argc, char **argp)
|
|
{
|
|
register errors = 0;
|
|
|
|
while( --argc > 0)
|
|
errors |= file_brand( *++argp);
|
|
exit(errors != 0);
|
|
}
|
|
|
|
The above will generate an executable which takes an .EXE or .COM
|
|
file as an argument. The checksum will be appended to the end of
|
|
the file, which will make the file a little longer, but do no
|
|
damage. If you wish to compress the .EXE or .COM file (e.g.,
|
|
with Pklite), do so BEFORE running the branding program.
|
|
|
|
The companion routines belong in the .C source file which
|
|
generated the .EXE or .COM file which was just branded:
|
|
|
|
#include <dos.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <io.h>
|
|
|
|
/* Sanity check for file */
|
|
int file_changed(char *filename)
|
|
{
|
|
FILE *fin;
|
|
register c;
|
|
register long accum=0;
|
|
long compare;
|
|
register long count=0;
|
|
int error=0;
|
|
|
|
if ((fin=fopen(name, "rb"))==NULL) {
|
|
perror(name);
|
|
return -1;
|
|
}
|
|
length=filelength(fileno(fin))-sizeof(long);
|
|
|
|
for(count=0; count<length; count++) {
|
|
accum+=c^count;
|
|
}
|
|
|
|
fread(&compare, sizeof(long), 1, fin);
|
|
|
|
if (ferror(fin)) {
|
|
perror(name);
|
|
error = -1;
|
|
}
|
|
|
|
fclose(fin);
|
|
|
|
if(compare==accum)
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
if(file_changed(argv[0]))
|
|
{
|
|
puts(
|
|
" WARNING! The program has failed its internal diagnostic.\n"
|
|
" This can be caused by a viral attack, by use of compression\n"
|
|
" software or an illegal hack attempt.\n\n
|
|
" For your own safety, this program will not execute. Please\n"
|
|
" reinstall from the original archive or diskette.");
|
|
};
|
|
|
|
/* Your program follows */
|
|
};
|
|
|
|
|
|
The warning text above probably says everything that needs to be
|
|
said...
|
|
|
|
Although the above routine will be effective in 99.9% of all
|
|
cases in detecting infections or alterations of an executable
|
|
program, you should probably -not- use the routine verbatim.
|
|
|
|
The reason is simple: if this becomes a common, drop-in program
|
|
used in all executables, then new virii will simply contain the
|
|
same code to fake their own signatures or disable the routine.
|
|
Although this scenario isn't highly likely, it can be avoided
|
|
through simple alterations to the checksum calculations, such as
|
|
using exclusionary-or between a constant and each byte from the
|
|
file, or adding a number to the result, or subtracting, etc.
|
|
Just make sure the routines in the brand program and the
|
|
executable program match.
|
|
|
|
The main lesson here is that ALL executable files should contain
|
|
some kind of sanity check. It only makes sense for a program to
|
|
determine if it is the same version you released -- especially if
|
|
you're going to support it. The additional security that it
|
|
provides the user is worth some brownie points as well. I've
|
|
received several letters from users who were impressed that my
|
|
programs (which are not anti-virus programs) alerted them to
|
|
problems in their hardware or the presence of virii in their
|
|
system.
|
|
|
|
There is certainly room for improvement. Instead of the checksum
|
|
approach, a CRC approach would provide a greater degree of
|
|
confidence in the uniqueness of the signature. Also note that
|
|
this implementation requires that the entire executable be read
|
|
from disk twice; although this is not significant on systems
|
|
using a disk cache, it doubles the startup time on systems which
|
|
do not. This can be reduced or eliminated using a number of
|
|
techniques, including reading only key parts of the file (the
|
|
beginning, end, and approximate location of copyright notices,
|
|
for example.)
|
|
|
|
The included C source code is hereby released to the public
|
|
domain. I encourage all authors to consider using this or
|
|
another sanity-checking technique to ensure the integrity of
|
|
their programs.
|
|
|
|
-----BEGIN PGP SIGNATURE-----
|
|
Version: 2.3a
|
|
|
|
iQBVAgUBLNc4XKM4CDusTF+9AQFwNQH+MzLjYdK+TdUzICtaDxev2I/J+12i+x5I
|
|
hZn/hK4MJN5qxdMzos72L+Zcbr+wQchZyOxYo+BsSIl7t9QPBztL3Q==
|
|
=bf4z
|
|
-----END PGP SIGNATURE-----
|