-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add mach-o support * Update readme
- Loading branch information
Showing
13 changed files
with
306 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package macho | ||
|
||
import "github.com/liamg/extrude/pkg/parser/macho/hardening" | ||
|
||
func (m *Metadata) analyse() error { | ||
|
||
if m.fat != nil { | ||
var coreAttr hardening.Attributes | ||
for _, arch := range m.fat.Arches { | ||
attr := hardening.IdentifyAttributes(arch.File) | ||
coreAttr = coreAttr.Merge(attr) | ||
} | ||
m.Hardening = coreAttr | ||
} else { | ||
m.Hardening = hardening.IdentifyAttributes(m.thin) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package hardening | ||
|
||
import ( | ||
"debug/macho" | ||
) | ||
|
||
func checkAutomaticReferenceCounting(f *macho.File) bool { | ||
symbols, err := f.ImportedSymbols() | ||
if err != nil { | ||
return false | ||
} | ||
for _, imp := range symbols { | ||
if imp == "_objc_release" { | ||
return true | ||
} | ||
} | ||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package hardening | ||
|
||
import "debug/macho" | ||
|
||
const ( | ||
EncInfo32 = 0x21 | ||
EncInfo64 = 0x2c | ||
) | ||
|
||
func checkEncrypted(f *macho.File) bool { | ||
return f.Symtab.Cmd&EncInfo32 > 0 || f.Symtab.Cmd&EncInfo64 > 0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package hardening | ||
|
||
import "debug/macho" | ||
|
||
type Attributes struct { | ||
init bool | ||
PositionIndependentExecutable bool | ||
StackExecutionNotAllowed bool | ||
HeapExecutionNotAllowed bool | ||
StackProtected bool | ||
AutomaticReferenceCounting bool | ||
Encrypted bool | ||
} | ||
|
||
func (a Attributes) Merge(b Attributes) Attributes { | ||
if !a.init { | ||
return b | ||
} | ||
if !b.init { | ||
return a | ||
} | ||
return Attributes{ | ||
PositionIndependentExecutable: a.PositionIndependentExecutable && b.PositionIndependentExecutable, | ||
StackExecutionNotAllowed: a.StackExecutionNotAllowed && b.StackExecutionNotAllowed, | ||
HeapExecutionNotAllowed: a.HeapExecutionNotAllowed && b.HeapExecutionNotAllowed, | ||
StackProtected: a.StackProtected && b.StackProtected, | ||
AutomaticReferenceCounting: a.AutomaticReferenceCounting && b.AutomaticReferenceCounting, | ||
Encrypted: a.Encrypted && b.Encrypted, | ||
} | ||
} | ||
|
||
func IdentifyAttributes(f *macho.File) Attributes { | ||
return Attributes{ | ||
init: true, | ||
PositionIndependentExecutable: f.Flags&macho.FlagPIE > 0, | ||
StackExecutionNotAllowed: f.Flags&macho.FlagAllowStackExecution == 0, | ||
HeapExecutionNotAllowed: f.Flags&macho.FlagNoHeapExecution > 0, | ||
StackProtected: checkStackProtected(f), | ||
AutomaticReferenceCounting: checkAutomaticReferenceCounting(f), | ||
Encrypted: checkEncrypted(f), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package hardening | ||
|
||
import ( | ||
"debug/macho" | ||
) | ||
|
||
func checkStackProtected(f *macho.File) bool { | ||
symbols, err := f.ImportedSymbols() | ||
if err != nil { | ||
return false | ||
} | ||
for _, imp := range symbols { | ||
if imp == "___stack_chk_fail" || imp == "___stack_chk_guard" { | ||
return true | ||
} | ||
} | ||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package macho | ||
|
||
import ( | ||
"debug/macho" | ||
|
||
"github.com/liamg/extrude/pkg/format" | ||
"github.com/liamg/extrude/pkg/parser/macho/hardening" | ||
) | ||
|
||
type Metadata struct { | ||
File struct { | ||
Path string | ||
Name string | ||
Format format.Format | ||
} | ||
Hardening hardening.Attributes | ||
thin *macho.File | ||
fat *macho.FatFile | ||
Notes []Note | ||
} | ||
|
||
type Note struct { | ||
Heading string | ||
Content string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package macho | ||
|
||
import ( | ||
"debug/macho" | ||
"io" | ||
"path/filepath" | ||
|
||
"github.com/liamg/extrude/pkg/format" | ||
"github.com/liamg/extrude/pkg/report" | ||
) | ||
|
||
type parser struct{} | ||
|
||
func New() *parser { | ||
return &parser{} | ||
} | ||
|
||
func (*parser) Parse(r io.ReaderAt, path string, format format.Format) (report.Reporter, error) { | ||
|
||
var metadata Metadata | ||
|
||
metadata.File.Path = path | ||
metadata.File.Name = filepath.Base(path) | ||
metadata.File.Format = format | ||
|
||
fat, err := macho.NewFatFile(r) | ||
if err != nil { | ||
if err != macho.ErrNotFat { | ||
return nil, err | ||
} | ||
thin, err := macho.NewFile(r) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer func() { _ = thin.Close() }() | ||
metadata.thin = thin | ||
} else { | ||
defer func() { _ = fat.Close() }() | ||
metadata.fat = fat | ||
} | ||
|
||
if err := metadata.analyse(); err != nil { | ||
return nil, err | ||
} | ||
return &metadata, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package macho | ||
|
||
import ( | ||
"strings" | ||
|
||
"github.com/liamg/extrude/pkg/report" | ||
) | ||
|
||
func (m *Metadata) CreateReport() (report.Report, error) { | ||
rep := report.New() | ||
|
||
overview := report.NewSection("Overview") | ||
|
||
overview.AddKeyValue("File", m.File.Path) | ||
overview.AddKeyValue("Format", m.File.Format.String()) | ||
|
||
if m.fat != nil { | ||
overview.AddKeyValue("Universal", "Yes (Fat)") | ||
var arches []string | ||
for _, arch := range m.fat.Arches { | ||
arches = append(arches, arch.Cpu.String()) | ||
} | ||
overview.AddKeyValue("Architectures", strings.Join(arches, ", ")) | ||
} else { | ||
overview.AddKeyValue("Univeral", "No (Thin)") | ||
overview.AddKeyValue("Type", m.thin.Type.String()) | ||
overview.AddKeyValue("Architecture", m.thin.Cpu.String()) | ||
} | ||
|
||
rep.AddSection(overview) | ||
|
||
security := report.NewSection("Security Features") | ||
|
||
security.AddTest( | ||
"Position Independent Executable", | ||
boolToResult(m.Hardening.PositionIndependentExecutable), | ||
`A PIE binary and all of its dependencies are loaded into random locations within virtual memory each time the application is executed. This makes Return Oriented Programming (ROP) attacks much more difficult to execute reliably.`, | ||
) | ||
|
||
security.AddTest( | ||
"Stack Canary", | ||
boolToResult(m.Hardening.StackProtected), | ||
`A "canary" value is pushed onto the stack immediately after the function return pointer. The canary value is then checked before the function returns; if it has changed, the program will abort. This makes buffer overflow attacks much more difficult to carry out.`, | ||
) | ||
|
||
security.AddTest( | ||
"Non-Executable Stack", | ||
boolToResult(m.Hardening.StackExecutionNotAllowed), | ||
`Preventing the stack from being executable means that malicious code injected onto the stack cannot be run.`, | ||
) | ||
|
||
security.AddTest( | ||
"Non-Executable Heap", | ||
boolToResult(m.Hardening.HeapExecutionNotAllowed), | ||
`Preventing the heap from being executable means that malicious code written to the heap cannot be run.`, | ||
) | ||
|
||
security.AddTest( | ||
"Automatic Reference Counting", | ||
boolToResult(m.Hardening.AutomaticReferenceCounting), | ||
`ARC is a runtime memory safety mechanism which keeps track of objects and frees them once they are no longer referenced.`, | ||
) | ||
|
||
/* In progress... | ||
security.AddTest( | ||
"Encryption", | ||
boolToResult(m.Hardening.Encrypted), | ||
``, | ||
) | ||
*/ | ||
|
||
rep.AddSection(security) | ||
|
||
if len(m.Notes) > 0 { | ||
notes := report.NewSection("Other Findings") | ||
for _, note := range m.Notes { | ||
notes.AddTest(note.Heading, report.Warning, note.Content) | ||
} | ||
rep.AddSection(notes) | ||
} | ||
|
||
return rep, nil | ||
} | ||
|
||
func boolToResult(in bool) report.Result { | ||
if in { | ||
return report.Pass | ||
} | ||
return report.Fail | ||
} |
Oops, something went wrong.