|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
很古老的技术了:
原理:ring3的绝大对数api函数最终都是在0环实现的,
通过传递调用号和sysenter指令进入0环找到ssdt表,然后在ssdt的函数地址表里获取函数地址。
所以先拿到SSDT表的地址,然后修改ssdt函数表的地址就达到了保护的目的。
一般来说破解软件着会先调用openprocess获取被破解exe的句柄,
所以为了保护exe文件不被破解,hook ssdt的函数地址,
在ring0 openprocess是通过ntopenprocess来实现的
所以修改ssdt地址表的ntopenprocess地址为自己的myntopenprocess函数地址,
在myntopenprocess里,如果被打开的进程pid和要保护的进程一样,就返回STATUS_ACCESS_DENIED这个宏,表示无效句柄,如果是其他pid则继续调用原来的ntopenprocess
1、第一步获取目标进程的pid,这个内核中EPROCESS偏移为b8的ActiveProcessLinks完成,这个是个ListEntry链表,通过这个链表可以获取下一个进程的EPROCESS,
通过对比进程名找到要保护的进程,pid放在UniqueProcessId这个位置,在EPROCESS偏移为b4的地方,最终pid放在client_id 的第一个元素里。
代码如下:
ULONG FindTargetPid(char* processname)
{
//遍历进程
ULONG process = 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;
}
2、第二步,拿到ssdt表的地址:
typedef struct _SSDT
{
PULONG funcaddr;
PULONG counttable;
ULONG funcnum;
PULONG argtable;
}SSDT, * PSSDT;
EXTERN_C PSSDT KeServiceDescriptorTable;
这里ssdt通过导出的方法获得,可以用汇编写,ssdt分为4项,第一项是函数地址表
第三步拿到ntopenprcess的地址:
ULONG* GetCurrentAddr()
{
ULONG SSDT_OpenProcess_Cur_Addr = 0;
//[[KeServiceDescriptorTable]+eax*4]
__asm
{
push ebx;
push eax;
mov ebx, KeServiceDescriptorTable;
mov ebx, [ebx];
mov eax, 0xBE;
shl eax, 2;//imul eax, eax,0x4;//shl eax,2;
add ebx, eax;
mov ebx, [ebx];//[[KeServiceDescriptorTable]+eax*4]
mov SSDT_OpenProcess_Cur_Addr, ebx;
pop eax;
pop ebx;
}
return (ULONG*)SSDT_OpenProcess_Cur_Addr;
}
ULONG* Get_Old_Addr()
{
UNICODE_STRING old_NtOpenProcess = RTL_CONSTANT_STRING(L"NtOpenProcess");
ULONG* oldaddr = (ULONG*)MmGetSystemRoutineAddress(&old_NtOpenProcess);
return oldaddr;//取得NtOpenProcess的地址
}
ULONG* Curaddr=NULL;
ULONG* oldaddr=NULL;
BYTE oldcode[5] = { 0 };//保存hook前的指令
第四步,编写自己的myntopenprocess:这里abc.exe是要保护的进程
NTSTATUS MyNtOpenProcess(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId
)
{
ULONG pid = FindTargetPid("abc.exe");
if (pid == 0)
{
return STATUS_SUCCESS;
}
if ((ULONG)ClientId->UniqueProcess == pid)
{
DbgPrint("别想打开!\n");
return STATUS_ACCESS_DENIED;//返回无效句柄
}
uninstallhook();
NTSTATUS res=NtOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
installhook();
return res;
}
第五步:安装钩子,和卸载钩子
NTSTATUS installhook()
{
//Curaddr = GetCurrentAddr();//获取当前openprocess函数在ssdt表里的地址
ULONG* addr=KeServiceDescriptorTable->funcaddr;
PHYSICAL_ADDRESS physicaladdr = MmGetPhysicalAddress(addr);
ULONG* g_functable = MmMapIoSpace(physicaladdr, PAGE_SIZE, MmNonCached);
g_functable[0xBE] = (ULONG)MyNtOpenProcess;//替换自己的函数
return STATUS_SUCCESS;
}
NTSTATUS uninstallhook()
{
UNICODE_STRING old_NtOpenProcess = RTL_CONSTANT_STRING(L"NtOpenProcess");
ULONG* oldaddr = (ULONG*)MmGetSystemRoutineAddress(&old_NtOpenProcess);
ULONG* addr = KeServiceDescriptorTable->funcaddr;
PHYSICAL_ADDRESS physicaladdr= MmGetPhysicalAddress(addr);
ULONG* g_functable = MmMapIoSpace(physicaladdr, PAGE_SIZE, MmNonCached);
g_functable[0xBE] = (ULONG)oldaddr;
return STATUS_SUCCESS;
}
ssdt不一定可写,这里可以用清零cr0的方式或者映射的方式都可以
最终主函数里调用:
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRegPath)
{
installhook();//安装hook
pDriver->DriverUnload = unload;
return STATUS_SUCCESS;
}
图片无法上传,等级不够,最终做到了ce无法附加abc.exe的功能
ps我也是结合了郁金香老师和51hook老师的讲解,加上自己的实践,感谢二位老师。 |
|