代碼:
/*
web: http://www.sbasm.cn/
*/
#include <ntddk.h>
#include "struct.h"
//int pos_CreateFile; /* 保存這些函數的服務號 */
int pos_ReadVirtualMemory;
UNICODE_STRING uProcessName;
UNICODE_STRING MyuProcessName;
ANSI_STRING aProcessName;
//特殊的值,目標進程的ID
DWORD dwTargetProcessID;
#define MY_CONTROL_CODE 0x4021
#define IOCTL_SET_TARGET_PROCESS_ID (ULONG)CTL_CODE( FILE_DEVICE_UNKNOWN, MY_CONTROL_CODE, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA )
//一些常量定義
#define EPROCESS_SIZE 1
#define PEB_OFFSET 2
#define FILE_NAME_OFFSET 3
#define PROCESS_LINK_OFFSET 4
#define PROCESS_ID_OFFSET 5
#define EXIT_TIME_OFFSET 6
DWORD GetPlantformDependentInfo ( DWORD dwFlag )
{
DWORD current_build;
DWORD ans = 0;
PsGetVersion(NULL, NULL,¤t_build, NULL);
switch ( dwFlag )
{
case EPROCESS_SIZE:
if (current_build == 2195) ans = 0 ; // 2000,當前不支持2000,下同
if (current_build == 2600) ans = 0x25C; // xp
if (current_build == 3790) ans = 0x270; // 2003
break;
case PEB_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x1b0;
if (current_build == 3790) ans = 0x1a0;
break;
case FILE_NAME_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x174;
if (current_build == 3790) ans = 0x164;
break;
case PROCESS_LINK_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x088;
if (current_build == 3790) ans = 0x098;
break;
case PROCESS_ID_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x084;
if (current_build == 3790) ans = 0x094;
break;
case EXIT_TIME_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x078;
if (current_build == 3790) ans = 0x088;
break;
}
return ans;
}
/*++
函數名: HookNtReadVirtualMemory
參數:
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
OUT PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG ReturnLength OPTIONAL
功能:
隱藏保護模塊的內存,若是發現有內存掃描到這塊內存,則返回垃圾數據擾亂掃描過程
返回:
NTSTATUS
說明:
//獲得了進程對象的對象體,也就是進程的eprocess結構,在xp sp3下,eprocess偏移
//+0x084 就是一個4字節的UniqueProcessId 調用一個GetPlantformDependentInfo便可得到不一樣版本的 UniqueProcessId
--*/
NTSTATUS
HookNtReadVirtualMemory(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
OUT PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG ReturnLength OPTIONAL
)
{
NTSTATUS ret;
PVOID pEprocess; //經過進程句柄獲得ID
PVOID pExplorer_Eprocess; //過濾掉桌面進程explorer時用到的一個EPROCESS類型臨時變量
DWORD dwCurrentPID; //當前ProcessHandle句柄對應的進程號
DWORD dwProcessId;
DWORD dwFileName;
pEprocess = NULL;
dwProcessId = GetPlantformDependentInfo(PROCESS_ID_OFFSET);
dwFileName = GetPlantformDependentInfo(FILE_NAME_OFFSET);
ret = ObReferenceObjectByHandle(ProcessHandle , 0, NULL, KernelMode, &pEprocess, NULL);
if(STATUS_SUCCESS == ret)
{
DbgPrint("the caller ProcessName is %s\n",(PUCHAR)((BYTE*)pEprocess + dwFileName));
dwCurrentPID = *(DWORD*)((BYTE*)pEprocess+dwProcessId); //獲得被掃描的進程的PID
if(dwCurrentPID == dwTargetProcessID) //dwTargetProcessID //若是被掃描的進程PID跟預約的同樣,那麼就開始bypass
{
DbgPrint("call NtReadVirtualMemory!Target Process is %d. The Caller is %d\n",dwTargetProcessID, PsGetCurrentProcessId());
if(dwTargetProcessID == (DWORD)PsGetCurrentProcessId()) //排除本身調用NtReadVirtualMemory來讀取本身內存的狀況
{
DbgPrint("call NtReadVirtualMemory by myself\n");
goto Next;
}
pExplorer_Eprocess = PsGetCurrentProcess(); //獲得當前進程eprocess結構
RtlInitUnicodeString(&uProcessName,L"explorer.exe");
RtlInitAnsiString(&aProcessName,(PUCHAR)((BYTE*)pExplorer_Eprocess + dwFileName));
RtlAnsiStringToUnicodeString(&MyuProcessName,&aProcessName,TRUE);
DbgPrint("call NtReadVirtualMemory by %wZ ---%wZ\n",&MyuProcessName,&uProcessName);
if(RtlCompareUnicodeString(&uProcessName,&MyuProcessName, TRUE) == 0) //不區分大小寫的對比!
{
DbgPrint("call NtReadVirtualMemory by explorer process\n"); //排除explorer調用NtReadVirtualMemory來讀取本身內存的狀況
goto Next;
}
DbgPrint("call NtReadVirtualMemory by other process %d\n",PsGetCurrentProcessId());
//排除了本身對本身的內存操做,桌面進程對所關心的進程的操做以外,其餘的一切進程對多關心的進程進行操做,一概pass
ret = ((NTREADVIRTUALMEMORY)(OldNtReadVirtualMemory))(
ProcessHandle,
BaseAddress,
L"ffffffffff", //自定義的垃圾數據
BufferLength,
ReturnLength
);
return ret;
}
}
Next:
ret = ((NTREADVIRTUALMEMORY)(OldNtReadVirtualMemory))(
ProcessHandle,
BaseAddress,
Buffer,
BufferLength,
ReturnLength
);
return ret;
}
///////////////////////////////////////////////////////////////// -- --
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// -- - - --
//+ +// -- - - --
//+ 下面2個函數用於獲得部分SDT函數的地址 +// -- - --
//+ +// - sudami -
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// -- --
///////////////////////////////////////////////////////////////// -- --
// -- --
// --
DWORD GetDllFunctionAddress (
char* lpFunctionName,
PUNICODE_STRING pDllName
)
/*++
逆向: sudami 08/02/28
參數:
lpFunctionName - 函數名稱
pDllName - 要映射的模塊名稱
功能 :
把給定的模塊映射到內存,讀取其EAT,獲得Zw系列函數地址,還在R3中,
1. 映射ntdll.dll到內存-->ZwMapViewOfSection.
2. 搜索其EAT, 獲得 ZwXxxx的地址p
3. p + 1 處即是ntdll.dll 轉入ntoskrnl.exe的服務號.
4. NtXxxx 的地址 就能夠經過這個服務號 在KeServiceDescriptorTable中取出
5. 用你的fake函數替換掉便可.
--*/
{
HANDLE hThread, hSection, hFile, hMod;
SECTION_IMAGE_INFORMATION sii;
IMAGE_DOS_HEADER* dosheader;
IMAGE_OPTIONAL_HEADER* opthdr;
IMAGE_EXPORT_DIRECTORY* pExportTable;
DWORD* arrayOfFunctionAddresses;
DWORD* arrayOfFunctionNames;
WORD* arrayOfFunctionOrdinals;
DWORD functionOrdinal;
DWORD Base, x, functionAddress;
char* functionName;
STRING ntFunctionName, ntFunctionNameSearch;
PVOID BaseAddress = NULL;
SIZE_T size=0;
OBJECT_ATTRIBUTES oa = {sizeof oa, 0, pDllName, OBJ_CASE_INSENSITIVE};
IO_STATUS_BLOCK iosb;
//_asm int 3;
ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
oa.ObjectName = 0;
ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0,PAGE_EXECUTE, SEC_IMAGE, hFile);
ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 1000, 0, &size, (SECTION_INHERIT)1, MEM_TOP_DOWN, PAGE_READWRITE);
ZwClose(hFile);
hMod = BaseAddress;
dosheader = (IMAGE_DOS_HEADER *)hMod;
opthdr =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hMod+dosheader->e_lfanew+24);
pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*) hMod + opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress);
arrayOfFunctionAddresses = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfFunctions);
arrayOfFunctionNames = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfNames);
arrayOfFunctionOrdinals = (WORD*)( (BYTE*)hMod + pExportTable->AddressOfNameOrdinals);
Base = pExportTable->Base;
RtlInitString(&ntFunctionNameSearch, lpFunctionName);
for(x = 0; x < pExportTable->NumberOfFunctions; x++) {
functionName = (char*)( (BYTE*)hMod + arrayOfFunctionNames[x]);
RtlInitString(&ntFunctionName, functionName);
functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1;
functionAddress = (DWORD)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]);
if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0) {
ZwClose(hSection);
return functionAddress;
}
}
ZwClose(hSection);
return 0;
}
NTSTATUS
DispatchCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
//dprintf("[KsBinSword] IRP_MJ_CREATE\n");
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
DispatchClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS status = STATUS_SUCCESS;
//DbgBreakPoint();
Irp->IoStatus.Information = 0;
//dprintf("[KsBinSword] IRP_MJ_CLOSE\n");
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
DispatchDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP irp
)
{
PIO_STACK_LOCATION irpStack;
PVOID InputBuffer; //若是用到的話,會指向輸入緩衝區
PVOID OutputBuffer; //同上,輸出緩衝區
ULONG IoControlCode; //控制碼
DWORD dwOutBufferLen; //輸出緩衝區長度
DWORD dwInBufferLen; //輸入緩衝區長度
NTSTATUS ntstatus;
ntstatus = irp->IoStatus.Status = STATUS_SUCCESS;
irp->IoStatus.Information = 0;
irpStack = IoGetCurrentIrpStackLocation( irp ); //獲得堆棧指針
//控制碼
IoControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
//控制碼操做
switch ( IoControlCode )
{
//傳遞目標進程ID給驅動,用戶層給驅動數據
case IOCTL_SET_TARGET_PROCESS_ID: //這裏須要用到r3的輸入,即進程ID號
//獲得輸入
InputBuffer = irp->AssociatedIrp.SystemBuffer;
dwInBufferLen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
if(dwInBufferLen != sizeof(DWORD)) //輸入的確定是個DWORD
{ DbgPrint("IOCTL_SET_TARGET_PROCESS_ID error\n");
break;
}
dwTargetProcessID = *(PULONG)InputBuffer; //好了,應該這樣就獲得ID號了
break;
default:
DbgPrint("no such IOCODE\n");
irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
ntstatus = irp->IoStatus.Status;
IoCompleteRequest( irp, IO_NO_INCREMENT );
return ntstatus;
}
// 驅動入口
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath )
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT Device;
UNICODE_STRING DeviceName, DeviceLink; //設備名,符號連接名
DbgPrint("[MyDriver] DriverEntry\n");
RtlInitUnicodeString(&DeviceName, L"\\Device\\MyDriver"); //初始化設備名
RtlInitUnicodeString(&DeviceLink, L"\\DosDevices\\MyDriver"); //初始化符號連接名
/* IoCreateDevice 生成設備對象 */
ntStatus = IoCreateDevice(DriverObject, //生成設備的驅動對象
0, //設備擴展區內存大小
&DeviceName, //設備名,\Device\MyDriver
FILE_DEVICE_UNKNOWN, //設備類型
0, //填寫0便可
FALSE, //必須爲FALSE
&Device); //設備對象指針返回到DeviceObject中
if (!NT_SUCCESS(ntStatus))
{
DbgPrint("[MyDriver] IoCreateDevice FALSE: %.8X\n", ntStatus);
return ntStatus; //生成失敗就返回
}
else
DbgPrint("[MyDriver] IoCreateDevice SUCCESS\n");
/* IoCreateSymbolicLink 生成符號連接 */
ntStatus = IoCreateSymbolicLink(&DeviceLink, &DeviceName);
if (!NT_SUCCESS(ntStatus))
{
DbgPrint("[MyDriver] IoCreateSymbolicLink FALSE: %.8X\n", ntStatus);
IoDeleteDevice(Device); //刪除設備
return ntStatus;
}
else
DbgPrint("[MyDriver] IoCreateSymbolicLink SUCCESS\n");
Device->Flags &= ~DO_DEVICE_INITIALIZING; //設備初始化完成標記
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;
DriverObject->DriverUnload = OnUnload;
Hook(); //SSDT hook
return ntStatus;
}
// 驅動卸載
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING dosDeviceName;
Unhook();
RtlInitUnicodeString(&dosDeviceName, L"\\DosDevices\\MyDriver");
IoDeleteSymbolicLink(&dosDeviceName);
if (DriverObject->DeviceObject != NULL)
{
IoDeleteDevice(DriverObject->DeviceObject); //刪除設備
}
}
// 此處修改SSDT中的NtCreateFile服務地址
VOID Hook()
{
UNICODE_STRING dllName;
DWORD functionAddress;
int position;
RtlInitUnicodeString( &dllName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntdll.dll" );
//獲取NtReadVirtualMemory的服務號完畢!
functionAddress = GetDllFunctionAddress("NtReadVirtualMemory", &dllName);
position = *((WORD*)( functionAddress + 1 ));
pos_ReadVirtualMemory = position;
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
OldNtReadVirtualMemory = (NTREADVIRTUALMEMORY) (*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + pos_ReadVirtualMemory)); //獲得NtReadVirtualMemory函數的原始地址
DbgPrint( "Address of Real OldNtReadVirtualMemory: 0x%08X\n", OldNtReadVirtualMemory );
// 去掉內存保護
__asm
{
cli
mov eax, cr0
and eax, not 10000h
mov cr0, eax
}
(NTREADVIRTUALMEMORY) (*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + pos_ReadVirtualMemory)) = HookNtReadVirtualMemory; //SSDT HOOK NtReadVirtualMemory
DbgPrint(" Address of HookNtReadVirtualMemory: 0x%08X\n", HookNtReadVirtualMemory );
// 恢復內存保護
__asm
{
mov eax, cr0
or eax, 10000h
mov cr0, eax
sti
}
}
//////////////////////////////////////////////////////
VOID Unhook()
{
__asm
{
cli
mov eax, cr0
and eax, not 10000h
mov cr0, eax
}
// 還原SSDT
(NTREADVIRTUALMEMORY) (*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + pos_ReadVirtualMemory)) = OldNtReadVirtualMemory;
__asm
{
mov eax, cr0
or eax, 10000h
mov cr0, eax
sti
}
DbgPrint("Unhook");
}
PS:已經好久沒像之前那樣有時間寫點小東西跟你們分享了