Golang : Simple file scaning and remove virus example
Just for fun, for this tutorial, we will simulate a simple anti-virus program. Let's create a simple file scanner that will detect a virus signature and remove the bytes associated with the file virus.
Now, this is a trivial example, it looks for a string that has been identified as a virus body and will remove the entire body of the virus. It won't be able to detect obfuscated/polymorphic virus code. You will have to add your own "advanced" features into the code.
The code example below will attempt to scan a file block by block and report to you where it detected a virus/virii base on a given signature.
Here you go!
antivirus.go
package main
import (
"bytes"
"fmt"
"io/ioutil"
"math"
"os"
"strings"
)
// because in this example we will scan a small file
// we just settle for 1KB chunk per block
const fileChunk = 1024
var (
virusSignature = []byte("<hello I am a computer virus. yeah!>")
startSignature = "<hello"
endSignature = "yeah!>"
)
func main() {
if len(os.Args) != 2 {
fmt.Printf("Usage : %s <filename to scan> \n", os.Args[0])
os.Exit(0)
}
fileToScan := os.Args[1]
fmt.Printf("Scanning %s....\n", fileToScan)
file, err := os.Open(fileToScan)
if err != nil {
fmt.Println("Unable to open file : ", err)
os.Exit(-1)
}
defer file.Close()
// calculate the file size
info, _ := file.Stat()
filesize := info.Size()
blocks := uint64(math.Ceil(float64(filesize) / float64(fileChunk)))
// we scan the file for virusSignature
// block by block
for i := uint64(0); i < blocks; i++ {
blocksize := int(math.Min(fileChunk, float64(filesize-int64(i*fileChunk))))
buf := make([]byte, blocksize)
fmt.Printf("Scanning block #%d , size of %d\n", i, blocksize)
file.Read(buf)
if strings.Contains(string(buf), string(virusSignature)) {
//fmt.Println(string(buf))
fmt.Println("Found virus signature at block # : ", i)
// we want to find the out start and end positions of the signature
start := strings.Index(string(buf), startSignature)
end := strings.LastIndex(string(buf), endSignature)
// sanity check - verify
fmt.Println("Virus signature size is : ", len(virusSignature))
// because of LastIndex returning the first index
// calcuting (end - start) alone will be inaccurate.
// we need to compensate for len(endSignature)
virusSize := ((end - start) + len(endSignature))
fmt.Println("Detected virus size is : ", virusSize)
// calculate start and end positions(offsets) relative to file
// you can use this information for ReadAt() or Seek() operations
// but because this is a simple virus scanner and removal
// we will just use the bytes.Replace() function below
startPosition := (i * fileChunk) + uint64(start)
endPosition := startPosition + uint64(virusSize)
fmt.Println("Infection start position : ", startPosition)
fmt.Println("Infection end position : ", endPosition)
//ok, let us create a new file without the virus signature
// ignoring error for simplicty sake
infectedFile, _ := ioutil.ReadFile(fileToScan)
//
cleanedFile := bytes.Replace(infectedFile, virusSignature, []byte(""), -1)
if err = ioutil.WriteFile("cleanedFile", cleanedFile, 0666); err != nil {
fmt.Println(err)
os.Exit(-1)
}
fmt.Printf("Disinfected %s and saved clean file to cleanedFile.\n", fileToScan)
}
}
}
Sample output of scanning a text file:
./antivirus suspiciousFile.go
Scanning suspiciousFile.go....
Scanning block #0 , size of 196
Found virus signature at block # : 0
Virus signature size is : 36
Detected virus size is : 36
Infection start position : 76
Infection end position : 112
Disinfected suspiciousFile.go and saved clean file to cleanedFile.
and the suspiciousFile.go
/ cleanedFile
content.
package main
import "fmt"
func virusFunc() {
greeting := []byte("<hello I am a computer virus. yeah!>")
fmt.Println(string(greeting))
}
func main() {
fmt.Printf("Hello World!\n")
}
cleanedFile
- notice the diff?
package main
import "fmt"
func virusFunc() {
greeting := []byte("")
fmt.Println(string(greeting))
}
func main() {
fmt.Printf("Hello World!\n")
}
try scanning a binary file that has the virus signature, it works as well.
Happy coding!
References:
https://www.socketloop.com/tutorials/golang-read-a-text-file-and-replace-certain-words
https://socketloop.com/references/golang-os-file-read-and-seek-functions-example
https://www.socketloop.com/references/golang-bytes-reader-readat-function-example
https://golang.org/pkg/strings/#LastIndex
https://golang.org/pkg/strings/#Index
https://www.socketloop.com/tutorials/how-to-generate-checksum-for-file-in-go
See also : Golang : Convert file content to Hex
By Adam Ng
IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.
Advertisement
Tutorials
+5.1k Golang : Get FX sentiment from website example
+12.4k Golang : Send data to /dev/null a.k.a blackhole with ioutil.Discard
+6.9k Golang : A simple forex opportunities scanner
+17.6k Golang : Simple client server example
+7k Golang : Use modern ciphers only in secure connection
+5.2k Golang : Return multiple values from function
+10.5k Golang : Simple File Server
+30.2k Get client IP Address in Go
+16.2k CodeIgniter/PHP : Create directory if does not exist example
+7.4k Golang : Mapping Iban to Dunging alphabets