2011-11-12 4 views
0

私はCコードから呼び出すことができる一種のキーロガー関数を書く必要があります。 これは、cプログラムがstartlogというアセンブリ関数を呼び出し、endlogという関数が呼び出されるまで押されたキーの記録を開始することを示します。ロギングは次のように動作するはずです:startlogとendlogの間にCコードを乱さずに押されたキーのascii値を書き込みます。つまり、Cコードも入力を読み込む必要がある場合です。キーボード入力をx86 DOSアセンブリで「消費」せずに読む方法

私は、割り込みベクタの9番目のエントリ(キーボード・プレスの割り込み)をファイルに値を書き込む関数に変更してロガーを書き込むことができました。しかし、Cコードは入力を取得しません。 基本的には、int 21hを使用して押されたキーが読み込まれますが、アスキーの値を読み取った後は「消費される」ため、キーをもう一度シミュレートするか、次の時間に「消費する」ことなく値を読み取りますキーが読み取られると、同じキーが読み取られます。 (私は長いと不器用なアセンブリコードであるため、英語でコードを記述しました)

+0

'int 9'ハンドラから' int 21'を呼び出しましたが、それは爆発しませんでしたか? – ninjalj

+0

あなたがそれらを正しく呼び出すと何も爆発しません。 – Bob

答えて

2

は、あなたがそれを行うことができます方法は次のとおりです。

// 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(&regs, &regs, &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(&regs, &regs, &sregs); 
} 

void DosCloseFile(unsigned handle) 
{ 
    union REGS regs; 
    struct SREGS sregs; 

    regs.h.ah = 0x3E; 
    regs.x.bx = handle; 

    intdosx(&regs, &regs, &sregs); 
} 

void StartLog(const char* FileName) 
{ 
    union REGS regs; 
    struct SREGS sregs; 

    LogFileHandle = DosCreateFile(FileName); 

    regs.h.ah = 0x34; // get InDos flag address 
    intdosx(&regs, &regs, &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ファイルI/Oルーチンを安全に呼び出せない間に、それらを累積するスキャンコード用の循環バッファがあるためです。 EndLog()はバッファがなくなるまで待ちます。早くも排水を強制する必要があるかもしれません。

また、int 1Chの代わりにint 28hをフックしようとしましたが、int 28hのISRが呼び出されることはありません。

バックグラウンドで起こって物事を知らないのですメインプログラムに干渉しないように私は、ログファイルのCのfopen()fwrite()/fprintf()の使用を避けています。同様の理由により、ISRで最も単純な標準C関数のみが使用されます。

+0

注: '' ?? ""で、このコードはほぼ[trigrpahs](https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C)を使用しています。おそらく二重 ''? ''を区切ります。 '' ?? " "1234567890- =" "??" ... ' – chux

1

INT 9がキーボード割り込みで、このベクトルを変更して文字を傍受するコードを指しているのであれば、古いベクトルとあなたのフックコードの最後にジャンプしますか?ここで

+0

私はそれを行います。私はそれをキーボード入力を処理し、それを読み込むためにint21hを呼び出すために元のINT 9にジャンプします。 – Bob

+0

OK、文字列をバッファリングしてint 21をフックする必要があります。 –

関連する問題