能力值:
( LV13,RANK:410 )
2 楼
ULONG_PTR GetExportRva(IN TCHAR *FileName, IN CHAR *FunctionName)
{
HMODULE hModule = LoadLibrary(FileName);
if (hModule == NULL)
return 0;
ULONG_PTR VA = (ULONG_PTR) GetProcAddress(hModule,
FunctionName);
FreeLibrary(hModule);
return (ULONG_PTR) (VA - (ULONG_PTR) hModule);
}
Very useful isn't it? Here's the code of the dll i inject:
#include <windows.h>
#include <tchar.h>
//
// 驱动部分
//
#ifndef NTSTATUS
typedef LONG NTSTATUS;
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
BOOL OpenDevice(IN LPCTSTR DriverName, HANDLE * lphDevice);
#define FILE_DEVICE_ANTIMIDA 0x8000
#define CODE_RESTORE_INFO CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x800, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_READ_MEM CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x801, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_QUERY_MEM CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x802, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_WRITE_MEM CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x803, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_ALLOC_MEM CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x804, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_CREATE_THREAD CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x805, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_DBG_CONTINUE CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x806, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
//
// ZwReadVirtualMemory 部分
//
typedef struct _Input_ZwReadVirtualMemory
{
HANDLE ProcessHandle;
PVOID BaseAddress;
PVOID Buffer;
ULONG BufferLength;
PULONG ReturnLength;
} Input_ZwReadVirtualMemory;
extern "C" __declspec(dllexport)
BOOL WINAPI FakeReadProcessMemory(HANDLE hProcess,
LPCVOID lpBaseAddress,
LPVOID lpBuffer, DWORD nSize,
LPDWORD lpNumberOfBytesRead)
{
HANDLE hDevice;
if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
return FALSE;
Input_ZwReadVirtualMemory Input;
Input.ProcessHandle = hProcess;
Input.BaseAddress = (PVOID) lpBaseAddress;
Input.Buffer = (PVOID) lpBuffer;
Input.BufferLength = (ULONG) nSize;
Input.ReturnLength = (PULONG) lpNumberOfBytesRead;
DWORD RetBytes;
if (!DeviceIoControl(hDevice, CODE_READ_MEM,
&Input, sizeof (Input_ZwReadVirtualMemory), NULL, 0, &RetBytes, NULL))
{
CloseHandle(hDevice);
return FALSE;
}
CloseHandle(hDevice);
return TRUE;
}
//
// ZwQueryVirtualMemory 部分
//
typedef enum _MEMORY_INFORMATION_CLASS {
MemoryBasicInformation,
MemoryWorkingSetList,
MemorySectionName,
MemoryBasicVlmInformation
} MEMORY_INFORMATION_CLASS;
typedef struct _Input_ZwQueryVirtualMemory
{
HANDLE ProcessHandle;
PVOID BaseAddress;
MEMORY_INFORMATION_CLASS MemoryInformationClass;
ULONG MemoryInformationLength;
PVOID MemoryInformation;
PULONG ReturnLength;
} Input_ZwQueryVirtualMemory;
extern "C" __declspec(dllexport)
SIZE_T WINAPI FakeVirtualQueryEx(IN HANDLE hProcess,
IN LPCVOID lpAddress,
OUT PMEMORY_BASIC_INFORMATION lpBuffer,
IN SIZE_T dwLength)
{
Input_ZwQueryVirtualMemory Input;
ULONG ReturnLength;
Input.ProcessHandle = hProcess;
Input.BaseAddress = (PVOID) lpAddress;
Input.MemoryInformationClass = MemoryBasicInformation;
Input.MemoryInformationLength = (ULONG) dwLength;
Input.MemoryInformation = (PVOID) lpBuffer;
Input.ReturnLength = &ReturnLength;
HANDLE hDevice;
if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
return FALSE;
DWORD RetBytes;
if (!DeviceIoControl(hDevice, CODE_QUERY_MEM,
&Input, sizeof (Input_ZwQueryVirtualMemory),
NULL, 0, &RetBytes, NULL))
{
CloseHandle(hDevice);
return 0;
}
CloseHandle(hDevice);
return (SIZE_T) ReturnLength;
}
//
// ZwReadVirtualMemory 部分
//
typedef struct _Input_ZwWriteVirtualMemory
{
HANDLE ProcessHandle;
PVOID BaseAddress;
PVOID Buffer;
ULONG BufferLength;
PULONG ReturnLength;
} Input_ZwWriteVirtualMemory;
extern "C" __declspec(dllexport)
BOOL WINAPI FakeWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress,
LPVOID lpBuffer, DWORD nSize,
LPDWORD lpNumberOfBytesWritten)
{
HANDLE hDevice;
if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
return FALSE;
//
// 修改内存保护
//
DWORD dwOldProtection;
if (!VirtualProtectEx(hProcess, lpBaseAddress, nSize,
PAGE_EXECUTE_READWRITE, &dwOldProtection))
{
CloseHandle(hDevice);
return FALSE;
}
Input_ZwWriteVirtualMemory Input;
Input.ProcessHandle = hProcess;
Input.BaseAddress = (PVOID) lpBaseAddress;
Input.Buffer = (PVOID) lpBuffer;
Input.BufferLength = (ULONG) nSize;
Input.ReturnLength = (PULONG) lpNumberOfBytesWritten;
DWORD RetBytes;
BOOL bRet;
if (!DeviceIoControl(hDevice, CODE_WRITE_MEM,
&Input, sizeof (Input_ZwWriteVirtualMemory), NULL, 0, &RetBytes, NULL))
{
bRet = FALSE;
}
CloseHandle(hDevice);
//
// 恢复内存保护
//
VirtualProtectEx(hProcess, lpBaseAddress, nSize,
dwOldProtection, &dwOldProtection);
return TRUE;
}
//
// ZwAllocateVirtualMemory 部分
//
typedef struct _Input_ZwAllocateVirtualMemory
{
HANDLE ProcessHandle;
PVOID *BaseAddress;
ULONG_PTR ZeroBits;
PSIZE_T RegionSize;
ULONG AllocationType;
ULONG Protect;
} Input_ZwAllocateVirtualMemory;
extern "C" __declspec(dllexport)
NTSTATUS NTAPI FakeNtAllocateVirtualMemory(IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG_PTR ZeroBits,
IN OUT PSIZE_T RegionSize,
IN ULONG AllocationType,
IN ULONG Protect)
{
Input_ZwAllocateVirtualMemory Input;
Input.ProcessHandle = ProcessHandle;
Input.BaseAddress = BaseAddress;
Input.ZeroBits = ZeroBits;
Input.RegionSize = RegionSize;
Input.AllocationType = AllocationType;
Input.Protect = Protect;
HANDLE hDevice;
if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
return FALSE;
DWORD RetBytes;
if (!DeviceIoControl(hDevice, CODE_ALLOC_MEM,
&Input, sizeof (Input_ZwAllocateVirtualMemory),
NULL, 0, &RetBytes, NULL))
{
CloseHandle(hDevice);
// who cares? (invalid parameter)
return ((NTSTATUS)0xC000000DL);
}
CloseHandle(hDevice);
return STATUS_SUCCESS;
}
//
// ZwCreateThread 部分
//
typedef struct _Input_ZwCreateThread
{
PHANDLE ThreadHandle;
ACCESS_MASK DesiredAccess;
PVOID ObjectAttributes;
HANDLE ProcessHandle;
PVOID ClientId;
PCONTEXT ThreadContext;
PVOID UserStack;
BOOLEAN CreateSuspended;
} Input_ZwCreateThread;
extern "C" __declspec(dllexport)
NTSTATUS NTAPI FakeNtCreateThread(OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN PVOID ObjectAttributes,
IN HANDLE ProcessHandle,
OUT PVOID ClientId,
IN PCONTEXT ThreadContext,
IN PVOID UserStack,
IN BOOLEAN CreateSuspended)
{
Input_ZwCreateThread Input;
Input.ThreadHandle = ThreadHandle;
Input.DesiredAccess = DesiredAccess;
Input.ObjectAttributes = ObjectAttributes;
Input.ProcessHandle = ProcessHandle;
Input.ClientId = ClientId;
Input.ThreadContext = ThreadContext;
Input.UserStack = UserStack;
Input.CreateSuspended = CreateSuspended;
HANDLE hDevice;
if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
return FALSE;
DWORD RetBytes;
if (!DeviceIoControl(hDevice, CODE_CREATE_THREAD,
&Input, sizeof (Input_ZwCreateThread),
NULL, 0, &RetBytes, NULL))
{
CloseHandle(hDevice);
// 谁关心呢?(无效的参数)
return ((NTSTATUS)0xC000000DL);
}
CloseHandle(hDevice);
return STATUS_SUCCESS;
}
//
// ZwDebugContinue 部分
//
typedef struct _Input_ZwDebugContinue
{
PVOID *A;
PVOID *B;
PVOID *C;
} Input_ZwDebugContinue; extern "C" __declspec(dllexport)
NTSTATUS NTAPI FakeZwDebugContinue(PVOID *A, PVOID *B, PVOID *C)
{
Input_ZwDebugContinue Input;
Input.A = A;
Input.B = B;
Input.C = C;
HANDLE hDevice;
if (OpenDevice(_T("antimida"), &hDevice) == FALSE)
return FALSE;
DWORD RetBytes;
if (!DeviceIoControl(hDevice, CODE_DBG_CONTINUE,
&Input, sizeof (Input_ZwDebugContinue),
NULL, 0, &RetBytes, NULL))
{
CloseHandle(hDevice);
// 谁关心呢?(无效的参数)
return ((NTSTATUS)0xC000000DL);
}
CloseHandle(hDevice);
return STATUS_SUCCESS;
}
BOOL OpenDevice(IN LPCTSTR DriverName, HANDLE * lphDevice)
{
TCHAR completeDeviceName[64];
HANDLE hDevice;
/*if ( (GetVersion() & 0xFF) >= 5 ) { wsprintf(completeDeviceName, TEXT("\\\\.\\Global\\%s"), DriverName); } else {*/
wsprintf(completeDeviceName, TEXT("\\\\.\\%s"), DriverName);
//}
hDevice = CreateFile(completeDeviceName, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDevice == ((HANDLE)-1))
return FALSE;
if (lphDevice)
*lphDevice = hDevice;
else
CloseHandle(hDevice);
return TRUE;
}
BOOL APIENTRY DllMain(HANDLE hModule, DWORD Reason, LPVOID lpReserved)
{
switch (Reason)
{
case DLL_PROCESS_ATTACH:
{
DisableThreadLibraryCalls((HMODULE) hModule);
break;
}
case DLL_PROCESS_DETACH:
{
return TRUE;
}
default:
{
return FALSE;
}
}
return TRUE;
}
我不认为对这段代码还有什么要解释的。因为我说会在驱动中完成请求的操作,但是怎么做的?仅仅是调用 ntoskrnl 中的原始的服务。问题是 ntoskrnl 没有在他的导出表中输出 SDT 中的服务,那么是什么获得正确的地址的呢?这其实是个小小的骗局。在 ntoskrnl 中有一个 SDT 的复本。所以我写了这些代码来获取原始的服务的地址:
//
// 感谢 90210 提供这些代码
// http://www.rootkit.com/newsread.php?newsid=176
// 你节省了我的时间
//
#include "stdafx.h"
#define RVATOVA(base,offset) ((PVOID)((DWORD)(base)+(DWORD)(offset)))
#define ibaseDD *(PDWORD)&ibase
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
typedef struct {
WORD offset:12;
WORD type:4;
} IMAGE_FIXUP_ENTRY, *PIMAGE_FIXUP_ENTRY; typedef LONG NTSTATUS;
NTSTATUS (WINAPI *pNtQuerySystemInformation)(
DWORD SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
); typedef struct _SYSTEM_MODULE_INFORMATION {//信息类 11
ULONG Reserved[2];
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[256];
}SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION;
typedef struct {
DWORD dwNumberOfModules;
SYSTEM_MODULE_INFORMATION smi;
} MODULES, *PMODULES;
#define SystemModuleInformation 11
DWORD GetHeaders(PBYTE ibase,
PIMAGE_FILE_HEADER *pfh,
PIMAGE_OPTIONAL_HEADER *poh,
PIMAGE_SECTION_HEADER *psh)
{
PIMAGE_DOS_HEADER mzhead=(PIMAGE_DOS_HEADER)ibase;
if ((mzhead->e_magic!=IMAGE_DOS_SIGNATURE) ||
(ibaseDD[mzhead->e_lfanew]!=IMAGE_NT_SIGNATURE))
return FALSE;
*pfh=(PIMAGE_FILE_HEADER)&ibase[mzhead->e_lfanew];
if (((PIMAGE_NT_HEADERS)*pfh)->Signature!=IMAGE_NT_SIGNATURE)
return FALSE;
*pfh=(PIMAGE_FILE_HEADER)((PBYTE)*pfh+sizeof(IMAGE_NT_SIGNATURE));
*poh=(PIMAGE_OPTIONAL_HEADER)((PBYTE)*pfh+sizeof(IMAGE_FILE_HEADER));
if ((*poh)->Magic!=IMAGE_NT_OPTIONAL_HDR32_MAGIC)
return FALSE;
*psh=(PIMAGE_SECTION_HEADER)((PBYTE)*poh+sizeof(IMAGE_OPTIONAL_HEADER));
return TRUE;
} DWORD FindKiServiceTable(HMODULE hModule,DWORD dwKSDT)
{
PIMAGE_FILE_HEADER pfh;
PIMAGE_OPTIONAL_HEADER poh;
PIMAGE_SECTION_HEADER psh;
PIMAGE_BASE_RELOCATION pbr;
PIMAGE_FIXUP_ENTRY pfe;
DWORD dwFixups=0,i,dwPointerRva,dwPointsToRva,dwKiServiceTable;
BOOL bFirstChunk;
GetHeaders((PBYTE)hModule,&pfh,&poh,&psh);
// 循环通过重定位以加速搜索
if ((poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) &&
(!((pfh->Characteristics)&IMAGE_FILE_RELOCS_STRIPPED))) {
pbr=(PIMAGE_BASE_RELOCATION)RVATOVA(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,hModule);
bFirstChunk=TRUE;
// 1st IMAGE_BASE_RELOCATION.VirtualAddress 在 ntoskrnl 中是 0
while (bFirstChunk || pbr->VirtualAddress) {
bFirstChunk=FALSE;
pfe=(PIMAGE_FIXUP_ENTRY)((DWORD)pbr+sizeof(IMAGE_BASE_RELOCATION));
for (i=0;i<(pbr->SizeOfBlock-sizeof(IMAGE_BASE_RELOCATION))>>1;i++,pfe++) {
if (pfe->type==IMAGE_REL_BASED_HIGHLOW) {
dwFixups++;
dwPointerRva=pbr->VirtualAddress+pfe->offset;
// DONT_RESOLVE_DLL_REFERENCES 标识意味着重定位没有被修复
dwPointsToRva=*(PDWORD)((DWORD)hModule+dwPointerRva)-(DWORD)poh->ImageBase;
// 这个重定位地址是 KeServiceDescriptorTable.Base?
if (dwPointsToRva==dwKSDT) {
// 检查 mov [mem32],imm32. 我们正在尝试找
// "mov ds:_KeServiceDescriptorTable.Base, offset _KiServiceTable"
// 从 KiInitSystem.
if (*(PWORD)((DWORD)hModule+dwPointerRva-2)==0x05c7) {
// 这里应该要检查在 KiServiceTable 的重定位的
// 但是不管它了
dwKiServiceTable=*(PDWORD)((DWORD)hModule+dwPointerRva+4)-poh->ImageBase;
return dwKiServiceTable;
}
}
} else
if (pfe->type!=IMAGE_REL_BASED_ABSOLUTE)
{
// 理论上不应该会用到这里的
}
}
*(PDWORD)&pbr+=pbr->SizeOfBlock;
}
}
if (!dwFixups)
{
// 应该不会到这里的 - nt, 2k, xp 的核心有重定位数据
}
return 0;
}
BOOL SDT_GetOriginalFunctions(PRESTORE_INFO pRestoreInfo)
{
HMODULE hKernel;
DWORD dwKSDT; // rva of KeServiceDescriptorTable
DWORD dwKiServiceTable; // rva of KiServiceTable
PMODULES pModules=(PMODULES)&pModules;
DWORD dwNeededSize,rc;
DWORD dwKernelBase,dwServices=0;
PCHAR pKernelName;
PDWORD pService;
PIMAGE_FILE_HEADER pfh;
PIMAGE_OPTIONAL_HEADER poh;
PIMAGE_SECTION_HEADER psh;
pNtQuerySystemInformation = (NTSTATUS (WINAPI *)(
DWORD, PVOID, ULONG, PULONG)) GetProcAddress(
GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
// 获取系统模块 - 在这里 ntoskrnl 是第一个
rc=pNtQuerySystemInformation(SystemModuleInformation,pModules,4,&dwNeededSize);
if (rc==STATUS_INFO_LENGTH_MISMATCH) {
pModules = (PMODULES) GlobalAlloc(GPTR,dwNeededSize);
rc=pNtQuerySystemInformation(SystemModuleInformation,pModules,dwNeededSize,NULL);
} else {
strange:
return FALSE;
}
if (!NT_SUCCESS(rc)) goto strange;
// 映像基址
dwKernelBase=(DWORD)pModules->smi.Base;
// 文件名 - 他可能会在 boot.ini 中被重命名
pKernelName=pModules->smi.ModuleNameOffset+pModules->smi.ImageName;
// 映射 ntoskrnl - 希望他有重定位
hKernel=LoadLibraryEx(pKernelName,0,DONT_RESOLVE_DLL_REFERENCES);
if (!hKernel) {
return FALSE;
}
GlobalFree(pModules);
// 我们自己的重定位操作在这里一无是处 - 因为我们有 GetProcAddress :)
if (!(dwKSDT=(DWORD)GetProcAddress(hKernel,"KeServiceDescriptorTable"))) {
return FALSE;
}
// 获取 KeServiceDescriptorTable rva
dwKSDT-=(DWORD)hKernel;
// 查找 KiServiceTable
if (!(dwKiServiceTable=FindKiServiceTable(hKernel,dwKSDT))) {
return FALSE;
}
// 我们来转存 KiServiceTable 的内容
// 可能会失败!!!
// 这里应该会获得正确的 ServiceLimit,但是这在核心模式中的价值不高
GetHeaders((PBYTE) hKernel,&pfh,&poh,&psh);
//
// 我们的代码
//
//
// 获取 ZwAllocateVirtualMemory
//
DWORD nServ = GrabService("ZwAllocateVirtualMemory");
pService = (PDWORD)((nServ * sizeof (DWORD)) +
(DWORD) hKernel + dwKiServiceTable);
pRestoreInfo->ZwAllocateVirtualMemory =
(*pService-poh->ImageBase + dwKernelBase);
//
// 获取 ZwCreateThread
//
nServ = GrabService("ZwCreateThread");
pService = (PDWORD)((nServ * sizeof (DWORD)) +
(DWORD) hKernel + dwKiServiceTable);
pRestoreInfo->ZwCreateThread =
(*pService-poh->ImageBase + dwKernelBase);
//
// 获取 ZwDebugContinue
//
nServ = GrabService("ZwDebugContinue");
pService = (PDWORD)((nServ * sizeof (DWORD)) +
(DWORD) hKernel + dwKiServiceTable);
pRestoreInfo->ZwDebugContinue =
(*pService-poh->ImageBase + dwKernelBase);
//
// 获取 ZwQueryVirtualMemory
//
nServ = GrabService("ZwQueryVirtualMemory");
pService = (PDWORD)((nServ * sizeof (DWORD)) +
(DWORD) hKernel + dwKiServiceTable);
pRestoreInfo->ZwQueryVirtualMemory =
(*pService-poh->ImageBase + dwKernelBase);
//
// 获取 ZwReadVirtualMemory
//
nServ = GrabService("ZwReadVirtualMemory");
pService = (PDWORD)((nServ * sizeof (DWORD)) +
(DWORD) hKernel + dwKiServiceTable);
pRestoreInfo->ZwReadVirtualMemory =
(*pService-poh->ImageBase + dwKernelBase);
//
// 获取 ZwTerminateProcess
//
nServ = GrabService("ZwTerminateProcess");
pService = (PDWORD)((nServ * sizeof (DWORD)) +
(DWORD) hKernel + dwKiServiceTable);
pRestoreInfo->ZwTerminateProcess =
(*pService-poh->ImageBase + dwKernelBase);
//
// 获取 ZwWriteVirtualMemory
//
nServ = GrabService("ZwWriteVirtualMemory");
pService = (PDWORD)((nServ * sizeof (DWORD)) +
(DWORD) hKernel + dwKiServiceTable);
pRestoreInfo->ZwWriteVirtualMemory =
(*pService-poh->ImageBase + dwKernelBase);
FreeLibrary(hKernel);
}
能力值:
( LV13,RANK:410 )
3 楼
GrabService 函数是基于另一个小骗局来获取 SDT 项目的。事实上 SDT 的项目随着 windows 的变化而变化,所以获取他的最好的方法是从 ntdll 中读取。看看 NtReadVirtualMemory:
.text:7C91E2BB public ZwReadVirtualMemory
.text:7C91E2BB B8 BA 00 00 00 mov eax, 0BAh ; 这就是 SDT 项目
.text:7C91E2C0 BA 00 03 FE 7F mov edx, 7FFE0300h
.text:7C91E2C5 FF 12 call dword ptr [edx]
.text:7C91E2C7 C2 14 00 retn 14h
所以我写了这个函数来获取正确的 SDT 项目:
//
// 感谢 gareth 提供这个点子
// http://www.rootkit.com/newsread.php?newsid=248
//
#include "stdafx.h"
DWORD GrabService(IN CHAR *FunctionName)
{
DWORD Exp = (DWORD) GetProcAddress(
GetModuleHandle(_T("ntdll.dll")), FunctionName);
Exp++; // mov opcode
DWORD *ptr = (DWORD *) Exp;
return *ptr;
}
嗯,我在收集信息并发送给驱动(恢复信息),我还把 KeAttachProcess 原始的代码发送了过去。我并不需要他,但是他在进行恢复时会很有用:
#include "stdafx.h"
ULONG_PTR RvaToOffset(IMAGE_NT_HEADERS *, ULONG_PTR);
BOOL GetExport(BYTE *, ULONG_PTR *, WORD *, CHAR *);
BOOL GetNtoskrnlOriginalBytes(PRESTORE_INFO pRestoreInfo)
{
TCHAR Buffer[MAX_PATH];
GetSystemDirectory(Buffer, MAX_PATH);
_tcscat(Buffer, _T("\\ntoskrnl.exe"));
HANDLE hFile = CreateFile(Buffer, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
DWORD FileSize = GetFileSize(hFile, NULL);
BYTE *ptrNtoskrnl = (BYTE *) VirtualAlloc(NULL, FileSize,
MEM_COMMIT, PAGE_READWRITE);
if (ptrNtoskrnl == NULL)
{
CloseHandle(hFile);
return FALSE;
}
DWORD BR;
if (!ReadFile(hFile, ptrNtoskrnl, FileSize, &BR, NULL))
{
VirtualFree(ptrNtoskrnl, 0, MEM_RELEASE);
CloseHandle(hFile);
return FALSE;
}
CloseHandle(hFile);
IMAGE_DOS_HEADER *ImgDosHdr = (IMAGE_DOS_HEADER *) ptrNtoskrnl;
IMAGE_NT_HEADERS *ImgNtHdrs = (IMAGE_NT_HEADERS *)
&ptrNtoskrnl[ImgDosHdr->e_lfanew];
ULONG_PTR EP_Rva = 0;
if (!GetExport(ptrNtoskrnl, &EP_Rva, NULL, "KeAttachProcess"))
{
VirtualFree(ptrNtoskrnl, 0, MEM_RELEASE);
return FALSE;
}
BYTE *ptr = (BYTE *) (EP_Rva + (ULONG_PTR) ptrNtoskrnl);
memcpy(pRestoreInfo->KeAttachProcessPatch, ptr, 5);
VirtualFree(ptrNtoskrnl, 0, MEM_RELEASE);
return TRUE;
}
BOOL CollectInformation(PRESTORE_INFO pRestoreInfo)
{
if (SDT_GetOriginalFunctions(pRestoreInfo) == FALSE)
return FALSE;
return GetNtoskrnlOriginalBytes(pRestoreInfo);
}
函数 GetExport 是我已有的函数,很有用,从输出表中获取你请求的信息:
BOOL GetExport(BYTE *PE, ULONG_PTR *EP, WORD *Ordinal, CHAR *FuncName)
{
IMAGE_DOS_HEADER *ET_DOS;
IMAGE_NT_HEADERS *ET_NT;
IMAGE_EXPORT_DIRECTORY *Export;
ULONG_PTR ET, *Functions;
PSTR *Names;
WORD *Ordinals;
CHAR *ApiName;
__try
{
ET_DOS = (IMAGE_DOS_HEADER *)(ULONG_PTR) PE;
ET_NT = (IMAGE_NT_HEADERS *)(ULONG_PTR) &PE[ET_DOS->e_lfanew];
ET = ET_NT->OptionalHeader.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (ET == NULL)
return FALSE;
ET = RvaToOffset(ET_NT, ET);
if (ET == 0) return FALSE;
Export = (IMAGE_EXPORT_DIRECTORY *)(ET + (ULONG_PTR) PE);
Functions = (ULONG_PTR *)(RvaToOffset(ET_NT,
Export->AddressOfFunctions) + (ULONG_PTR) PE);
Ordinals = (WORD *)(RvaToOffset(ET_NT,
Export->AddressOfNameOrdinals) + (ULONG_PTR) PE);
Names = (PSTR *)(RvaToOffset(ET_NT,
Export->AddressOfNames) + (ULONG_PTR) PE);
if (EP != NULL && *EP != 0)
{
for (WORD x = 0; x < Export->NumberOfFunctions; x++)
{
if (*EP == Functions[x])
{
if (Ordinal) *Ordinal = (WORD) (x + Export->Base);
if (FuncName != NULL)
{
for (WORD i = 0; i < Export->NumberOfNames; i++)
{
if (Ordinals[i] == x)
{
ApiName = (char *) RvaToOffset(ET_NT, (ULONG_PTR) Names[i]);
if (ApiName != NULL)
{
ApiName = (char *)((ULONG_PTR) ApiName +
(ULONG_PTR) PE);
strcpy(FuncName, ApiName);
break;
}
}
}
}
return TRUE;
}
}
return FALSE;
}
else
{
if (FuncName == NULL || FuncName[0] == 0)
{
if (Ordinal == NULL || *Ordinal == 0)
return FALSE;
if (*Ordinal < Export->Base ||
*Ordinal > (Export->Base + (Export->NumberOfFunctions - 1)))
return FALSE;
WORD FuncEntry = (WORD) (*Ordinal - Export->Base);
if (EP) *EP = Functions[FuncEntry];
if (FuncName != NULL)
{
for (DWORD i = 0; i < Export->NumberOfNames; i++)
{
if (Ordinals[i] == FuncEntry)
{
ApiName = (char *) RvaToOffset(ET_NT, (ULONG_PTR) Names[i]);
if (ApiName != NULL)
{
ApiName = (char *)((ULONG_PTR) ApiName + (ULONG_PTR) PE);
strcpy(FuncName, ApiName);
break;
}
}
}
}
return TRUE;
}
else
{
for (DWORD x = 0; x < Export->NumberOfFunctions; x++)
{
if (Functions[x] == 0)
continue;
for (DWORD i = 0; i < Export->NumberOfNames; i++)
{
if (Ordinals[i] == x)
{
ApiName = (char *) RvaToOffset(ET_NT, (ULONG_PTR) Names[i]);
if (ApiName != NULL)
{
ApiName = (char *)((ULONG_PTR) ApiName + (ULONG_PTR) PE);
if (strcmp(ApiName, FuncName) == 0)
{
if (Ordinal) *Ordinal = (WORD) (x + Export->Base);
if (EP) *EP = Functions[x];
return TRUE;
}
}
}
}
}
return FALSE;
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return FALSE;
}
return FALSE;
}
在收集信息后,我把它通过 DeviceIoControl 发送给了驱动并接受及处理信息:
NTSTATUS ControlDispatcher(PDEVICE_CONTEXT pDeviceContext, DWORD dwCode,
BYTE *pInput, DWORD dwInputSize,
BYTE *pOutput, DWORD dwOutputSize, DWORD *pdwInfo)
{
switch (dwCode)
{
case CODE_RESTORE_INFO:
{
RtlCopyMemory(&RestoreInfo, pInput, sizeof (RESTORE_INFO));
pZwReadVirtualMemory = (NTSTATUS (*)(HANDLE,
PVOID, PVOID, ULONG, PULONG))
RestoreInfo.ZwReadVirtualMemory;
pZwQueryVirtualMemory = (NTSTATUS (*)(HANDLE,
PVOID, MEMORY_INFORMATION_CLASS, PVOID, ULONG,
PULONG)) RestoreInfo.ZwQueryVirtualMemory;
pZwWriteVirtualMemory = (NTSTATUS (*)(HANDLE, PVOID,
PVOID, ULONG, PULONG))
RestoreInfo.ZwWriteVirtualMemory;
pZwAllocateVirtualMemory = (NTSTATUS (*)(HANDLE,
PVOID *, ULONG_PTR, PSIZE_T, ULONG, ULONG))
RestoreInfo.ZwAllocateVirtualMemory;
pZwCreateThread = (NTSTATUS (*)(PHANDLE, ACCESS_MASK,
POBJECT_ATTRIBUTES, HANDLE, PCLIENT_ID,
PCONTEXT, PUSER_STACK, BOOLEAN))
RestoreInfo.ZwCreateThread;
pZwDebugContinue = (NTSTATUS (*)(PVOID *A, PVOID *B, PVOID *C))
RestoreInfo.ZwDebugContinue;
RebuildNtoskrnl();
break;
}
RebuildNtoskrnl 函数修补了 KeAttachProcess 被替换的字节:
//
// 修改 KeAttachProcess
//
VOID RebuildNtoskrnl()
{
PMDL Mdl;
DWORD CR0Backup;
DWORD *ptr;
BYTE *Patch;
ptr = (DWORD *)(2 + (DWORD) &KeAttachProcess);
ptr = (DWORD*) *ptr;
Patch = (BYTE *) *ptr;
Mdl = MmCreateMdl(0, (PVOID) Patch, 5);
if (Mdl == NULL)
return;
MmProbeAndLockPages(Mdl, 0, 0);
if (*Patch == 0xE9)
{
__asm
{
mov eax, cr0
mov CR0Backup, eax
and eax, 0xFFFEFFFF
mov cr0, eax
}
//
// 修改
//
memcpy(Patch, RestoreInfo.KeAttachProcessPatch, 5);
__asm
{
mov eax, CR0Backup
mov cr0, eax
}
}
MmUnlockPages(Mdl);
IoFreeMdl(Mdl);
}
这就是 SDT 的全部了。现在让我们谈谈监视,就是: regmon 和 filemon. 这两个中只要有任何一个启动了,TheMida 就不会启动。这里有不少检测他们驱动的方法,恐怕太多了些。下面是他们中的一部分:
1 - 查找进程。
2 - 查找窗口(我在某些壳中也发现了这个)。
3 - 查找注册表中的驱动。
4 - 查找内存中的驱动。
5 - 查找驱动的对象表。
6 - 查找 SDT (只对 regmon)。
还有一些其他的方式,但是我认我这些应该是最常用的。我尝试解决了 4 和 5 (因为我有作这些的源代码)。
#include <wdm.h>
typedef struct _MODULE_ENTRY
{
LIST_ENTRY le_mod;
ULONG unknown[4];
ULONG base;
ULONG driver_start;
ULONG unk1;
UNICODE_STRING driver_Path;
UNICODE_STRING driver_Name;
//...
} MODULE_ENTRY, *PMODULE_ENTRY;
//
// 这个结构在 valerino 的代码中丢失了
//
typedef struct _OBJECT_HEADER
{
ULONG PointerCount;
ULONG HandleCount;
PVOID Type;
UCHAR NameInfoOffset;
UCHAR HandleInfoOffset;
UCHAR QuotaInfoOffset;
UCHAR Flags;
PVOID ObjectCreateInfo;
PVOID SecurityDescriptor;
struct _QUAD Body;
}OBJECT_HEADER, * POBJECT_HEADER;
// valerino 的代码
#define NUMBER_HASH_BUCKETS 37
typedef struct _OBJECT_DIRECTORY_ENTRY {
struct _OBJECT_DIRECTORY_ENTRY *ChainLink;
PVOID Object;
} OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY;
typedef struct _OBJECT_DIRECTORY {
struct _OBJECT_DIRECTORY_ENTRY *HashBuckets[ NUMBER_HASH_BUCKETS ];
struct _OBJECT_DIRECTORY_ENTRY **LookupBucket;
BOOLEAN LookupFound;
USHORT SymbolicLinkUsageCount;
struct _DEVICE_MAP *DeviceMap;
} OBJECT_DIRECTORY, *POBJECT_DIRECTORY;
typedef struct _DEVICE_MAP {
ULONG ReferenceCount;
POBJECT_DIRECTORY DosDevicesDirectory;
ULONG DriveMap;
UCHAR DriveType[ 32 ];
} DEVICE_MAP, *PDEVICE_MAP;
typedef struct _OBJECT_HEADER_NAME_INFO {
POBJECT_DIRECTORY Directory;
UNICODE_STRING Name;
ULONG Reserved;
} OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO;
#define OBJECT_TO_OBJECT_HEADER( o ) \
CONTAINING_RECORD( (o), OBJECT_HEADER, Body )
#define OBJECT_HEADER_TO_NAME_INFO( oh ) ((POBJECT_HEADER_NAME_INFO) \
((oh)->NameInfoOffset == 0 ? NULL : ((PCHAR)(oh) - (oh)->NameInfoOffset)))
NTSTATUS ObOpenObjectByName (IN POBJECT_ATTRIBUTES ObjectAttributes,
IN POBJECT_TYPE ObjectType OPTIONAL, IN KPROCESSOR_MODE AccessMode,
IN OUT PACCESS_STATE AccessState OPTIONAL, IN ACCESS_MASK DesiredAccess OPTIONAL,
IN OUT PVOID ParseContext OPTIONAL, OUT PHANDLE Handle);
// 结束
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath);
VOID Unload(IN PDRIVER_OBJECT DriverObject);
VOID StealthInitializeLateMore(VOID);
VOID HideModule(PDRIVER_OBJECT DriverObject);
#pragma code_seg("INIT")
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
PDEVICE_OBJECT pDeviceObject = NULL;
NTSTATUS Status = IoCreateDevice(DriverObject, 0, NULL,
FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
if (NT_SUCCESS(Status))
{
DriverObject->DriverUnload = Unload;
HideModule(DriverObject);
StealthInitializeLateMore();
}
return Status;
}
#pragma code_seg() VOID Unload(IN PDRIVER_OBJECT DriverObject)
{
IoDeleteDevice(DriverObject->DeviceObject);
}
// 从 PsLoadedModuleList 中隐藏模块
VOID HideModule(PDRIVER_OBJECT DriverObject)
{
PMODULE_ENTRY pCurrentModule = NULL;
// 指向 PsLoadedModuleList 的指针
pCurrentModule = ((PMODULE_ENTRY)(ULONG_PTR) DriverObject->DriverSection);
if (pCurrentModule == NULL)
return;
// 开始扫描以查找我们的驱动
while (TRUE)
{
pCurrentModule = (PMODULE_ENTRY) pCurrentModule->le_mod.Flink;
if (pCurrentModule == NULL)
return;
if (pCurrentModule->driver_Name.Length > 3 &&
pCurrentModule->driver_Name.Buffer)
{
if (wcscmp(pCurrentModule->driver_Name.Buffer, L"hide.sys") == 0)
{
// 断开与我们的驱动的连接+
pCurrentModule->le_mod.Blink->Flink = pCurrentModule->le_mod.Flink;
pCurrentModule->le_mod.Flink->Blink = pCurrentModule->le_mod.Blink;
break;
}
}
}
}
// 感谢 valerino 提供代码
// rootkit 上的文章
//************************************************************************
// VOID HideFromObjectDirectory()
//
// 从对象目录中隐藏驱动
//************************************************************************/
VOID StealthInitializeLateMore(VOID)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING ucName;
NTSTATUS Status;
HANDLE hDirectory = NULL;
POBJECT_DIRECTORY pDirectoryObject = NULL;
KIRQL OldIrql;
POBJECT_HEADER ObjectHeader;
POBJECT_HEADER_NAME_INFO NameInfo;
POBJECT_DIRECTORY_ENTRY DirectoryEntry;
POBJECT_DIRECTORY_ENTRY DirectoryEntryNext;
POBJECT_DIRECTORY_ENTRY DirectoryEntryTop;
ULONG Bucket = 0;
UNICODE_STRING ObjectName;
BOOLEAN found = FALSE;
// 打开对象目录中的驱动目录
RtlInitUnicodeString(&ucName,L"\\Driver");
InitializeObjectAttributes(&ObjectAttributes,&ucName,OBJ_CASE_INSENSITIVE,NULL,NULL);
Status = ObOpenObjectByName(&ObjectAttributes,NULL,KernelMode,NULL,
0x80000000,NULL,&hDirectory);
if (!NT_SUCCESS (Status))
goto __exit;
// 获取指针
Status = ObReferenceObjectByHandle(hDirectory,FILE_ANY_ACCESS,NULL,
KernelMode,&pDirectoryObject, NULL);
if (!NT_SUCCESS (Status))
goto __exit;
// 我们提高 irql 以保护这个列表不被 kernel APC 访问
KeRaiseIrql(APC_LEVEL,&OldIrql);
// 历遍对象目录
for (Bucket=0; Bucket<NUMBER_HASH_BUCKETS; Bucket++)
{
// 完成了吗?
if (found)
break;
DirectoryEntry = pDirectoryObject->HashBuckets[Bucket];
if (!DirectoryEntry)
continue;
// 检查我们是不是在 bucket 的顶端
ObjectHeader = OBJECT_TO_OBJECT_HEADER( DirectoryEntry->Object );
NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
if (NameInfo != NULL)
{
ObjectName = NameInfo->Name;
// 这里我们将自己的驱动的名称与对象的名称进行比较(例如: ROOTKIT)
// 这个函数只是我对 wcsstr 的的扩展,不要管它了 .......
if (wcscmp(ObjectName.Buffer, L"hide") == 0)
{
// 到达顶部并获取下一个指针
DirectoryEntryTop = pDirectoryObject->HashBuckets[Bucket];
DirectoryEntryNext = DirectoryEntryTop->ChainLink;
// 替代顶部
pDirectoryObject->HashBuckets[Bucket] = DirectoryEntryNext;
DirectoryEntryTop = pDirectoryObject->HashBuckets[Bucket];
// 历遍链并通过一处替换返回项目
while (DirectoryEntryNext)
{
DirectoryEntryTop->ChainLink = DirectoryEntryNext->ChainLink;
DirectoryEntryTop = DirectoryEntryTop->ChainLink;
DirectoryEntryNext = DirectoryEntryNext->ChainLink;
}
if (DirectoryEntryTop)
DirectoryEntryTop->ChainLink = NULL;
found = TRUE;
// 我们可以安全退出了
break;
}
}
// 如果我们不在 bucket 顶端的话,检查 项目->下一个区域
// 对每个项目我们都要检查下一个
DirectoryEntryNext = DirectoryEntry->ChainLink;
while (DirectoryEntryNext)
{
ObjectHeader = OBJECT_TO_OBJECT_HEADER( DirectoryEntryNext->Object );
NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
if (NameInfo != NULL)
{
ObjectName = NameInfo->Name;
if (wcscmp(ObjectName.Buffer, L"hide") == 0)
{
// 找到我们的对象,现在我们必须脱开与他的连接,这次简单些
DirectoryEntry->ChainLink = DirectoryEntryNext->ChainLink;
found = TRUE;
// 退出
break;
}
}
// walk the next entry if any
if (DirectoryEntry)
{
DirectoryEntry = DirectoryEntry->ChainLink;
DirectoryEntryNext = DirectoryEntry->ChainLink;
}
else
{
DirectoryEntryNext = NULL;
}
}
}
// 调回 irql
KeLowerIrql(OldIrql);
__exit:
// dereference and cleanup
if (pDirectoryObject)
ObDereferenceObject(pDirectoryObject);
if (hDirectory)
ZwClose (hDirectory);
return;
}
当然是用真实名称替换藏在代码里的哪些是很重要的。不管怎么样,TheMida 至少查找了 PsLoadedModuleList,而且还检查了其他什么东西(我想他检查了注册表)。我没有时间来尝试,我很快就会知道的(只要隐藏一些键就行了)。然而我必须要看看他有没有检查 SDT 是否被关联了(使用 regmon 的代码来关联一个),而且很明显他没有,他很正常的执行了。我也能执行一个小的监视器来检视注册表和我的工具中的文件(这是可能的)。当然我无法编写一个文件系统的过滤器,只像 regmon 一样关联 SDT (这更简单一些)。然我想想,现在这些是驱动代码(带有 SDT 关联代码,这些可以被扩展成一个监视器之类的东西).
能力值:
( LV13,RANK:410 )
4 楼
#include <ntddk.h>
#include <common.h>
WCHAR DeviceName[] = L"\\Device\\antimida";
WCHAR SymLinkName[] = L"\\DosDevices\\antimida";
UNICODE_STRING usDeviceName;
UNICODE_STRING usSymbolicLinkName;
typedef struct _DEVICE_CONTEXT
{
PDRIVER_OBJECT pDriverObject;
PDEVICE_OBJECT pDeviceObject;
}
DEVICE_CONTEXT, *PDEVICE_CONTEXT, **PPDEVICE_CONTEXT;
PDEVICE_OBJECT g_pDeviceObject = NULL;
PDEVICE_CONTEXT g_pDeviceContext = NULL;
#define FILE_DEVICE_ANTIMIDA 0x8000
#define CODE_RESTORE_INFO CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x800, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_READ_MEM CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x801, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_QUERY_MEM CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x802, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_WRITE_MEM CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x803, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_ALLOC_MEM CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x804, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_CREATE_THREAD CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x805, \
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define CODE_DBG_CONTINUE CTL_CODE(FILE_DEVICE_ANTIMIDA, 0x806, \
METHOD_BUFFERED, FILE_ANY_ACCESS) NTSTATUS DriverInitialize(PDRIVER_OBJECT pDriverObject,
PUNICODE_STRING pusRegistryPath);
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,
PUNICODE_STRING pusRegistryPath);
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, DriverInitialize)
#pragma alloc_text (INIT, DriverEntry)
#endif
VOID NTAPI KeAttachProcess(IN PEPROCESS);
//
// ZwReadVirtualMemory 部分
//
typedef struct _Input_ZwReadVirtualMemory
{
HANDLE ProcessHandle;
PVOID BaseAddress;
PVOID Buffer;
ULONG BufferLength;
PULONG ReturnLength;
} Input_ZwReadVirtualMemory;
NTSTATUS (*pZwReadVirtualMemory)(IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
OUT PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG ReturnLength OPTIONAL); KMUTEX DumpMutex;
//
// ZwQueryVirtualMemory 部分
//
typedef enum _MEMORY_INFORMATION_CLASS {
MemoryBasicInformation,
MemoryWorkingSetList,
MemorySectionName,
MemoryBasicVlmInformation
} MEMORY_INFORMATION_CLASS; NTSTATUS (*pZwQueryVirtualMemory)(IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
OUT PVOID MemoryInformation,
IN ULONG MemoryInformationLength,
OUT PULONG ReturnLength OPTIONAL);
typedef struct _Input_ZwQueryVirtualMemory
{
HANDLE ProcessHandle;
PVOID BaseAddress;
MEMORY_INFORMATION_CLASS MemoryInformationClass;
ULONG MemoryInformationLength;
PVOID MemoryInformation;
PULONG ReturnLength;
} Input_ZwQueryVirtualMemory;
//
// ZwWriteVirtualMemory 部分
//
NTSTATUS (*pZwWriteVirtualMemory)(IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG ReturnLength OPTIONAL);
typedef struct _Input_ZwWriteVirtualMemory
{
HANDLE ProcessHandle;
PVOID BaseAddress;
PVOID Buffer;
ULONG BufferLength;
PULONG ReturnLength;
} Input_ZwWriteVirtualMemory;
//
// ZwAllocateVirtualMemory 部分
//
NTSTATUS (*pZwAllocateVirtualMemory)(IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG_PTR ZeroBits,
IN OUT PSIZE_T RegionSize,
IN ULONG AllocationType,
IN ULONG Protect);
typedef struct _Input_ZwAllocateVirtualMemory
{
HANDLE ProcessHandle;
PVOID *BaseAddress;
ULONG_PTR ZeroBits;
PSIZE_T RegionSize;
ULONG AllocationType;
ULONG Protect;
} Input_ZwAllocateVirtualMemory;
//
// ZwCreateThread 部分
//
typedef struct _USER_STACK {
PVOID FixedStackBase;
PVOID FixedStackLimit;
PVOID ExpandableStackBase;
PVOID ExpandableStackLimit;
PVOID ExpandableStackBottom;
} USER_STACK, *PUSER_STACK; NTSTATUS (*pZwCreateThread)(OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN HANDLE ProcessHandle,
OUT PCLIENT_ID ClientId,
IN PCONTEXT ThreadContext,
IN PUSER_STACK UserStack,
IN BOOLEAN CreateSuspended);
typedef struct _Input_ZwCreateThread
{
PHANDLE ThreadHandle;
ACCESS_MASK DesiredAccess;
POBJECT_ATTRIBUTES ObjectAttributes;
HANDLE ProcessHandle;
PCLIENT_ID ClientId;
PCONTEXT ThreadContext;
PUSER_STACK UserStack;
BOOLEAN CreateSuspended;
} Input_ZwCreateThread;
//
// ZwDebugContinue 部分
// 我已经懒得去查找正确的声明了
//
NTSTATUS (*pZwDebugContinue)(PVOID *A, PVOID *B, PVOID *C);
typedef struct _Input_ZwDebugContinue
{
PVOID *A;
PVOID *B;
PVOID *C;
} Input_ZwDebugContinue; //
// 恢复信息结构
//
typedef struct _RESTORE_INFO
{
DWORD ZwAllocateVirtualMemory;
DWORD ZwCreateThread;
DWORD ZwDebugContinue;
DWORD ZwQueryVirtualMemory;
DWORD ZwReadVirtualMemory;
DWORD ZwTerminateProcess;
DWORD ZwWriteVirtualMemory;
BYTE KeAttachProcessPatch[5];
} RESTORE_INFO, *PRESTORE_INFO;
RESTORE_INFO RestoreInfo;
//
// SDT 关联部分
//
extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;
PVOID *KeServiceTablePointers;
PMDL KeServiceTableMdl;
BOOLEAN *ServiceIsHooked;
PPVOID MapServiceTable(BOOLEAN **);
VOID UnmapServiceTable(PVOID);
#ifdef ALPHA
#define FUNCTION_PTR(_Function) (*(PULONG) _Function) & 0x0000FFFF
#else
#define FUNCTION_PTR(_Function) *(PULONG)((PUCHAR) _Function + 1)
#endif
#define HOOK_SYSCALL(_Function, _Hook, _Orig) \
if (!ServiceIsHooked[FUNCTION_PTR(_Function)]) { \
_Orig = (PVOID) InterlockedExchange((PLONG) \
&KeServiceTablePointers[FUNCTION_PTR(_Function)], (LONG) _Hook ); \
ServiceIsHooked[ FUNCTION_PTR(_Function) ] = TRUE; } #define UNHOOK_SYSCALL(_Function, _Hook, _Orig) \
if (ServiceIsHooked[FUNCTION_PTR(_Function)] && \
KeServiceTablePointers[FUNCTION_PTR(_Function) ] == (PVOID) _Hook ) { \
InterlockedExchange((PLONG) &KeServiceTablePointers[ \
FUNCTION_PTR(_Function)], (LONG) _Orig ); \
ServiceIsHooked[FUNCTION_PTR(_Function)] = FALSE; }
NTSTATUS (*RealZwCreateFile)(OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength
);
NTSTATUS (*RealZwOpenKey)(OUT PHANDLE, IN ACCESS_MASK, IN POBJECT_ATTRIBUTES);
NTSTATUS HookedZwCreateFile(OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength)
{
DbgPrint("%ws\n", ObjectAttributes->ObjectName->Buffer);
return RealZwCreateFile(FileHandle, DesiredAccess, ObjectAttributes,
IoStatusBlock, AllocationSize, FileAttributes, ShareAccess,
CreateDisposition, CreateOptions, EaBuffer, EaLength);
}
NTSTATUS HookedZwOpenKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes)
{
return RealZwOpenKey(KeyHandle, DesiredAccess, ObjectAttributes);
}
PPVOID MapServiceTable(BOOLEAN **ServiceIsHooked)
{
PVOID Mem;
Mem = ExAllocatePoolWithTag(0,
KeServiceDescriptorTable->ntoskrnl.ServiceLimit,
0x206B6444);
if (Mem == NULL)
return NULL;
*ServiceIsHooked = (BOOLEAN *) Mem;
memset(Mem, 0, KeServiceDescriptorTable->ntoskrnl.
ServiceLimit);
KeServiceTableMdl = MmCreateMdl(NULL,
KeServiceDescriptorTable->ntoskrnl.ServiceTable,
(KeServiceDescriptorTable->ntoskrnl.ServiceLimit *
sizeof (POINTER)));
if (KeServiceTableMdl == NULL)
return NULL;
MmBuildMdlForNonPagedPool(KeServiceTableMdl);
return (PPVOID) MmMapLockedPages(KeServiceTableMdl, 0);
}
VOID UnmapServiceTable(PVOID KeServiceTablePointers)
{
if (KeServiceTableMdl == NULL)
return;
MmUnmapLockedPages(KeServiceTablePointers,
KeServiceTableMdl);
ExFreePool(KeServiceTableMdl);
}
//
// 修改 KeAttachProcess
//
VOID RebuildNtoskrnl()
{
PMDL Mdl;
DWORD CR0Backup;
DWORD *ptr;
BYTE *Patch;
ptr = (DWORD *)(2 + (DWORD) &KeAttachProcess);
ptr = (DWORD*) *ptr;
Patch = (BYTE *) *ptr;
Mdl = MmCreateMdl(0, (PVOID) Patch, 5);
if (Mdl == NULL)
return;
MmProbeAndLockPages(Mdl, 0, 0);
if (*Patch == 0xE9)
{
__asm
{
mov eax, cr0
mov CR0Backup, eax
and eax, 0xFFFEFFFF
mov cr0, eax
}
//
// 修改
//
memcpy(Patch, RestoreInfo.KeAttachProcessPatch, 5);
__asm
{
mov eax, CR0Backup
mov cr0, eax
}
}
MmUnlockPages(Mdl);
IoFreeMdl(Mdl);
} NTSTATUS ControlDispatcher(PDEVICE_CONTEXT pDeviceContext, DWORD dwCode,
BYTE *pInput, DWORD dwInputSize,
BYTE *pOutput, DWORD dwOutputSize, DWORD *pdwInfo)
{
switch (dwCode)
{
case CODE_RESTORE_INFO:
{
RtlCopyMemory(&RestoreInfo, pInput, sizeof (RESTORE_INFO));
pZwReadVirtualMemory = (NTSTATUS (*)(HANDLE,
PVOID, PVOID, ULONG, PULONG))
RestoreInfo.ZwReadVirtualMemory;
pZwQueryVirtualMemory = (NTSTATUS (*)(HANDLE,
PVOID, MEMORY_INFORMATION_CLASS, PVOID, ULONG,
PULONG)) RestoreInfo.ZwQueryVirtualMemory;
pZwWriteVirtualMemory = (NTSTATUS (*)(HANDLE, PVOID,
PVOID, ULONG, PULONG))
RestoreInfo.ZwWriteVirtualMemory;
pZwAllocateVirtualMemory = (NTSTATUS (*)(HANDLE,
PVOID *, ULONG_PTR, PSIZE_T, ULONG, ULONG))
RestoreInfo.ZwAllocateVirtualMemory;
pZwCreateThread = (NTSTATUS (*)(PHANDLE, ACCESS_MASK,
POBJECT_ATTRIBUTES, HANDLE, PCLIENT_ID,
PCONTEXT, PUSER_STACK, BOOLEAN))
RestoreInfo.ZwCreateThread;
pZwDebugContinue = (NTSTATUS (*)(PVOID *A, PVOID *B, PVOID *C))
RestoreInfo.ZwDebugContinue;
RebuildNtoskrnl();
break;
}
case CODE_READ_MEM:
{
Input_ZwReadVirtualMemory Input;
RtlCopyMemory(&Input, pInput, sizeof (Input_ZwReadVirtualMemory));
return pZwReadVirtualMemory(Input.ProcessHandle, Input.BaseAddress,
Input.Buffer, Input.BufferLength, Input.ReturnLength);
}
case CODE_QUERY_MEM:
{
Input_ZwQueryVirtualMemory Input;
RtlCopyMemory(&Input, pInput, sizeof (Input_ZwQueryVirtualMemory));
return pZwQueryVirtualMemory(Input.ProcessHandle, Input.BaseAddress,
Input.MemoryInformationClass, Input.MemoryInformation,
Input.MemoryInformationLength, Input.ReturnLength);
}
case CODE_WRITE_MEM:
{
Input_ZwWriteVirtualMemory Input;
RtlCopyMemory(&Input, pInput, sizeof (Input_ZwWriteVirtualMemory));
return pZwWriteVirtualMemory(Input.ProcessHandle, Input.BaseAddress,
Input.Buffer, Input.BufferLength, Input.ReturnLength);
}
case CODE_ALLOC_MEM:
{
Input_ZwAllocateVirtualMemory Input;
RtlCopyMemory(&Input, pInput, sizeof (Input_ZwAllocateVirtualMemory));
return pZwAllocateVirtualMemory(Input.ProcessHandle, Input.BaseAddress,
Input.ZeroBits, Input.RegionSize, Input.AllocationType, Input.Protect);
}
case CODE_CREATE_THREAD:
{
Input_ZwCreateThread Input;
RtlCopyMemory(&Input, pInput, sizeof (Input_ZwCreateThread));
return pZwCreateThread(Input.ThreadHandle, Input.DesiredAccess,
Input.ObjectAttributes, Input.ProcessHandle, Input.ClientId,
Input.ThreadContext, Input.UserStack, Input.CreateSuspended);
}
case CODE_DBG_CONTINUE:
{
Input_ZwDebugContinue Input;
RtlCopyMemory(&Input, pInput, sizeof (Input_ZwDebugContinue));
return pZwDebugContinue(Input.A, Input.B, Input.C);
}
default:
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
NTSTATUS DeviceDispatcher(PDEVICE_CONTEXT pDeviceContext, PIRP pIrp)
{
PIO_STACK_LOCATION pisl;
DWORD dwInfo = 0;
NTSTATUS ns = STATUS_NOT_IMPLEMENTED;
pisl = IoGetCurrentIrpStackLocation(pIrp);
switch (pisl->MajorFunction)
{
case IRP_MJ_CREATE:
case IRP_MJ_CLEANUP:
case IRP_MJ_CLOSE:
{
ns = STATUS_SUCCESS;
break;
}
case IRP_MJ_DEVICE_CONTROL:
{
MUTEX_ACQUIRE(DumpMutex);
ns = ControlDispatcher(pDeviceContext,
pisl->Parameters.DeviceIoControl.IoControlCode,
(BYTE *) pIrp->AssociatedIrp.SystemBuffer,
pisl->Parameters.DeviceIoControl.InputBufferLength,
(BYTE *) pIrp->AssociatedIrp.SystemBuffer,
pisl->Parameters.DeviceIoControl.OutputBufferLength,
&dwInfo);
MUTEX_RELEASE(DumpMutex);
break;
}
}
pIrp->IoStatus.Status = ns;
pIrp->IoStatus.Information = dwInfo;
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
return ns;
}
NTSTATUS DriverDispatcher(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
return (pDeviceObject == g_pDeviceObject ?
DeviceDispatcher(g_pDeviceContext, pIrp)
: STATUS_INVALID_PARAMETER_1);
} VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
UNHOOK_SYSCALL(ZwCreateFile, HookedZwCreateFile, RealZwCreateFile);
UNHOOK_SYSCALL(ZwOpenKey, HookedZwOpenKey, RealZwOpenKey);
UnmapServiceTable(KeServiceTablePointers);
IoDeleteSymbolicLink(&usSymbolicLinkName);
IoDeleteDevice(pDriverObject->DeviceObject);
}
NTSTATUS DriverInitialize(PDRIVER_OBJECT pDriverObject,
PUNICODE_STRING pusRegistryPath)
{
PDEVICE_OBJECT pDeviceObject = NULL;
NTSTATUS ns = STATUS_DEVICE_CONFIGURATION_ERROR;
RtlInitUnicodeString(&usDeviceName, DeviceName);
RtlInitUnicodeString(&usSymbolicLinkName, SymLinkName);
if ((ns = IoCreateDevice(pDriverObject, sizeof (DEVICE_CONTEXT),
&usDeviceName, FILE_DEVICE_ANTIMIDA, 0, FALSE,
&pDeviceObject)) == STATUS_SUCCESS)
{
if ((ns = IoCreateSymbolicLink(&usSymbolicLinkName,
&usDeviceName)) == STATUS_SUCCESS)
{
g_pDeviceObject = pDeviceObject;
g_pDeviceContext = pDeviceObject->DeviceExtension;
g_pDeviceContext->pDriverObject = pDriverObject;
g_pDeviceContext->pDeviceObject = pDeviceObject;
}
else
{
IoDeleteDevice(pDeviceObject);
}
}
return ns;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,
PUNICODE_STRING pusRegistryPath)
{
PDRIVER_DISPATCH *ppdd;
NTSTATUS ns = STATUS_DEVICE_CONFIGURATION_ERROR;
if ((ns = DriverInitialize(pDriverObject, pusRegistryPath)) == STATUS_SUCCESS)
{
ppdd = pDriverObject->MajorFunction;
ppdd[IRP_MJ_CREATE ] =
ppdd[IRP_MJ_CREATE_NAMED_PIPE ] =
ppdd[IRP_MJ_CLOSE ] =
ppdd[IRP_MJ_READ ] =
ppdd[IRP_MJ_WRITE ] =
ppdd[IRP_MJ_QUERY_INFORMATION ] =
ppdd[IRP_MJ_SET_INFORMATION ] =
ppdd[IRP_MJ_QUERY_EA ] =
ppdd[IRP_MJ_SET_EA ] =
ppdd[IRP_MJ_FLUSH_BUFFERS ] =
ppdd[IRP_MJ_QUERY_VOLUME_INFORMATION] =
ppdd[IRP_MJ_SET_VOLUME_INFORMATION ] =
ppdd[IRP_MJ_DIRECTORY_CONTROL ] =
ppdd[IRP_MJ_FILE_SYSTEM_CONTROL ] =
ppdd[IRP_MJ_DEVICE_CONTROL ] =
ppdd[IRP_MJ_INTERNAL_DEVICE_CONTROL ] =
ppdd[IRP_MJ_SHUTDOWN ] =
ppdd[IRP_MJ_LOCK_CONTROL ] =
ppdd[IRP_MJ_CLEANUP ] =
ppdd[IRP_MJ_CREATE_MAILSLOT ] =
ppdd[IRP_MJ_QUERY_SECURITY ] =
ppdd[IRP_MJ_SET_SECURITY ] =
ppdd[IRP_MJ_POWER ] =
ppdd[IRP_MJ_SYSTEM_CONTROL ] =
ppdd[IRP_MJ_DEVICE_CHANGE ] =
ppdd[IRP_MJ_QUERY_QUOTA ] =
ppdd[IRP_MJ_SET_QUOTA ] =
ppdd[IRP_MJ_PNP ] = DriverDispatcher;
pDriverObject->DriverUnload = DriverUnload;
MUTEX_INIT(DumpMutex);
KeServiceTablePointers = MapServiceTable(&ServiceIsHooked);
HOOK_SYSCALL(ZwCreateFile, HookedZwCreateFile, RealZwCreateFile);
HOOK_SYSCALL(ZwOpenKey, HookedZwOpenKey, RealZwOpenKey);
}
return ns;
}
好了,我现在很累了。没有什么要解释的了,如果你有疑惑的话,google 在那里等着你。这项工程的继续取决于我得到的信息。我对逆向 TheMida 没有兴趣。 译者:我现在同样也是累得不行了。。。好长的程序代码,不过最后还是发现有词还是不会译。郁闷。。。