|
前段時(shí)間在研究51單片機(jī),花了兩個(gè)月的時(shí)間,總算是摸熟了單片機(jī)的工作方式以及程序設(shè)計(jì)的方法以及焊接技術(shù)的提升。寫程序,時(shí)序圖很重要啊...可惜因?yàn)橘Y金不足,想做很多實(shí)驗(yàn)都沒法...例如自己想整個(gè)語音控制程序,實(shí)現(xiàn)通過以說話的方式控制單片機(jī)執(zhí)行。也想整個(gè)GPS+GPRS,實(shí)現(xiàn)追蹤器,也沒錢買相應(yīng)的硬件。想整個(gè)遙控車+攝像頭,實(shí)現(xiàn)移動(dòng)監(jiān)控。也想整個(gè)自動(dòng)導(dǎo)航飛機(jī),實(shí)現(xiàn)高空巡邏。.... 錢錢錢...真讓人糾結(jié).....
所以在沒有穩(wěn)定的工作前,就先暫時(shí)放下單片機(jī),復(fù)習(xí)一下編程知識(shí)。這個(gè)編程作品,也是在復(fù)習(xí)的時(shí)候,蔣哥想在需要的時(shí)候結(jié)束幾個(gè)隱藏的進(jìn)程。隱藏進(jìn)程的實(shí)現(xiàn)方法通常都是通過DLL遠(yuǎn)程注入的方式,也有RING3 下HOOK相關(guān)API。而蔣哥的增值程序采用的是 SSDT HOOK技術(shù)(具體請(qǐng)看我的另外一篇《學(xué)習(xí)筆記 -> HOOK SSDT表的理解(1) 》http://www.torrancerestoration.com/bbs/dpj-30383-1.html )。那個(gè)增值程序僅僅只是HOOK了 NtQuerySystemInformation,修改里它的返回值,所以普通的任務(wù)管理器自然就看不到該進(jìn)程。就幫他整了一個(gè)簡(jiǎn)單的程序。后來想想,他在網(wǎng)吧工作,所以可能會(huì)有別的需要,所以索性就改進(jìn)成通用版的,可以恢復(fù)指定被HOOK 的NtAPI。方便他用批處理器調(diào)用,也算是自己的第一個(gè)內(nèi)核驅(qū)動(dòng)編程作品吧。
恢復(fù)比HOOK要簡(jiǎn)單多。只需要把被修改的地址改回原來的即可。留下驅(qū)動(dòng)代碼供日后自己復(fù)習(xí)用:
GetAPI_Addr.h :用來獲取原始API地址和被修改的API地址
======================================================================================================
typedef struct _ServiceDescriptorTable
{
PVOID ServiceTableBase;// SSDT 基地址
PVOID ServiceCounterTable;// 包含SSDT中每個(gè)服務(wù)被調(diào)用次數(shù)的計(jì)數(shù)器,一般由sysenter更新
unsigned int NumberOfServices;// 由ServiceTableBase 描述的服務(wù)的數(shù)目
PVOID ParamTableBase;// 包含每個(gè)系統(tǒng)服務(wù)參數(shù)字節(jié)數(shù)表的基地址-系統(tǒng)服務(wù)參數(shù)表
}*PServiceDescriptorTable;
extern PServiceDescriptorTable KeServiceDescriptorTable; // 導(dǎo)出
#pragma PAGECODE
// 獲取當(dāng)前Nt函數(shù)的地址
ULONG GetNt_DQ_Addr(int PianYi_Addr)
{
LONG SSDT_Addr, NtAPI_Addr, *t_addr;
// 讀取SSDT基地址
SSDT_Addr = (LONG)KeServiceDescriptorTable->ServiceTableBase;
// 根據(jù)SSDT基址確定存放指定Nt函數(shù)的地址位置
t_addr = (PLONG)(SSDT_Addr+PianYi_Addr*4);
// 取出Nt函數(shù)的地址
NtAPI_Addr = *t_addr;
return NtAPI_Addr;
}
#pragma PAGECODE
// 獲取原來的Nt函數(shù)的地址
ULONG GetNt_YL_Addr(WCHAR NtAPIName[])
{
UNICODE_STRING YL_NtAPI;
ULONG YL_NtAPI_Addr;
RtlInitUnicodeString(&YL_NtAPI, NtAPIName);
// 讀取原來的地址
YL_NtAPI_Addr = (ULONG)MmGetSystemRoutineAddress(&YL_NtAPI);
return YL_NtAPI_Addr;
}
//UnHook函數(shù)構(gòu)建
//////////////////////////////////////////////////////
#pragma PAGECODE
VOID UnHook(int PianYi_Addr, ULONG YL_Nt_Addr)
{
ULONG SSDT_Nt_Addr;
SSDT_Nt_Addr = (ULONG)KeServiceDescriptorTable->ServiceTableBase + PianYi_Addr * 4;
/*修改 cr0 寄存器,關(guān)閉寫保護(hù)*/
__asm
{
cli
mov eax, cr0
and eax, not 10000h
mov cr0, eax
}
// 還原SSDT
*((ULONG*)SSDT_Nt_Addr) = YL_Nt_Addr;
/*恢復(fù)寫保護(hù)*/
__asm
{
mov eax, cr0
or eax, 10000h
mov cr0, eax
sti
}
return;
}
main.h
======================================================================================================
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include <NTDDK.h> //這里包含需要用C方式編譯的頭文件
#include "GetAPI_Addr.h"
#ifdef __cplusplus
}
#endif
#include <windef.h>
#define INITCODE code_seg("INIT")
#define PAGECODE code_seg("PAGE") /*表示內(nèi)存不足時(shí),可以被置換到硬盤*/
// 定義宏,用來判斷應(yīng)用程序傳遞下來的數(shù)據(jù)。應(yīng)用程序也需要相應(yīng)的宏定義
#define UHook CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED,FILE_ANY_ACCESS)
VOID DDK_Unload (IN PDRIVER_OBJECT pDriverObject); //前置說明 卸載例程
NTSTATUS DispatchRoutine(IN PDEVICE_OBJECT pDevobj,IN PIRP pIrp);//派遣函數(shù)
// 創(chuàng)建設(shè)備
#pragma INITCODE /*指的代碼運(yùn)行后 就從內(nèi)存釋放掉*/
NTSTATUS CreateMyDevice (IN PDRIVER_OBJECT pDriverObject)
{
NTSTATUS status;
PDEVICE_OBJECT pDevObj;/*用來返回創(chuàng)建設(shè)備*/
//創(chuàng)建設(shè)備名稱
UNICODE_STRING devName;
UNICODE_STRING symLinkName; //
RtlInitUnicodeString(&devName,L"\\Device\\L_Device");/*對(duì)devName初始化字串為 "\\Device\\L_Device"*/
//創(chuàng)建設(shè)備
status = IoCreateDevice( pDriverObject,0, &devName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj);
if (!NT_SUCCESS(status))
{
if (status==STATUS_INSUFFICIENT_RESOURCES)
{
KdPrint(("資源不足 STATUS_INSUFFICIENT_RESOURCES"));
}
if (status==STATUS_OBJECT_NAME_EXISTS )
{
KdPrint(("指定對(duì)象名存在"));
}
if (status==STATUS_OBJECT_NAME_COLLISION)
{
KdPrint(("//對(duì)象名有沖突"));
}
KdPrint(("設(shè)備創(chuàng)建失敗...++++++++"));
return status;
}
KdPrint(("設(shè)備創(chuàng)建成功...++++++++"));
pDevObj->Flags |= DO_BUFFERED_IO;
RtlInitUnicodeString(&symLinkName,L"\\??\\LoveMengx_UnSSDTHOOK_Driver");// 初始化
status = IoCreateSymbolicLink( &symLinkName,&devName );// 創(chuàng)建符號(hào)鏈接
if (!NT_SUCCESS(status)) /*status等于0*/
{
IoDeleteDevice( pDevObj );
return status;
}
return STATUS_SUCCESS;
}
main.cpp
======================================================================================================#include "main.h"
#pragma INITCODE
// 此函數(shù)形同應(yīng)用程序的main()函數(shù)
extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING B) //TYPEDEF LONG NTSTATUS
{
//注冊(cè)派遣函數(shù)
pDriverObject->MajorFunction[IRP_MJ_CREATE]=DispatchRoutine; //IRP_MJ_CREATE相關(guān)IRP處理函數(shù)
pDriverObject->MajorFunction[IRP_MJ_CLOSE]=DispatchRoutine; //IRP_MJ_CREATE相關(guān)IRP處理函數(shù)
pDriverObject->MajorFunction[IRP_MJ_READ]=DispatchRoutine; //IRP_MJ_CREATE相關(guān)IRP處理函數(shù)
pDriverObject->MajorFunction[IRP_MJ_CLOSE]=DispatchRoutine; //IRP_MJ_CREATE相關(guān)IRP處理函數(shù)
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=DispatchRoutine; //IRP_MJ_CREATE相關(guān)IRP處理函數(shù)
CreateMyDevice(pDriverObject);//創(chuàng)建相應(yīng)的設(shè)備
pDriverObject->DriverUnload=DDK_Unload; // 指定卸載驅(qū)動(dòng)的時(shí)候要執(zhí)行的函數(shù) 如果未指定則無法卸載
return (1);
}
// 卸載驅(qū)動(dòng)的時(shí)候必須提供,否則無法卸載
#pragma PAGECODE
VOID DDK_Unload (IN PDRIVER_OBJECT pDriverObject)
{
PDEVICE_OBJECT pDev;//用來取得要?jiǎng)h除設(shè)備對(duì)象
UNICODE_STRING symLinkName; //
pDev=pDriverObject->DeviceObject;
IoDeleteDevice(pDev); //刪除設(shè)備
//取符號(hào)鏈接名字
RtlInitUnicodeString(&symLinkName,L"\\??\\LoveMengx_UnSSDTHOOK_Driver");
//刪除符號(hào)鏈接
IoDeleteSymbolicLink(&symLinkName);
KdPrint(("驅(qū)動(dòng)成功被卸載...OK-----------")); //sprintf,printf
}
/* 不知道為什么 atoi 在驅(qū)動(dòng)中無法使用 就只能用這個(gè)替代 */
int my_atoi(const char* p)
{
bool neg_flag = false;// 符號(hào)標(biāo)記
int res = 0;// 結(jié)果
if(p[0] == '+' || p[0] == '-')
neg_flag = (*p++ != '+');
while(isdigit(*p)) res = res*10 + (*p++ - '0');
return neg_flag ?0 -res : res;
}
#pragma PAGECODE
NTSTATUS DispatchRoutine(IN PDEVICE_OBJECT pDevobj,IN PIRP pIrp)
{ //
ULONG info = 0;
//得到當(dāng)前棧指針
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
ULONG mf=stack->MajorFunction; //區(qū)分IRP
switch (mf)
{
case IRP_MJ_DEVICE_CONTROL:
{
KdPrint(("Enter myDriver_DeviceIOControl\n"));
NTSTATUS status = STATUS_SUCCESS;
//得到輸入緩沖區(qū)大小
ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
//得到輸出緩沖區(qū)大小
ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
//得到IOCTL碼
ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
switch (code) // 通過 code分析
{
case UHook: // 如果是自己的定義的消息
{
char NtAPIName[100] = {0};
char Tmp[100] = {0};
int Index = 0;
// 取得應(yīng)用程序傳遞下來的數(shù)據(jù)
char* InputBuffer = (char*)pIrp->AssociatedIrp.SystemBuffer;
char* OutputBuffer = (char*)pIrp->AssociatedIrp.SystemBuffer;
strcpy(NtAPIName, InputBuffer);
// 檢查格式。如果格式不對(duì),容易導(dǎo)致藍(lán)屏
if (strstr(NtAPIName,"-") && strstr(NtAPIName, "+"))
{
KdPrint(("從應(yīng)用程序中得到的數(shù)據(jù):%s\n", NtAPIName));
*(strstr(NtAPIName,"-")) = '\0';
Index = my_atoi(NtAPIName);// 分析得到第一個(gè)參數(shù) NtAPI 的序號(hào)
if(Index >= 0 && Index <=295)
{
strcpy(Tmp, InputBuffer);
char *Tou = strstr(Tmp, "-")+1;
Tou = strstr(Tmp, "-") +1;
*(strstr(Tou,"+")) = '\0';// 分析得到第二個(gè)參數(shù) NtAPI 的名字
KdPrint(("Tou:%s\n", Tou));
UNICODE_STRING wText;
ANSI_STRING Name;
RtlInitString(&Name, Tou);// 初始化 Name
RtlAnsiStringToUnicodeString(&wText,&Name, TRUE);// 轉(zhuǎn)換為UNICODE_STRING
ULONG YL_NtAPI = (ULONG)MmGetSystemRoutineAddress(&wText);// 獲取指定的 NtAPI 原始的地址
KdPrint(("YL_NtAPI:0x%X\n", YL_NtAPI));
if(YL_NtAPI > 0x80000000 && YL_NtAPI < 0x90000000)
{
UnHook(Index, YL_NtAPI);// 恢復(fù) SSDT
strcpy(Tmp, "OK...");
}
else
strcpy(Tmp, "獲取NtAPI地址失敗,請(qǐng)檢查NtAPI名。");
}
else
strcpy(Tmp, "NtAPI的序號(hào)超出大小限制。WinXP:0-283 Win2003:0-295");
}
else
strcpy(Tmp, "參數(shù)格式不對(duì)。");
KdPrint(("處理結(jié)果:%s\n", Tmp));
strcpy(OutputBuffer, Tmp); // 將數(shù)據(jù)返回至應(yīng)用層。
info = strlen(Tmp);
break;
}
}
break;
}
case IRP_MJ_CREATE:
break;
case IRP_MJ_CLOSE:
break;
case IRP_MJ_READ:
break;
}
//對(duì)相應(yīng)的IPR進(jìn)行處理
pIrp->IoStatus.Information=info;//設(shè)置操作的字節(jié)數(shù)為0,這里無實(shí)際意義
pIrp->IoStatus.Status=STATUS_SUCCESS;//返回成功
IoCompleteRequest(pIrp,IO_NO_INCREMENT);//指示完成此IRP
//KdPrint(("離開派遣函數(shù)\n"));//調(diào)試信息
return STATUS_SUCCESS; //返回成功
}
==========================================================================================
程序下載地址:
SSDT_UnHOOK.rar
(19.35 KB, 下載次數(shù): 4)
2015-1-10 23:24 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
調(diào)用方法:
UnSSDTHOOK [ID]-[NtAPI]+
ID:SSDT表中函數(shù)服務(wù)號(hào)
NtAPI:函數(shù)名字
通過XueTr可以知道有那些API被HOOK,ID就是
里面的序號(hào)。NtAPI就是函數(shù)的名字。
例如:UnSSDTHOOK 122-NtOpenProcess+
注意,在執(zhí)行前需要確定序號(hào)與函數(shù)名是相對(duì)應(yīng)的。
可以通過批處理(.bat),循環(huán)調(diào)用,也可以自己寫程
序調(diào)用。
UnSSDTHOOK 執(zhí)行后會(huì)加載驅(qū)動(dòng),所以驅(qū)動(dòng)名字不得修改。
恢復(fù)指定的函數(shù)地址后,會(huì)自動(dòng)卸載驅(qū)動(dòng)。
|
|