mirror of
https://github.com/EgeBalci/sgn
synced 2026-06-08 10:56:31 +00:00
Fixes several bugs in encoding and obfuscation and adds a new payload execution stress test.
- fix(encode): Remove redundant modulo operations from ADD/SUB ciphers - fix(obfuscate): Remove "JMP 2" from the list of safe garbage instructions - fix(obfuscate): Use correct slice length when selecting random garbage instruction - fix(sgn): Correct register exclusion logic in GetSafeRandomRegister - test: Add integration stress test for payload execution on Windows
This commit is contained in:
+2
-2
@@ -154,9 +154,9 @@ func (encoder *Encoder) SchemaCipher(data []byte, index int, schema SCHEMA) []by
|
||||
case "XOR":
|
||||
binary.BigEndian.PutUint32(data[index:index+4], (binary.BigEndian.Uint32(data[index:index+4]) ^ binary.LittleEndian.Uint32(cursor.Key)))
|
||||
case "ADD":
|
||||
binary.LittleEndian.PutUint32(data[index:index+4], (binary.LittleEndian.Uint32(data[index:index+4])-binary.BigEndian.Uint32(cursor.Key))%0xFFFFFFFF)
|
||||
binary.LittleEndian.PutUint32(data[index:index+4], binary.LittleEndian.Uint32(data[index:index+4])-binary.BigEndian.Uint32(cursor.Key))
|
||||
case "SUB":
|
||||
binary.LittleEndian.PutUint32(data[index:index+4], (binary.LittleEndian.Uint32(data[index:index+4])+binary.BigEndian.Uint32(cursor.Key))%0xFFFFFFFF)
|
||||
binary.LittleEndian.PutUint32(data[index:index+4], binary.LittleEndian.Uint32(data[index:index+4])+binary.BigEndian.Uint32(cursor.Key))
|
||||
case "ROL":
|
||||
binary.LittleEndian.PutUint32(data[index:index+4], bits.RotateLeft32(binary.LittleEndian.Uint32(data[index:index+4]), -int(binary.BigEndian.Uint32(cursor.Key))))
|
||||
case "ROR":
|
||||
|
||||
@@ -47,7 +47,6 @@ var SafeGarbageInstructions = []string{
|
||||
"FNOP",
|
||||
"FXAM",
|
||||
"FTST",
|
||||
"JMP 2",
|
||||
"ROL {R},0",
|
||||
"ROR {R},0",
|
||||
"SHL {R},0",
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ func GetRandomSafeAssembly() string {
|
||||
newSafeGarbageInstructions = append(newSafeGarbageInstructions, jmp+" {L};{G};{L}:")
|
||||
//newSafeGarbageInstructions = append(newSafeGarbageInstructions, jmp+" 2")
|
||||
}
|
||||
return newSafeGarbageInstructions[rand.Intn(len(SafeGarbageInstructions))]
|
||||
return newSafeGarbageInstructions[rand.Intn(len(newSafeGarbageInstructions))]
|
||||
}
|
||||
|
||||
// GetRandomUnsafeAssembly return a safe garbage instruction assembly
|
||||
|
||||
+7
-2
@@ -162,11 +162,16 @@ func (encoder Encoder) GetBasePointer() string {
|
||||
func (encoder Encoder) GetSafeRandomRegister(size int, excludes ...string) (string, error) {
|
||||
regs := []REG{}
|
||||
for _, r := range REGS[encoder.architecture] {
|
||||
safe := true
|
||||
for _, x := range excludes {
|
||||
if r.Extended != x && r.Full != x && r.High != x && r.Low != x {
|
||||
regs = append(regs, r)
|
||||
if r.Extended == x || r.Full == x || r.High == x || r.Low == x {
|
||||
safe = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if safe {
|
||||
regs = append(regs, r)
|
||||
}
|
||||
}
|
||||
|
||||
r := regs[rand.Intn(len(regs))]
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
"unsafe"
|
||||
|
||||
"github.com/EgeBalci/sgn/pkg"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
virtualAlloc = kernel32.NewProc("VirtualAlloc")
|
||||
virtualFree = kernel32.NewProc("VirtualFree")
|
||||
|
||||
// NOP NOP NOP RET works on both x86 and x64
|
||||
dummyPayload = []byte{0x90, 0x90, 0x90, 0xC3}
|
||||
)
|
||||
|
||||
func TestIntegrationExecution(t *testing.T) {
|
||||
var arch int
|
||||
if runtime.GOARCH == "386" {
|
||||
arch = 32
|
||||
} else if runtime.GOARCH == "amd64" {
|
||||
arch = 64
|
||||
} else {
|
||||
t.Skipf("Unsupported architecture: %s", runtime.GOARCH)
|
||||
}
|
||||
|
||||
t.Logf("[*] Starting SGN execution stress test (%d-bit)...\n", arch)
|
||||
|
||||
iterations := 1000
|
||||
|
||||
for i := 0; i < iterations; i++ {
|
||||
enc, err := sgn.NewEncoder(arch)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to init encoder: %v", err)
|
||||
}
|
||||
|
||||
enc.ObfuscationLimit = 50
|
||||
|
||||
encoded, err := enc.Encode(dummyPayload)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to encode: %v", err)
|
||||
}
|
||||
|
||||
addr, _, errInfo := virtualAlloc.Call(
|
||||
0,
|
||||
uintptr(len(encoded)),
|
||||
0x1000|0x2000, // MEM_COMMIT | MEM_RESERVE
|
||||
0x40, // PAGE_EXECUTE_READWRITE
|
||||
)
|
||||
if addr == 0 {
|
||||
t.Fatalf("VirtualAlloc failed: %v", errInfo)
|
||||
}
|
||||
|
||||
ptr := (*[1 << 30]byte)(unsafe.Pointer(addr))
|
||||
copy(ptr[:], encoded)
|
||||
|
||||
// Execute payload
|
||||
syscall.Syscall(addr, 0, 0, 0, 0)
|
||||
|
||||
// Free memory
|
||||
virtualFree.Call(addr, 0, 0x8000)
|
||||
}
|
||||
|
||||
t.Logf("[+] Stress test complete: %d executions with no crashes!", iterations)
|
||||
}
|
||||
Reference in New Issue
Block a user