过一般保护(7)

2019-03-23 11:57

NULL, &Handle );

SeDeleteAccessState( &AccessState ); if ( NT_SUCCESS(Status) ) { try {

*ProcessHandle = Handle;

} except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode (); } }

return Status; }

if ( ClientIdPresent ) { Thread = NULL;

if (CapturedCid.UniqueThread) {

Status = PsLookupProcessThreadByCid( &CapturedCid, &Process, &Thread );

if (!NT_SUCCESS(Status)) {

SeDeleteAccessState( &AccessState ); return Status; } } else {

Status = PsLookupProcessByProcessId( CapturedCid.UniqueProcess, &Process );

if ( !NT_SUCCESS(Status) ) {

SeDeleteAccessState( &AccessState ); return Status; } }

Status = ObOpenObjectByPointer( Process, Attributes, &AccessState, 0,

*PsProcessType, PreviousMode, &Handle

); //得到进程句柄

30

SeDeleteAccessState( &AccessState ); if (Thread) {

ObDereferenceObject(Thread); }

ObDereferenceObject(Process); if (NT_SUCCESS (Status)) { try {

*ProcessHandle = Handle;

} except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode (); } }

return Status; }

return STATUS_INVALID_PARAMETER_MIX; } }

5.6 移除EPROCESS->DebugPort端口

现在一般游戏的保护都会对游戏进程的EPROCESS->DebugPort调试端口清0,这样OD调试器就会收不到调试事件信息。有种方法是把Windows系统内核下所有操作EPROCESS->DebugProt的内核函数,改写成操作EPROCESS结构中不重要的地方,比如操作EPROCESS结构的CreateTime成员,这样就算它对ERPCESS->DebugPort调试端口每时每刻清0,但是并不会影响我们调试的。

由于我们用的所有调试模块都是我们自己实现的,我们可以不用这么做,当OD调用NtDebugActiveProcess()时,进入我们的函数,之后会调用DbgkpPostFakeProcessCreateMessages()函数把这个要调试的游戏进程的所有模块,线程调试事件插入在DebugObject的事件链表中。之后会调用DbgkpSetProcessDebugObject()这个函数设置被调试进程EPROCESS的Debugport成员为先前建立的调试对象,下次有调试事件了就会插入在这个调试对象的事件链表中。

设置代码如下:

if (Process->DebugPort != NULL) {

Status = STATUS_PORT_ALREADY_SET; break; } //

// Assign the debug port to the process to pick up any new threads

//

Process->DebugPort = DebugObject;

我们其实可以自己定义一个结构体来对应要调试的进程的EPROCESS和DEBUGPORT

31

typedef struct __EPROCESSDEBUGPORT {

PEPROCESS Process;

PDEBUG_OBJECT DebugPort;

} EPROCESSDEBUGPORT,*LP EPROCESSDEBUGPORT;

5.7 HOOK Windows 内核下会发送调试事件的内核函数

上面已经提到怎么定义一个结构体,但是怎么改变Windows内核下调试的处理机制,也就是怎么会把调试事件发送到我们自己定义的这个结构体中的DebugPort,而不是原来的EPROCESS的DebugPort成员。这就需要改变Windows内核下一切的这些内核函数。比如常见的DbgkCreateThread,DbgkExitThread,DbgkMapViewOfSection,DbgkUnMapViewOfSection,DbgkExitProcess等等这些函数。

比如用户层建立一个线程,会调用CreateThread(),CreateRemoteThread()。这两个函数。这两个函数最终都会通过ntdll.dll的sysenter进入Ring 0,然后调用系统调用NtCreateThread()。一层一层的调用PspCreateThread()。最后这个线程被Windows系统调度程序调度运行时,首先会调用PspUserThreadStartup()这个函数,它里面会判断调用DbgkCreateThread()函数通知调试器接受建立线程的调试事件信息。部分代码如下:

// If the create worked then notify the debugger. //

if ((Thread->CrossThreadFlags&

(PS_CROSS_THREAD_FLAGS_DEADTHREAD|PS_CROSS_THREAD_FLAGS_HIDEFROMDBG)) == 0) {

DbgkCreateThread (Thread, StartContext);

}

最终DbgkCreateThread会调用DbgkpSendApiMessage()-> DbgkpQueueMessage(),这个函数就会向Process->DebugPort发送调试事件信息。

用户层线程加载DLL时会调用LoadLibrary,LoadLibraryEx,函数,它们同样会通过sysenter进入Ring 0调用系统调用NtMapViewOfSection(),它里面同样会调用DbgkMapViewOfSection()向Process->DebugPort发送调试事件信息。

所以我们做的是HOOK调用这个函数的地方,向它进入我们自己的函数里面处理,然后我们自己再把调试事件信息发向我们想要的地方去。

具体HOOK代码如下:

typedef struct __hook_find {

DWORD* dwFindSrc; //查找的源地址 DWORD* dwFindDst; //查找的函数地址 DWORD dwCallDst; //重定向

32

DWORD dwFindPos; //位置找旱后旱位置 }__hook_find;

__hook_find HookData[]={

{&Addr_PspUserThreadStartup,&Addr_DbgkCreateThread,(DWORD)HxDbgkCreateThread,0},

{&Addr_PspExitThread,&Addr_DbgkExitProcess,(DWORD)HxDbgkExitProcess,0},

{&Addr_PspExitThread,&Addr_DbgkExitThread,(DWORD)HxDbgkExitThread,0},

{&Addr_NtMapViewOfSection,&Addr_DbgkMapViewOfSection,(DWORD)HxDbgkMapViewOfSection,0},

{&Addr_MiUnmapViewOfSection,&Addr_DbgkUnMapViewOfSection,(DWORD)HxDbgkUnMapViewOfSection,0},

{&Addr_CommonDispatchException,&Addr_KiDispatchException,(DWORD)HxKiDispatchException,0},

{&Addr_KiRaiseException,&Addr_KiRaiseException,(DWORD)HxKiDispatchException,0}

};

PUCHAR Search_CallFunction(PUCHAR pbCode,PUCHAR pbCallfunc,IN OUT UINT* pnPos)

{

//e8baf1feff call nt!ObOpenObjectByPointer (80933d4c)

ULONG nSearchAddr=(ULONG)pbCallfunc; ULONG nLen=0,nTmpLen=0;

PUCHAR pPos=pbCode+(*pnPos),pFind=NULL; UCHAR uTemp[20]={0};

UCHAR btCode[5]={0xE8,0,0,0,0}; while(*pPos!=0xCC){

nTmpLen = getNextInstruction(pPos,1,uTemp,20); nLen+=nTmpLen; pPos+=nTmpLen;

if(*pPos==0xE8){

*((ULONG*)(btCode+1)) = ((ULONG)nSearchAddr-(ULONG)pPos-5);

//

DbgPrint(\%2X%2X%2X%2X%2X==%2X%2X%2X%2X%2X\],pPos[3],pPos[4],btCode[0],btCode[1],btCode[2],btCode[3],btCode[4]);

33

if(pPos[0]==btCode[0] && pPos[1]==btCode[1] && pPos[2]==btCode[2] && pPos[3]==btCode[3] && pPos[4]==btCode[4] ) {

pFind=pPos; *pnPos = nLen; break; } } }

return pFind; }

VOID StartHook() {

UINT ln=sizeof(HookData)/sizeof(__hook_find); UINT i,pos; PUCHAR pAddr; DWORD dwOldAddr; KIRQL oldirql; for (i=0;i

pos=0;

pAddr=Search_CallFunction((PUCHAR)(*HookData[i].dwFindSrc), (PUCHAR)(*HookData[i].dwFindDst),

&pos); if(pos) {

HookData[i].dwFindPos=(DWORD)pAddr; dwOldAddr = *((ULONG*)(pAddr+1)); CLR_WP();

oldirql=KeAcquireQueuedSpinLockRaiseToSynch(LockQueueDispatcherLock);

*((ULONG*)(pAddr+1)) = (HookData[i].dwCallDst-HookData[i].dwFindPos-5);

KeReleaseQueuedSpinLock(LockQueueDispatcherLock,oldirql);

SET_WP();

HookData[i].dwCallDst=dwOldAddr; }

34


过一般保护(7).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:部编新人教版七年级历史下册知识点复习提纲(改版) - 图文

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: