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