SProtect 最全脱壳教程 原理剖析.pdf
SProtect 最全脱壳教程+原理剖析 废话不多说,上步骤!1、什么强度?别问,问就是全保护!2、加壳:超级模式 3、导入表:超级模式 4、内存校验:虚拟模式 5、.文章内容:1.IAT扫描与修复 2.antidump处理 3.IAT导入表修复 4.写补丁进行修复antidump IAT扫描之出入01之牛头马面之自动运算扫描大法:超级模式的IAT保护强了点,但是没啥用,加密类型大致分为如下几种模式 1、Call 到IAT解密 2、JMP 到 IAT解密 3、CALL 到IAT解密 然后 Jmp进入虚拟机 通过以上的特征进行扫描,扫描大概的原理:1、指定代码段开始与结束(.text),一般代码段的开始地址是0 x00401000 2、扫描代码段和代码段结束的所有call和jmp,并且都是IMM类型 3、判断call和jmp的imm是否处于svmp1区段,如果是svmp1区段,则可能是antidump或iat下面通过扫描得出结果:1.2.修复原理:0 首先扫描出来的call和jmp要排除antidump 1 遍历进程所有的模块,取出导出表的各个函数地址,并且记录 2 跟踪每一个call和jmp,一直到跟踪到ret 3 判断栈顶esp的值是否处于系统库的导出表函数头部 4 如果栈顶esp的值处于某个系统库的导出函数头部,那么esp的值就是api地址,这里记录一下api地址(这里还有一种方式可以确定,就是如果esp的地址不处于主模块的区间,则就是第系统库或第三方库API地址)5 如果确定了esp的值就是api,那么esp+4的地址如果处于代码段区间就是CALL IAT,如果esp+4的地址如果不处于代码段区间,则是JMP IAT类型 6 如果esp的地址处于主模块的区间,那么可能就是MOV R32,IAT类型 区分IAT加密的方式分为push call和call retn方式:invoke_code_address是扫描出来的调用IAT的地址此时如果esp+4-invoke_code_address=5,那么就是push call模式,此时iat的开始修复地址就要减1如果esp+4-invoke_code_address!=5,那么就是call_retn模式,此时地址,此时iat的开始修复地址就要不需减1 引用上述第6点,如果esp的地址处于主模块的区间,那么可能就是MOV R32,IAT类型,那么这里需要再次判断esp的地址是否处于代码段区间,如果处于代码段区间那么确定就是MOV R32,IAT类型 如果确定是MOV R32.IAT类型,则判断api地址 IAT调用的地址如果结果是5 且 mov r32,iat的r32不等于eax,那么就是push call模式,否则就是none模式none模式就是原mov eax,iat的模式,因为mov eax,dword ptr ds:iat正好够5个字节,所以在修复的地址不需要减1 如果结果不等于5,则是call retn模式通过上面的+1或-1以及各种识别操作,可以扫描到IAT如下:if(.|esp4=g_svmp1_start&esp4 g_svmp1_end)/这个的意思就是,有些IAT在虚拟的情况下调用完成了系统库API,然后返回的不是代码段地址,而是svmp1的地址,所以这里再加个判断!通过上述的方式搜索到iat的数据之后,就可以开始修复了,因为antidump会检测IAT的调用处,所以不能直接完整的修复。所以中转API跳转的地址可以在call IAT解密的地方或 JMP IAT(VMEnter)的虚拟机入口进行hook,然后直接扩展最后一个区段,把调用的IAT的指令修复到扩展的区段,流程如下:Hook IAT解密的地方中转到修复的IAT调用处:HOOK IAT的虚拟机入口:因为有些调用IAT需要平栈,所以修复方式根据IAT是否被虚拟化,IAT是call还是jmp还是mov,类型是否是push call 或 call retn进行修复:代码如下(懂的都懂):修复完成之后大概如下:全自动模拟玛雅轮转算法处理antidump 这里解析一个常用的antidump,通过上述的代码扫码之后,扫描到了一堆antidump,如下:anti_dump 0040100F jmp 0 x1307435anti_dump 0040107B jmp 0 x1307574anti_dump 004010E7 jmp 0 x130765danti_dump 00401164 jmp 0 x130777canti_dump 004011D0 jmp 0 x130785eanti_dump 0040123C jmp 0 x1307956anti_dump 004012A8 jmp 0 x1307a97anti_dump 00401314 jmp 0 x1307b6aanti_dump 00401380 jmp 0 x1307cb1anti_dump 004013EC jmp 0 x1307dca 首先什么是antidump?antidump就是在你脱掉外壳之后的检测等阻碍你脱壳的校验!Antidump大致分为 堆antidump,cpuid antidump,校验PE相关的数据的antidump,以及可以结合fs段和系统动态库地址等变动的数据进行antidump!例如:1、运行壳代码的时候,将一个在”加密壳加密期间生成的”随机值放入到堆里,然后把堆的地址放入到某一个区段里,然后antidump SDK可以在区段里面取出这个堆地址,然后拿到这个随机值,然后比对是否相等,如果不相等则触发校验!这里出现了堆,如果程序被脱壳了,此时没有外壳的加载,所以堆可能就无法被创建,所以脱壳后的程序访问堆地址就会触发异常,如果异常程序就会崩溃 2、antidump里面可以检测区段的地址,以及区段的数量,以及是否添加了新的区段来检测是否被脱壳!这里我分析0 x00401311这个窗口载入事件的地址,其他也一样 通过跟踪扫描并总结如下:通过分析0 x00401311地址,总结Antidump流程:1、在svmp1取出堆地址进行校验2、校验rsrc资源段数据3、校验IAT调用处是否被修改4、校验区段的数量5、校验区段的虚拟地址6、解密堆地址,后续用于取出cpuid的校验值7、Cupid校验8、将上面的所有的值介入运算,将结果与返回地址或栈顶运算,如果校验失败那么返回地址或栈顶的值可能就是一个错误的值 这里讲解一下提高耦合的运算,意思就是说将需要跳转的地址不通过原生的if else进行跳转,而是通过0 和 1运算直接运算出跳转的值,那么可以增强防破解难度,从上述antidump扣取的算法如下:Antidump细节流程:这里从svmp1区段里面拿到数据,取出C592FC1B和91CB8A99,后面会介入运算取出rsrc的数据,后面会介入运算 校验IAT的调用处地址是否修改,因为IAT的调用处要么是push call,要么是call retn和单call,如果你修复IAT的时候完整修复,那么就会触发这个校验,所以修复IAT还是用我上述的方法进行修复较好!通过代码得知,这里会取出区段的数量和校验区段的虚拟地址以及下一个新区段地址,后面会介入运算x1=not(4583DA0D)=BA7C25F2x2=not(6D63035F)=929CFCA0 x3=and(x1,x2)=921C24A0 x4=not(x3)=6DE3DB5Fx5=4503020D /pop ecxx6=not(x5)=BAFCFDF2x7=and(x4,x6)=28E0D952x8=not(28E0D952)=D71F26ADx9=not(28E0D952)=D71F26ADx10=and(x8,x9)=D71F26ADx11=add(D71F26AD,28E0D952)=FFFFFFFFx12=FFFFFFFFx13=not(FFFFFFFF)=00000000 x14=not(x12)=00000000 x15=and(x13,x14)=00000000 x16=add(x15,0019FCDC)/最后把计算结果和esp相加懂的都懂!这里会取出堆的加密地址,解密之后就是堆地址了,如A5D2B8F1,解密之后就是182E0029,后续可用于校验cpuid的数据 取出cpuid的数据,后续介入运算 然后注意 00440B1B ret,这行地址,虚拟机退出的时候会跳入到代码段的IAT调用处的call ret的ret IAT之阿吉古德轮换量子颗粒修复输入算法 用UIF工具进行指定CALL/JMP/MOV CONST的IAT调用处开始地址和结尾地址 然后UIF开启修复,这一步将call imm,jmp imm,mov r32,imm转换成call dword ptr ds:xxxx,jmp dword ptr ds:xxxx,mov r32,dword ptr ds:xxxx 修复完成之后,效果如下:最后dump,然后配合scllya86进行修复,最后修复转储就好了!(常规操作不介绍那么多)注意,修复转储这一步会导致添加导入表.SCY,所以antidump需要固定区段数量和下一个区段的占位值 修复之尖嘴猴腮牛马基因遗传自动算法之修复antidump 此时需要对如下的代码进行固定即可:由于后续修复的过程中会增加区段,所以需要把如下这两行代码固定掉:区段虚拟地址没变,就不需要固定了!固定cpuid的值,hook cupid即可,然后把eax edx ecx ebx固定住即可!固定cpuid的堆校验值,固定如下代码:;把ecx固定成C592FC1B,通过eip进行判断(vEIP)00EE8A91 mov ecx,dword ptr ecx ecx:18231560 m32:18231560 m32:C592FC1B;把ecx固定成91CB8A99,通过eip进行判断(vEIP)00EA3F3B mov ecx,dword ptr ecx ecx:18242FF6 m32:18242FF6 m32:91CB8A99;把dx固定8(或者是在PE头把区段数量修改成8)00EAC0BF mov dx,word ptr edx edx:40010E m32:40010E m32:CAF00008;把ecx固定0(或者是在PE头把下一个区段地址修改成0)00F3E78D mov ecx,dword ptr ecx ecx:40034C m32:40034C m32:0;如果是push dword ptr ecx,就可以固定成push 6D63035F,通过esi(vEIP)判断是否到达这个位置!00EBFC60 push dword ptr ecx ecx:182E0029 m32:182E0029 m32:6D63035F;把edx固定成B7CC2BE7,通过esi(vEIP)判断是否到达这个位置!00ED3518 mov edx,dword ptr edx edx:182E00FA m32:182E00FA m32:B7CC2BE7;固定成push DD42A310,通过esi(vEIP)判断是否到达这个位置!00E9864C push dword ptr ecx ecx:182E021F m32:182E021F m32:DD42A310;把eax固定成D4CC8987,通过esi(vEIP)判断是否到达这个位置!00EAEE23 mov eax,dword ptr eax eax:182E02F8 m32:182E02F8 m32:D4CC8987;把edx固定成8D41BC1,通过esi(vEIP)判断是否到达这个位置!00EBFC60 push dword ptr ecx ecx:182E03C9 m32:182E03C9 m32:8D41BC1 HOOK handle代码如下:;注意:固定6D63035F,B7CC2BE7,DD42A310,D4CC8987,8D41BC1 如果是push dword ptr ecx,就可以固定成push 6D63035F,通过vEIP判断是否到达这个位置!/固定区段数量和下一个区段校验wMemInt(HANDLE)-1,0 x40010E,0 xCAF00008);/因为我转储了导入表,会导致添加导入表,所以我这里固定区段数量为8wMemInt(HANDLE)-1,0 x40034C,0);/因为我转储了导入表,会导致添加导入表,下一个地址被占位,这里固定区段数量为0wMemInt(HANDLE)-1,0 x4BA667,400000);/刚开始这里为了不触发内存访问异常,随便写的一个值1.过antidump的C语言代码可以通过扫描antidump的过程生产的 2.过antidump就很快了,把上述的代码编译成DLL,后续可以进行劫持导入表进行HOOK 添加导入表 因为有些antidump的代码在程序启动过程运行,所以我这里通过导入表注入的方式patch,首先patch补丁是一个dll,然后打开IAT重建工具添加一下导入表!运行效果如下:最后总结:也就那样吧 文章教程仅供学习娱乐与参考!由于一些特殊问题不放bin和完整的脱壳代码和工具!感兴趣的自行按照文章的教程学习!SProtect脱壳大型纪录片持续更新中!