Skip to content

Commit ab53481

Browse files
committed
Aggiunte nuove euristiche sulle sezioni
1 parent e1836e8 commit ab53481

16 files changed

Lines changed: 381 additions & 123 deletions

formats/elf/sections.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ func parseSections64(endianness binary.ByteOrder, shnum uint16, table uint16) []
5252
return nil
5353
}
5454
buffer := make([]byte, headers[i].Size)
55-
binary.Read(reader, endianness, &buffer)
55+
err = binary.Read(reader, endianness, &buffer)
56+
if err != nil {
57+
fmt.Println("Impossibile leggere la sezione")
58+
return nil
59+
}
5660
tmp.Raw = buffer
5761
tmp.Entropy = utils.CalculateEntropy(tmp.Raw)
5862
} else {

formats/pe/exports.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ func readExports(virtualAddress uint32) {
3131

3232
if err != nil {
3333
fmt.Println("Impossibile leggere la struttura exportDirectory " + err.Error())
34+
return
35+
}
36+
37+
if exportDirectory.NumberOfFunctions == 0 {
38+
fmt.Println("Attenzione: numero di funzioni esportate uguale a 0")
39+
return
3440
}
3541

3642
namesTableRVA := exportDirectory.NameRva - section.VirtualAddress
@@ -39,11 +45,10 @@ func readExports(virtualAddress uint32) {
3945

4046
fileAnalyzed.ExportNameMap = make(map[string]*Export)
4147
fileAnalyzed.ExportOrdinalMap = make(map[int]*Export)
42-
48+
fmt.Printf("%d \n", exportDirectory.NumberOfName)
4349
// Per ogni entry della tabella degli exports
4450
for i := 0; i < int(exportDirectory.NumberOfName); i++ {
4551

46-
//
4752
_, err = reader.Seek(int64(namesTableRVA+uint32(i*4)), io.SeekStart)
4853
if err != nil {
4954
fmt.Println("Errore nel seek per la tabella delle funzioni esportate")
@@ -56,7 +61,7 @@ func readExports(virtualAddress uint32) {
5661
fmt.Println("Impossibile leggere la struttura ExportAddressTable per il seguente motivo : " + err.Error())
5762
return
5863
}
59-
64+
fmt.Printf("%+v \n", exportAddressTable)
6065
name := utils.ReadString(section.Raw[exportAddressTable.ExportRva-section.VirtualAddress:])
6166
ordinal = binary.LittleEndian.Uint16(section.Raw[ordinalsTableRVA+uint32(i*2) : ordinalsTableRVA+uint32(i*2)+2])
6267
_, err = reader.Seek(int64(uint32(ordinal)*4+exportDirectory.AddressOfFunctions-section.VirtualAddress), io.SeekStart)

formats/pe/pe.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ func Analysis(PEStruct *PEBINARY, content []byte) {
226226

227227
// Se, all'interno del binario, la dimensione della sezione per l'export è diverso 0, procediamo con la lettura degli export
228228
if DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].Size != 0 {
229-
readExports(DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
229+
//readExports(DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
230230
}
231231

232232
// Sezione Import
@@ -253,6 +253,7 @@ func Analysis(PEStruct *PEBINARY, content []byte) {
253253
err = binary.Read(reader, binary.LittleEndian, &contenuto)
254254
fileAnalyzed.Resource[i].Content = contenuto
255255
fileAnalyzed.Resource[i].ContentType = utils.IdentifyFile(contenuto)
256+
fileAnalyzed.Resource[i].Entropy = utils.CalculateEntropy(contenuto)
256257
if fileAnalyzed.Resource[i].Name == "" {
257258
fileAnalyzed.Resource[i].Name = PrintResource(fileAnalyzed.Resource[i].Type)
258259
}

formats/pe/pe_structs.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ type Section struct {
162162
type ExportDirectory struct {
163163
Characteristics uint32 // In genere tutti zero per PE, campo riservato
164164
TimeDateStamp uint32 // data di creazione
165-
MajorVersion uint32 // Riservato: zero
166-
MinorVersion uint32 // Riservato: zero
165+
MajorVersion uint16 // Riservato: zero
166+
MinorVersion uint16 // Riservato: zero
167167
NameRva uint32 // RVA che punta al nome del modulo
168168
OrdinalBase uint32 // Numero che va sommato all'indice per ottenere l'ordinal della funzione
169169
NumberOfFunctions uint32 // Numero di funzioni esportate dal modulo
@@ -231,12 +231,14 @@ type ResourceDirString struct {
231231
}
232232

233233
type Resource struct {
234-
Name string
235-
Offset uint64
236-
Size uint64
237-
Content []byte
238-
Type int
239-
ContentType string
234+
Name string
235+
Offset uint64
236+
Size uint64
237+
Content []byte
238+
Type int
239+
ContentType string
240+
TimedateStamp uint32
241+
Entropy float64
240242
}
241243

242244
// CompID è una struttura che riporta le informazioni del compilatore all'interno del RichHeader.
@@ -322,9 +324,10 @@ type WinCertificate struct {
322324
}
323325

324326
type SecurityHeader struct {
325-
Header WinCertificate
326-
Content *pkcs7.PKCS7
327-
IsSigned bool
327+
Header WinCertificate
328+
Content *pkcs7.PKCS7
329+
IsSigned bool
330+
ReasonFail string
328331
}
329332

330333
// APISET

formats/pe/resources.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ func readResourceDirectory(virtualAddress uint32) {
8181
var single byte
8282
// Lettura della stringa
8383
for j := 0; j <= int(ResourceDir.Length)*2; j = j + 1 {
84+
// Lettura della stringa byte per byte
8485
err = binary.Read(reader, binary.LittleEndian, &single)
8586
if err != nil {
8687
fmt.Println("Impossibile leggere la struttura byte per il seguente motivo " + err.Error())
@@ -93,6 +94,7 @@ func readResourceDirectory(virtualAddress uint32) {
9394
_, err = reader.Seek(seekPosition, io.SeekStart)
9495
if err != nil {
9596
fmt.Println("Impossibile riallineare l'offset allo stato iniziale per il seguente errore " + err.Error())
97+
return
9698
}
9799
} else {
98100
// PrintResource(int(ImgTmp.Name))
@@ -210,7 +212,7 @@ func readResourceDirectory(virtualAddress uint32) {
210212
return
211213
}
212214

213-
resourceTmpFrom := Resource{Name: string(tmpString), Type: int(ImgResDirEntry[i].Name), Offset: uint64(resourceTmp.Offset), Size: uint64(resourceTmp.Size), Content: nil}
215+
resourceTmpFrom := Resource{Name: string(tmpString), Type: int(ImgResDirEntry[i].Name), Offset: uint64(resourceTmp.Offset), Size: uint64(resourceTmp.Size), Content: nil, TimedateStamp: resource.TimeDateStamp}
214216
fileAnalyzed.Resource = append(fileAnalyzed.Resource, resourceTmpFrom)
215217
}
216218
_, err = reader.Seek(seekPosition, io.SeekStart)

formats/pe/security.go

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package pe
22

33
import (
4-
"bytes"
54
"crypto/x509"
65
"encoding/binary"
76
"fmt"
@@ -19,17 +18,16 @@ func readSecuritySection(virtualAddress uint32) {
1918
return
2019
}
2120

22-
offset := virtualAddress - section.VirtualAddress
21+
//offset := virtualAddress - section.VirtualAddress
22+
offset := virtualAddress
2323
if offset < 0 {
2424
fmt.Println("L'offset non può essere minore di 0.")
2525
return
2626
}
2727

28-
readerRaw := bytes.NewReader(section.Raw)
29-
3028
for {
31-
_, err := readerRaw.Seek(int64(offset), io.SeekStart)
32-
29+
_, err := reader.Seek(int64(offset), io.SeekStart)
30+
var reasonString string
3331
if err != nil {
3432
fmt.Println("Impossibile effettuare il seek per il seguente motivo: " + err.Error())
3533
return
@@ -38,9 +36,9 @@ func readSecuritySection(virtualAddress uint32) {
3836
// Parsa ogni certificato
3937
var Certificate WinCertificate
4038

41-
err = binary.Read(readerRaw, binary.LittleEndian, &Certificate)
39+
err = binary.Read(reader, binary.LittleEndian, &Certificate)
4240
if err != nil {
43-
fmt.Println("Impossibile leggere la struttura WinCertificate")
41+
fmt.Println("Impossibile leggere la struttura WinCertificate per il seguente motivo: " + err.Error())
4442
return
4543
}
4644

@@ -49,16 +47,20 @@ func readSecuritySection(virtualAddress uint32) {
4947
return
5048
}
5149

52-
certificateContent := make([]byte, Certificate.Length)
53-
err = binary.Read(readerRaw, binary.LittleEndian, certificateContent)
50+
fmt.Printf("%+v\n", Certificate)
51+
52+
certificateContent := make([]byte, Certificate.Length-uint32(binary.Size(WinCertificate{})))
53+
err = binary.Read(reader, binary.LittleEndian, certificateContent)
5454
if err != nil {
5555
fmt.Println("Impossibile leggere il contenuto del certificato " + err.Error())
5656
return
5757
}
5858

5959
pkcs, err := pkcs7.Parse(certificateContent)
6060
if err != nil {
61-
fmt.Println("Errore: il certificato non è valido")
61+
reasonString = err.Error()
62+
fmt.Println("Errore: il certificato non è valido: " + reasonString)
63+
fileAnalyzed.SecuritySection = append(fileAnalyzed.SecuritySection, SecurityHeader{Header: Certificate, Content: pkcs, IsSigned: false, ReasonFail: reasonString})
6264
return
6365
}
6466

@@ -71,13 +73,14 @@ func readSecuritySection(virtualAddress uint32) {
7173
isValid := true
7274
err = pkcs.VerifyWithChain(certPool)
7375
if err != nil {
74-
fmt.Println("Il certificato non è valido")
76+
reasonString = err.Error()
77+
fmt.Println("Il certificato non è valido: " + err.Error())
7578
isValid = false
7679
}
7780

7881
offset = Certificate.Length + offset
7982
offset = offset + 8 - 1
80-
fileAnalyzed.SecuritySection = append(fileAnalyzed.SecuritySection, SecurityHeader{Header: Certificate, Content: pkcs, IsSigned: isValid})
83+
fileAnalyzed.SecuritySection = append(fileAnalyzed.SecuritySection, SecurityHeader{Header: Certificate, Content: pkcs, IsSigned: isValid, ReasonFail: reasonString})
8184
}
8285

8386
}

heuristics/dotnet_heuristics.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package heuristics
2+
3+
import "strings"
4+
5+
func CalculatePointsStringDOTNET(extractedStrings []string) {
6+
7+
// Tutti gli import dei binari .NET
8+
NetImports := map[string]int{
9+
"Systems.diagnostic": 2,
10+
"GetProcessesByName": 10,
11+
"get_SpecialDirectories": 20,
12+
"get_FileSystem": 2,
13+
"SpecialDirectoriesProxy": 10,
14+
"setShowInTaskBar": 20,
15+
"AESEncryptFile": 10,
16+
"AESDecryptFile": 10,
17+
"AESEncryptBytes": 10,
18+
"AESDecryptBytes": 10,
19+
}
20+
21+
for i := 0; i < len(extractedStrings); i++ {
22+
for stringToCompare, pointsToAdd := range NetImports {
23+
if strings.Contains(extractedStrings[i], stringToCompare) {
24+
InsertAnomalyString("La stringa "+extractedStrings[i]+" indica una funzione strettamente correlata ad un ransomware codificato in .NET.", pointsToAdd)
25+
}
26+
}
27+
}
28+
29+
//AESEncryptFile, AESDecryptFile, AESEncryptBytes,AESDecryptBytes,CheckPassword,GenerateKey 20 per ognuno tranne gli ultimi due
30+
// System.Security.Cryptography,AesCryptoServiceProvider
31+
}

heuristics/heuristics.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,24 @@ func Execute(analyzed *formats.FileAnalyzed) {
1818

1919
if analyzed.Format == "PE" {
2020

21-
var isDotNet bool
2221
if len(analyzed.PEInterface.Imports) == 1 {
2322
if analyzed.PEInterface.Imports[0].APICalled == "_CorExeMain" {
24-
isDotNet = true
2523
InsertAnomalyOthers("Il programma è un file eseguibile .NET.", 0)
24+
CalculatePointsStringDOTNET(analyzed.ExtractedStrings)
2625
}
2726
}
2827

2928
// Binario Tradizionale
3029
// Euristica sulle intestazioni
3130
CheckHeaders()
3231
// Euristica sulle stringhe
33-
CalculatePointsStringPE(analyzed.ExtractedStrings, isDotNet)
32+
CalculatePointsStringPE(analyzed.ExtractedStrings)
3433
// Euristica sugli imports
3534
CalculatePointsImports(analyzed.PEInterface.Imports)
3635
// Euristica sull'entropia
3736
CalculatePointsEntropy(analyzed.PEInterface.Sections)
38-
37+
// Euristica sulle risorse
38+
CalculatePointsResources(analyzed.PEInterface.Resource)
3939
// Euristica sui binari signed/unsigned
4040
CalculatePointsSecurity(analyzed.PEInterface.SecuritySection)
4141
}

heuristics/pe_headers_heuristics.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,6 @@ func CheckOptionalHeader32(header pe.PEOptionalHeaderT) {
8787
InsertAnomalyFileFormat("ImageDataDirectory valore invalido.", 10)
8888
}
8989

90-
if int(header.NumberOfRvaAndSizes) != len(FileAnalyzed.PEInterface.Sections) {
91-
InsertAnomalyFileFormat("Il numero delle sezioni è diverso rispetto a quello dichiarato. Valore ottenuto: "+strconv.Itoa(int(header.NumberOfRvaAndSizes))+", numero di sezioni effettive: "+strconv.Itoa(len(FileAnalyzed.PEInterface.Sections)), 10)
92-
}
93-
9490
if header.LoaderFlags != 0 {
9591
InsertAnomalyFileFormat("Attenzione: LoaderFlags diverso da zero.", 10)
9692
}
@@ -178,6 +174,10 @@ func CheckCOFFHeader(CoffHeader *pe.COFFHeaderT) {
178174
InsertAnomalyFileFormat("Attenzione: il numero di sezioni non può essere minore di 1.", 10)
179175
}
180176

177+
if int(CoffHeader.NumberOfSections) != len(FileAnalyzed.PEInterface.Sections) {
178+
InsertAnomalyFileFormat("Il numero delle sezioni è diverso rispetto a quello dichiarato. Valore ottenuto: "+strconv.Itoa(int(CoffHeader.NumberOfSections))+", numero di sezioni effettive: "+strconv.Itoa(len(FileAnalyzed.PEInterface.Sections)), 10)
179+
}
180+
181181
// Un programma di solito ha NOVE sezioni predefinite (.text, .bss, .rdata, .data, .rsrc, .edata, .idata, .pdata e .debug)
182182
// Windows NT 5 o precedenti: valore non può essere maggiore di 96
183183
// Windows NT 6: valore può raggiungere 65535
@@ -218,8 +218,17 @@ func CheckCOFFHeader(CoffHeader *pe.COFFHeaderT) {
218218
InsertAnomalyFileFormat("SizeOfOptionalHeader è zero.", 10)
219219
}
220220

221-
if CoffHeader.SizeOfOptionalHeader > uint16(binary.Size(pe.COFFHeaderT{})) {
222-
InsertAnomalyFileFormat("La dimensione della SizeOfOptionalHeader è particolare. Valore ottenuto: "+strconv.Itoa(int(CoffHeader.SizeOfOptionalHeader))+".", 10)
221+
sizePrevista32bit := 4 + uint16(binary.Size(pe.PEOptionalHeaderT{})) + uint16(binary.Size(pe.ImageDataDirectory{})*16)
222+
sizePrevista64bit := 4 + uint16(binary.Size(pe.PEPOptionalHeaderT{})) + uint16(binary.Size(pe.ImageDataDirectory{})*16)
223+
224+
if FileAnalyzed.PEInterface.Is64bit {
225+
if CoffHeader.SizeOfOptionalHeader > sizePrevista64bit {
226+
InsertAnomalyFileFormat("La dimensione della SizeOfOptionalHeader è particolare. Valore ottenuto: "+strconv.Itoa(int(CoffHeader.SizeOfOptionalHeader))+".", 10)
227+
}
228+
} else {
229+
if CoffHeader.SizeOfOptionalHeader > sizePrevista32bit {
230+
InsertAnomalyFileFormat("La dimensione della SizeOfOptionalHeader è particolare. Valore ottenuto: "+strconv.Itoa(int(CoffHeader.SizeOfOptionalHeader))+".", 10)
231+
}
223232
}
224233

225234
}

heuristics/resources_heuristics.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ func CalculatePointsResources(resources []pe.Resource) {
1818
if resources[i].Size == 0 {
1919
blank++
2020
}
21+
22+
if resources[i].Entropy >= 6.6 {
23+
InsertAnomalyOthers("Il binario contiene delle risorse offuscate", 20)
24+
}
2125
}
2226

2327
if binary > 0 {

0 commit comments

Comments
 (0)