|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
之前的帖子讨论过hook sddt,VEH保护进程不被ce附加,今天尝试句柄表降权的方式保护进程不被ce附加。
原理:在windows操作系统上有私有句柄表和全局句柄表,用openprocess打开某个进程的时候会在私有句柄表里创建一个句柄,并且指向被打开进程的EPROCESS结构体。
私有句柄表一共64位,其中31~47这个位置是私有句柄表的属性,可以设置一些权限,所以通过查找ce的私有句柄表,把它的句柄表权限改为不可读,就无法读出内存了。
第一步,根据进程名遍历进程,之前的帖子讨论过原理,不在赘述:
ULONG FindTargetPid(char* processname)
{
//遍历进程
ULONG process = (ULONG)PsGetCurrentProcess();
PLIST_ENTRY processlist = (PLIST_ENTRY)(process + 0xb8);
PLIST_ENTRY pnext = processlist->Flink;
while (pnext != processlist)
{
char* name = (char*)((ULONG)pnext - 0xb8 + 0x16c);
if (strcmp(name, processname) == 0)
{
PCLIENT_ID client_id = (PCLIENT_ID)((ULONG)pnext - 0xb8 + 0xB4);//
return (ULONG)client_id->UniqueProcess;//返回目标进程pid
}
pnext = pnext->Flink;
}
return 0;
}
第二部:
遍历私有句柄表:
因为这个事情要一直进程,知道被保护的进程退出,所以考虑写一个死循环,这里涉及内核中创建进程的操作,
使用系统的api:PsCreateSystemThread(&hthread, THREAD_ALL_ACCESS, NULL, NULL, NULL, threadproc,peprocess);
回调函数是threadproc,同时把它的引用计数器-1避免检测
KeInitializeEvent(&kevent,SynchronizationEvent, FALSE);
ULONG pid = FindTargetPid("abc.exe");//查找目标进程的pid
if (pid == 0)
{
return STATUS_SUCCESS;
}
PEPROCESS peprocess;
NTSTATUS status=PsLookupProcessByProcessId((HANDLE)pid, &peprocess);
HANDLE hthread = 0;
if (NT_SUCCESS(status))
{
ObReferenceObject(peprocess);
PsCreateSystemThread(&hthread, THREAD_ALL_ACCESS, NULL, NULL, NULL, threadproc,peprocess);
}
由于进程的线程结束函数要采用被动的方法,所以创建一个event事件,设定每1s修改一个句柄权限,用waitforsignlobject等待超时。
这部分不赘述
void threadproc(PVOID peprocess)
{
PEPROCESS pTargetProcess;
LARGE_INTEGER timeout=RtlConvertLongToLargeInteger(-10*2000*1000);//1s
ethread=KeGetCurrentThread();
while (1)
{
NTSTATUS status=KeWaitForSingleObject(&kevent, Executive, KernelMode, FALSE, &timeout);
if (status==STATUS_TIMEOUT)//超时,说明没等到信号,继续执行
{
for (ULONG i = 0; i < 10000; i++)
{
NTSTATUS status = PsLookupProcessByProcessId((HANDLE)(i * 4), &pTargetProcess);
if (NT_SUCCESS(status))
{
SetHandAccess(peprocess, pTargetProcess);
}
}
}
else
{
DbgPrint("teminate\n");
PsTerminateSystemThread(STATUS_SUCCESS);//终止线程
}
}
}
第三步:遍历私有句柄表,这里采用EPROCESS+0XF4的位置获取ObjectTable的方式获得TableCode,同时判断句柄表的层级,以及抹除低位的操作,最终得到句柄值,根据ms提供的文档修改读权限。
void SetHandAccess(PVOID srcProcess, PVOID targetProcess)
{
ULONG pObjectTable = *(ULONG*)((ULONG)targetProcess + 0xf4);
ULONG TableCode = *(ULONG*)pObjectTable;
ULONG TableDeeth = TableCode & 0xF;//拿到最后一位
switch (TableDeeth)
{
case 0:
{
for (ULONG j = 0; j < 512; j++)
{
TableCode &= 0xFFFFFFF0;//TableCode最后一位置0
ULONG handle = (ULONG) * (ULONG*)(TableCode + j * 8);
if (MmIsAddressValid((PVOID)handle))
{
handle &= 0xFFFFFFF8;//
if ((ULONG)(handle + 0x18) == (ULONG)srcProcess)
{
ULONG* handleaddr = (ULONG*)(TableCode + j * 8);
handleaddr++;//+4
if (MmIsAddressValid(handleaddr))
{
DbgPrint("找到了%x", *handleaddr);//001fffff
//001fffff`88f1f361
*handleaddr = *handleaddr& 0xFFFFFFCF;//取消读权限
}
}
}
}
break;
}
case 1:
{
for (ULONG i = 0; i < 1024; i++)
{
for (ULONG j = 0; j < 512; j++)
{
TableCode &=0xFFFFFFF0;//TableCode最后一位置0
ULONG subtable = *(ULONG*)((ULONG)TableCode + i * 4);
if (subtable == 0)
{
break;
}
ULONG handle = (ULONG) * (ULONG*)(subtable + j * 8);
if (MmIsAddressValid((PVOID)handle))
{
handle &= 0xFFFFFFF8;//
if ((ULONG)(handle + 0x18) == (ULONG)srcProcess)
{
ULONG* handleaddr = (ULONG*)(TableCode + j * 8);
handleaddr++;
if (MmIsAddressValid(handleaddr))
{
DbgPrint("找到了%x", *handleaddr);
*handleaddr = (*handleaddr) & 0xFFFFFFCF;//取消读权限
}
}
}
}
}
break;
}
default:
break;
}
}
最后驱动卸载:
void unload(PDRIVER_OBJECT pDriver)
{
//uninstallhook();
KeSetEvent(&kevent, 0, FALSE);
NTSTATUS status = KeWaitForSingleObject(ethread,Executive,KernelMode,FALSE,NULL);
if (NT_SUCCESS(status))
{
DbgPrint("exit");
}
}
总结:调试了好久,蓝屏无数次,太恶心了。
感谢51hook的老师,我看了d版视频,大一穷学生,实在不好意思。 |
|