windows-nt/Source/XPSP1/NT/base/wow64/setup/boot/virwinn.c
2020-09-26 16:20:57 +08:00

230 lines
8.4 KiB
C

#include <windows.h>
#include "stdtypes.h"
/*
** VIRWINN.C
**
** This is an attempt at virus detection. The routine FVirCheck
** should be called sometime during the boot process, and takes
** one argument, a handle to the application instance. The
** ComplainAndQuit() call should be replaced with code appropriate
** to your application. It is recommended that this bring up
** a dialog with an error message, and give the user the option of
** continuing (defaults to terminating). If the user chooses to
** terminate (or if the option is not given), ComplainAndQuit()
** should clean up anything that has been done so far, and exit.
*/
/* WARNING!! Do not change WHashGood at all!!
** WARNING!! WHashGood must be a near procedure, compiled native.
*/
/*
** EXE header format definitions. Lifted from linker.
*/
#define EMAGIC 0x5A4D /* Old magic number */
#define ERES2WDS 0x000A /* No. of reserved words in e_res2 */
struct exe_hdr /* DOS 1, 2, 3 .EXE header */
{
unsigned short e_magic; /* Magic number */
unsigned short e_cblp; /* Bytes on last page of file */
unsigned short e_cp; /* Pages in file */
unsigned short e_crlc; /* Relocations */
unsigned short e_cparhdr; /* Size of header in paragraphs */
unsigned short e_minalloc; /* Minimum extra paragraphs needed */
unsigned short e_maxalloc; /* Maximum extra paragraphs needed */
unsigned short e_ss; /* Initial (relative) SS value */
unsigned short e_sp; /* Initial SP value */
unsigned short e_csum; /* Checksum */
unsigned short e_ip; /* Initial IP value */
unsigned short e_cs; /* Initial (relative) CS value */
unsigned short e_lfarlc; /* File address of relocation table */
unsigned short e_ovno; /* Overlay number */
unsigned long e_sym_tab; /* offset of symbol table file */
unsigned short e_flags; /* old exe header flags */
unsigned short e_res; /* Reserved words */
unsigned short e_oemid; /* OEM identifier (for e_oeminfo) */
unsigned short e_oeminfo; /* OEM information; e_oemid specific */
unsigned short e_res2[ERES2WDS]; /* Reserved words */
long e_lfanew; /* File address of new exe header */
};
/*
** NEW EXE format definitions. Lifted from linker
*/
#define NEMAGIC 0x454E /* New magic number */
#define NERESBYTES 8 /* Eight bytes reserved (now) */
#define NECRC 8 /* Offset into new header of NE_CRC */
struct new_exe /* New .EXE header */
{
unsigned short ne_magic; /* Magic number NE_MAGIC */
unsigned char ne_ver; /* Version number */
unsigned char ne_rev; /* Revision number */
unsigned short ne_enttab; /* Offset of Entry Table */
unsigned short ne_cbenttab; /* Number of bytes in Entry Table */
long ne_crc; /* Checksum of whole file */
unsigned short ne_flags; /* Flag word */
unsigned short ne_autodata; /* Automatic data segment number */
unsigned short ne_heap; /* Initial heap allocation */
unsigned short ne_stack; /* Initial stack allocation */
long ne_csip; /* Initial CS:IP setting */
long ne_sssp; /* Initial SS:SP setting */
unsigned short ne_cseg; /* Count of file segments */
unsigned short ne_cmod; /* Entries in Module Reference Table */
unsigned short ne_cbnrestab; /* Size of non-resident name table */
unsigned short ne_segtab; /* Offset of Segment Table */
unsigned short ne_rsrctab; /* Offset of Resource Table */
unsigned short ne_restab; /* Offset of resident name table */
unsigned short ne_modtab; /* Offset of Module Reference Table */
unsigned short ne_imptab; /* Offset of Imported Names Table */
long ne_nrestab; /* Offset of Non-resident Names Table */
unsigned short ne_cmovent; /* Count of movable entries */
unsigned short ne_align; /* Segment alignment shift count */
unsigned short ne_cres; /* Count of resource entries */
unsigned char ne_exetyp; /* Target operating system */
unsigned char ne_flagsothers; /* Other .EXE flags */
char ne_res[NERESBYTES];
/* Pad structure to 64 bytes */
};
/*
** WHashGood()
**
** This returns the correct hash value.
**
** WARNING!! This routine must not be altered in ANY way. It gets
** patched and/or rewritten by VIRPATCH!!
*/
unsigned near WHashGood ( void );
unsigned near WHashGood ()
{
return (0x1234);
}
/*
** WHash(wHash, rgb, cb)
**
** Update hash value to account for cb new bytes pointed to by rgb.
** Old hash value is wHash; returns new hash value.
**
** We do the hash on a word basis; the hash function is a simple
** rotate and add.
*/
unsigned WHash ( unsigned wHash, BYTE rgb[], int cb );
unsigned WHash ( unsigned wHash, BYTE rgb[], int cb )
{
while (cb > 1)
{
#pragma warning(disable:4213) /* nonstandard extension : cast on l-value */
wHash = (wHash << 3) + (wHash >> 13) + *((int *)rgb)++;
#pragma warning(default:4213)
cb -= 2;
}
if (cb != 0)
wHash = (wHash << 3) + (wHash >> 13) + *rgb;
return (wHash);
}
/*
** FVirCheck(hinst)
**
** This is the main virus detection routine. It should be called
** during boot, with a handle to the application instance.
** The detection method used is to hash the EXE headers; this
** hash value will change if the number or type of segments change,
** or if their length changes.
*/
BOOL FVirCheck ( HANDLE hinst );
BOOL FVirCheck ( HANDLE hinst )
{
int fh;
unsigned wHash;
unsigned cb, cbT;
long lPos;
char sz[256];
BYTE rgb[512];
#define pehdr ((struct exe_hdr *)rgb)
#define pnex ((struct new_exe *)rgb)
/* First we have to get a handle to the executable file.
Unfortunately, although Windows already has this file open,
there's no way to use its handle. Instead we have to reopen
the file. */
if (GetModuleFileName(hinst, (char far *)sz, 256) == 0)
return TRUE; //This shouldn't happen but still continue loading
if ((fh = OpenFile((LPSTR)sz, (LPOFSTRUCT)rgb, OF_READ)) == -1)
{
/* We can't open the file. This should never happen; if
it does, it means we're in a weird state, and probably
did something wrong in this code. We'll just say
everything is OK, and continue the boot. */
return TRUE;
}
/* Read old header */
if (_lread(fh, (LPSTR)rgb, sizeof (struct exe_hdr)) != sizeof (struct
exe_hdr) ||
pehdr->e_magic != EMAGIC)
goto Corrupted;
/* Hash old header */
wHash = WHash(0, rgb, sizeof (struct exe_hdr));
lPos = pehdr->e_lfanew;
/* Read new header (and some more) */
if (lPos == 0 || _llseek(fh, lPos, 0) != lPos ||
_lread(fh, (LPSTR)rgb, 512) != 512 || pnex->ne_magic != NEMAGIC)
goto Corrupted;
/* Figure out size of total header; nonresident table is last part
of header. */
cb = (unsigned)(pnex->ne_nrestab - lPos) + pnex->ne_cbnrestab;
/* Do hash on buffer basis */
while (cb > 512)
{
/* Hash this buffer */
wHash = WHash(wHash, rgb, 512);
cb -= 512;
cbT = (cb > 512 ? 512 : cb);
/* and read in next */
if (_lread(fh, (LPSTR)rgb, cbT) != cbT)
goto Corrupted;
}
/* Update hash for final partial buffer, and compare with good value. */
if (WHash(wHash, rgb, cb) != WHashGood())
{
Corrupted:
/* We've got an error reading the file or, more likely,
a hash mismatch. Close the file, give an error, and
quit. */
_lclose(fh);
/* CHANGE THE FOLLOWING LINE TO CODE APPROPRIATE TO YOUR
** APPLICATION!!
** This should be replaced with code giving an error message (such as
** "Application file is corrupted"). It is recommended that this
** bring up
** a dialog with an error message, and give the user the option of
** continuing (defaults to terminating). If the user chooses to
** terminate (or if the option is not given), ComplainAndQuit()
** should clean up anything that has been done so far, and exit.
*/
/* MessageBox(NULL, "Executable File Corrupted",
* "WARNING", MB_ICONSTOP | MB_OK);
*/
/* ComplainAndQuit();
*/
/* END OF CHANGE */
return FALSE;
}
/* Everything's OK. Just close the file, and continue. */
_lclose(fh);
return TRUE;
#undef pehdr
#undef pnex
}