为PE文件添加新节显示启动信息

下载本节例子程序和源代码 (7.66 KB)

病毒并不神秘,也不复杂。相当多的大侠已经在这方面作出了杰出的贡献,例如 29A 组织,我对他们的崇拜之情啊,真是……咳咳,先别扔鸡蛋。其实我想说的是:技术是一柄双刃剑,我们应该把它运用在对社会有益的事情上。所以请勿利用本文的代码进行违法违纪的活动,否则本人保留追究的权利。

本文的技术其实早已是老掉牙的东西了,so如果你已经懂得了编写病毒的方法,请跳过本文;如果你对病毒抱有好奇心,但是还没知道怎么编写,那么本文应该适合你。  :)

言归正传。在 Windows 环境下,所有的可执行文件都是 PE 格式,因此编写病毒最重要的环节之一就是对 PE 文件进行操作。但是在此我不打算对 PE 格式进行讲解,请读者自行参考有关资料。我只对我在实际编写中遇到的难点进行分析:

首先,计算机病毒之所以叫做病毒,是因为它跟自然界中病毒一样,都需要有一个宿主——它本身是无法单独执行的。那么,当病毒寄生在宿主上后,怎样让它的代码执行呢?我们先来看一些概念。

PE 的代码映象分为几个 SECTION,在文件中会对齐页边界(4K)。一般来说,文件会加载在 400000h 开始的空间,而第一个 SECTION 在 401000h 处,同时入口地址也是 401000h。这个入口地址 401000h 是怎么计算出来的呢?如果你查看 PE 头的 IMAGE_OPTIONAL_HEADER ,就会发现它的 ImageBase 一般是 400000h ,而 AddressOrEntryPoint 一般是 1000h 。 400000 + 1000 = 401000h ,明白了吧?掌握了这一点,我们就可以在 PE 中添加我们自己的新节,然后把这个入口地址改成指向新节的第一条代码。当新节执行完毕后,再把原入口恢复,这样一来就能继续执行宿主的代码了。

在几乎每个 Win32 病毒的开头都有这样的语句:

    call nStart
nStart:
    pop ebp
    sub ebp, offset nStart

这些语句是用来干嘛的呢?好像是吃饱了饭没事干哦……其实不然。让我们来仔细考虑一下。当正常的 PE 程序执行时,它的基址(如前所述)一般是 400000h ,这个地址会由操作系统为你重定位,因此总是能保证程序被成功地装载运行。但是,如果我们在 PE 中插入了一段新的代码,假设它要从 654321h 处开始执行,那么事情就没有那么简单了。因为宿主程序并没有预料到这段代码的存在,而操作系统也不可能为你修正这个偏移。因此我们就要自己进行重定位操作。上面的语句就是取得病毒在宿主中的实际偏移地址。call 指令实际上是 push 和 jmp 的组合。当 call nStart 时,实际上是把 call nStart 的下一条指令(也就是pop ebp)的地址压入堆栈然后 jmp 到 nStart ,由于之前已经把 pop ebp 的地址压入了堆栈,所以当真正执行到 pop ebp 这条指令的时候,实际上就是把 pop ebp 这条指令的地址放到了 ebp 中。这样就得到了当前病毒代码的真正的偏移地址。这也是病毒中常用的手法。几乎无一例外。

接下来还有一个关键的问题。我们的病毒代码是附属在宿主上的,如果要在病毒中使用 API ,则必须首先得到 API 的入口地址。不过这可不是一件容易的事情啊。为什么这样说呢?让我们先来看看下面的代码:

invoke ExitProcess, 0

在经过编译器的编译、连接后,它在内存中形如:

:00401015    Call 0040101A
:0040101A    Jmp dword ptr [00402000]

也就是说,ExitProcess 的调用是通过 Call 0040101A ,而 0040101A 处的代码是一个 Jmp ,指向 [00402000] ,这个 [00402000] 处储存的才是真正的 ExitProcess 的入口地址。

为什么要经过那么多周折呢?呵呵,其实我也不知道。但是我们知道的是,调用一个 API 实际上是调用它在内存中的地址。而病毒由于是在宿主编译完之后才附属上去的,所以如果病毒要运行 API ,则必须自己指定 API 的入口地址。

是不是很烦呢?Hoho,坚持一下吧,就快大功告成了。

要得到 API 的入口地址,方法有很多种,例如可以通过硬编码,这是比较简单的方法,但是它的缺陷是不能在不同的 Windows 版本下运行,不过由于它实现起来比较简便,因此本文还是采用这种方法。

在同一个版本的 Windows 下,同一个核心函数的入口总是固定不变的(指由 Kernel32, Gdi32, User32 导出的函数),所以我们就可以利用下面的方法得到 API 的入口:

szDllName        db    "User32", 0
szMessageBoxA    db    "MessageBoxA", 0
MessageBoxA_Addr dd    0

invoke GetModuleHandle, addr szDllName
invoke LoadLibrary, addr szDllName
invoke GetProcAddress, eax, addr szMessageBoxA
mov MessageBoxA_Addr, eax

在病毒中我们就可以用 Call MessageBoxA_Addr[ebp] 来执行 MessageBoxA 这个 API 了。

好啦,我已经把我认为比较重要的难点解释了一次了,如果你还有什么不清楚的地方,欢迎给我来信。lcother@163.net

下面我给出了一个例子程序,它的作用是为 PE 文件添加一个新节以显示启动信息。这个东东会在 PE 文件的末尾添加一个新节,我给这个节命名为“.LC”,被附加的程序在运行的时候会先弹出一个对话框,显示我们的提示信息。你可以对它稍作修改,例如加上自己的版权信息,然后给 CS 的主程序打上这个“病毒”,接着……呵呵,等着看舍友的惊讶的目光吧!实际上只要对它进行一些额外的补充,它就可以算是一个小小的病毒了。

值得注意的是,本程序要对代码段进行写操作(也就是SMC),所以在编译连接的时候应该这样做:

rc Add_Section.rc
ml /c /coff Add_Section.asm
link /subsystem:windows /section:.text,RWE Add_Section.res Add_Section.obj

Have fun!

;***********************************************
;程序名称:为PE文件添加新节显示启动信息
;作者:罗聪
;日期:2002-11-10
;出处:http://www.luocong.com(老罗的缤纷天地)
;本代码使用了病毒技术,但纯粹只用于技术研究。
;切记:请勿用于非法用途!!!!!!
;注意事项:如欲转载,请保持本程序的完整,并注明:
;转载自“老罗的缤纷天地”(http://www.luocong.com)
;***********************************************

.386
.model flat, stdcall
option casemap:none

include /masm32/include/windows.inc
include /masm32/include/kernel32.inc
include /masm32/include/user32.inc
include /masm32/include/comdlg32.inc
includelib /masm32/lib/kernel32.lib
includelib /masm32/lib/user32.lib
includelib /masm32/lib/comdlg32.lib

WndProc          proto :DWORD, :DWORD, :DWORD, :DWORD
AddNewSection    proto :DWORD

;很有用的宏:
CTEXT    MACRO y:VARARG
    LOCAL sym
    CONST segment
    ifidni <y>,<>            
        sym db 0        
    else            
        sym db y,0
    endif
    CONST ends
    exitm <offset sym>
ENDM

.const
IDI_LC           equ    1
IDC_BUTTON_OPEN  equ    3000
MAXSIZE          
阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itaolu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值