概述
PPT:链接: http://pan.baidu.com/s/1c18L4w4 密码: rp2n
增加了一些东西 有兴趣的可以看看PPT
一些很基础的东西
主流软件的保护--比如SSDT Inline Hook 了哪些函数 这些函数有什么用 在x86下
在x64下 讲解进线程回调并AnTi这些回调(可用自己的例子,比如保护计算器 然后Anti后在结束)讲解为什么x64下不能随意HOOK,并怎么突破(破PG),突破后SSDT HOOK 进行测试
讲解x64下DSE 以及如何过掉DSE(仅仅讲win7 x64)并演示
讲解一般软件的保护方法
讲解在x64下过TP 调试LOL
讲解句柄的保护
讲解强制读写内存
软件的一般保护方法:
1.加壳
压缩壳除外:比如ASP,北斗
保护壳:Themida ,VMP,UPX,WinLicense,Zprotect,ACProtect
强壳:Themida,VMP(大于2.3版本),国产的Shielden,WinLicense
2.花指令 对付静态反汇编:
花指令是程序中的无用指令或者垃圾指令,故意干扰各种反汇编静态分析工具,但是程序不受任何影响,缺少了它也能正常运行
jmp Label1
db opcode; //垃圾数值
Label1:
……
jmp Label1
db opcode; //垃圾数值
Label1:
……
jz Label
jnz Label
db opcode;//垃圾数值
Label:
……
3.反调试 对付动态调试
常用反调试方法:
R3可以使用IsDebuggerPresent来判断自身进程是否被调试(需放到线程中或启动时)
CheckRemoteDebuggerPresent可以得到某一个进程的调试状态
不过这些都是导出函数 使用很容易被发现
我们可以结合GetTickCount和异常处理结构来实现反调试
VOID DeubgForX64()
{
DWORD dwTime1 = 0;
DWORD dwTime2 = 0;
//故意引发异常查找调试器
dwTime1 = GetTickCount();
__try
{
memcpy((PVOID)1234,(PVOID)5678,90);
//DebugBreak();
}
__except(1)
{
dwTime2 = GetTickCount();
puts("goto __except!n");
}
if(dwTime2 - dwTime1 > 10)
puts("FIND DBGn");
else
puts("NO DBGn");
}
或者检测PEB结构中BeingDebugged
0:009> dt _peb
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 BitField : UChar
BOOL PebIsDebuggerPresent()
{
char result = 0;
__asm
{
// 进程的PEB地址放在fs这个寄存器位置上
mov eax, fs:[30h]
// 查询BeingDebugged标志位
mov al, BYTE PTR [eax + 2]
mov result, al
}
return result != 0;
}
在PEB中0x68 或者0xbc 偏移处 NtGlobalFlag 如果发现其中的值&0x70不等于0就存在说明进程被调试
对付附加的方法还有R3 Hook DbgUiRemoteBreakin函数 OD在附加时会调用这个函数 直接写入return 将使附加失败
代码:
#include <windows.h>
#include "stdio.h"
UCHAR* DbgUiRemoteBreakin;
int main()
{
DWORD lpflProtect;
HMODULE hModule = LoadLibrary(L"ntdll.dll");
if (hModule == NULL)
{
return false;
}
DbgUiRemoteBreakin = (UCHAR*)GetProcAddress(hModule,"DbgUiRemoteBreakin");
if (DbgUiRemoteBreakin)
{
if(VirtualProtect(DbgUiRemoteBreakin, 1, PAGE_EXECUTE_READWRITE, &lpflProtect))
{
*DbgUiRemoteBreakin = 0xc3;
}
}
printf("Now Can attach me !n");
getchar();
}
其它反调试方法还有很多 比如检测父进程 一般程序的父进程是explorer.exe 当被调试时 父进程就是调试器
但是这个涉及枚举进程 枚举进程的函数离不开EnumProcess CreateToolhelp32Snapsho OpenProcess ProcessNext等等太过于明显
所以国内很多对软件的保护工作都放到内核中
内核下:EPROCESS结构下的DebugPort 进程被调试时指向一个地址,反之为NULL
NP TP保护使用过 对DebugPort进行疯狂清0
1: kd> dt _eprocess
ntdll!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x098 ProcessLock : _EX_PUSH_LOCK
+0x0a0 CreateTime : _LARGE_INTEGER
+0x0a8 ExitTime : _LARGE_INTEGER
+0x0b0 RundownProtect : _EX_RUNDOWN_REF
+0x0b4 UniqueProcessId : Ptr32 Void
+0x0b8 ActiveProcessLinks : _LIST_ENTRY
+0x0c0 ProcessQuotaUsage : [2] Uint4B
+0x0c8 ProcessQuotaPeak : [2] Uint4B
+0x0d0 CommitCharge : Uint4B
+0x0d4 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK
+0x0d8 CpuQuotaBlock : Ptr32 _PS_CPU_QUOTA_BLOCK
+0x0dc PeakVirtualSize : Uint4B
+0x0e0 VirtualSize : Uint4B
+0x0e4 SessionProcessLinks : _LIST_ENTRY
+0x0ec DebugPort : Ptr32 Void
2在EPROCESS下有一个域可以到达反调试的效果ProtectedProcess 一般进程是0y0 如果我们改为0y1
那么当调试器附加的时候就会被返回错误
效果如下:
图
:kd> dt _eprocess
ntdll!_EPROCESS
+0x000 Pcb : _KPROCESS
.........
+0x26c NumaAware : Pos 10, 1 Bit
+0x26c ProtectedProcess : Pos 11, 1 Bit
3.在EPROCESS下NoDebugInherit 如果进程被调试则为1 反之为0
kd> dt _eprocess
ntdll!_EPROCESS
+0x000 Pcb : _KPROCESS
...............................
+0x270 Flags : Uint4B
+0x270 CreateReported : Pos 0, 1 Bit
+0x270 NoDebugInherit : Pos 1, 1 Bit
+0x270 ProcessExiting : Pos 2, 1 Bit
4.在ETHREAD下的CrossThreadFlags成员的第二位ThreadInserted 正常为1 这个不能检测 但我们可以将这个位置0 可以到达反调试的效果
3: kd> dt _ethread
ntdll!_ETHREAD
+0x000 Tcb : _KTHREAD
........
+0x280 CrossThreadFlags : Uint4B
+0x280 Terminated : Pos 0, 1 Bit
+0x280 ThreadInserted : Pos 1, 1 Bit
+0x280 HideFromDebugger : Pos 2, 1 Bit
图:
TP:对全局进程对象ValidAccessMask清零 这个域保存的调试权限的合集 正常为0x1fffff,清零后将调试权限值0 就没有调试权限了 调试器会提示没有权限附加/创建进程
//这里演示如何过TP 调试LOL 告诉步骤就行 使用CE调试或者OD调试
3: kd> dd psprocesstype
83f7502c 863e3e38 863e3f00 863e3ca8 863e3be0
83f7503c 863e38a8 83f40640 8a1fd0c0 00010000
83f7504c 00000cd8 00000258 00000000 00000001
83f7505c 00000001 0000004b 00000001 00989680
83f7506c 00000000 00000029 00000002 c0ffffff
83f7507c c0607ff8 00000000 00000000 c0403080
83f7508c 00000000 00010100 00000500 00000000
83f7509c 00000001 00000000 00000027 00040107
3: kd> dt _object_type 863e3e38
ntdll!_OBJECT_TYPE
+0x000 TypeList : _LIST_ENTRY [ 0x863e3e38 - 0x863e3e38 ]
+0x008 Name : _UNICODE_STRING "Process"
+0x010 DefaultObject : (null)
+0x014 Index : 0x7 ''
+0x018 TotalNumberOfObjects : 0x35
+0x01c TotalNumberOfHandles : 0x12d
+0x020 HighWaterNumberOfObjects : 0x3b
+0x024 HighWaterNumberOfHandles : 0x13a
+0x028 TypeInfo : _OBJECT_TYPE_INITIALIZER
+0x078 TypeLock : _EX_PUSH_LOCK
+0x07c Key : 0x636f7250
+0x080 CallbackList : _LIST_ENTRY [ 0x863e3eb8 - 0x863e3eb8 ]
3: kd> dt _OBJECT_TYPE_INITIALIZER 863e3e38+0x28
ntdll!_OBJECT_TYPE_INITIALIZER
+0x000 Length : 0x50
............................
+0x00c GenericMapping : _GENERIC_MAPPING
+0x01c ValidAccessMask : 0x1fffff
+0x020 RetainAccess : 0x101000
............................
对调试系统的检测(也称双机调试检测)
KdDisableDebugger/KdEnableDebugger
关闭系统调试/开启系统调试
首先当调试器要调试内核时需要调用KdSystemDebugControl函数
反汇编:
PAGE:00000001404D9C00
PAGE:00000001404D9C00 mov [rsp+arg_0], rbx
PAGE:00000001404D9C05 mov [rsp+arg_8], rdi
PAGE:00000001404D9C0A push r12
PAGE:00000001404D9C0C sub rsp, 170h
PAGE:00000001404D9C13 mov r10, rdx
PAGE:00000001404D9C16 and [rsp+178h+var_134], 0
PAGE:00000001404D9C1B and qword ptr [rsp+178h+var_130], 0
PAGE:00000001404D9C21 and [rsp+178h+P], 0
PAGE:00000001404D9C27 cmp cs:KdpBootedNodebug, 0 //全局变量1
PAGE:00000001404D9C2E jnz loc_1404DA4B7
PAGE:00000001404D9C34 cmp cs:KdPitchDebugger, 0 //全局变量2
PAGE:00000001404D9C3B jnz loc_1404DA4B7
PAGE:00000001404D9C41 cmp cs:KdDebuggerEnabled, 0 //全局变量3
PAGE:00000001404D9C48 jz loc_1404DA4B7
PAGE:00000001404D9C4E cmp ecx, 0Eh
PAGE:00000001404D9C51 jg loc_1404DA1D1
PAGE:00000001404D9C57 cmp ecx, 0Eh
PAGE:00000001404D9C5A jz loc_1404DA112
PAGE:00000001404D9C60 sub ecx, 7
PAGE:00000001404D9C63 jz loc_1404DA0EB
内部分别对三个变量的值进行的比较
KdpBootedNodebug非调试为1 也是调试模式得代表之一
KdPitchDebugger 非调试也为1
KdDebuggerEnabled 调试为1 非调试为0
KdDisableDebugger的内部对这三个全局变量进行修改并对
KdpBootedNodebug 置1
KdPitchDebugger 置1
KdDebuggerEnabled 置0
还有一个KdEnteredDebugger全局变量也会置0(这个全局变量时TP实现禁止双机调试的重要参数)
3: kd> u KdEnterDebugger L50
nt!KdEnterDebugger:
8413816d 8bff mov edi,edi
...........................................
84138228 57 push edi
84138229 a2d4b61784 mov byte ptr [nt!KdpPortLocked (8417b6d4)],al
8413822e e8b73fceff call nt!KdSave (83e1c1ea)
84138233 5f pop edi
84138234 8935240df783 mov dword ptr [nt!KdEnteredDebugger (83f70d24)],esi
TP检查KdEnteredDebugger的值(试出来的) 为1则说明是双机调试状态,反之
KdEnableDebugger的内部反操作
并将另一个全局函数指针置为KdpTrap函数的地址 即设置回调地址
KiDebugRoutine = KdpTrap;
http://bbs.pediy.com/showthread.php?t=186091&highlight=%E5%8F%8C%E6%9C%BA+%E6%9C%BA%E8%B0%83+%E8%B0%83%E8%AF%95
某一些游戏在x86下载内核HOOK了以下函数
NtOpenThread():防止调试器在程序内部创建线程
NtOpenProcess():防止OD(OllyDbg)等调试工具在进程列表中看到
KiAttachProcess():防止被附加上
NtReadVirtualMemory():防止被读内存
NtWriteVirtualMemory():防止内存被写
KdReceivePacket():KDCOME.dll 中Com串口接收数据函数
KdSendPacket():KDCOME.dll 中Com串口发送数据函数
演示一个NtOpenProcess即可
这里插入句柄的保护 和 强制读写内存
在x64下游戏都采用进线程回调进行保护(演示实现保护,并实现Anti这种保护)
为什么在x64下只能用回调保护呢?
因为在x64下存在PatchGuard
摘自百度百科
PatchGuard就是Windows Vista的内核保护系统,防止任何非授权软件试图“修改”Windows内核,也就是说,Vista内核的新型金钟罩。
其实应该是这么写
PatchGuard就是Windows x64 (Vista及以上)的内核保护系统,防止任何非授权软件试图“修改”Windows内核,也就是说,x64内核的新型金钟罩。
蓝屏代码:0x109
演示x64下的SSDT HOOK 造成蓝屏
废掉Win7 x64 PatchGuard演示:破解内核和winload.exe (支持Win8,Win8.1)
并替换内核 然后进行SSDT Hook演示:
x64内核保护机制之二,中文名称“驱动签名强制”,禁止加载不包含正确签名的驱动。
简称DSE
最后
以上就是还单身路灯为你收集整理的[已完结]我在学校举办软件安全讲座提纲的全部内容,希望文章能够帮你解决[已完结]我在学校举办软件安全讲座提纲所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复