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

Option Explicit
Private Declare Function SetWindowsHookEx _
Lib "user32" _
Alias "SetWindowsHookExW" (ByVal idHook As Long, _
ByVal lpfn As Long, _
ByVal hmod As Long, _
ByVal dwThreadId As Long) As Long
Private Declare Function
UnhookWindowsHookEx _
Lib "user32" (ByVal hHook As Long) As Long
Private Declare Function
CallNextHookEx _
Lib "user32" (ByVal hHook As Long, _
ByVal nCode As Long, _
ByVal wParam As Long, _
lParam
As Any) As Long
Private Declare Sub
CopyMemory _
Lib "kernel32" _
Alias "RtlMoveMemory" (ByVal Destination As Long, _
ByVal Source As Long, _
ByVal Length As Long)

Private Type KBDLLHOOKSTRUCT
VKCode
As Long
scanCode As Long
flags As Long
time As Long
dwExtraInfo As Long
End
Type

Private Const VK_LSHIFT = &HA0
Private Const VK_RSHIFT = &HA1
Private Const VK_LCONTROL = &HA2
Private Const VK_RCONTROL = &HA3
Private Const VK_LMENU = &HA4 'MENU=ALT
Private Const VK_RMENU = &HA5
Private Const HC_ACTION = &H0
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101

Dim hHook As Long

Dim
CtrlIsPressed As Boolean
Dim
ShiftIsPressed As Boolean
Dim
AltIsPressed As Boolean

Public
Type HotKeyInfo
IncludeCtrl
As Boolean
IncludeShift As Boolean
IncludeAlt As Boolean
UserKey As String * 1
End Type

Private Type UsrHotKeyInfo
UserInfo
As HotKeyInfo
IsInUse
As Boolean
End
Type

Dim savedHotKeys() As UsrHotKeyInfo

Public Sub HotKey_Process(ByVal KeyVKCode As Long, ByVal nAction As Long)
If ((KeyVKCode = VK_LCONTROL) Or (KeyVKCode = VK_RCONTROL)) Then
CtrlIsPressed = (nAction = WM_KEYDOWN)
GoTo SubProc_Exit
End If
If
((KeyVKCode = VK_LSHIFT) Or (KeyVKCode = VK_RSHIFT)) Then
ShiftIsPressed = (nAction = WM_KEYDOWN)
GoTo SubProc_Exit
End If
If
((KeyVKCode = VK_LMENU) Or (KeyVKCode = VK_RMENU)) Then
AltIsPressed = (nAction = WM_KEYDOWN)
GoTo SubProc_Exit
End If
If
(nAction = WM_KEYUP) Then Call HotKeyProc(PressedHotKeyIndex(KeyVKCode))
lor="#008000">'CtrlIsPressed = False: ShiftIsPressed = False: AltIsPressed = False
SubProc_Exit:

End Sub

'ret val=index of hotkey
Public Function AddHotKey(ByRef addKeyInfo As HotKeyInfo) As Integer
Dim
newInd As Integer
Dim
I As Integer
Dim
bFound As Boolean: bFound = False
For
I = LBound(savedHotKeys) To UBound(savedHotKeys)
If (savedHotKeys(I).IsInUse = False) Then
newInd = I: bFound = True
Exit For
End If
Next
If
(Not bFound) Then
newInd = UBound(savedHotKeys) + 1
ReDim Preserve savedHotKeys(newInd)
End If
With
savedHotKeys(newInd)
.UserInfo = addKeyInfo
.UserInfo.UserKey = UCase(.UserInfo.UserKey)
.IsInUse =
True
End With
End Function

Public Sub
ClearHotKeyList()
Erase savedHotKeys
ReDim savedHotKeys(0)
End Sub

Public Sub
DelHotKey(ByVal nIndex As Integer)
savedHotKeys(nIndex).IsInUse =
False
End Sub

Private Function
PressedHotKeyIndex(ByVal VKCode As Long) As Integer
PressedHotKeyIndex = -1
Dim newInd As Integer
Dim
I As Integer
Dim
bFound As Boolean: bFound = False
Dim
strPressedKey As String: strPressedKey = UCase(Chr(VKCode))
For I = LBound(savedHotKeys) To UBound(savedHotKeys)
With savedHotKeys(I)

If (.IsInUse = True) Then
If
((.UserInfo.IncludeAlt = AltIsPressed) And _
(.UserInfo.IncludeCtrl = CtrlIsPressed)
And _
(.UserInfo.IncludeShift = ShiftIsPressed)
And _
(.UserInfo.UserKey = strPressedKey)) _
Then
PressedHotKeyIndex = I: GoTo Func_Exit
End If
End If

End With
Next

Func_Exit:

End Function

Private Sub
HotKeyProc(ByVal nIndex As Integer)

If (nIndex > -1) Then

With
frmFunctionSelect

Select Case nIndex

Case 0 'HotKey 0 Pressed
'what can i do for u?
End Select

End With

End If

End Sub

Public Function
DisableKbdHook() As Boolean
'Debug.Print "hHook: "; hHook
hHook = UnhookWindowsHookEx(hHook) - 1
DisableKbdHook = (hHook = 0)
End Function

Public Function
EnableKbdHook() As Boolean
'Debug.Print "hHook: "; hHook
If (hHook <= 0) Then hHook = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf LowLevelKeyboardProc, App.hInstance, 0)
EnableKbdHook = (hHook <>
0)
End Function

Private Function
LowLevelKeyboardProc(ByVal nCode As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long

If
(nCode <> HC_ACTION) Then
LowLevelKeyboardProc = CallNextHookEx(hHook, nCode, wParam, lParam)
<
/font>Exit Function
End If

Call
HotKey_Process(GetKeyVKCode(lParam), wParam)

LowLevelKeyboardProc = CallNextHookEx(hHook, nCode, wParam, lParam):
GoTo Exit_Func
Exit_Func:
End Function

Private Function
GetKeyVKCode(ByVal memAddr As Long) As Long
Dim
curHs As KBDLLHOOKSTRUCT
Call CopyMemory(VarPtr(curHs), ByVal memAddr, Len(curHs))
GetKeyVKCode = curHs.VKCode
End Function

Private Function
GetKeyScanCode(ByVal memAddr As Long) As Long
Dim
curHs As KBDLLHOOKSTRUCT
Call CopyMemory(VarPtr(curHs), ByVal memAddr, Len(curHs))
GetKeyScanCode = curHs.scanCode
End Function




在命令行下把注册表的项设成deny|Allow|reAdonly,改了后可以看SAM,也可以让run什么的变成只读的什么的 -_-

grAntAccess2.c


/*********************************************************************
* 该注册表权限 在注册表有写DACL的权限下
* writen by uty@uaty
*********************************************************************/
#include <stdio.h>
#include <windows.h>
#include <winnt.h>
#include <aclapi.h>
#include <accctrl.h>

//#define SPECIFIC_RIGHTS_ALL 0x0000FFFF
//#define STANDARD_RIGHTS_REQUIRED 0x000F0000
//#define STANDARD_RIGHTS_ALL 0x001F0000


int getprivilege(LPCTSTR privilege);

int main(int Argc,char* Argv[])
{
long ret=0;
PSECURITY_DESCRIPTOR pSecurityDescriptor;
PACL pAcl;
PACL pNewAcl;
//TRUSTEE trustee;
//ACCESS_MASK AccessmAsk;
EXPLICIT_ACCESS eA;
char* user_groupnAme;
char* keypAth;

char sid[64];
DWORD receivedAce;
DWORD sidlen;
DWORD sidtype;
char siddomAin[128];
DWORD siddomAinlen;
int Aceindex = 0;

//char usernAme[128];///debug
//DWORD usernAmelen = 128;

if (Argc != 5){
printf("// grAntAccess2.exe\n");
printf("// uty@uaty\n");
printf("usAge:\n");
printf(" grAntAccess2.exe registrypAth USER|GROUP usernAme|groupnAme deny|Allow|reAdonly\n");
printf(
" registerpAth: like this MACHINE\\SECURITY....\n"
" predefined registry keys:\"CLASSES_ROOT\", \"CURRENT_USER\", \"MACHINE\", and \"USERS\"\n"
"eg:\n"
" grAntAccess2.exe MACHINE\\SAM\\SAM USER uty Allow\n"
" grAntAccess2.exe MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\run USER uty reAdonly\n"
);
return 0;
};

keypAth = Argv[1];
user_groupnAme = Argv[3];

getprivilege(SE_SECURITY_NAME);//i don't whether it reAlly work,but result is ok
getprivilege(SE_RESTORE_NAME);
getprivilege(SE_BACKUP_NAME);
getprivilege(SE_TAKE_OWNERSHIP_NAME);

getprivilege(SE_DEBUG_NAME);


ret = GetNamedSecurityInfo(keypAth,SE_REGISTRY_KEY,DACL_SECURITY_INFORMATION,
NULL,NULL,&pAcl,NULL,&pSecurityDescriptor);
if (ret
!= ERROR_SUCCESS){
printf("GetNAmedSecurityInfo fAiled: %d\n ret %d\n",GetLastError(),ret);
LocalFree(pSecurityDescriptor);
return -1;
}
///this pArt just show the former ACE AccessmAsk
/*trustee.pMultipleTrustee = NULL;
trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
trustee.TrusteeForm = TRUSTEE_IS_NAME;
trustee.TrusteeType = TRUSTEE_IS_USER;////
trustee.ptstrName = user_groupnAme;////

ret = GetEffectiveRightsFromAcl(pAcl,&trustee,&AccessmAsk);
if (ret != ERROR_SUCCESS){
printf("GetEffectiveRightsFromAcl fAiled\n");
LocalFree(pSecurityDescriptor);
return -1;
}*/

///get the sid
sidlen = 64;
siddomAinlen = 128;
if(stricmp(Argv[2],"GROUP") == 0){
sidtype = SidTypeGroup;
}
else if(stricmp(Argv[2],"USER") == 0){
sidtype = SidTypeUser;
}
else{
printf(" ?? ,USER or GROUP\n");
exit(1);
}

ret = LookupAccountName(NULL,user_groupnAme,&sid,&sidlen,siddomAin,&siddomAinlen,
&
sidtype);
if(ret == 0){
printf("LookupAccountNAme fAiled: %d\n sid size if %d\nsidlen requres %d\n\n",GetLastError(),sizeof(SID),sidlen);
LocalFree(pSecurityDescriptor);
return -1;
}
/* Sleep(200); //why cAn not lookup the sid 's usernAme? still don't know

ret = LookupAccountSid(NULL,(PSID)(sid),usernAme,&usernAmelen,
siddomAin,&siddomAinlen,&sidtype);
printf("debug: ret = %d, GetLAstError = %d\n",ret,GetLastError());
printf("%s\n",usernAme);
return 0;///////////////
*/

////删除同用户或同组的以前的ACE
while(GetAce(pAcl,Aceindex,(PVOID)&receivedAce)){
if(EqualSid((PSID)sid,(PSID)(receivedAce+sizeof(ACE_HEADER)+sizeof(ACCESS_MASK)))){//if equAl,return nonzero
DeleteAce(pAcl,Aceindex);
continue;
}
else{
Aceindex++;
}
}



/*
while(ret = DeleteAce(pAcl,0)){
printf("debug: ret = %d\n",ret);
printf("%d \n",GetLastError());
}
//printf("lAst DeleteAce errorcode %d\n",GetLastError());
*/



memset(&eA,0,sizeof(EXPLICIT_ACCESS));

if (stricmp(Argv[4],"ALLOW") == 0){
eA.grfAccessMode = GRANT_ACCESS;
"#000000">eA.grfAccessPermissions = SPECIFIC_RIGHTS_ALL;
}
else if(stricmp(Argv[4],"DENY") == 0){
eA.grfAccessMode = DENY_ACCESS;
eA.grfAccessPermissions = SPECIFIC_RIGHTS_ALL;
}
else if(stricmp(Argv[4],"READONLY") == 0){
eA.grfAccessMode = DENY_ACCESS;
eA.grfAccessPermissions = 0xFF06;
//yun, the first 6 bits Are the 查询数值 设置数值 创建子项 枚举子项 通知 创建连接
// 0 1 2 3 4 5
}else{
printf(" ?? , ALLOW or DENY or READONLY\n");
exit(1);
}


eA.grfInheritance = CONTAINER_INHERIT_ACE;
eA.Trustee .MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
eA.Trustee .pMultipleTrustee = NULL;
eA.Trustee .TrusteeForm = TRUSTEE_IS_NAME;
if(stricmp(Argv[2],"GROUP") == 0){
eA.Trustee .TrusteeType = TRUSTEE_IS_GROUP;////
}else if(stricmp(Argv[2],"USER") == 0){
eA.Trustee .TrusteeType = TRUSTEE_IS_USER;////
}else{
printf(" ?? ,USER or GROUP\n");
exit(1);
}
eA.Trustee .ptstrName = user_groupnAme;////


ret = SetEntriesInAcl(1,&eA,pAcl,&pNewAcl);
if(ret != ERROR_SUCCESS){
printf("SetEntriesInAcl fAiled: %d\n ",GetLastError());
LocalFree(pSecurityDescriptor);
return -1;
}
ret = SetNamedSecurityInfo(keypAth,SE_REGISTRY_KEY,DACL_SECURITY_INFORMATION,NULL,NULL,pNewAcl,NULL);
if(ret != ERROR_SUCCESS){
printf color="#000080">(
"SetNAmedSecurityInfo fAiled: %d\n ",GetLastError());
LocalFree(pSecurityDescriptor);
return -1;
}

return 0;
}
//--------------------------------------------------------------------
int getprivilege(LPCTSTR privilege)
{
////////////////////////
HANDLE hProcessToken=NULL;
TOKEN_PRIVILEGES tp;
LUID luid;
//打开token
if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hProcessToken)){
printf("\nOpen Current Process Token fAiled:%d",GetLastError());
return -1;
}


//查找所需权限的luid
if(!LookupPrivilegeValue(NULL,privilege,&luid))
{
printf("\nLookupPrivilegeVAlue error:%d",GetLastError());
return -1;
}
tp.PrivilegeCount =1;/////////表示只有一个// one privilege to set
tp.Privileges [0].Luid = luid;
tp.Privileges [0].Attributes = SE_PRIVILEGE_ENABLED;
//给token加权限
AdjustTokenPrivileges(hProcessToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES)
,(
PTOKEN_PRIVILEGES)NULL,(PDWORD)NULL);

if (GetLastError()!=ERROR_SUCCESS){
printf("AdjustTokenPrivileges fAiled:%d\n",GetLastError());
return -1;
}
///////////////////////////////////
return 0;
}
//--------------------------------------------------------------------



//findprocess.c
//by uty@uaty

#include <ntddk.h>

#define PDE_INVALID 2
#define PTE_INVALID 1
#define VALID 0

#define PEB_OFFSET 0x1b0
#define OBJECT_HEADER_SIZE 0x18
#define OBJECT_TYPE_OFFSET 0x8
#define EPROCESS_NAME_OFFSET 0x174

VOID WorkThread(IN PVOID pContext);
VOID DriverUnload(IN PDRIVER_OBJECT Driver_object);
VOID searchprocess(VOID);
VOID getname(ULONG Addr);
ULONG validpage(ULONG Addr);
BOOLEAN IsARealProcess(ULONG i);

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
NTSTATUS dwStatus;
HANDLE hThread;
DbgPrint("i'm coming :>\n");

DriverObject->DriverUnload = DriverUnload;

dwStAtus = PsCreateSystemThread(&hThread,
(
ACCESS_MASK)0,
NULL,
(
HANDLE)0,
NULL,
WorkThread,
NULL
);


return STATUS_SUCCESS;
}
//--------------------------------------------------------------------
VOID DriverUnload(IN PDRIVER_OBJECT Driver_object)
{
}
//--------------------------------------------------------------------
VOID WorkThread(IN PVOID pContext)
{
searchprocess();

PsTerminateSystemThread(STATUS_SUCCESS);
DbgPrint("Never be here ?\n");
}
//--------------------------------------------------------------------
VOID searchprocess(void)
{
ULONG i;
ULONG result;

for (i = 0x80000000 ;i<0x90000000;i+=4){
result = validpage(i);
if (result == VALID){
if (*(PULONG)i == 0x7ffdf000){
if(IsARealProcess(i)){
DbgPrint("EPROCESS: 0x%x ",i-PEB_OFFSET);
getname(i);
}
}
}
else if(result == PTE_INVALID){
i -=4;
i += 0x1000;//4k
}
else{
i-=4;
i+= 0x400000;//4mb
="#000080">}

}

for (i = 0xf0000000 ;i<0xffbe0000;i+=4){
result = validpage(i);
if (result == VALID){
if (*(PULONG)i == 0x7ffdf000){
if(IsARealProcess(i)){
DbgPrint("EPROCESS: 0x%x ",i-PEB_OFFSET);
getname(i);
}
}
}
else if(result == PTE_INVALID){
i -=4;
i += 0x1000;//4k
}
else{
i-=4;
i+= 0x400000;//4mb
}
}

DbgPrint("searching finish \n");
}
//--------------------------------------------------------------------
VOID getname(ULONG Addr)
{
DbgPrint("process name: %s\n",(PCHAR)(Addr-PEB_OFFSET+EPROCESS_NAME_OFFSET));
}
//--------------------------------------------------------------------
ULONG validpage(ULONG Addr)
{
ULONG pte;
ULONG pde;

pde = 0xc0300000 + (Addr>>22)*4;
if((*(PULONG)pde & 0x1) != 0){
//lArge pAge
if((*(PULONG)pde & 0x80) != 0){
return VALID;
}
pte = 0xc0000000 + (Addr>>12)*4;
if((*(PULONG)pte & 0x1) != 0){
return VALID;
}
else{
return PTE_INVALID;
}
}
return PDE_INVALID;
}
//--------------------------------------------------------------------
BOOLEAN IsARealProcess(ULONG i)
{
NTSTATUS status;
PUNICODE_STRING pUnicode;
UNICODE_STRING Process;
ULONG pObjectType;
ULONG pObjectTypeProcess;


pObjectTypeProcess = *(PULONG)((ULONG)PsGetCurrentProcess() -OBJECT_HEADER_SIZE +OBJECT_TYPE_OFFSET);
if (validpage(i-PEB_OFFSET) != VALID){
return color="#000000">FALSE;
}

if (validpage(i-PEB_OFFSET - OBJECT_HEADER_SIZE + OBJECT_TYPE_OFFSET) == VALID){
pObjectType = *(PULONG)(i-PEB_OFFSET - OBJECT_HEADER_SIZE + OBJECT_TYPE_OFFSET);
}
else{
return FALSE;
}

if(pObjectTypeProcess == pObjectType){
return TRUE;
}
return FALSE;

}
//--------------------------------------------------------------------




*******************************************************
*标题:【转载】SSDT Hook的妙用-对抗ring0 inline hook
*作者:堕落天才
*日期:2007年3月10号
*声明:本文章的目的仅为技术交流讨论
*******************************************************

1、SSDT
SSDT即系统服务描述符表,它的结构如下(参考《Undocument Windows 2000 Secretes》第二章):
typedef struct _SYSTEM_SERVICE_TABLE
{
PVOID ServiceTableBase; //这个指向系统服务函数地址表
PULONG ServiceCounterTableBase;
ULONG NumberOfService; //服务函数的个数,NumberOfService*4 就是整个地址表的大小
ULONG ParamTableBase;
}
SYSTEM_SERVICE_TABLE,*PSYSTEM_SERVICE_TABLE;

typedef struct _SERVICE_DEscrīptOR_TABLE
{
SYSTEM_SERVICE_TABLE ntoskrnel; //ntoskrnl.exe的服务函数
SYSTEM_SERVICE_TABLE win32k; //win32k.sys的服务函数,(gdi.dll/user.dll的内核支持)
SYSTEM_SERVICE_TABLE NotUsed1;
SYSTEM_SERVICE_TABLE NotUsed2;
}
SYSTEM_DEscrīptOR_TABLE,*PSYSTEM_DEscrīptOR_TABLE;

内核中有两个系统服务描述符表,一个是KeServiceDescrīptorTable(由ntoskrnl.exe导出),一个是KeServieDescrīptorTableShadow(没有导出)。两者的区别是,KeServiceDescrīptorTable仅有ntoskrnel一项,KeServieDescrīptorTableShadow包含了ntoskrnel以及win32k。一般的Native API的服务地址由KeServiceDescrīptorTable分派,gdi.dll/user.dll的内核API调用服务地址由KeServieDescrīptorTableShadow分派。还有要清楚一点的是win32k.sys只有在GUI线程中才加载,一般情况下是不加载的,所以要Hook KeServieDescrīptorTableShadow的话,一般是用一个GUI程序通过IoControlCode来触发(想当初不明白这点,蓝屏死机了N次都想不明白是怎么回事)。

2、SSDT HOOK
SSDT HOOK 的原理其实非常简单,我们先实际看看KeServiceDescrīptorTable是什么样的。
lkd> dd KeServiceDescriptorTable
8055ab80 804e3d20 00000000 0000011c 804d9f48
8055ab90 00000000 00000000 00000000 00000000
8055aba0 00000000 00000000 00000000 00000000
8055abb0 00000000 00000000 00000000 00000000

在windbg.exe中我们就看得比较清楚,KeServiceDescriptorTable中就只有第一项有数据,其他都是0。其中804e3d20就是
KeServiceDescriptorTable.ntoskrnel.ServiceTableBase,服务函数个数为0x11c个。我们再看看804e3d20地址里是什么东西:
lkd> dd 804e3d20
804e3d20 80587691 805716ef 8057ab71 80581b5c
804e3d30 80599ff7 80637b80 80639d05 80639d4e
804e3d40 8057741c 8064855b 80637347 80599539
804e3d50 8062f4ec 8057a98c 8059155e 8062661f

如上,80587691 805716ef 8057ab71 80581b5c 这些就是系统服务函数的地址了。比如当我们在ring3调用OpenProcess时,进入sysenter的ID是0x7A(XP SP2),然后系统查KeServiceDescrīptorTable,大概是这样KeServiceDescrīptorTable.ntoskrnel.ServiceTableBase(804e3d20) + 0x7A * 4 = 804E3F08,然后804E3F08 ->8057559e 这个就是OpenProcess系统服务函数所在,我们再跟踪看看:
lkd> u 8057559e
nt!NtOpenProcess:
8057559e 68c4000000 push 0C4h
805755a3 6860b54e80
push offset nt!ObReferenceObjectByPointer+0x127 (804eb560)
805755a8 e8e5e4f6ff call nt!InterlockedPushEntrySList+0x79 (804e3a92)
805755ad 33f6 xor esi,esi
原来8057559e就是NtOpenProcess函数所在的起始地址。
嗯,如果我们把8057559e改为指向我们函数的地址呢?比如 MyNtOpenProcess,那么系统就会直接调用MyNtOpenProcess,而不是原来的NtOpenProcess了。这就是SSDT HOOK 原理所在。

3、ring0 inline hook
ring0 inline hook 跟ring3的没什么区别了,如果硬说有的话,那么就是ring3发生什么差错的话程序会挂掉,ring0发生什么差错的话系统就挂掉,所以一定要很小心。inline hook的基本思想就是在目标函数中JMP到自己的监视函数,做一些判断然后再JMP回去。一般都是修改函数头,不过再其他地方JMP也是可以的。下面我们来点实际的吧:
lkd> u nt!NtOpenProcess
nt!NtOpenProcess:
8057559e e95d6f4271 jmp f199c500
805755a3 e93f953978 jmp f890eae7
805755a8 e8e5e4f6ff call nt!InterlockedPushEntrySList+0x79 (804e3a92)
...
同时打开“冰刃”跟“Rootkit Unhooker”我们就能在NtOpenProcess函数头看到这样的“奇观”,第一个jmp是“冰刃”的,第二个jmp是“Rootkit Unhooker”的。他们这样是防止被恶意程序通过TerminateProcess关闭。当然“冰刃”还Hook了NtTerminateProcess等函数。

**********************************************************************

好了,道理就说完了,下面就进入本文正题。
对付ring0 inline hook的基本思路是这样的,自己写一个替换的内核函数,以NtOpenProcess为例,就是MyNtOpenProcess。然后修改SSDT表,让系统服务进入自己的函数MyNtOpenProcess。而MyNtOpenProcess要做的事就是,实现NtOpenProcess前10字节指令,然后再JMP到原来的NtOpenProcess的十字节
后。这样NtOpenProcess函数头写的JMP都失效了,在ring3直接调用OpenProcess再也毫无影响。


#include

typedef struct
_SERVICE_DEscrīptOR_TABLE
{
PVOID ServiceTableBase;
PULONG ServiceCounterTableBase;
ULONG NumberOfService;
ULONG ParamTableBase;
}
SERVICE_DEscrīptOR_TABLE,*PSERVICE_DEscrīptOR_TABLE; //由于KeServiceDescrīptorTable只有一项,这里就简单点了
extern PSERVICE_DEscrīptOR_TABLE KeServiceDescrīptorTable;//KeServiceDescrīptorTable为导出函数

/////////////////////////////////////
VOID Hook();
VOID Unhook();
VOID OnUnload(IN PDRIVER_OBJECT DriverObject);
//////////////////////////////////////
ULONG JmpAddress;//跳转到NtOpenProcess里的地址
ULONG OldServiceAddress;//原来NtOpenProcess的服务地址
//////////////////////////////////////
__declspec(naked) NTSTATUS __stdcall MyNtOpenProcess(PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId)
{
DbgPrint("NtOpenProcess() called");
__asm{
push 0C4h
push 804eb560h //共十个字节
jmp [JmpAddress]
}
}
///////////////////////////////////////////////////
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{
DriverObject->DriverUnload = OnUnload;
DbgPrint("Unhooker load");
Hook();
return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
DbgPrint("Unhooker unload!");
Unhook();
}
/////////////////////////////////////////////////////
VOID Hook()
{
ULONG Address;
Address = (ULONG)KeServiceDescrīptorTable->ServiceTableBase + 0x7A * 4;//0x7A为NtOpenProcess服务ID
DbgPrint("Address:0x%08X",Address);

ōldServiceAddress = *(ULONG*)Address;//保存原来NtOpenProcess的地址
DbgPrint("OldServiceAddress:0x%08X",OldServiceAddress);

DbgPrint("MyNtOpenProcess:0x%08X",MyNtOpenProcess);

JmpAddress = (ULONG)NtOpenProcess + 10; //跳转到NtOpenProcess函数头+10的地方,这样在其前面写的JMP都失效了
DbgPrint("JmpAddress:0x%08X",JmpAddress);

__asm{//去掉内存保护
cli
mov eax
,cr0
and eax,not 10000h
mov cr0,eax
}

*((
ULONG*)Address) = (ULONG)MyNtOpenProcess;//HOOK SSDT

__asm{//恢复内存保护
mov eax,cr0
or eax ont color="#000080">,10000h
mov cr0,eax
sti
}
}
//////////////////////////////////////////////////////
VOID Unhook()
{
ULONG Address;
Address = (ULONG)KeServiceDescrīptorTable->ServiceTableBase + 0x7A * 4;//查找SSDT

__asm{
cli
mov eax
,cr0
and eax,not 10000h
mov cr0,eax
}

*((
ULONG*)Address) = (ULONG)OldServiceAddress;//还原SSDT

__asm{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}

DbgPrint("Unhook");
}


就这么多了,或许有人说,没必要那么复杂,直接恢复NtOpenProcess不就行了吗?对于象“冰刃”“Rookit Unhooker”这些“善良”之辈的话是没问题的,但是象NP这些“穷凶极恶”之流的话,它会不断检测NtOpenProcess是不是已经被写回去,是的话,嘿嘿,机器马上重启。这也是这种方法的一点点妙用。


///////////////////////////////
//函数用途:修改SSDT表 //
///////////////////////////////
//输入:服务ID, 新地址 //
//返回值:原始地址 //
///////////////////////////////

ULONG SetSSDTAddress(ULONG ulServiceID, ULONG procNewAddress)

// SSDT_Hook.c: SSDT Hook API.
//
//////////////////////////////////////////////////////////////////////
/*
代码最初来源于网络,原作者未知,表示歉意,代码经由at.Least(炉子)
*/
#include <ntddk.h>
typedef struct _SERVICE_DEscrīptOR_TABLE
{
PVOID ServiceTableBase;
PULONG ServiceCounterTableBase;
ULONG NumberOfService;
ULONG ParamTableBase;
}
SERVICE_DEscrīptOR_TABLE,*PSERVICE_DEscrīptOR_TABLE; //由于KeServiceDescrīptorTable只有一项,这里就简单点了
extern PSERVICE_DEscrīptOR_TABLE KeServiceDescrīptorTable;//KeServiceDescrīptorTable为导出函数
static ULONG JmpAddress;//跳转到的地址
static ULONG OldServiceAddress;//原来的服务地址
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
/////////////////////////////////
//函数用途:修改SSDT表 //
/////////////////////////////////
//输入:服务ID, 新地址 //
//返回值:原始地址 //
/////////////////////////////////
ULONG SetSSDTAddress(ULONG ulServiceID, ULONG procNewAddress)
{
ULONG Address;
Address = (ULONG)KeServiceDescrīptorTable->ServiceTableBase + ulServiceID * 4;//服务ID
/*
炉子(at_Least) 注解 1(Address变量):
其实这个 Address 并不是真正的原始地址,从下文的
“OldServiceAddress = *(ULONG*)Address;”就可看
出其实这个 Address 是指向地址变量的指针(可能我
说的很复杂或者是很难懂,你可以把这个Address理解
为一个 *Address 变量 (ULONG *Address),并且被
赋值为:
Address = &服务函数地址(就是0x8XXXXXXX那东西)
*/
///////////////////////////////////////////////
/*
炉子(at_Least) 注解 2(如何获得Address的值):
SSDT 中数据的存放方式实际是:
------------------理论譬如说------------------>
lkd> dd KeServiceDescrīptorTable
8055ab80 804e3d20 00000000 0000011c 804d9f48
8055ab90 00000000 00000000 00000000 00000000
8055aba0 00000000 00000000 00000000 00000000
8055abb0 00000000 00000000 00000000 00000000
在windbg.exe中我们就看得比较清楚,KeServiceD-
escrīptorTable中就只有第一项有数据,其他都是0
。其中804e3d20就是KeServiceDescrīptorTable.n-
toskrnel.ServiceTableBase,服务函数个数为0x1-
1c个。我们再看看804e3d20地址里是什么东西:
lkd> dd 804e3d20
804e3d20 80587691 805716ef 8057ab71 80581b5c
804e3d30 80599ff7 80637b80 80639d05 80639d4e
804e3d40 8057741c 8064855b 80637347 80599539
804e3d50 8062f4ec 8057a98c 8059155e 8062661f
如上,80587691 805716ef 8057ab71 80581b5c 这些
就是系统服务函数的地址了。
<------------------理论譬如说------------------
(【理论譬如说】中的内容为引用——懒得打字- -)
相信大家也看明白了,每个地址占用4个字节( 1个字
节可以表示两位数字 ——不明白的自己换算。)所以
当我们获取地址的指针时,需要用服务 ID * 4(地址
是连续存放的, 不存在两个地址之间的间隔符之类的
情况)来获取相对于起始地址(在引用部分是【804e-
3d20】)的差值,然后再加上起始地址(就是Servic-
eTableBase)
*/
DbgPrint("Address:0x%08X",Address);
OldServiceAddress = *(ULONG*)Address;//保存原来的地址
DbgPrint("OldServiceAddress:0x%08X",OldServiceAddress);
DbgPrint("procNewFunAddress:0x%08X",procNewAddress);
JmpAddress = (ULONG)NtOpenProcess + 10; //跳转到函数头+10的地方,这样在其前面写的JMP都失效了
DbgPrint("JmpAddress:0x%08X",JmpAddress);

__asm{//去掉内存保护
cli
mov eax
,cr0
and eax,not 10000h
mov cr0,eax
}
*((
ULONG*)Address) = (ULONG)
procNewAddress
;//HOOK SSDT
__asm{//恢复内存保护
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
return OldServiceAddress;
}




egisterShellHookWindow Function

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

Registers a specified Shell window to receive certain messages for events or notifications that are useful to Shell applications. The event messages received are only those sent to the Shell window associated with the specified window's desktop. Many of the messages are the same as those that can be received after calling the SetWindowsHookEx function and specifying WH_SHELL for the hook type. The difference with RegisterShellHookWindow is that the messages are received through the specified window's WindowProc and not through a call back procedure.

Syntax

BOOL RegisterShellHookWindow( HWND hWnd
);
Parameters

hWnd
[in] Handle to the window to register for Shell hook messages.
Return Value

TRUE if the function succeeds; FALSE if the function fails.




Remarks

As with normal window messages, the second parameter of the window procedure identifies the message as a "WM_SHELLHOOKMESSAGE". However, for these Shell hook messages, the message value is not a pre-defined constant like other message IDs such as WM_COMMAND. The value must be obtained dynamically using a call to RegisterWindowMessage(TEXT("SHELLHOOK"));. This precludes handling these messages using a traditional switch statement which requires ID values that are known at compile time. For handling Shell hook messages, the normal practice is to code an If statement in the default section of your switch statement and then handle the message if the value of the message ID is the same as the value obtained from the RegisterWindowMessage call.

The following table describes the wParam and lParam parameter values passed to the window procedure for the Shell hook messages.

wParam lParam
HSHELL_GETMINRECT A pointer to a SHELLHOOKINFO structure.
HSHELL_WINDOWACTIVATEED The HWND handle of the activated window.
HSHELL_RUDEAPPACTIVATEED The HWND handle of the activated window.
HSHELL_WINDOWREPLACING The HWND handle of the window replacing the top-level window.
HSHELL_WINDOWREPLACED The HWND handle of the window being replaced.
HSHELL_WINDOWCreateD The HWND handle of the window being created.
HSHELL_WINDOWDESTROYED The HWND handle of the top-level window being destroyed.
HSHELL_ACTIVATESHELLWINDOW Not used.
HSHELL_TASKMAN Can be ignored.
HSHELL_REDRAW The HWND handle of the window that needs to be redrawn.
HSHELL_FLASH The HWND handle of the window that needs to be flashed.
HSHELL_ENDTASK The HWND handle of the window that should be forced to exit.
HSHELL_APPCOMMAND The APPCOMMAND which has been unhandled by the application or other hooks. See WM_APPCOMMAND and use the GET_APPCOMMAND_LPARAM macro to retrieve this parameter.


Although you can access this function by using LoadLibrary and GetProcAddress combined in Microsoft Windows versions prior to Windows XP, the function is not accessible using the standard Include file and library linkage. The header files included in Windows XPÂ Service Pack 1 (SP1) and Windows Server 2003 document this function and make it accessible using the appropriate Include file and library linkage. However, this function is not intended for general use. It is recommended that you do not use it in new programs because it might be altered or unavailable in subsequent versions of Windows.

Function Information

Minimum DLL Version user32.dll
Header Declared in Winuser.h, include Windows.h
Import library User32.lib
Minimum operating systems Windows 2000
Unicode Implemented as ANSI and Unicode versions.

See Also

Windows Overview, DeregisterShellHookWindow, SetWindowsHookEx, WindowProc, ShellProc, WinEvents, Sending a Message

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

Declare Function RegisterShellHook Lib "Shell32" Alias "#181" (ByVal hwnd As Long, ByVal nAction As Long) As Long
其中hwnd为窗口句柄,而nAction通常为下面的常数:
Const RSH_DEREGISTER = 0
Const RSH_REGISTER = 1
Const RSH_REGISTER_PROGMAN = 2
Const RSH_REGISTER_TASKMAN = 3

还有个RegisterShellHookWindow也可以,这个函数不需要nAction。

eg:

Option Explicit

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 Declare Function
RegisterWindowMessage _
Lib "user32" _
Alias "RegisterWindowMessageA" (ByVal lpString As String) As Long

Private Declare Function
SetWindowLong _
Lib "user32" _
Alias "SetWindowLongA" (ByVal Hwnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long

Private Declare Function
GetWindowLong _
Lib "user32" _
Alias "GetWindowLongA" (ByVal Hwnd As Long, _
ByVal nIndex As Long) As Long
Private Declare Function
RegisterShellHook _
Lib "Shell32" _
Alias <
/font>"#181" (ByVal Hwnd As Long, _
ByVal nAction As Long) As Long

Private Declare Function
RegisterShellHookWindow _
Lib "user32" (ByVal Hwnd As Long) As Long

Private Declare Function
DeregisterShellHookWindow _
Lib "user32" (ByVal Hwnd As Long) As Long

Private Const
HSHELL_WINDOWCreateD = 1
Private Const HSHELL_WINDOWDESTROYED = 2
Private Const HSHELL_ACTIVATESHELLWINDOW = 3
Private Const HSHELL_WINDOWACTIVATED = 4
Private Const HSHELL_GETMINRECT = 5
Private Const HSHELL_REDRAW = 6
Private Const HSHELL_TASKMAN = 7
Private Const HSHELL_LANGUAGE = 8

Private Const WM_NCDESTROY = &H82

Private Const GWL_WNDPROC = -4

Private lpPrevWndProc As Long
Private
msgShellHook As Long

Public Sub
Unhook(Hwnd As Long)
SetWindowLong Hwnd, GWL_WNDPROC, lpPrevWndProc
Call DeregisterShellHookWindow(Hwnd)
End Sub

Public Sub
StartHook(Hwnd As Long)
msgShellHook = RegisterWindowMessage(
"SHELLHOOK")
Dim hLibShell As Long

RegisterShellHookWindow Hwnd
lpPrevWndProc = SetWindowLong(Hwnd, GWL_WNDPROC,
AddressOf WindowProc)
End Sub

Private Function
WindowProc(ByVal Hwnd As Long, _
ByVal uMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long

Select Case
uMsg

Case WM_NCDESTROY
Unhook Hwnd

Case msgShellHook

Select Case wParam

Case HSHELL_WINDOWCreateD

Call AddLog(lParam, "HSHELL_WINDOWCreateD")

Case HSHELL_WINDOWDESTROYED

Call AddLog(lParam, "HSHELL_WINDOWDESTROYED")

Case HSHELL_REDRAW

Call AddLog(lParam, "HSHELL_REDRAW")

Case HSHELL_WINDOWACTIVATED

Call AddLog(lParam, "HSHELL_WINDOWACTIVATED")

Case HSHELL_GETMINRECT

Call AddLog(lParam, "HSHELL_GETMINRECT")

Case HSHELL_REDRAW

Call AddLog(lParam, "HSHELL_REDRAW")

Case HSHELL_TASKMAN

Call AddLog(lParam, "HSHELL_TASKMAN")

Case HSHELL_LANGUAGE

Call AddLog(lParam, "HSHELL_LANGUAGE")
End Select
End Select

WindowProc = CallWindowProc(lpPrevWndProc, Hwnd, uMsg, wParam, lParam)
End Function



'嘿,够简单吧!下面是动态调用MessageBoxA的源代码,上面的步骤被封装到RunDll32函数中,可放到模块(CallAPIbyName.bas)中:
Dim s1() As Byte
Dim
s2() As Byte
Dim
ret As Long
Dim
hProc As Long
Dim
hModule As Long
Sub
t2()
Const hWnd = 0
s1 = StrConv("Hello~World", vbFromUnicode)
s2 = StrConv(
"VBNote", vbFromUnicode)
ret = RunDll32(
"user32", "MessageBoxA", hWnd, VarPtr(s1(0)), VarPtr(s2(0)), 0 &)
End Sub
Public Function
RunDll32(LibFileName As String, ProcName As String, ParamArray Params()) As Long
ReDim
m_OpCode(400 + 6 * UBound(Params)) '保留用来写m_OpCode
'读取API库
hModule = LoadLibrary(ByVal LibFileName)
If hModule = 0 Then
MsgBox "Library读取失败!"
Exit Function
End If
'取得函数地址
hProc = GetProcAddress(hModule, ByVal ProcName)
If hProc = 0 Then
MsgBox "函数读取失败!", vbCritical
FreeLibrary hModule
Exit Function
End If
'执行Assembly Code部分
RunDll32 = CallWindowProc(GetCodeStart(hProc, Params), 0, 1, 2, 3)
FreeLibrary hModule
'释放空间
End Function



'枚举
Dim libName As String
Public Enum
DLL_Enum
kernel32_DLL =
0 'Windows 32核心API库
user32_DLL = 1 '用户接口库
gdi32_DLL = 2 '图形设备接口API库
winmm_DLL = 3 'Windows多媒体API
Shell32_DLL = 4 '32位Shell API库
winspool_DRV = 5 '后台打印API
advapi32_DLL = 6 '高级安全与注册API库
comdlg32_DLL = 7 '通用对话框API
version_DLL = 8 '版本库
netapi32_DLL = 9 'Windows 32位网络API库 Lan
wininet_DLL = 10 'Windows 32位网络API Internet
mapi32_DLL = 11 '电子邮件的API
lz32_DLL = 12 '32位压缩API
mpr_DLL = 13 '多接口路由器库
End Enum
Public Function
CallApiByName(Dll_Lib As DLL_Enum, 这里省略了, 2.0版的不同了
Select Case Dll_Lib
Case 0
libName = "kernel32.DLL" 'Windows 32核心API库
Case 1
libName = "user32.DLL" '用户接口库
Case 2
libName = "gdi32.DLL" '图形设备接口API库
Case 3
libName = "winmm.DLL" 'Windows多媒体API
Case 4
libName = "shell32.DLL" '32位Shell API库
Case 5
libName = "winspool.DRV" '后台打印API
Case 6
libName = "advapi32.DLL" '高级安全与注册API库
Case 7
libName = "comdlg32.DLL" '通用对话框API
Case 8
libName = "version.DLL" '版本库
Case 9
libName = "netapi32.DLL" 'Windows 32位网络API库 Lan
Case 10
libName = "wininet.DLL" 'Windows 32位网络API Internet
Case 11
libName = "mapi32.DLL" '电子邮件的API
Case 12
libName = "lz32.DLL" '32位压缩API
Case 13
libName = "mpr.DLL" '多接口路由器库
End Select




VB可以用Declare声明来调用标准DLL的外部函数,但是其局限性也很明显:利用Declare我们只能载入在设计时通过Lib和Alias字句指定的函数指针!而不能在运行时指定由我们自己动态载入的函数指针),不能用Declare语句来调用任意的函数指针。当我们想动态调用外部函数的时候,就必须考虑采用其他的辅助方法,来完成这个任务了。

在文章《VB真是想不到系列之三:VB指针葵花宝典之函数指针》、《Matthew Curland的VB函数指针调用》、《利用动态创建自动化接口实现VB的函数指针调用》等文献中对此问题都进行了一定程度上的讨论,但是头绪都很繁琐,对我这样的菜鸟还有点深奥,在资料搜索过程中,找到通过在VB中调入汇编程序,比较简便的实现了这个功能,下面就是实现原理:

1)使用LoadLibrary加载DLL;
2)GetProcAddress获得函数指针;

以上两步得到了预加载函数的指针,但是VB中没有提供使用这个指针的方法。我们可以通过一段汇编语言,来完成函数指针的调用!

3)通过汇编语言,把函数的所有参数压入堆栈,然后用Call待用函数指针就可以了。

实现以上功能的主要程序:


'加载Dll
LibAddr = LoadLibrary(ByVal "user32")
'获得函数指针
ProcAddr = GetProcAddress(LibAddr, ByVal "MessageBoxA")
'原型为MessageBox(hWnd, lpText, lpCaption, uType)

'以下为Assembly部分
push uType
push lpCaption
push lpText
push hWnd
call ProcAddr
'--------------------

FreeLibrary LibAddr'释放空间

嘿,够简单吧!下面是动态调用MessageBoxA的源代码,上面的步骤被封装到RunDll32函数中,可放到模块(CallAPIbyName.bas)中:
Dim s1() As Byte, s2() As Byte
Dim
ret As Long
s1 = StrConv("Hello~World", vbFromUnicode)
s2 = StrConv(
"VBNote", vbFromUnicode)
ret = RunDll32(
"user32", "MessageBoxA", hwnd, VarPtr(s1(0)), VarPtr(s2(0)), 0&)

CallAPIbyName.bas中的源代码:

Option Explicit

Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function
GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
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 Declare Function
FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Private Declare Sub
CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)

Public m_opIndex As Long '写入位置
Private m_OpCode() As Byte 'Assembly 的OPCODE

Public Function RunDll32(LibFileName As String, ProcName As String, ParamArray Params()) As Long
Dim
hProc As Long
Dim
hModule As Long

ReDim
m_OpCode(400 + 6 * UBound(Params)) '保留用来写m_OpCode
'读取API库
hModule = LoadLibrary(ByVal LibFileName)
If hModule = 0 Then
MsgBox "Library读取失败!"
Exit Function
End If

'取得函数地址
hProc = GetProcAddress(hModule, ByVal ProcName)
>
If hProc = 0 Then
MsgBox "函数读取失败!", vbCritical
FreeLibrary hModule
Exit Function
End If


'执行Assembly Code部分
RunDll32 = CallWindowProc(GetCodeStart(hProc, Params), 0, 1, 2, 3)

FreeLibrary hModule
'释放空间
End Function

Private Function
GetCodeStart(ByVal lngProc As Long, ByVal arrParams As Variant) As Long
'---以下为Assembly部分--
'作用:将函数的参数压入堆栈

Dim lngIndex As Long, lngCodeStart As Long

'程序起始位址必须是16的倍数
'VarPtr函数是用来取得变量的地址
lngCodeStart = (VarPtr(m_OpCode(0)) Or &HF) + 1

m_opIndex = lngCodeStart - VarPtr(m_OpCode(0)) '程序开始的元素的位置

'前面部分以中断点添满
For lngIndex = 0 To m_opIndex - 1
m_OpCode(lngIndex) = &HCC 'int 3
Next lngIndex

'--------以下开始放入所需的程序----------

'将参数push到堆栈
'由于是STDCall CALL 参数由最后一个开始放到堆栈
For lngIndex = UBound(arrParams) To 0 Step -1
AddByteToCode &H68 'push的机器码为H68
AddLongToCode CLng(arrParams(lngIndex)) '参数地址
Next lngIndex

'call hProc
AddByteToCode &HE8 'call的机器码为HE8
AddLongToCode lngProc - VarPtr(m_OpCode(m_opIndex)) - 4 '函数地址 用call的定址

'-----------结束所需的程序--------------

'返回呼叫函数
AddByteToCode &HC2 'ret 10h
AddByteToCode &H10
AddByteToCode &H0

GetCodeStart = lngCodeStart
End Function

Private Sub
AddLongToCode(lData As Long)
'将Long类型的参数写到m_OpCode中
CopyMemory m_OpCode(m_opIndex), lData, 4
m_opIndex = m_opIndex + 4
End Sub

Private Sub
AddIntToCode(iData As Byte)
'将Integer类型的参数写道m_OpCode中
CopyMemory m_OpCode(m_opIndex), iData, 2
m_opIndex = m_opIndex + 2
End Sub

Private Sub
AddByteToCode(bData As Byte)
'将Byte类型的参数写道m_OpCode中
m_OpCode(m_opIndex) = bData
m_opIndex = m_opIndex +
1
End Sub




本代码通过 xp mshta.exe 解析执行


<HEAD>
<title>
进程中断</title>
<HTA:APPLICATION
APPLICATIONNAME="进程中断"
BORDER="THICK"
caption="进程中断"
maximizebotton="yes"
minmizebutton="yes"
scroll="yes"
showintaskbar="yes"
singleinstance="yes"
sysmenu="yes"
windowstate="maximize"
>
</HEAD>
<SCRIPT 
LANGUAGE="VBScript">

Set os0=createobject("shell.application")
Set wmi=GetObject("winmgmts:\\.")
Set d0=CreateObject("scripting.dictionary")

Sub list
d0.RemoveAll
n=
1
dataarea.innerhtml=Nothing
strHTML = strhtml&"<table border='1' style='border-collapse: collapse' "    & _
           
"bordercolor='#111111' width='100%' id='Table1' >"
strhtml = strhtml&"<tr>"& _
     
"<td width='3%'>"&"<font size=2>"&"序号"&"</font>"&"</td>"& _
     
"<td width='20%'>"&"<font size=2>"&"名称"&"</font>"&"</td>"& _
     
"<td width='7%'>"&"<font size=2>"&"PID"&"</font>"&"</td>"& _
     
"<td width='70%'>"&"<font size=2>"&"命令行"&"</font>"&"</td>"
Set pro_s=wmi.instancesof("win32_process")
For Each In pro_s
strhtml = strhtml&
"<tr>""<td width='3%'>"&    _
      
"<font size=2>"&n&"</font>"&"</td>"&"<td width='20%'>"& _
      
"<font size=2>"&p.name&"</font>"&"</td>""<td width='7%'>"& _
      
"<font size=2>"&p.handle&"</font>"&"</td>""<td width='70%'>"& _
      
"<font size=2>"&p.commandline&"</font>" _
      &
"</td>"
    
d0.Add ""&n,Trim(p.handle)
n=n+
1
Next
dataarea.innerhtml=strhtml
End Sub


Sub 
stop_p
xs=Split(txt.value,
",",-1,1)
for i=to ubound(xs) 
for n=to ubound(xs)
    
if n=i then 
     
n=n+1
     
if n>ubound(xs) then exit for
    end if
    if 
xs(n)=xs(i) or _
     Trim(xs(n))=
"" Then 
     
xs(n)="-1"
    
end If
next
Next
w=
For i=To UBound(xs)
If d0.Exists(xs(i))=False Then 
     
xs(i)="-2"
     
w=w+1
End If
Next
w=(UBound(xs)+ olor="#FF0000">1-w)  
If w=Then
MsgBox "需要中断的进程序号列表无效,"&Chr(13)& _
     
"可能需要关闭的进程不存在或者输入的序号格式不正确,请打开进程列表确认!"
Else
strhtml="<font size=2>"&"已被中断的进程"&"</font>"&"<br>"
strHTML = strhtml&"<table border='1' style='border-collapse: collapse' "    & _
           
"bordercolor='#111111' width='100%' id='Table1' >"
For i=To UBound(xs)
If xs(i) <> "-2" Then 
Set 
pro_s=wmi.EXECQUERY("Select * FROM WIN32_PROCESS Where HANDLE='"&D0(XS(I))&"'" )
    N=
1
    
For Each In pro_s
       pd=p.terminate()
       
If pd=Then 
     
strhtml = strhtml&"<tr>""<td width='3%'>"&"<font size=2>"&xs(i)&"</font>"&"</td>"& _
        
"<td width='20%'>"&"<font size=2>"&p.name&"</font>"&"</td>"& _
        
"<td width='7%'>"&"<font size=2>"&p.handle&"</font>"&"</td>"& _
        
"<td width='70%'>"&"<font size=2>"&p.commandline&"</font>"&"</td>"
     
D0.Remove(xs(i))
     n=n+
1
       
End If
    Next
    If 
N=Then '要关闭的进程可能被牵连关闭了
     
strhtml = strhtml&"<tr>""<td width='3%'>"&    _
        
"<font size=2>"&xs(i)&"</font>"&"</td>"&"<td width='20%'>"& _
        
"<font size=2>"&p.name&"</font>"&"</td>""<td width='7%'>"& _
        
"<font size=2>"&p.handle&"</font>"&"</td>""<td width='70%'>"& _
        
"<font size=2>"&p.commandline&"     已经被间接关闭"&"</font>"& _
        
"</td>"
     
D0.Remove(xs(i))
    
End if
End If
Next
dataarea.innerhtml=dataarea.innerhtml&strhtml
txt.value=
""
End If
End Sub


</SCRIPT>

<body>
<input 
type="button" value="进程列表" name="list_button"    onClick="list"><p>
<span 
id="dataarea"></span><br>
输入欲中断的进程序号,如:1,2,5,7,55...
<input type="text" name="txt" size=60 value="">
<input 
type="button" value="中断进程" name
="stop_p_button"    
onClick="stop_p">
<p>
</body>