Copy Link
Add to Bookmark
Report
40Hex Issue 13 File 003
40Hex Number 13 Volume 4 Issue 1 File 003
===============================================================================
Extracting virus signatures from F-PROT
by Peter Vincent
The program included here does just that: Extracts signatures used by the
notorious anti-virus product F-PROT. Before we get to the code though, there
are a couple of things that need to be said.
There are two sets of signatures used in F-PROT. One is used by F-PROT.EXE,
and is included in a file named SIGN.DEF, while the other is used by
VIRSTOP.EXE and is included in VIRSTOP.EXE itself.
A virus signature is defined as a sequence of hex bytes, which can also include
one or more wildcards. A wildcard, represented here as "??", matches any given
hex byte. F-PROT does not use wildcards that can match more than one byte.
Note that F-PROT defines at least two different signatures for each virus.
This is apparently aimed at better identification of viruses. Also, the search
algorithm used ignores any hex bytes of value 90 or CC. This means that code
that contains a F-PROT signature with some of these bytes inserted into it will
still match the signature. In addition to signatures for detecting known
viruses, there are a few other signatures included that can presumably detect
some unknown viruses. These signatures are named as "unknown".
How to extract signatures from F-PROT: easy as 1-2-3. Extract the source code
included here and store it to a file named GETFP211.PAS. Compile this program
with Turbo Pascal (version 4.0 or later). Copy SIGN.DEF and VIRSTOP.EXE from
F-PROT distribution to the default DOS directory, and run GETFP211. On
successful completion, two text files will be created: F-PROT.STR and
VIRSTOP.STR. They will contain the signatures found in SIGN.DEF and
VIRSTOP.EXE, respectively. Each line of these files will contain a signature,
and the corresponding virus name on every line. VIRSTOP signatures for boot
sector viruses are not included. The program has been tested to work
successfully with F-PROT 2.11; it might or might not work with future versions
if they change the formats.
The internal format used by F-PROT to store signatures can be easily retrieved
by reading the source code by any knowledgeable programmer.
And now for the source code:
--- Begin GETFP211.PAS --------------------------------------------------------
{
GETFP211.PAS: Extract virus signatures from F-PROT version 2.11.
This program is in the Public Domain. Courtesy of Peter Vincent.
}
{$i-,r-}
program getfpstr;
type ba = array[0..$fffe] of byte;
wa = array[0..$7ffe] of word;
bp = ^ba;
wp = ^wa;
function alloc(i: word): pointer;
var p: pointer;
begin
if maxavail < i then begin
writeln('Error: Not enough memory.');
halt(1);
end;
getmem(p,i);
alloc := p
end;
procedure writesig(var f: text; var s, name: string; x: char);
const hexstr: string[16] = '0123456789ABCDEF';
var i: word;
c: char;
begin
for i := 1 to length(s) do begin
c := s[i];
if c = x
then write(f,'?? ')
else write(f,hexstr[ord(c) shr 4+1],hexstr[ord(c) and 15+1],' ');
end;
for i := length(s)*3 to 79-length(name) do write(f,' ');
writeln(f,name);
end;
procedure dovirstop;
var len: longint;
virstop: pointer;
adj: word;
procedure readvirstop;
var f: file;
begin
writeln('Reading VIRSTOP.EXE...');
assign(f,'VIRSTOP.EXE');
reset(f,1);
if ioresult <> 0 then begin
writeln('Error: Cannot open VIRSTOP.EXE.');
halt(1);
end;
len := filesize(f);
if len > $fffe then begin
writeln('Error: VIRSTOP.EXE too big.');
halt(1);
end;
virstop := alloc(len);
blockread(f,virstop^,len);
if ioresult <> 0 then begin
writeln('Error: Cannot read VIRSTOP.EXE.');
halt(1);
end;
close(f);
case wp(virstop)^[0] of
$5a4d, $4d5a: else begin
writeln('Error: VIRSTOP.EXE is invalid.');
halt(1);
end;
end;
adj := wp(virstop)^[4]*16
end;
procedure writesigs;
var i,j,k,l,startpos,endpos,sigcnt: word;
found: boolean;
f: text;
buf: array[0..2047] of byte;
sig, name: string;
procedure chkioerr;
begin
if ioresult <> 0 then begin
writeln('Error: Cannot write to VIRSTOP.STR.');
halt(1);
end;
end;
begin
found := false;
j := 0;
k := 0;
for i := 0 to len-1 do
if chr(bp(virstop)^[i]) = '$' then begin
if i-j > 30
then
if found
then begin
endpos := j-adj;
i := len-1;
end else startpos := i-adj-30
else
if not found then begin
inc(k);
if k = 20 then inc(found);
end;
j := i;
end;
sigcnt := 0;
if found then
for i := 0 to len-1 do begin
j := i;
k := 0;
found := true;
while found do begin
l := bp(virstop)^[j];
if (l-1 > 24) or (wp(@bp(virstop)^[j+l+1])^[0]-startpos > endpos)
then dec(found)
else begin
inc(k);
inc(j,l+3);
end;
end;
if k >= 20 then begin
if sigcnt = 0 then begin
writeln('Writing VIRSTOP.STR...');
assign(f,'VIRSTOP.STR');
settextbuf(f,buf,sizeof(buf));
rewrite(f);
chkioerr;
end;
k := i;
repeat
sig := '';
for l := bp(virstop)^[k] downto 1 do begin
inc(sig[0]);
sig[length(sig)] := chr(bp(virstop)^[k+l]);
end;
inc(k,bp(virstop)^[k]+3);
name := '';
l := wp(@bp(virstop)^[k-2])^[0]+adj;
while chr(bp(virstop)^[l]) <> '$' do begin
inc(name[0]);
name[length(name)] := chr(bp(virstop)^[l]);
inc(l);
end;
writesig(f,sig,name,#$fe);
chkioerr;
inc(sigcnt);
until k = j;
writeln(f);
chkioerr;
i := k;
end;
end;
if sigcnt <> 0 then begin
close(f);
chkioerr;
writeln(sigcnt,' signatures found in VIRSTOP.EXE.');
end else writeln('Error: No signatures found in VIRSTOP.EXE.');
end;
begin
readvirstop;
writesigs;
freemem(virstop,len);
end;
procedure dosigndef;
var sigs, nameidx, names: pointer;
procedure readsigndef;
var f: file;
date: record
y: word;
d,m: byte
end;
procedure chkioerr;
begin
if ioresult <> 0 then begin
writeln('Error: Cannot read SIGN.DEF.');
halt(1);
end;
end;
procedure checksigndef;
var buf: array[0..4095] of byte;
i: word;
l,c0,c1: longint;
function rol(l: longint): longint;
begin
rol := l shl 1 or l shr 31
end;
begin
l := filesize(f)-4;
c0 := 0;
repeat
c1 := 0;
i := sizeof(buf);
if l < i then i := l;
blockread(f,buf,i);
chkioerr;
dec(l,i);
for i := 0 to i-1 do c1 := rol(c1) xor buf[i];
c0 := c0 xor c1;
until l = 0;
blockread(f,c1,sizeof(c1));
chkioerr;
if c0 <> c1 then begin
writeln('Error: SIGN.DEF has an invalid checksum.');
halt(1);
end;
end;
procedure readsigs;
const frisk: string[15] = 'Copyright (c) F';
var l: longint;
i,c: word;
x: byte;
function ror(x: byte): byte;
begin
ror := x shr 1 or x shl 7;
end;
begin
seek(f,0);
blockread(f,l,sizeof(l));
chkioerr;
seek(f,l+4);
blockread(f,i,sizeof(i));
chkioerr;
sigs := alloc(i-8);
blockread(f,sigs^,i-8);
chkioerr;
c := -wp(@bp(sigs)^[i-10])^[0];
for i := 0 to i-11 do begin
x := not ror(bp(sigs)^[i]) xor ord(frisk[i mod 100 mod 15+1]);
x := x xor i mod 100;
bp(sigs)^[i] := x;
inc(c,x xor i mod 100)
end;
if c <> 0 then begin
writeln('Error: Invalid signatures checksum.');
halt(1);
end;
end;
procedure readnames;
var i: word;
begin
blockread(f,i,sizeof(i));
chkioerr;
nameidx := alloc(i*2);
blockread(f,nameidx^,i*2);
chkioerr;
i := filesize(f)-filepos(f)-4;
names := alloc(i);
blockread(f,names^,i);
chkioerr;
date.y := not wp(@bp(names)^[i-4])^[0];
date.d := not bp(names)^[i-2];
date.m := not bp(names)^[i-1];
end;
begin
writeln('Reading SIGN.DEF...');
assign(f,'SIGN.DEF');
reset(f,1);
if ioresult <> 0 then begin
writeln('Error: Cannot open SIGN.DEF.');
halt(1);
end;
checksigndef;
readsigs;
readnames;
writeln('Signatures created ',date.m,'-',date.d,'-',date.y);
close(f);
end;
procedure writesigs;
var buf: array[0..2047] of byte;
i,sigcnt: word;
f: text;
sig, name: string;
procedure chkioerr;
begin
if ioresult <> 0 then begin
writeln('Error: Cannot write to F-PROT.STR.');
halt(1);
end;
end;
procedure extract(n: word);
var i,j,k: word;
begin
inc(sig[0]);
for i := 1 to bp(sigs)^[n] do begin
sig[length(sig)] := chr(bp(sigs)^[n+i+1]);
j := wp(@bp(sigs)^[n+bp(sigs)^[n]])^[i];
if i > bp(sigs)^[n+1]
then extract(j-8)
else begin
inc(j,512);
for k := bp(sigs)^[j] downto 1 do begin
inc(sig[0]);
sig[length(sig)] := chr(bp(sigs)^[j+k]);
end;
k := wp(@bp(sigs)^[j+bp(sigs)^[j]+1])^[0];
if k = 0 then
name := 'unknown'
else begin
k := wp(nameidx)^[k-1];
name := '';
while bp(names)^[k] <> 0 do begin
inc(name[0]);
name[length(name)] := chr(bp(names)^[k]);
inc(k);
end;
end;
writesig(f,sig,name,#$90);
chkioerr;
dec(sig[0],bp(sigs)^[j]);
inc(sigcnt);
end;
end;
dec(sig[0]);
end;
begin
writeln('Writing F-PROT.STR...');
assign(f,'F-PROT.STR');
settextbuf(f,buf,sizeof(buf));
rewrite(f);
chkioerr;
sigcnt := 0;
for i := 0 to 255 do begin
sig := chr(i);
if wp(sigs)^[i] >= 512 then extract(wp(sigs)^[i]-8);
end;
writeln(f);
chkioerr;
close(f);
chkioerr;
writeln(sigcnt,' signatures found in SIGN.DEF.');
end;
begin
readsigndef;
writesigs;
end;
begin
dovirstop;
dosigndef;
writeln('Done.');
end.
--- End GETFP211.PAS ----------------------------------------------------------
<<< end of file >>>