- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我需要编写一种可以从 C 代码调用的键盘记录器函数。这意味着一个 c 程序将调用一个名为 startlog 的汇编函数,该函数将指示开始记录按下的键,直到调用一个名为 endlog 的函数。日志记录应该像这样工作:在不干扰 startlog 和 endlog 之间的 C 代码的情况下写入按下的任何键的 ascii 值,这意味着如果 C 代码也需要读取输入(比如通过 scanf,它会工作正常)。
我设法通过将中断 vector 第 9 个条目(键盘按下中断)更改为我编写的将值写入文件的函数来编写记录器,并且工作正常。但是 C 代码没有得到输入。基本上我所做的是使用 int 21h 读取按下的键,但是在读取 ascii 值后它被“消耗”所以我需要一种方法来再次模拟按键或读取值而不“消耗”它所以下一次键被读取它读取相同的 key 。(我用英文描述了代码,因为它是又长又笨拙的汇编代码)
最佳答案
这里是你如何做到的:
// 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
键盘记录.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 文件 I/O 例程时,有一个用于累积扫描码的循环缓冲区。 EndLog()
等待缓冲区耗尽。您可能还需要提前强制排空。
我也试过 Hook int 28h 作为 int 1Ch 的替代品,但我的 int 28h 的 ISR 从未被调用,不知道为什么。
我避免使用 C 的 fopen()
和 fwrite()
/fprintf()
作为日志文件,以免干扰不知道后台发生的事情的主程序。出于同样的原因,在 ISR 中只使用了最普通的标准 C 函数。
关于c - 如何在 x86 DOS 程序集中读取没有 "consuming"的键盘输入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8103609/
我是一名优秀的程序员,十分优秀!