注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

熊猫正正的博客

熊猫正正的天空

 
 
 

日志

 
 

2012年03月16日  

2012-03-16 10:59:49|  分类: window驱动学习 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

过TesSafe源码


转自天道酬情技术论坛~~

简而言之其原理就是,任何人调用了NtOpenProcess的时候会先进入 
Nakd_NtOpenProcess函数,我们判断。如果是游戏进程访问的话,就有可能是验证之类的 
我们转到它自己的函数里面。让它保持与ring3层的通信。否则的话,嘿嘿…… 

接下来是第3步处理debugport清零的这块了。 
我想绝大多数人关心的都是这里了 
网络上能搜多到的办法几乎都失效了 
有办法的人又不肯放出来,急眼了就自己想了个土办法 
虽然不那么时尚。但是绝对的奏效。 
由于代码凌乱不堪,简单说下其原理。 
我们定位内核模块TxxxSxxx.sys的首地址 
然后根据特征码遍历整个模块找到我们需要的地方,然后干掉他们。 
那么我们又如何能够通过人工的判断出来到底是哪里在作怪呢 
利用syser或Start SoftICE对EPROCESS+BC处设置断点。就可以一层一层的追溯上去了 
到底如何用他们,我想大家自己多花点时间在看雪和GOOGLE或者BAIDU上面是不会吃亏的。 
由于ZwQuerySystemInformation函数的使用非常繁琐。而且篇幅有限。所以我只给出关键代码,至于这个函数如何使用。大家可以自己在搜索引擎找“枚举内核模块” 


代码: 
////////////////////////////////////////////////////////////////////// 
// 名称: MyEnumKernelModule 
// 功能: 枚举内核模块 
// 参数: str:内核模块名称 
// moduleadd:该模块地址[传出] 
// modulesie:该模块大小[传出] 
// 返回: 
////////////////////////////////////////////////////////////////////// 
NTSTATUS MyEnumKernelModule(IN CHAR* str,OUT ULONG *moduleadd,OUT ULONG *modulesie) 
NTSTATUS status = STATUS_SUCCESS; 
ULONG n = 0; 
ULONG i = 0; 
PSYSTEM_MODULE_INFORMATION_ENTRY module = NULL; 
PVOID pbuftmp = NULL; 
ANSI_STRING ModuleName1,ModuleName2; 
BOOLEAN tlgstst= FALSE; //如果找到了指定模块则设置为TRUE 

//利用11号功能枚举内核模块 
status = ZwQuerySystemInformation(11, &n, 0, &n); 

//申请内存 
pbuftmp = ExAllocatePool(NonPagedPool, n); 

//再次执行,将枚举结果放到指定的内存区域 
status = ZwQuerySystemInformation(11, pbuftmp, n, NULL); 

module = (PSYSTEM_MODULE_INFORMATION_ENTRY)((PULONG )pbuftmp + 1 ); 

//初始化字符串 
RtlInitAnsiString(&ModuleName1,str); 
// 
n = *((PULONG)pbuftmp ); 
for ( i = 0; i < n; i++ ) 
RtlInitAnsiString(&ModuleName2,&module[i].ImageName); 
//DbgPrint("%d\t0x%08X 0x%08X %s\n",module[i].LoadOrderIndex,module[i].Base,module[i].Size,module[i].ImageName); 

if (RtlCompareString(&ModuleName1,&ModuleName2,TRUE) == 0) 
DbgPrint("MyEnumKernelModule:%s:%0X \n",ModuleName2.Buffer,module[i].Base); 
*moduleadd = module[i].Base; 
*modulesie = module[i].Size; 
tlgstst = TRUE; 
break; 
ExFreePool(pbuftmp); 
if tlgstst == FALSE) 
return FAILED_TO_OBTAIN_FUNCTION_ADDRESSES; 
return status; 

////////////////////////////////////////////////////////////////////// 
// 名称: My_Recovery_Debugport 
// 功能: 恢复游戏对debugport的清零操作 
// 参数: 
// 返回: 
////////////////////////////////////////////////////////////////////// 
NTSTATUS My_Recovery_Debugport() 
NTSTATUS stats; 
BYTE *sd1 = NULL,*sd2 = NULL,*pd = NULL; 
ULONG ModuleSize,ModuleAddress,i,number = 0; 
BYTE *p; 
KIRQL Irql; 
BYTE C390[2] = {0xc3,0x90}; 

//获取指定的内核模块地址和字节数 
stats = MyEnumKernelModule("\\??\\c:\\windows\\system32\\tessafe.sys",&ModuleAddress,&ModuleSize); 
if (stats == FAILED_TO_OBTAIN_FUNCTION_ADDRESSES) 
return FAILED_TO_OBTAIN_FUNCTION_ADDRESSES; 
KdPrint(("Address:%0X Sie:%d \n",ModuleAddress,ModuleSize)); 
//特征码 
/* sd1特征 
p-1:18 p-2:87 p-3:DB p-4:33 p-5:07 
p-6:03 p :33 p+1:C0 p+7:3B p+8:D8 
sd2特征 
p-1:07 p-2:87 p-3:c0 p-4:33 p+14:89 
p+15:1c p+16:38 
*/ 

//将P指向内核模块开始处 
p = (BYTE*)ModuleAddress + 20; 
for (i = 0; i < ModuleSize - 20; i++,p++) 
//sd1 
if ((*(p-1) == 0x18) && 
(*(p-2) == 0x87) && 
(*(p-3) == 0xDB) && 
(*(p-4) == 0x33) && 
(*(p-5) == 0x07) && 
(*(p-6) == 0x03) && 
(*p == 0x33) && 
(*(p+1) == 0xC0) && 
(*(p+7) == 0x3B) && 
(*(p+8) == 0xD8) ) 
KdPrint(("--SD1 -- %0X \n",(ULONG)p)); 
sd1 = p; 
number+=1; //记录已经获取一个特征 
//sd2 
if ((*(p-1) == 0x07) && 
(*(p-2) == 0x87) && 
(*(p-3) == 0xC0) && 
(*(p-4) == 0x33) && 
(*(p+14)== 0x89) && 
(*(p+15)== 0x1C) && 
(*(p+16)== 0x38) && 
(*p == 0xA1)) 
KdPrint(("--SD2 -- %0X \n",(ULONG)p)); 
sd2 = p; 
number+=1; //记录已经获取一个特征 
//pd 
if ((*(p-2) == 0xE3) && 
(*(p-3) == 0xC1) && 
(*(p-7) == 0xF3) && 
(*(p-8) == 0x33) && 
(*(p-10)== 0xEB) && 
(*(p-11)== 0xC1) && 
(*(p+1) == 0xF3) && 
(*(p+2) == 0x42) && 
(*(p+3) == 0x3B) && 
(*(p+4) == 0xD1) && 
(*p == 0x33)) 
KdPrint(("--PD -- %0X \n",(ULONG)p)); 
pd = p; 
number+=1; //记录已经获取一个特征 
if (number >= 3) 
KdPrint(("特征 %d ---退出\n",number)); 
break; 

//首先干掉监视函数 
while (1) 
if ((*(pd-1) == 0xcc) && (*(pd-2) == 0xcc)) 
KdPrint(("pd首地址:%0X \n",(ULONG)pd)); 
WPOFF(); //清除CR0 
//提升IRQL中断级 
Irql=KeRaiseIrqlToDpcLevel(); 
//写入 
RtlCopyMemory(pd,C390,2); 
//恢复Irql 
KeLowerIrql(Irql); 
WPON(); //恢复CR0 
break; 
pd--; 
//干掉2个SD 
while (1) 
if ((*(sd1-1) == 0xcc) && (*(sd1-2) == 0xcc)) 
KdPrint(("sd1首地址:%0X \n",(ULONG)sd1)); 
WPOFF(); //清除CR0 
//提升IRQL中断级 
Irql=KeRaiseIrqlToDpcLevel(); 
//写入 
RtlCopyMemory(sd1,C390,2); 
//恢复Irql 
KeLowerIrql(Irql); 
WPON(); //恢复CR0 
break; 
sd1--; 
while (1) 
if ((*(sd2-1) == 0xcc) && (*(sd2-2) == 0xcc)) 
KdPrint(("sd2首地址:%0X \n",(ULONG)sd2)); 
WPOFF(); //清除CR0 
//提升IRQL中断级 
Irql=KeRaiseIrqlToDpcLevel(); 
//写入 
RtlCopyMemory(sd2,C390,2); 
//恢复Irql 
KeLowerIrql(Irql); 
WPON(); //恢复CR0 
break; 
sd2--; 

return STATUS_SUCCESS; 

最后,处理一下硬件断点就可以了 
这里我们使用到了SSDT HOOK 
分别HOOK了 SSDT 表中索引为 0xD5和0x55的函数。由于这里比较简单 
我想10个人有9个人懂得SSDT HOOK的。所以直接给出源码,不做原理分析了 


代码: 
//处理硬件断点时 
ULONG uNtSetContextThreadAddress; 
ULONG uNtGetContextThreadAddress; 
ULONG TenNtSetContextThread, 
TenNtGetContextThread; 
////////////////////////////////////////////////////////////////////// 
// 名称: _MyNtGetThreadContext 
// 功能: 两个SSDT HOOK伪造函数的中继函数 
// 参数: 
// 返回: 
////////////////////////////////////////////////////////////////////// 
static NAKED NTSTATUS Nakd_NtGetThreadContext(HANDLE hThread, PCONTEXT pContext) 
__asm 
jmp dword ptr[TenNtGetContextThread] 

static NAKED NTSTATUS Nakd_NtSetThreadContext(HANDLE hThread, PCONTEXT pContext) 
__asm 
jmp dword ptr[TenNtSetContextThread] 
////////////////////////////////////////////////////////////////////// 
// 名称: MyNtGetThreadContext && MyNtSetThreadContext 
// 功能: NtGetThreadContext与NtSetThreadContext函数被SSDT HOOK的伪造函数 
// 参数: 
// 返回: 
////////////////////////////////////////////////////////////////////// 
NTSTATUS MyNtGetThreadContext(HANDLE hThread, PCONTEXT pContext) 
if ( _stricmp((const char*)PsGetProcessImageFileName(PsGetCurrentProcess()),DNF_EXE) ) 
return Nakd_NtGetThreadContext(hThread, pContext); 
return STATUS_UNSUCCESSFUL; 


NTSTATUS MyNtSetThreadContext(HANDLE hThread, PCONTEXT pContext) 
if ( _stricmp((const char*)PsGetProcessImageFileName(PsGetCurrentProcess()),DNF_EXE) ) 
return Nakd_NtSetThreadContext(hThread, pContext); 
//DbgPrint("Dr7:%08X\n", pContext->Dr7); 
if ( pContext->Dr7 == 0x101 ) 
return Nakd_NtSetThreadContext(hThread, pContext); 
return STATUS_UNSUCCESSFUL; 

////////////////////////////////////////////////////////////////////// 
// 名称: My_Recovery_HardwareBreakpoint 
// 功能: 通过对set与get进行SSDT HOOK来恢复硬件断点 
// 参数: 
// 返回: 
////////////////////////////////////////////////////////////////////// 
NTSTATUS My_Recovery_HardwareBreakpoint() 
KIRQL Irql; 
//获取地址 
uNtSetContextThreadAddress = (ULONG)KeServiceDescriptorTable->ServiceTableBase+0xD5 * 4; 
uNtGetContextThreadAddress = (ULONG)KeServiceDescriptorTable->ServiceTableBase+0x55 * 4; 

TenNtSetContextThread = *(ULONG*)uNtSetContextThreadAddress; 
TenNtGetContextThread = *(ULONG*)uNtGetContextThreadAddress; 

KdPrint(("Set地址:%0X\n",TenNtSetContextThread)); 
KdPrint(("Get地址:%0X\n",TenNtGetContextThread)); 

KdPrint(("Process:%0X \n",(ULONG)p_MyHookAddress)); 
KdPrint(("Thread:%0X \n",(ULONG)t_MyHookAddress)); 

WPOFF(); //清除CR0 
//提升IRQL中断级 
Irql=KeRaiseIrqlToDpcLevel(); 

//完成SSDT HOOK 
*(ULONG*)uNtGetContextThreadAddress = (ULONG)MyNtGetThreadContext; 
*(ULONG*)uNtSetContextThreadAddress = (ULONG)MyNtSetThreadContext; 

//恢复Irql 
KeLowerIrql(Irql); 
WPON(); //恢复CR0 

return STATUS_UNSUCCESSFUL; 
另外还有一些功能型的函数一并给出,省的大家迷糊 
我也算服务到位了,再看上面代码迷糊的时候。看这里找找 
看看有没有能用到的,或者翻一下我以往的帖子。里面应该有 


代码: 
//保存5字节代码的结构 
#pragma pack(1) 
typedef struct _TOP5CODE 
UCHAR instruction; //指令 
ULONG address; //地址 
}TOP5CODE,*PTOP5CODE; 
#pragma pack( ) 

//ssdt表结构 
typedef struct _ServiceDescriptorTable { 
PVOID ServiceTableBase; //System Service Dispatch Table 的基地址 
PVOID ServiceCounterTable; 
//包含着 SSDT 中每个服务被调用次数的计数器。这个计数器一般由sysenter 更新。 
unsigned int NumberOfServices;//由 ServiceTableBase 描述的服务的数目。 
PVOID ParamTableBase; //包含每个系统服务参数字节数表的基地址-系统服务参数表 
}*PServiceDescriptorTable; 
//由SSDT索引号获取当前函数地址 
//NtOpenProcess [[KeServiceDescriptorTable]+0x7A*4] 
extern PServiceDescriptorTable KeServiceDescriptorTable; 

////////////////////////////////////////////////////////////////////// 
// 名称: MyGetFunAddress 
// 功能: 获取函数地址 
// 参数: 函数名称字符串指针 
// 返回: 函数地址 
////////////////////////////////////////////////////////////////////// 
ULONG MyGetFunAddress( IN PCWSTR FunctionName) 
UNICODE_STRING UniCodeFunctionName; 
RtlInitUnicodeString( &UniCodeFunctionName, FunctionName ); 
return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName ); 

////////////////////////////////////////////////////////////////////// 
// 名称: myGetCurrentAddress 
// 功能: 获取SSDT表中指定函数的当前地址 
// 参数: index:指定函数在表中的索引号 
// 返回: 地址 
////////////////////////////////////////////////////////////////////// 
ULONG myGetCurrentAddress(IN ULONG index) 
ULONG SSDT_Cur_Addr; 
__asm 
push ebx 
push eax 
mov ebx,KeServiceDescriptorTable 
mov ebx,[ebx] 
mov eax,index 
shl eax,2 
add ebx,eax 
mov ebx,[ebx] 
mov SSDT_Cur_Addr,ebx 
pop eax 
pop ebx 

return SSDT_Cur_Addr; 

VOID WPOFF() 
__asm 
cli 
mov eax,cr0 
and eax,not 10000h 
mov cr0,eax 

VOID WPON() 
__asm 
mov eax,cr0 
or eax,10000h 
mov cr0,eax 
sti 
}
  评论这张
 
阅读(63)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017