Remove nm and readelf subroutines and replace them by elf package API
Signed-off-by: Gaulthier Gain <gaulthier.gain@uliege.be>
This commit is contained in:
parent
c1c9f21b7e
commit
597c47c27d
4 changed files with 78 additions and 111 deletions
|
@ -48,7 +48,6 @@ func getElf(filename string) (*elf.File, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
_elf, err := elf.NewFile(f)
|
_elf, err := elf.NewFile(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -25,68 +25,6 @@ type recursiveData struct {
|
||||||
|
|
||||||
// --------------------------------Static Output--------------------------------
|
// --------------------------------Static Output--------------------------------
|
||||||
|
|
||||||
// parseReadELF parses the output of the 'readelf' command.
|
|
||||||
//
|
|
||||||
func parseReadELF(output string, data *u.StaticData) {
|
|
||||||
types := map[string]bool{"FUNC": true, "FILE": true, "OBJECT": true}
|
|
||||||
|
|
||||||
// Check the output of 'readelf' command
|
|
||||||
for _, line := range strings.Split(output, "\n") {
|
|
||||||
words := strings.Fields(line)
|
|
||||||
|
|
||||||
if len(words) > 8 && types[words[3]] {
|
|
||||||
symbol := strings.Split(words[7], "@")
|
|
||||||
if len(symbol) > 2 {
|
|
||||||
data.Symbols[symbol[0]] = symbol[1]
|
|
||||||
} else {
|
|
||||||
data.Symbols[words[7]] = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseNMMacos parses the output of the 'nm' command (Mac os).
|
|
||||||
//
|
|
||||||
func parseNMMac(output string, data *u.StaticData) {
|
|
||||||
// Get the list of system calls
|
|
||||||
systemCalls := initSystemCalls()
|
|
||||||
|
|
||||||
// Check the output of 'nm' command
|
|
||||||
var re = regexp.MustCompile(`(?m)([U|T|B|D]\s)(.*)\s*`)
|
|
||||||
for _, match := range re.FindAllStringSubmatch(output, -1) {
|
|
||||||
if len(match) > 2 {
|
|
||||||
if match[2][0] == '_' {
|
|
||||||
match[2] = match[2][1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add to system calls map if symbol is a system call
|
|
||||||
if _, isSyscall := systemCalls[match[2]]; isSyscall {
|
|
||||||
data.SystemCalls[match[2]] = systemCalls[match[2]]
|
|
||||||
} else {
|
|
||||||
data.Symbols[match[2]] = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseNMLinux parses the output of the 'nm' command (Linux).
|
|
||||||
//
|
|
||||||
func parseNMLinux(output string, data *u.StaticData) {
|
|
||||||
// Get the list of system calls
|
|
||||||
systemCalls := initSystemCalls()
|
|
||||||
|
|
||||||
// Check the output of 'nm' command
|
|
||||||
var re = regexp.MustCompile(`(?m)([U|u|T|t|w|W]\s)(.*)\s*`)
|
|
||||||
for _, match := range re.FindAllStringSubmatch(output, -1) {
|
|
||||||
// Add to system calls map if symbol is a system call
|
|
||||||
if _, isSyscall := systemCalls[match[2]]; isSyscall {
|
|
||||||
data.SystemCalls[match[2]] = systemCalls[match[2]]
|
|
||||||
} else {
|
|
||||||
data.Symbols[match[2]] = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parsePackagesName parses the output of the 'apt-cache pkgnames' command.
|
// parsePackagesName parses the output of the 'apt-cache pkgnames' command.
|
||||||
//
|
//
|
||||||
// It returns a string which represents the name of application used by the
|
// It returns a string which represents the name of application used by the
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dependtool
|
package dependtool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"debug/elf"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
|
@ -52,8 +53,11 @@ func RunAnalyserTool(homeDir string, data *u.Data) {
|
||||||
displayProgramDetails(programName, programPath, args)
|
displayProgramDetails(programName, programPath, args)
|
||||||
|
|
||||||
// Check if the program is a binary
|
// Check if the program is a binary
|
||||||
|
|
||||||
|
var elfFile *elf.File
|
||||||
|
dynamicCompiled := false
|
||||||
if strings.ToLower(runtime.GOOS) == "linux" {
|
if strings.ToLower(runtime.GOOS) == "linux" {
|
||||||
checkElf(&programPath)
|
elfFile, dynamicCompiled = checkElf(&programPath)
|
||||||
} else if strings.ToLower(runtime.GOOS) == "darwin" {
|
} else if strings.ToLower(runtime.GOOS) == "darwin" {
|
||||||
checkMachOS(&programPath)
|
checkMachOS(&programPath)
|
||||||
}
|
}
|
||||||
|
@ -61,7 +65,7 @@ func RunAnalyserTool(homeDir string, data *u.Data) {
|
||||||
if typeAnalysis == 0 || typeAnalysis == 1 {
|
if typeAnalysis == 0 || typeAnalysis == 1 {
|
||||||
// Run static analyser
|
// Run static analyser
|
||||||
u.PrintHeader1("(1.1) RUN STATIC ANALYSIS")
|
u.PrintHeader1("(1.1) RUN STATIC ANALYSIS")
|
||||||
runStaticAnalyser(args, programName, programPath, outFolder, data)
|
runStaticAnalyser(elfFile, dynamicCompiled, args, programName, programPath, outFolder, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run dynamic analyser
|
// Run dynamic analyser
|
||||||
|
@ -117,7 +121,8 @@ func checkMachOS(programPath *string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkElf checks if the program (from its path) is an ELF file
|
// checkElf checks if the program (from its path) is an ELF file
|
||||||
func checkElf(programPath *string) {
|
func checkElf(programPath *string) (*elf.File, bool) {
|
||||||
|
dynamicCompiled := false
|
||||||
elfFile, err := getElf(*programPath)
|
elfFile, err := getElf(*programPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
u.PrintErr(err)
|
u.PrintErr(err)
|
||||||
|
@ -126,20 +131,32 @@ func checkElf(programPath *string) {
|
||||||
u.PrintWarning("Only ELF binaries are supported! Some analysis" +
|
u.PrintWarning("Only ELF binaries are supported! Some analysis" +
|
||||||
" procedures will be skipped")
|
" procedures will be skipped")
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Get ELF architecture
|
// Get ELF architecture
|
||||||
architecture, machine := GetElfArchitecture(elfFile)
|
architecture, machine := GetElfArchitecture(elfFile)
|
||||||
fmt.Println("ELF Class: ", architecture)
|
fmt.Println("ELF Class: ", architecture)
|
||||||
fmt.Println("Machine: ", machine)
|
fmt.Println("Machine: ", machine)
|
||||||
fmt.Println("Entry Point: ", elfFile.Entry)
|
fmt.Println("Entry Point: ", elfFile.Entry)
|
||||||
|
for _, s := range elfFile.Sections {
|
||||||
|
if strings.Contains(s.Name, ".dynamic") {
|
||||||
|
fmt.Println("Type: Dynamically compiled")
|
||||||
|
dynamicCompiled = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !dynamicCompiled {
|
||||||
|
fmt.Println("Type: Statically compiled")
|
||||||
|
}
|
||||||
fmt.Println("----------------------------------------------")
|
fmt.Println("----------------------------------------------")
|
||||||
}
|
}
|
||||||
|
return elfFile, dynamicCompiled
|
||||||
}
|
}
|
||||||
|
|
||||||
// runStaticAnalyser runs the static analyser
|
// runStaticAnalyser runs the static analyser
|
||||||
func runStaticAnalyser(args *u.Arguments, programName, programPath,
|
func runStaticAnalyser(elfFile *elf.File, dynamicCompiled bool, args *u.Arguments, programName, programPath,
|
||||||
outFolder string, data *u.Data) {
|
outFolder string, data *u.Data) {
|
||||||
|
|
||||||
staticAnalyser(*args, data, programPath)
|
staticAnalyser(elfFile, dynamicCompiled, *args, data, programPath)
|
||||||
|
|
||||||
// Save static Data into text file if display mode is set
|
// Save static Data into text file if display mode is set
|
||||||
if *args.BoolArg[saveOutputArg] {
|
if *args.BoolArg[saveOutputArg] {
|
||||||
|
|
|
@ -8,6 +8,7 @@ package dependtool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"debug/elf"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -17,41 +18,55 @@ import (
|
||||||
|
|
||||||
// ---------------------------------Gather Data---------------------------------
|
// ---------------------------------Gather Data---------------------------------
|
||||||
|
|
||||||
|
func addSymbols(symbols []elf.Symbol, data *u.StaticData, systemCalls map[string]int) {
|
||||||
|
for _, s := range symbols {
|
||||||
|
if _, isSyscall := systemCalls[s.Name]; isSyscall {
|
||||||
|
data.SystemCalls[s.Name] = systemCalls[s.Name]
|
||||||
|
} else {
|
||||||
|
data.Symbols[s.Name] = s.Library
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// gatherStaticSymbols gathers symbols of a given application.
|
// gatherStaticSymbols gathers symbols of a given application.
|
||||||
//
|
//
|
||||||
// It returns an error if any, otherwise it returns nil.
|
// It returns an error if any, otherwise it returns nil.
|
||||||
func gatherStaticSymbols(programPath string, data *u.StaticData) error {
|
func gatherStaticSymbols(elfFile *elf.File, dynamicCompiled bool, data *u.StaticData) error {
|
||||||
|
|
||||||
// Use 'readelf' to get symbols
|
// Get the list of system calls
|
||||||
if output, err := u.ExecuteCommand("readelf", []string{"-s",
|
systemCalls := initSystemCalls()
|
||||||
programPath}); err != nil {
|
|
||||||
return err
|
symbols, err := elfFile.Symbols()
|
||||||
|
if err != nil {
|
||||||
|
if !dynamicCompiled {
|
||||||
|
// Skip message for dynamically compiled binary
|
||||||
|
u.PrintWarning(err)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
parseReadELF(output, data)
|
addSymbols(symbols, data, systemCalls)
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// gatherStaticSymbols gathers system calls of a given application.
|
|
||||||
//
|
|
||||||
// It returns an error if any, otherwise it returns nil.
|
|
||||||
func gatherStaticSystemCalls(programPath, argument string, data *u.StaticData) error {
|
|
||||||
|
|
||||||
var args []string
|
|
||||||
if len(argument) > 0 {
|
|
||||||
args = []string{argument, programPath}
|
|
||||||
} else {
|
|
||||||
args = []string{programPath}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use 'nm' to get symbols and system calls
|
// Additional symbols when dynamically compiled
|
||||||
if output, err := u.ExecuteCommand("nm", args); err != nil {
|
if dynamicCompiled {
|
||||||
return err
|
|
||||||
} else {
|
symbols, err = elfFile.DynamicSymbols()
|
||||||
if strings.ToLower(runtime.GOOS) == "linux" {
|
if err != nil {
|
||||||
parseNMLinux(output, data)
|
u.PrintWarning(err)
|
||||||
} else {
|
} else {
|
||||||
parseNMMac(output, data)
|
addSymbols(symbols, data, systemCalls)
|
||||||
|
}
|
||||||
|
|
||||||
|
importedSymbols, err := elfFile.ImportedSymbols()
|
||||||
|
if err != nil {
|
||||||
|
u.PrintWarning(err)
|
||||||
|
} else {
|
||||||
|
for _, s := range importedSymbols {
|
||||||
|
if _, isSyscall := systemCalls[s.Name]; isSyscall {
|
||||||
|
data.SystemCalls[s.Name] = systemCalls[s.Name]
|
||||||
|
} else {
|
||||||
|
data.Symbols[s.Name] = s.Library
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -177,7 +192,7 @@ func executeDependAptCache(programName string, data *u.StaticData,
|
||||||
// staticAnalyser runs the static analysis to get shared libraries,
|
// staticAnalyser runs the static analysis to get shared libraries,
|
||||||
// system calls and library calls of a given application.
|
// system calls and library calls of a given application.
|
||||||
//
|
//
|
||||||
func staticAnalyser(args u.Arguments, data *u.Data, programPath string) {
|
func staticAnalyser(elfFile *elf.File, dynamicCompiled bool, args u.Arguments, data *u.Data, programPath string) {
|
||||||
|
|
||||||
programName := *args.StringArg[programArg]
|
programName := *args.StringArg[programArg]
|
||||||
fullDeps := *args.BoolArg[fullDepsArg]
|
fullDeps := *args.BoolArg[fullDepsArg]
|
||||||
|
@ -196,21 +211,14 @@ func staticAnalyser(args u.Arguments, data *u.Data, programPath string) {
|
||||||
|
|
||||||
if strings.ToLower(runtime.GOOS) == "linux" {
|
if strings.ToLower(runtime.GOOS) == "linux" {
|
||||||
u.PrintHeader2("(*) Gathering symbols from binary file")
|
u.PrintHeader2("(*) Gathering symbols from binary file")
|
||||||
if err := gatherStaticSymbols(programPath, staticData); err != nil {
|
if err := gatherStaticSymbols(elfFile, dynamicCompiled, staticData); err != nil {
|
||||||
u.PrintWarning(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u.PrintHeader2("(*) Gathering symbols & system calls from binary file")
|
|
||||||
if err := gatherStaticSystemCalls(programPath, "-D", staticData); err != nil {
|
|
||||||
// Check without the dynamic argument
|
|
||||||
if err := gatherStaticSystemCalls(programPath, "", staticData); err != nil {
|
|
||||||
u.PrintWarning(err)
|
u.PrintWarning(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u.PrintHeader2("(*) Gathering shared libraries from binary file")
|
u.PrintHeader2("(*) Gathering shared libraries from binary file")
|
||||||
if strings.ToLower(runtime.GOOS) == "linux" {
|
if strings.ToLower(runtime.GOOS) == "linux" {
|
||||||
|
// Cannot use "elfFile.ImportedLibraries()" since we need the .so path
|
||||||
if err := gatherStaticSharedLibsLinux(programPath, staticData,
|
if err := gatherStaticSharedLibsLinux(programPath, staticData,
|
||||||
fullDeps); err != nil {
|
fullDeps); err != nil {
|
||||||
u.PrintWarning(err)
|
u.PrintWarning(err)
|
||||||
|
@ -221,6 +229,10 @@ func staticAnalyser(args u.Arguments, data *u.Data, programPath string) {
|
||||||
u.PrintWarning(err)
|
u.PrintWarning(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := elfFile.Close(); err != nil {
|
||||||
|
u.PrintWarning(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect symbols from shared libraries
|
// Detect symbols from shared libraries
|
||||||
|
@ -229,14 +241,15 @@ func staticAnalyser(args u.Arguments, data *u.Data, programPath string) {
|
||||||
for key, path := range staticData.SharedLibs {
|
for key, path := range staticData.SharedLibs {
|
||||||
if len(path) > 0 {
|
if len(path) > 0 {
|
||||||
fmt.Printf("\t-> Analysing %s - %s\n", key, path[0])
|
fmt.Printf("\t-> Analysing %s - %s\n", key, path[0])
|
||||||
if err := gatherStaticSymbols(path[0], staticData); err != nil {
|
libElf, err := getElf(path[0])
|
||||||
|
if err != nil {
|
||||||
u.PrintWarning(err)
|
u.PrintWarning(err)
|
||||||
}
|
}
|
||||||
if err := gatherStaticSystemCalls(path[0], "-D", staticData); err != nil {
|
if err := gatherStaticSymbols(libElf, true, staticData); err != nil {
|
||||||
// Check without the dynamic argument
|
u.PrintWarning(err)
|
||||||
if err := gatherStaticSystemCalls(path[0], "", staticData); err != nil {
|
}
|
||||||
u.PrintWarning(err)
|
if err := libElf.Close(); err != nil {
|
||||||
}
|
u.PrintWarning(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue