光纤熔接 ERP

弱电论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 1366|回复: 0
打印 上一主题 下一主题

害人实施

[复制链接]
跳转到指定楼层
1#
发表于 2005-10-20 17:37:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
华为代理商
病毒基础系列
前言:
   病毒没有什么可怕的,也并不象想像中的复杂,玩汇编的人如果没有看过病毒?简直是白活一遭...病毒就象是双刃剑,恶意使用就会带来恶果,我本人对于此类行为深恶痛绝!我们研究不是为了破坏而是为了知己知彼,另外病毒中确实也有很多高超的技巧值得我们学习,这才是我们的目的所在,我绝没有教唆人犯罪的意图而且就我的水平来讲也远达不到.
   在研究病毒之前有几项基础知识要了解:
       1)ring0的获取,可参见我翻译的一篇ring0的文章,另外这些资料internet上也很多.
       2)Seh的知识,可参见我写的<>
       3)PE结构的知识,ZouDan大侠的论文,IczeLion的PE教学和载 LUEVELSMEYER的《PE文件格式》,最为重要!
       4)文件读写的基本知识,主要是CreateFileA,ReadFile,WriteFile,CreateFileMapping...等文件读写知识,如果你还不了解,最好先学学win32ASM的基础知识.
       5)PolyEngine...metaMorphism等基本概念
       6)anti-debug的一些概念
       7)有关MBR,FAT等知识,对了解一些老Virus有用.
      

       下面我有的一些tips,可能会对理解病毒有所帮助.另外这些技术在加壳类软件中也很常见.


--------------------------------------------------------------------------------


                               tip1: api函数地址的获取


这是一个老题目了,如果我们不用任何引入库,能否在程序中调用api函数?当然可以!方法有很多,你可能早就知道了,如果你已经了解了,就此打住,这是为还不了解这一技术而写.另外这也是病毒必用的技巧之一,如果你对病毒技术感兴趣,接着看下去.

这里假设你了解PE的基本结构,如果还不懂,找点资料来看看,到处都是呦.

在几乎每个病毒的开头都用下面的语句:
       call    delta
delta: 
       pop     ebp                            
       sub     ebp,offset delta               
       mov     dword ptr [ebp+offset appBase],ebp
      
让我们考虑一下程序的执行情况,如果下面的代码由编译器自动编译连接,那么程序执行的基址一般是400000h,如果是在Nt下执行,那么基址可能不同,比如从100000h开始,不用担心,操作系统的Loader会自动为你重定位.但是这里停下来让我们看一下,如果你想要把这段代码附加到其他程序的后面并想让其正确执行的话,就不是那么简单了,因为你的代码可能要从555588h处开始执行,而在没有得到宿主程序许可的情况下期望操作系统自动为你修正偏移错误是不可能的,既然有非常的目的,就得费点力气,自己搞定重定位.而上面的代码就是首先得到eip指针,也是delta在程序执行时的实际偏移,然后减掉代码头到delta的偏移从而得到你的代码的真正基址,后面对于偏移的操作都应以这个真正的偏移为准.这就是你上面看到的.如果不明白,就仔细想一下,nothing difficult!下面的例子演示了这一点,并没有全部重定位,因为这只是技术演示.

现在回到本文的正式内容,要想获得api的地址,得首先获得诸如kernel32.dll,user32.dll的基址,然后再找到真正的函数地址.如何获得基址和函数地址呢呢?有几种方法
       1)搜寻宿主的引入表获得GetModuleHandleA函数和GetProcAddress的地址,然后通过他返回系统dll的基址.因为很多程序都要使用这两个函数,因此在某些情况下是可行的,如果宿主没有使用GetProcAddress,那你就不得不搜寻Export表了.
       2)直接获得kernel32.dll的基址,然后再搜寻Export表获得GetProcAddress和LoadLibraryA的地址,然后我们就能得到任何想调用的函数地址.

       3)硬编码调用函数,比如在9X下GetModuleHandleA的地址一般是BFF7****.

第一种和第三种方法存在兼容性的问题,假如宿主没有调用GetModuleHandleA,那么你就不能获得基址,别的就更别想了...硬编码问题更大,操作系统不同则不能运行了,比如9X下可能在有些计算机上正常,但肯定不能在Nt/2K下运行...

第二种方法兼容性比较好,因此作以介绍.

       一点背景:在PE Loader装入我们的程序启动后堆栈顶的地址是是程序的返回地址,肯定在Kernel中!

       因此我们可以得到这个地址,然后向低地址缩减验证一直到找到模块的起始地址,验证条件为PE头不能大于4096bytes,PE header的ImageBase值应该和当前指针相等,嘿嘿,简单吧,而且兼容性还不错.

       要获得Api的地址首先要获得GetModuleHandle,LoadLibraryA,GetProcAddress的地址,这是通过搜索Export表来实现的,具体原理就是PE Export表的结构,如果了解了PE结构就很简单了.下面我加了点注释,没有优化代码,是为了便于理解.

       好,这一部分结束了!

这是一个例子,没有用任何预引入函数,加了一条invoke InitCommonControls是为了在2K下也能正常运行,否则不能在2K下不加载!
程序得到MessageBoxA的地址然后显示一个消息框,目的在于演示,重要部分加了注释,很好明白.
注意连接时加入/section:.text,RWE选项。
.586
.model flat, stdcall
option casemap :none   ; case sensitive
include c:\hd\hd.h
include c:\hd\mac.h

;;--------------

GetApiA         proto    WORD,WORD

;;--------------
.CODE
appBase         dd ?
k32Base         dd ?

lpApiAddrs      label   near
               dd      offset sGetModuleHandle
               dd      offset sGetProcAddress
               dd      offset sExitProcess
               dd      offset sLoadLibrary
               dd      0

sGetModuleHandle       db "GetModuleHandleA",0
sGetProcAddress        db "GetProcAddress",0
sExitProcess           db "ExitProcess",0
sLoadLibrary           db "LoadLibraryA",0

sMessageBoxA           db "MessageBoxA",0


aGetModuleHandle                dd 0
aGetProcAddress                 dd 0
aExitProcess                    dd 0
aLoadLibrary                    dd 0
aMessageBoxA                    dd 0

u32                     db "User32.dll",0
k32                     db "Kernel32.dll",0

sztit                   db "By Hume,2002",0
szMsg0                  db "Hey,Hope U enjoy it!",0
;;-----------------------------------------

__Start:
       invokeInitCommonControls
      
       call    delta
delta: 
       pop     ebp                             ;得到delta地址
       sub     ebp,offset delta                ;因为在其他程序中基址可能不是默认的所以需要重定位
       mov     dword ptr [ebp+offset appBase],ebp     ;呵呵仔细想想
      
mov     ecx,[esp]                       ;返回地址
       xor     edx,edx
getK32Base:
       dec     ecx                             ;逐字节比较验证
       mov     dx,word  ptr [ecx+IMAGE_DOS_HEADER.e_lfanew]   ;就是ecx+3ch
       test    dx,0f000h                       ;Dos Header+stub不可能太大,超过4096byte
       jnz     getK32Base                      ;加速检验
       cmp     ecx,dword ptr [ecx+edx+IMAGE_NT_HEADERS.OptionalHeader.ImageBase]
       jnz     getK32Base                      ;看Image_Base值是否等于ecx即模块起始值,
       mov     [ebp+offset k32Base],ecx        ;如果是,就认为找到kernel32的Base值
      
       lea     edi,[ebp+offset aGetModuleHandle]
       lea     esi,[ebp+offset lpApiAddrs]
lop_get:
       lodsd
       cmp     eax,0
       jz      End_Get
       push    eax
       push    dword ptr [ebp+offset k32Base]
       callGetApiA                         ;获取API地址       
       stosd
       jmp     lop_get
End_Get:
       push    offset u32
       call    dword ptr [ebp+offset aLoadLibrary]     ;在程序空间加载User32.dll
      
       lea     EDX,[EBP+OFFSET sMessageBoxA]
       push    edx
       push    eax
       mov     eax,dword ptr [ebp+aGetProcAddress]     ;用GetProcAddress获得MessageBoxA的地址
       call    eax                                     ;调用GetProcAddress

       push    40h+1000h                               ;style
       push    offset sztit                            ;title
       push    offset  szMsg0                          ;消息内容
       push    0
       call    eax                                     ;一个消息框产生了...嘿

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|广告咨询|VIP注册|关于我们|联系我们|积分规则|手机版|Archiver|弱电之家论坛 ( 京ICP备11008917号-3 )

GMT+8, 2024-5-3 14:33 , Processed in 0.118893 second(s), 21 queries , Gzip On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表