我是靠谱客的博主 还单身路灯,最近开发中收集的这篇文章主要介绍[已完结]我在学校举办软件安全讲座提纲,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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



































































最后

以上就是还单身路灯为你收集整理的[已完结]我在学校举办软件安全讲座提纲的全部内容,希望文章能够帮你解决[已完结]我在学校举办软件安全讲座提纲所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(37)

评论列表共有 0 条评论

立即
投稿
返回
顶部