过TP学习手册.docx

上传人:b****6 文档编号:8057100 上传时间:2023-05-12 格式:DOCX 页数:47 大小:551.06KB
下载 相关 举报
过TP学习手册.docx_第1页
第1页 / 共47页
过TP学习手册.docx_第2页
第2页 / 共47页
过TP学习手册.docx_第3页
第3页 / 共47页
过TP学习手册.docx_第4页
第4页 / 共47页
过TP学习手册.docx_第5页
第5页 / 共47页
过TP学习手册.docx_第6页
第6页 / 共47页
过TP学习手册.docx_第7页
第7页 / 共47页
过TP学习手册.docx_第8页
第8页 / 共47页
过TP学习手册.docx_第9页
第9页 / 共47页
过TP学习手册.docx_第10页
第10页 / 共47页
过TP学习手册.docx_第11页
第11页 / 共47页
过TP学习手册.docx_第12页
第12页 / 共47页
过TP学习手册.docx_第13页
第13页 / 共47页
过TP学习手册.docx_第14页
第14页 / 共47页
过TP学习手册.docx_第15页
第15页 / 共47页
过TP学习手册.docx_第16页
第16页 / 共47页
过TP学习手册.docx_第17页
第17页 / 共47页
过TP学习手册.docx_第18页
第18页 / 共47页
过TP学习手册.docx_第19页
第19页 / 共47页
过TP学习手册.docx_第20页
第20页 / 共47页
亲,该文档总共47页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

过TP学习手册.docx

《过TP学习手册.docx》由会员分享,可在线阅读,更多相关《过TP学习手册.docx(47页珍藏版)》请在冰点文库上搜索。

过TP学习手册.docx

过TP学习手册

过NtOpenProcess:

其实这个函数TP只hook了一个地方,只是郁金香对比的数据太多了,超出了NtOpenProcess的范围,找到函数的结尾可以计算出它只有0x283个字节,因此只要对比0x283个字节的数据即可,通过对比只有一处被TP给HOOK了:

还是用一样的方法在上面两行来HOOK,然后JMP到TPhook的下一行执行,下面来看具体的实现吧:

首先我们先来封装几个功能函数放到一个头文件Func.h中:

#ifndefFUNC

#defineFUNC

extern"C"longKeServiceDescriptorTable;//导出SSDT表

intGetSSDTFunctionAddr(intnSSDTIndex);//通过索引号获得函数地址

boolPanDuanProcessName(char*szName);//判断当前进程名的函数,参数为一个进程名

intSearchFeature(intnAddr,char*pFeature,intnLeng);//搜索特征码,参数为起始地址,特征码,字节数

voidInLineHookEngine(intnRHookAddr,intnMyFunctionAddr);//挂钩函数

voidUnInLineHookEngine(intnRHookAddr,char*szMacCode,intnLeng);//恢复HOOK

intGetFunCtionAddr(WCHAR*szFunCtionAName);//获得函数原地址,参数为函数名

voidMemoryWritable();//关闭写保护

voidMemoryNotWritable();//恢复写保护

boolPanDuanProcessName(char*szName)//判断当前进程名的函数,参数为一个进程名

{

intnEProcess;

nEProcess=(int)PsGetCurrentProcess();//得到当前进程结构,这里转换为了int型

charszProessaName[16];

strcpy(szProessaName,(char*)(nEProcess+0x174));//将当前进程名复制到缓冲区

if(strcmp(szProessaName,szName)==0)//判断与传进来的进程名是否一致

{returntrue;}

returnfalse;

}

intSearchFeature(intnAddr,char*pFeature,intnLeng)//搜索特征码,参数为起始地址,特征码,字节数

{

charszStatus[256]="";//缓冲区

inti=5000;//遍历的字节数

while(i--)//循环递减次

{

RtlMoveMemory(szStatus,(char*)nAddr,nLeng);//将传进来的地址处的长度为nLeng的数据移动到缓冲区

if(RtlCompareMemory(pFeature,szStatus,nLeng)==nLeng)//比较缓冲区内数据和传进来的特征码是否一致

{returnnAddr+nLeng;//如果一致则返回特征码后面的地址}

nAddr++;//不一致则地址自加继续循环

}

return0;

}

intGetSSDTFunctionAddr(intnSSDTIndex)//通过函数索引号来获得函数在表中的地址

{

intAddr;

__asm

{

movebx,nSSDTIndex

shlebx,2

moveax,KeServiceDescriptorTable

moveax,[eax]

addeax,ebx

movecx,[eax]

movAddr,ecx

}

returnAddr;

}

voidInLineHookEngine(intnRHookAddr,intnMyFunctionAddr)//挂钩,参数为要HOOK的地址,自已的HOOK函数地址

{

MemoryWritable();//关闭写保护

intnJmpAddr=nMyFunctionAddr-nRHookAddr-5;//计算要跳转地址的特征码

__asm

{

moveax,nRHookAddr

movbyteptrds:

[eax],0xe9//JMP

movebx,nJmpAddr

movdwordptrds:

[eax+1],ebx//跳转到。

}

MemoryNotWritable();//开启写保护

}

voidUnInLineHookEngine(intnRHookAddr,char*szMacCode,intnLeng)//恢复,参数为要恢复的地址,码,长度

{

MemoryWritable();

RtlMoveMemory((char*)nRHookAddr,szMacCode,nLeng);//将原先的特征码写回去

MemoryNotWritable();

}

voidMemoryWritable()//关闭写保护

{

__asm

{

cli

moveax,cr0

andeax,not10000h

movcr0,eax

}

}

voidMemoryNotWritable()//恢复写保护

{

__asm

{

moveax,cr0

oreax,10000h

movcr0,eax

sti

}

}

intGetFunCtionAddr(WCHAR*szFunCtionAName)//获得函数原地址,参数为函数名

{

UNICODE_STRINGFsRtlLegalAnsiCharacterArray_String;

RtlInitUnicodeString(&FsRtlLegalAnsiCharacterArray_String,szFunCtionAName);

return(int)MmGetSystemRoutineAddress(&FsRtlLegalAnsiCharacterArray_String);

}

#endif

然后再将实现NtOpenProcess的HOOK放到另一个头文件HookNtOpenProcess.h中:

#ifndefHOOKNTOPENPROCESS

#defineHOOKNTOPENPROCESS

intnNtOpenProcessAddr;//作为函数地址

intnHookNtOpenProcessAddr;//作为我们要挂钩的地址

intnHookNtOpenPrpcessJmp;//TPHOOK的下一行地址

intnHookNtOpenPrpcessOldJmp;//TPHOOK的地址

intnObOpenObjectByPointerAddr;//TPHOOK的地址的未HOOK前的ObOpenObjectByPointer的地址

__declspec(naked)voidMyNtOpenProcess()//要跳到的函数

{

__asm

{

pushdwordptr[ebp-38h]//首先将改写的地址处的原代码执行

pushdwordptr[ebp-24h]

}

if(PanDuanProcessName("DNF.exe")||PanDuanProcessName("TenSafe.exe")||PanDuanProcessName("QQLogin.exe"))

//判断NtOpenProcess是否为游戏进程在调用,也就是游戏或TP本身在调用NtOpenProcess

{

__asm

{

jmpnHookNtOpenPrpcessOldJmp////如果是DNF调用的,则跳到TP自己HOOK的代码执行

}

}

else{

__asm

{

callnObOpenObjectByPointerAddr//不是则执行NtOpenProcess被HOOK处的原函数代码

jmpnHookNtOpenPrpcessJmp//跳回到TPHOOK的代码的下一行继续执行

}

}

}

voidHookNtOpenProcess()

{

//nNtOpenProcessAddr=GetSSDTFunctionAddr(122);//根据在表中的索引来获得它的地址,如果函数已经被其他程序给HOOK了,这里得到的就是HOOK后的地址,OD内的StrongOD插件就对NtOpenProcess进行了HOOK,因此这里得到的就不是源函数的地址,也就是错误的地址,这样如果先开了OD再加载我们写的驱动就会造成蓝屏,解决办法就是先过保护再开OD,或者用下面的函数获得函数原地址

nNtOpenProcessAddr=GetFunCtionAddr(L"NtOpenProcess");//获得函数源地址

charcode[7]={(char)0xff,(char)0x75,(char)0xc8,(char)0xff,(char)0x75,(char)0xdc,(char)0xe8};//特征码

nHookNtOpenProcessAddr=SearchFeature(nNtOpenProcessAddr,code,7)-7;//搜索特征码,-7处是我们要HOOK

//接上:

的地方,得到要挂钩的地址

DbgPrint("nHookNtOpenProcessAddr=%x\n",nHookNtOpenProcessAddr);

nHookNtOpenPrpcessJmp=nHookNtOpenProcessAddr+11;//TPHOOK的下一行地址

nHookNtOpenPrpcessOldJmp=nHookNtOpenProcessAddr+6;//TPHOOK的地址

DbgPrint("nHookNtOpenPrpcessJmp=%x\n",nHookNtOpenPrpcessJmp);

DbgPrint("nHookNtOpenPrpcessOldJmp=%x\n",nHookNtOpenPrpcessOldJmp);

nObOpenObjectByPointerAddr=GetFunCtionAddr(L"ObOpenObjectByPointer");//获得ObOpenObjectByPointer地址

DbgPrint("nObOpenObjectByPointerAddr=%x\n",nObOpenObjectByPointerAddr);

InLineHookEngine(nHookNtOpenProcessAddr,(int)MyNtOpenProcess);//挂钩函数,第一个参数为我们要HOOK

//接上:

的地址,第二个参数为要跳到的函数地址

}

voidUnHookNtOpenProcess()//恢复HOOK函数,将特征码写回去就OK了

{

charcode[7]={(char)0xff,(char)0x75,(char)0xc8,(char)0xff,(char)0x75,(char)0xdc,(char)0xe8};

UnInLineHookEngine(nHookNtOpenProcessAddr,code,5);//因为JMP指令只修改了五个字节,所以只需要恢

//接上:

复五个就可以了

}

#endif

然后驱动的入口函数内调用HookNtOpenProcess();,卸载例程内调用UnHookNtOpenProcess()就可以了。

这里用到了搜索特征码的技术,其实就是从NtOpenprocess的开始处逐字节递增来遍历,然后得到要HOOK的地址。

其实也没有什么可阐述的了,仔细看代码就可以了。

另外对NtOpenThread的处理和NtOpenProcess的处理是一样的。

对ReadProcessMemory的处理:

用OD随便附加一个进程,然后ctrl+g转到ReadProcessMemory:

如上图,该函数返回14个字节,可见压栈了14个字节的参数,如果在函数的开头就直接retn14,这样CE,OD等工具就不能读取到游戏的数据了,下面跟进它更深层的CALL看一下:

得到了它在SSDT中的索引号BA也就是第186号,用KD来看下186号为:

NtReadVirtualMemory,也就是ReadProcessMemory在内核中的函数,对比一下原函数和TPHOOK后:

可见TP在函数的头部前两句就进行了HOOK,我们可以做SSDT的HOOK,也就是非内联HOOK,然后执行TP未HOOK前的前两句,然后jmp到call805380e0也就是HOOK的下一行来执行。

还有一个问题就是TPHOOK的两句原代码:

Push1C这句是不会变的,而push804DAB8这句压栈的值会改变,所以这个值就不能直接拿来压栈,可以用首地址+偏移得到这个数据的地址,然后再取出该地址处的值,然后还要在游戏启动前加载驱动,也就是TP还没有HOOK前,因为它HOOK后就得不到这个原始数据了。

下面就来看具体实现吧:

在原先的Func.h头文件中再封装两个函数:

intSSDTHookEngine(intnSSDTIndex,intnFunctionAddr)//SSDTHOOK函数,参数为索引,假的函数地址

{

MemoryWritable();

intnOldAddr;//旧地址,作为TPHOOK的地址(函数首地址)

__asm

{

movebx,nSSDTIndex

shlebx,2

moveax,KeServiceDescriptorTable

moveax,[eax]

addeax,ebx//得到函数在表中基址

movecx,[eax]//得到函数当前地址,也就是TPHOOK的地址

movnOldAddr,ecx//保存TPHOOK的地址

movecx,nFunctionAddr

mov[eax],ecx//假到函数地址赋给函数在表中的基址,实现SSDTHOOK

}

MemoryNotWritable();

returnnOldAddr;

}

voidSSDTUnHookEngine(intnSSDTIndex,intnOldFunctionAddr)//恢复SSDTHOOK,索引,旧地址

{

MemoryWritable();

__asm

{

movebx,nSSDTIndex

shlebx,2

moveax,KeServiceDescriptorTable

moveax,[eax]

addeax,ebx

movecx,nOldFunctionAddr

mov[eax],ecx

}

MemoryNotWritable();

}

然后我们再添加一个用来实现HOOKNtReadVirtualMemory的头文件HookReadVirtualMemory.h:

#ifndefHOOKREAD

#defineHOOKREAD

intnNtReadVirtualMemoryAddr;//作为NtReadVirtualMemoryAddr函数地址

intnNtReadVirtualMemoryAddr_3;//函数三个字节后的地址处的数据

intnNtReadVirtualMemoryAddrJmp;//TPHOOK的下一行地址

__declspec(naked)voidMyNtReadVirtualMemory()//假的函数

{

if(PanDuanProcessName("DNF.exe")||PanDuanProcessName("TenSafe.exe")||PanDuanProcessName("QQLogin.exe"))

{

__asm

{

jmpnNtReadVirtualMemoryAddr//如果是游戏调用则跳回TP的原代码去执行

}

}

else{

__asm

{

push0x1c

pushnNtReadVirtualMemoryAddr_3//首先执行TP未HOOK函数前的两行

jmpnNtReadVirtualMemoryAddrJmp//跳转到原函数下一行去执行

}

}

}

VOIDHookReadVirtualMemory()

{

nNtReadVirtualMemoryAddr=GetSSDTFunctionAddr(186);//根据索引得到函数地址

nNtReadVirtualMemoryAddr_3=nNtReadVirtualMemoryAddr+3;//得到函数三个字节后的地址,一定要在开启

//接上:

游戏前加载驱动,否则得不到正确数据

nNtReadVirtualMemoryAddr_3=*((int*)nNtReadVirtualMemoryAddr_3);//得到该地址处的值,也就是push的数据

nNtReadVirtualMemoryAddrJmp=nNtReadVirtualMemoryAddr+7;//TPHOOK的下一行地址

SSDTHookEngine(186,(int)MyNtReadVirtualMemory);//SSDTHOOK

}

VOIDUnHookReadVirtualMemory()

{

SSDTUnHookEngine(186,nNtReadVirtualMemoryAddr);//恢复

}

#endif

然后在入口函数中和卸载例程中调用就可以了。

对写内存函数NtWriteVirtualMemory的处理方法是一模一样的。

对付KiAttchProcess的内联hook:

调用KiAttchProcess的函数有两个:

1.KeAttchProcess

2.KeStackAttachProcess(切换进程用,读写外部进程内存API最终会调用到此内核函数)

这两个内核函数的功能是一样的,只是第一个函数较老,以后将有可能被淘汰。

它们的功能就是对外部进程进行读写操作,我们知道每个进程都独占4GB的虚拟内存,互不干扰,用这两个函数就可以实现进程A访问进程B的内存了。

OD附加一个进程进行调试就会调用它们,从而实现对被调试进程的读写,原理应该就是OD将自己的线程用该函数注入到目标进程的进程空间中。

这两个函数都调用了KiAttchProcess,而TP对KiAttchProcess进行了HOOK,我们先来讲一下对KeAttchProcess调用KiAttchProcess的处理:

虽然TP对XT工具有检测,不过我们可以先用XT来分析一下TP所做的hook:

除了对读写内存的函数进行了HOOK(NtOpenProcess和NtOpenTread的HOOKXT检测不到),可以看出TP对内核模块中的一个地址进行了HOOK:

804F8438,用windbg来看一下这个地址:

可以看出TP的此处HOOK的确是对KiAttachProcess进行的HOOK。

然后用KD转到这个地址去看一下:

TP对它的前7个字节进行了HOOK,转到它jmp的地址去看一下:

转到它HOOK的内部来看是为了说明另外一种方法,我们一定非要用以前的方法来进行HOOK,也可以到它的里面能过修改代码来实现,比如TP在这里调用了IoGetCurrentProcess来得到当前进程的EPROCESS结构,调用PsGetCurrentProcessId来得到当前调用KiAttchProcess的进程ID,根据得到的这两个结果来判断是哪个进程在调用而决定是放过还是HOOK。

因此我们可以针对IoGetCurrentProcess和PsGetCurrentProcessId来进行HOOK,让它们返回DNF的EPROCESS结构地址和进程ID,当然这只是讲了一种思路,这里并不会对这种思路深究。

在windbg中对KiAttchProcess下断看是谁会调用它:

bp804f8438,然后查看调用堆栈:

alt+6:

可以看出KeStackAttachProcess+7B的位置对它进行了调用。

用u804f8438804f8438+100命令显示原KiAttchProcess全部反汇编代码,然后复制出来,做为我们要写的假KiAttchProcess代码,要注意的是,在反汇编代码中有很多jn,jne,jnz,jmp等跳转,如果跳转到的地址是在当前函数内,而我们假的KiAttchProcess函数的地址和原KiAttchProcess函数地址是不同的,因此就要做好各个跳转的目的地的标识以方便跳转,详细的看代码就好了。

还有函数内有一些CALLxxxx,因此还到得到xxxx函数的地址。

如下:

kd>u804f8438804f8438+100

nt!

KiAttachProcess:

804f84388bffmovedi,edi

804f843a55pushebp

804f843b8becmovebp,esp

804f843d53pushebx

804f843e8b5d0cmovebx,dwordptr[ebp+0Ch]

804f844166ff4360incwordptr[ebx+60h]

804f844556pushesi

804f84468b7508movesi,dwordptr[ebp+8]

804f844957pushedi

804f844aff7514pushdwordptr[ebp+14h]

804f844d8d7e34leaedi,[esi+34h]

804f845057pushedi

804f8451e81efdffffcallnt!

KiMoveApcState(804f8174)

804f8456897f04movdwordptr[edi+4],edi

804f8459893fmovdwordptr[edi],edi

804f845b8d463cleaeax,[esi+3Ch]

804f845e894004movdwordptr[eax+4],eax

804f84618900movdwordptr[eax],eax

804f84638d864c010000leaeax,[esi+14Ch]

804f8469394514cmpdwordptr[ebp+14h],eax

804f84

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2