有码无真像,关于内存隐藏,隐藏3层程序的指定区域, ITLB 和 DTLB 已经分别被载入,但是代码运行的时候被卡死
在WinDbg 里面看到 在访问和执行的时候 页面分别被换成了我们想要的页面,
目前的问题是读写成功,但是执行的时候,3层程序被卡死了也不蓝
call g_pfnCallIntoHookedPage //通过调用一下那个页面内的代码,装载ITLB
and dword ptr [ebx], 0xFFFFFFFE //重新标记为不存在
测试如果把 and dword ptr [ebx], 0xFFFFFFFE 这行去掉 那么程序可以正常运行,但是HOOK 也就失效了~~~~
求真像~~~~
所引用的头文件在 OllyBonE里面有
达人请指教
#include "ntddk.h"
#include "stdio.h"
#include "stdlib.h"
#include "multicpu.h"
typedef BOOLEAN BOOL;
typedef unsigned long DWORD;
typedef DWORD * PDWORD;
typedef unsigned long ULONG;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned long* PPTE;
typedef LARGE_INTEGER PHYSICAL_MEMORY;
#define HIGHEST_USER_ADDRESS 0x80000000
#define ERROR_PAGE_NOT_IN_LIST 0
PDEVICE_OBJECT g_PagefaultDevice;
void *g_OldInt0EHandler = NULL;
void *g_Int03Handler = NULL;
void *g_Int01Handler = NULL;
BOOL hooked = FALSE;
DWORD g_pidsaved = 0;
DWORD g_pfnCallIntoHookedPage;
PPTE g_pReadWritePTE;
PPTE g_pExePTE;
DWORD g_cr3=0;
DWORD g_pExecutePage=0;
DWORD g_ulHookCodeLen=0;
NTSTATUS PagefaultDispatch(IN PDEVICE_OBJECT, IN PIRP);
NTSTATUS PagefaultUnload(IN PDRIVER_OBJECT);
NTSTATUS PagefaultDeviceControl(IN PFILE_OBJECT, IN BOOLEAN, IN PVOID,
IN ULONG, OUT PVOID, IN ULONG, IN ULONG,
OUT PIO_STATUS_BLOCK, IN PDEVICE_OBJECT
);
#define FILE_DEVICE_IORIPROTECT 0x8000
#define IOCTL_OLLYBONE_SET CTL_CODE(FILE_DEVICE_IORIPROTECT, 1, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
#define IOCTL_OLLYBONE_RESTORE CTL_CODE(FILE_DEVICE_IORIPROTECT, 2, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
#pragma pack(push,1)
typedef struct _ioctlparams
{
DWORD pid;
DWORD va;
DWORD size;
DWORD ViewPag;
DWORD va_ret;
} IOCTLPARAMS;
#pragma pack(pop)
#define PROCESS_PAGE_DIR_BASE 0xC0300000
#define PROCESS_PAGE_TABLE_BASE 0xC0000000
#define KERNEL_ADDRESS_START 0x80000000
static DWORD MmSystemPteBase=0xc0000000;
const WCHAR deviceLinkBuffer[] = L"\\DosDevices\\ollybone";
const WCHAR deviceNameBuffer[] = L"\\Device\\ollybone";
char buf[100];
const char formatMsg[] = "Handling access fault (pte:%x) at %x for address %x\n";
VOID NTAPI KeAttachProcess( IN PEPROCESS );
VOID NTAPI KeDetachProcess( );
NTSTATUS NTAPI PsLookupProcessByProcessId( DWORD pid, PEPROCESS *eproc );
#define DebugPrint DbgPrint
PPTE GetPteAddress( PVOID VirtualAddress );
void HookMemoryPage( PVOID pReadWritePage );
void UnhookMemoryPage( PVOID pReadWritePage );
void MarkPageSupervisorOnly( void *pte );
void MarkPageUserMode( void *pte );
void *SetInterruptHandler(int IntNo, void *HandlerPtr, BYTE flags);
void *GetInterruptHandler(DWORD IntNo, DWORD IdtNum);
void InstallHandler();
void RemoveHandler();
#pragma optimize( "", off )
void __declspec (naked) NewInt0EHandler(void)
{
__asm
{
pushad
mov edx, dword ptr [esp+0x20] //PageFault.ErrorCode
test edx, 1 //不是缺页错误
jne PassDown
//通过CR3判断当前进程
mov eax, cr3
cmp eax, g_cr3
jnz PassDown
mov eax,cr2 //faulting virtual address
////////////////////////////////////////
//判断是否是Hook掉的page
/////////////////////////////////////////
mov ebx, g_pExecutePage
and ebx, 0xFFFFF000
and eax, 0xFFFFF000
cmp eax, ebx
mov eax, cr2
jnz PassDown //不是,传下去
///////////////////////////////////////
//下面处理Hook掉的页面了
/////////////////////////////////////
//mov eax, cr2
//push eax
//push eax
//call GetPteAddress
//mov ebx, eax //ebx = pPte
//pop eax
mov eax, cr2
mov esi, PROCESS_PAGE_DIR_BASE
mov ebx, eax
shr ebx, 22
lea ebx, [esi + ebx * 4] //ebx = pPTE for large page
test [ebx], 0x80 //check if its a large page
jnz IsLargePage
mov esi, PROCESS_PAGE_TABLE_BASE
mov ebx, eax
shr ebx, 12
lea ebx, [esi + ebx * 4] //ebx = pPTE
IsLargePage:
cmp [esp+0x24], eax //判断是执行出错还是读写时出错?
je LoadITLB
//判断是否是Hook的那些字节
cmp eax, g_pExecutePage
jb LoadDTLB
sub eax, g_pExecutePage
cmp eax, g_ulHookCodeLen
jg LoadDTLB
jmp LoadFakeFrame
LoadITLB:
////////////////////////////////
//是一次执行操作,所以Load ITLB
///////////////////////////////
mov eax, cr2
mov esi, g_pExePTE
mov ecx, dword ptr [esi] //ecx = PTE of the
//read / write page
//把页面替换为真的
mov edi, [ebx]
and edi, 0x00000FFF //preserve the lower 12 bits of the
//faulting page's PTE
and ecx, 0xFFFFF000 //isolate the physical address in
//the "fake" page's PTE
or ecx, edi
mov edx, [ebx] //save the old PTE so we can replace it
mov [ebx], ecx //replace the faulting page's phys frame
//address w/ the fake one
cli
or dword ptr [ebx], 0x01 //标志页面为存在
call g_pfnCallIntoHookedPage //通过调用一下那个页面内的代码,装载ITLB
and dword ptr [ebx], 0xFFFFFFFE //重新标记为不存在
//sti
jmp ReturnWithoutPassdown
////////////////////////////////
// 这是读写造成的异常,并且不在我们要隐藏的代码范围内,Load DTLB
///////////////////////////////
LoadDTLB:
cli
mov eax,cr2
or dword ptr [ebx], 0x01 //mark the page present
mov eax, dword ptr [eax] //load the DTLB
and dword ptr [ebx], 0xFFFFFFFE //mark page not present
//sti
jmp ReturnWithoutPassdown
/////////////////////////////////
//需要隐藏这段代码,所以Load伪装的页面
/////////////////////////////////
LoadFakeFrame:
mov eax, cr2
mov esi, g_pReadWritePTE
mov ecx, dword ptr [esi] //ecx = PTE of the
//read / write page
//把页面替换为假的
mov edi, [ebx]
and edi, 0x00000FFF //preserve the lower 12 bits of the
//faulting page's PTE
and ecx, 0xFFFFF000 //isolate the physical address in
//the "fake" page's PTE
or ecx, edi
mov edx, [ebx] //save the old PTE so we can replace it
cli
mov [ebx], ecx //replace the faulting page's phys frame
//address w/ the fake one
//load DTLB
or dword ptr [ebx], 0x01 //标志为存在
mov eax, cr2 //faulting virtual address
mov eax, dword ptr[eax] //访问一次页面的数据,Load DTLB
and dword ptr [ebx], 0xFFFFFFFE //重新标志为不存在
//Finally, restore the original PTE
mov [ebx], edx
//sti
ReturnWithoutPassDown:
popad
add esp,4
sti
iretd
PassDown:
popad
jmp [g_OldInt0EHandler]
}//end asm
}
#pragma optimize( "", on )
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath )
{
NTSTATUS ntStatus;
UNICODE_STRING deviceNameUnicodeString;
UNICODE_STRING deviceLinkUnicodeString;
RtlInitUnicodeString (&deviceNameUnicodeString,
deviceNameBuffer );
RtlInitUnicodeString (&deviceLinkUnicodeString,
deviceLinkBuffer );
ntStatus = IoCreateDevice ( DriverObject,
0,
&deviceNameUnicodeString,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&g_PagefaultDevice );
if(! NT_SUCCESS(ntStatus))
{
DebugPrint(("Failed to create device!\n"));
return ntStatus;
}
ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
&deviceNameUnicodeString );
if(! NT_SUCCESS(ntStatus))
{
IoDeleteDevice(DriverObject->DeviceObject);
DebugPrint("Failed to create symbolic link!\n");
return ntStatus;
}
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] =
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PagefaultDispatch;
DriverObject->DriverUnload = PagefaultUnload;
return STATUS_SUCCESS;
}
NTSTATUS PagefaultUnload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING deviceLinkUnicodeString;
PDEVICE_OBJECT p_NextObj;
p_NextObj = DriverObject->DeviceObject;
if (p_NextObj != NULL)
{
RtlInitUnicodeString( &deviceLinkUnicodeString, deviceLinkBuffer );
IoDeleteSymbolicLink( &deviceLinkUnicodeString );
IoDeleteDevice( DriverObject->DeviceObject );
return STATUS_SUCCESS;
}
return STATUS_SUCCESS;
}
NTSTATUS
PagefaultDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION irpStack;
PVOID inputBuffer;
PVOID outputBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
ULONG ioControlCode;
NTSTATUS ntstatus;
ntstatus = Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
irpStack = IoGetCurrentIrpStackLocation (Irp);
inputBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBuffer = Irp->AssociatedIrp.SystemBuffer;
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
break;
case IRP_MJ_SHUTDOWN:
break;
case IRP_MJ_CLOSE:
break;
case IRP_MJ_DEVICE_CONTROL:
ntstatus = PagefaultDeviceControl( irpStack->FileObject, TRUE,
inputBuffer, inputBufferLength,
outputBuffer, outputBufferLength,
ioControlCode, &Irp->IoStatus, DeviceObject );
break;
}
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return ntstatus;
}
NTSTATUS
PagefaultDeviceControl(
IN PFILE_OBJECT FileObject,
IN BOOLEAN Wait,
IN PVOID InputBuffer,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN ULONG OutputBufferLength,
IN ULONG IoControlCode,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS ntStatus;
DWORD va;
DWORD i;
DWORD size;
DWORD pid;
PEPROCESS eproc = NULL;
IOCTLPARAMS *params;
char buf[100];
IoStatus->Status = STATUS_SUCCESS;
IoStatus->Information = 0;
switch ( IoControlCode )
{
DbgPrint("IOCODE %08x %08x",IOCTL_OLLYBONE_SET,IoControlCode);
case IOCTL_OLLYBONE_SET:
DebugPrint(("IOCTL_OLLYBONE_SET\n"));
if ((InputBufferLength < sizeof(int) * 3) || (InputBuffer == NULL))
{
IoStatus->Status = STATUS_INVALID_BUFFER_SIZE;
break;
}
params = (IOCTLPARAMS *)InputBuffer;
pid = params->pid;
va = params->va & 0xFFFFF000;
size = params->size;
if (PsLookupProcessByProcessId(pid, &eproc) == STATUS_SUCCESS)
{
KeAttachProcess(eproc);
DbgPrint("PID:%d VA:%08x Size:%08x ViewPag:%08x va_ret:%08x \n",pid,va,size,params->ViewPag,params->va_ret);
g_pidsaved = pid;
g_pExecutePage=va;
g_ulHookCodeLen=size;
g_pReadWritePTE=GetPteAddress(params->ViewPag);
g_pExePTE=GetPteAddress(va);
g_pfnCallIntoHookedPage=params->va_ret;
__asm
{
push eax
xor eax,eax
mov eax,cr3
mov g_cr3,eax
pop eax
}
for (i = va; i < va+size; i+=4096)
HookMemoryPage((void *)i);
KeDetachProcess();
if( hooked == FALSE )
{
InstallHandler();
hooked = TRUE;
}
}
else
{
IoStatus->Status = STATUS_UNSUCCESSFUL;
}
break;
case IOCTL_OLLYBONE_RESTORE:
DebugPrint(("**** Got OLLYBONE_RESTORE IOCTL\n"));
if ((InputBufferLength < sizeof(int) * 3) || (InputBuffer == NULL))
{
IoStatus->Status = STATUS_INVALID_BUFFER_SIZE;
break;
}
params = (IOCTLPARAMS *)InputBuffer;
pid = params->pid;
va = params->va;
size = params->size;
if (PsLookupProcessByProcessId(pid, &eproc) == STATUS_SUCCESS)
{
KeAttachProcess(eproc);
g_pidsaved = 0;
for (i = va; i < va+size; i+=4096)
UnhookMemoryPage((void *)i);
KeDetachProcess();
}
else
{
IoStatus->Status = STATUS_UNSUCCESSFUL;
}
break;
default:
IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
return IoStatus->Status;
}
//GetPteAddress
//pte的计算公式
//PAE和非PAE有些差别。目前看不懂
PPTE GetPteAddress( PVOID VirtualAddress )
{
PPTE pPTE = 0;
__asm
{
cli
pushad
mov esi, PROCESS_PAGE_DIR_BASE
//#define PROCESS_PAGE_DIR_BASE 0xC0300000
mov edx, VirtualAddress
mov eax, edx
shr eax, 22
lea eax, [esi + eax*4]
test [eax], 0x80
jnz Is_Large_Page
mov esi, PROCESS_PAGE_TABLE_BASE
//#define PROCESS_PAGE_TABLE_BASE 0xC0000000
shr edx, 12
lea eax, [esi + edx*4]
mov pPTE, eax
jmp Done
Is_Large_Page:
mov pPTE, eax
Done:
popad
sti
}
return pPTE;
}
void MarkPageSupervisorOnly( void *pte )
{
*(DWORD *)pte &= 0xFFFFFFFE;
}
void MarkPageUserMode( void *pte )
{
*(DWORD *)pte |= 0x1;
}
void HookMemoryPage( PVOID pPage )
{
char buf[100];
void *pReadWritePte;
pReadWritePte = GetPteAddress( pPage );
DbgPrint( "Hooking page va:%x Ppte:%x pte:%x \n",pPage, pReadWritePte, *(DWORD *)pReadWritePte);
__asm {
mov eax, pPage // access page in case it is paged out
mov eax, [eax]
cli
}
pReadWritePte = GetPteAddress( pPage );
__asm {
mov eax, pPage
invlpg [eax]
}
// Pages marked Copy-on-Write won't work, change them to normal perms
//Mark the page supervisor mode only
MarkPageSupervisorOnly( pReadWritePte );
__asm {
mov eax, pPage
invlpg [eax]
sti //reenable interrupts
}
sprintf(buf, " New pte:%x\n", *(DWORD *)pReadWritePte);
DebugPrint(buf);
}
void UnhookMemoryPage( PVOID pPage )
{
void *pReadWritePte;
__asm {
mov eax, pPage // access page in case it is paged out
mov eax, [eax]
cli
}
pReadWritePte = GetPteAddress( pPage );
__asm {
mov eax, pPage
invlpg [eax]
}
MarkPageUserMode( pReadWritePte );
__asm {
mov eax, pPage
invlpg [eax]
sti //reenable interrupts
}
}
void InstallHandler()
{
g_OldInt0EHandler = GetInterruptHandler(0x0e,0);
g_Int03Handler = GetInterruptHandler(0x03,0);
g_Int01Handler = GetInterruptHandler(0x01,0);
SetInterruptHandler(0x0E,&NewInt0EHandler,0x8e);
}
void RemoveHandler()
{
if (g_OldInt0EHandler != NULL)
SetInterruptHandler(0x0E, g_OldInt0EHandler, 0x8e);
}
void* GetInterruptHandler(DWORD IntNo, DWORD IdtNum)
{
DWORD IDTBase=0;
DWORD OldIntr;
WORD *IdtEntry;
IDTBase = mp_GetIDTBase(IdtNum);
IdtEntry=(WORD*)(IDTBase+IntNo*8);
OldIntr=IdtEntry[0]+(IdtEntry[3]<<16);
return (void*)OldIntr;
}
void* SetInterruptHandler(int IntNo, void *HandlerPtr, BYTE flags)
{
__asm
{
pushad
mov eax, IntNo
mov dl, flags
mov edi, HandlerPtr
mov bx, cs
cli ; TO DO: StopSecondCPUs()
call mp_HookInterrupt
sti
popad
}
return (void*)mp_OldHandler;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)