HanDs
NO.2

[Delphi文章] 模拟击键输入密码的课题研究 





学习中请遵循国家相关法律法规,黑客不作恶。没有网络安全就没有国家安全

本站需要登陆后才能查看

由于支付宝安全输入控件,如同其他众多安全控件方法一样,采用驱动方法劫持了IRP。这导致无法向其输入字符,传统的方法无论是发送WM_Char或者是WM_Keydown消息,还是Keybd_event和SendInput均对其无效。

笔者摸索出了通过直接读取$60,$64硬件端口来操作键盘,模拟输入的方法。

由于在Ring3下,由于Windows的保护机制,我无法直接操作硬件端口,所以我们需要构造一个驱动,或者使用著名的WinIo库。

这里给出我封装好的使用WinIo库进行模拟击键输入的代码,此段代码只在PS/2下测试通过,未在USB情况下测试。本代码主要封装了ASCII码或字符与键盘扫描码之间转换。下表是第一套扫描码。

 

参考文献:PS/2技术参考(Adam Chapweske著 Roy show译)

在实际编程时,务必注意焦点转移问题。由于是模拟击键,还有相当多的问题需要考虑和处理。代码可能存在Bug,这些请您自行解决。也可致信或留言向我询问。

unit alipay_Interface;
 
interface
  uses
    Windows, messages, uWinIo , SysUtils,Dialogs;
 
   Procedure SendChrToAliedit(hwnd:Longint; C:Char);
   Procedure SendStrtoAliEdit(hwnd:Longint;s:String);
 
implementation
  const
    deytime = 30;
  Var
    spec:array[1..12]of char=('!','@','#','$','%','^','&','*','(',')','_','+');
 
function IsUpper(ch: char): boolean;
begin
  Result := ch in ['A'..'Z'];
end;
Function LowCase(s:char):char;
var
  t:string;
begin
  t:='TTTTTTTT';
  t[3]:=s;
  Result:=(LowerCase(T)[3]);
end;
Function IsSpec(ch:char):boolean;
begin
  Result:=ch in ['!','@','#','$','%','^','&','*','(',')','_','+','{','}','"','|',':','?','>','<','~'];
end;
Function IsSpec1(ch:char):boolean;
begin
  Result:=ch in ['!','@','#','$','%','^','&','*','(',')','_','+'];
end;
Function GetSpecCount(c:char):Longint;
var
  i:longint;
begin
  Result:=-1;
  for i:=1 to 12 do
    if spec[i]=c then Result:=i;
end;
Procedure SendChrToAliedit(hwnd:Longint; C:Char);
Var
  sc:longint;
begin
  {by bj}
 // sleep(200);
  Postmessage(hwnd,$0006,0,0);     {Wm_Active = $0006}
  Postmessage(hwnd,WM_SetFocus,0,0);
 //  sleep(30);
  {shift}
  if IsSpec(c) then
  begin
    if IsSpec1(c)
    then sc:=$02+GetSpecCount(c)-1 {上档字符对应bscan计算}
    else begin
    //,./;'\p[] 的上档对照表
      if c='{' then sc:=$1A;
      if c='}' then sc:=$1B;
      if c=':' then sc:=$27;
      if c='<' then sc:=$33;
      if c='>' then sc:=$34;
      if c='?' then sc:=$35;
      if c='"' then sc:=$28;
      if c='|' then sc:=$2B;
      if c='~' then sc:=$29;
    end;
    _WinIo_Send($36);   //bscan RShift=$36 MAKE CODE
    sleep(deytime);
    _WinIo_Send(sc);    //特殊字符的bscan
    sleep(deytime);
    _WinIo_Send(sc or $80);     //break code
    sleep(deytime);
    _WinIo_Send($B6);
     sleep(deytime);
    //go to finally
  //    sleep(30);
    Postmessage(hwnd,WM_KILLFOCUS,0,0);
    Postmessage(hwnd,$0006,0,0);
    exit;
  end;
  if IsUpper(c) then
    begin
      _WinIo_Send($36);   //bscan RShift=$36 MAKE CODE
      sleep(deytime)
    end;
  //  showmessage(c);
  _WinIo_KeyDown(VkKeyScan(LowCase(c)));
  sleep(deytime);
  _WinIo_KeyUP(VkKeyScan(LowCase(c)));
  {shift}
  if IsUpper(c) then
    begin
      sleep(deytime);
      _WinIo_Send($B6); //BREAK CODE
      //   sleep(20);
      sleep(deytime);
    end;
  //    sleep(30);
  Postmessage(hwnd,WM_KILLFOCUS,0,0);
  Postmessage(hwnd,$0006,0,0);
end;
Procedure SendStrtoAliEdit(hwnd:Longint;s:String);
var
  i:longint;
begin
  for i:=1 to length(s) do
    SendChrtoAliEdit(hwnd,s[i]);
end;
end.
单元引用了uWinIo封装单元,以下是其的源代码。这个封装并不是我所完成的,只是做了修改。

unit uWinio;
 
interface
  uses Windows, Messages, SysUtils;
const
  KBC_KEY_CMD = $64;
  KBC_KEY_DATA = $60;
 
  procedure _WinIo_KBCWait4IBE;
  procedure _WinIo_KeyDown(vKeyCoad:Integer);
  procedure _WinIo_KeyUp(vKeyCoad:Integer);
  Procedure _WinIo_Send(btScancode:Longint);
  function _WinIo_Initialize:Boolean;
  procedure _WinIo_ShutDown;
 
implementation
 
  function InitializeWinIo:Boolean;stdcall;external 'WinIo.dll' name'InitializeWinIo';
  function InstallWinIoDriver(pszWinIoDriverPath:PString;IsDemandLoaded:boolean=false):Boolean;stdcall;external 'WinIo.dll'
 
name 'InstallWinIoDriver';
  function RemoveWinIoDriver:Boolean;stdcall;external 'WinIo.dll' name 'RemoveWinIoDriver';
  function GetPortVal(PortAddr:Word;PortVal:PDWord;bSize:Byte):Boolean;stdcall;external 'WinIo.dll' name 'GetPortVal';
  function SetPortVal(PortAddr:Word;PortVal:DWord;bSize:Byte):Boolean;stdcall;external 'WinIo.dll' name 'SetPortVal';
  function GetPhysLong(PhysAddr:PByte;PhysVal:PDWord):Boolean;stdcall;external 'WinIo.dll' name 'GetPhysLong';
  function SetPhysLong(PhysAddr:PByte;PhysVal:DWord):Boolean;stdcall;external 'WinIo.dll' name 'SetPhysLong';
  function MapPhysToLin(PhysAddr:PByte;PhysSize:DWord;PhysMemHandle:PHandle):PByte;stdcall;external 'WinIo.dll' name
 
'MapPhysToLin';
  function UnMapPhysicalMemory(PhysMemHandle:THandle;LinAddr:PByte):Boolean;stdcall;external 'WinIo.dll' name
 
'UnmapPhysicalMemory';
  procedure ShutdownWinIo;stdcall;external 'WinIo.dll' name'ShutdownWinIo';
 
function _WinIo_Initialize:Boolean;
begin
  Result:=false;
  try
    Result:=InitializeWinIo;
  except
    Result:=false;
  end;
end;
 
procedure _WinIo_ShutDown;
begin
  ShutdownWinIo;
end;
 
procedure _WinIo_KBCWait4IBE; //等待键盘缓冲区为空
var
  dwVal:DWord;
begin
  repeat
    GetPortVal($64,@dwVal,1);
  until (dwVal and $2)=0;
end;
 
Procedure _WinIo_Send(btScancode:Longint);
begin
  _WinIo_KBCWait4IBE;// '等待键盘缓冲区为空
  SetPortVal(KBC_KEY_CMD, $D2, 1 );// '发送键盘写入命令
  _WinIo_KBCWait4IBE;
  SetPortVal(KBC_KEY_DATA, btScancode, 1);// '写入按键信息,按下键
end;
 
procedure _WinIo_KeyDown(vKeyCoad:Integer);
var
  btScancode:DWord;
begin
  btScancode:=MapVirtualKey(vKeyCoad, 0);
  _WinIo_KBCWait4IBE;
  SetPortVal($64, $D2, 1);
  _WinIo_KBCWait4IBE;
  SetPortVal($60, btScancode, 1);
end;
 
procedure _WinIo_KeyUp(vKeyCoad:Integer);
var
  btScancode:DWord;
begin
  btScancode:=MapVirtualKey(vKeyCoad, 0);
  _WinIo_KBCWait4IBE;
  SetPortVal($64, $D2, 1);
  _WinIo_KBCWait4IBE;
  SetPortVal($64, (btScancode or $80), 1);
end;
 
initialization
  _WinIo_Initialize;
finalization
  _WinIo_ShutDown;
 
end.


学习中请遵守法律法规,本网站内容均来自于互联网,本网站不负担法律责任
模拟 输入 密码 课题研究
#1楼
发帖时间:2016-7-9   |   查看数:0   |   回复数:0
游客组