Skip to content

Commit

Permalink
v2.0 stable release !! Better x64 decoder stub & lots of improvments
Browse files Browse the repository at this point in the history
  • Loading branch information
EgeBalci committed Nov 6, 2020
1 parent 6daefc0 commit 98d40a9
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 134 deletions.
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,13 @@ normal:
go build -ldflags="-s -w" -trimpath -o sgn
386:
CGO_ENABLED=1 GOARCH=386 go build -ldflags="-s -w" -trimpath -o sgn
linux_amd64:
GOOS=linux CGO_ENABLED=1 GOARCH=amd64 go build -ldflags="-s -w" -trimpath -o sgn
linux_386:
GOOS=linux CGO_ENABLED=1 GOARCH=386 go build -ldflags="-s -w" -trimpath -o sgn
windows_amd64:
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CGO_LDFLAGS="-lkeystone -L`pwd`/build/lib/" CXX=x86_64-w64-mingw32-g++ CC=x86_64-w64-mingw32-gcc go build -ldflags="-s -w" -trimpath -o sgn.exe
windows_386:
GOOS=windows GOARCH=386 CGO_ENABLED=1 CGO_LDFLAGS="-lkeystone -L`pwd`/build/lib32/" CXX=i686-w64-mingw32-g++ CC=i686-w64-mingw32-gcc go build -ldflags="-s -w" -trimpath -o sgn32.exe
darwin:
GOOS=darwin CGO_ENABLED=1 CGO_LDFLAGS="-lkeystone -L/usr/lib/" go build -ldflags="-s -w" -trimpath -o sgn
19 changes: 14 additions & 5 deletions lib/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@ data:
const x64DecoderStub = `
MOV {RL},{K}
MOV RCX,{S}
LEA {R},[RIP]
LEA {R},[RIP+data-1]
decode:
XOR BYTE PTR [{R}+RCX+data-decode],{RL}
ADD {RL},BYTE PTR [{R}+RCX+data-decode]
XOR BYTE PTR [{R}+RCX],{RL}
ADD {RL},BYTE PTR [{R}+RCX]
LOOP decode
data:
`

// NewDecoderAssembly creates a unobfuscated decoder stub to the given encoded payload
// with the given architecture and seed value
func (encoder *Encoder) NewDecoderAssembly(payload []byte) string {
func (encoder *Encoder) NewDecoderAssembly(payloadSize int) string {

decoder := STUB[encoder.architecture]
reg := encoder.GetSafeRandomRegister(encoder.architecture, "ECX")
Expand All @@ -48,10 +48,19 @@ func (encoder *Encoder) NewDecoderAssembly(payload []byte) string {
decoder = strings.ReplaceAll(decoder, "{R}", reg)
decoder = strings.ReplaceAll(decoder, "{RL}", regL)
decoder = strings.ReplaceAll(decoder, "{K}", fmt.Sprintf("0x%x", encoder.Seed))
decoder = strings.ReplaceAll(decoder, "{S}", fmt.Sprintf("0x%x", len(payload)))
decoder = strings.ReplaceAll(decoder, "{S}", fmt.Sprintf("0x%x", payloadSize))
//fmt.Println(decoder)
return decoder
}

// AddADFLDecoder creates decoder stub for binaries that are ciphered with CipherADFL function.
func (encoder *Encoder) AddADFLDecoder(payload []byte) ([]byte, error) {
decoderAssembly := encoder.NewDecoderAssembly(len(payload))
decoder, ok := encoder.Assemble(decoderAssembly)
if !ok {
return nil, errors.New("decoder assembly failed")
}
return append(decoder, payload...), nil
}

// AddSchemaDecoder creates decoder stub for binaries that are ciphered with SchemaCipher function.
Expand Down
69 changes: 34 additions & 35 deletions lib/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func NewEncoder() *Encoder {
encoder.architecture = 32
encoder.ObfuscationLimit = 50
encoder.PlainDecoder = false
encoder.Seed = RandomByte()
encoder.Seed = GetRandomByte()
encoder.EncodingCount = 1
encoder.SaveRegisters = false
return &encoder
Expand Down Expand Up @@ -67,6 +67,7 @@ func (encoder *Encoder) GetArchitecture() int {
// all nessary options and parameters are contained inside the encodder struct
func (encoder *Encoder) Encode(payload []byte) ([]byte, error) {

var final []byte
if encoder.SaveRegisters {
payload = append(payload, SafeRegisterSuffix[encoder.architecture]...)
}
Expand All @@ -79,41 +80,39 @@ func (encoder *Encoder) Encode(payload []byte) ([]byte, error) {
payload = append(garbage, payload...)
encoder.ObfuscationLimit -= len(garbage)
// Apply ADFL cipher to payload
ciperedPayload := CipherADFL(payload, encoder.Seed)
decoderAssembly := encoder.NewDecoderAssembly(ciperedPayload)
// Assemble decoder stub
decoder, ok := encoder.Assemble(decoderAssembly)
if !ok {
return nil, errors.New("decoder assembly failed")
}
// Combine decoder stub + ciphered payload into encoded payload
encodedPayload := append(decoder, ciperedPayload...)
if encoder.PlainDecoder {
if encoder.SaveRegisters && encoder.EncodingCount == 1 {
encodedPayload = append(SafeRegisterPrefix[encoder.architecture], encodedPayload...)
}
return encodedPayload, nil
}

// Add more garbage instrctions before the decoder stub
garbage, err = encoder.GenerateGarbageInstructions()
cipheredPayload := CipherADFL(payload, encoder.Seed)
encodedPayload, err := encoder.AddADFLDecoder(cipheredPayload)
if err != nil {
return nil, err
}
encodedPayload = append(garbage, encodedPayload...)
// Calculate schema size
schemaSize := ((len(encodedPayload) - len(ciperedPayload)) / (encoder.architecture / 8)) + 1
randomSchema := encoder.NewCipherSchema(schemaSize)

obfuscatedEncodedPayload := encoder.SchemaCipher(encodedPayload, 0, randomSchema)
final, err := encoder.AddSchemaDecoder(obfuscatedEncodedPayload, randomSchema)
if err != nil {
return nil, err
if encoder.PlainDecoder {
final = encodedPayload
} else {
// Add more garbage instrctions before the decoder stub
garbage, err = encoder.GenerateGarbageInstructions()
if err != nil {
return nil, err
}
encodedPayload = append(garbage, encodedPayload...)
// Calculate schema size
schemaSize := ((len(encodedPayload) - len(cipheredPayload)) / (encoder.architecture / 8)) + 1
randomSchema := encoder.NewCipherSchema(schemaSize)

obfuscatedEncodedPayload := encoder.SchemaCipher(encodedPayload, 0, randomSchema)
final, err = encoder.AddSchemaDecoder(obfuscatedEncodedPayload, randomSchema)
if err != nil {
return nil, err
}
}

if encoder.EncodingCount > 1 {
encoder.EncodingCount--
return encoder.Encode(final)
encoder.Seed = GetRandomByte()
final, err = encoder.Encode(final)
if err != nil {
return nil, err
}
}

if encoder.SaveRegisters {
Expand Down Expand Up @@ -167,16 +166,16 @@ func RandomOperand() string {
return OPERANDS[rand.Intn(len(OPERANDS))]
}

// RandomByte generates a random single byte
func RandomByte() byte {
// GetRandomByte generates a random single byte
func GetRandomByte() byte {
return byte(rand.Intn(255))
}

// RandomBytes generates a random byte slice with given size
func RandomBytes(num int) []byte {
// GetRandomBytes generates a random byte slice with given size
func GetRandomBytes(num int) []byte {
slice := make([]byte, num)
for i := range slice {
slice[i] = RandomByte()
slice[i] = GetRandomByte()
}
return slice
}
Expand All @@ -199,10 +198,10 @@ func (encoder *Encoder) NewCipherSchema(num int) SCHEMA {
cursor.Key = nil
} else if cursor.OP == "ROL" || cursor.OP == "ROR" {

cursor.Key = []byte{0, 0, 0, RandomByte()}
cursor.Key = []byte{0, 0, 0, GetRandomByte()}
} else {
// 4 byte blocks used because of the x64 xor qword ptr instruction boundaries
cursor.Key = RandomBytes(4)
cursor.Key = GetRandomBytes(4)
}
schema[i] = cursor
}
Expand Down
27 changes: 0 additions & 27 deletions lib/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -1472,33 +1472,6 @@ const INSTRUCTIONS string = `
}
]
},
{
"Mnemonic": "IN",
"V64": true,
"V32": true,
"Operands": [
{
"Types": [
"AL",
"AX",
"EAX",
"AL",
"AX",
"EAX"
]
},
{
"Types": [
"imm8",
"imm8",
"imm8",
"DX",
"DX",
"DX"
]
}
]
},
{
"Mnemonic": "INC",
"V64": true,
Expand Down
12 changes: 6 additions & 6 deletions lib/obfuscate.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (encoder *Encoder) GenerateGarbageAssembly() string {
randomGarbageAssembly := GetRandomSafeAssembly()
register := encoder.GetRandomRegister(encoder.architecture)
randomGarbageAssembly = strings.ReplaceAll(randomGarbageAssembly, "{R}", register)
randomGarbageAssembly = strings.ReplaceAll(randomGarbageAssembly, "{K}", fmt.Sprintf("0x%x", RandomByte()))
randomGarbageAssembly = strings.ReplaceAll(randomGarbageAssembly, "{K}", fmt.Sprintf("0x%x", GetRandomByte()))
randomGarbageAssembly = strings.ReplaceAll(randomGarbageAssembly, "{L}", RandomLabel())
randomGarbageAssembly = strings.ReplaceAll(randomGarbageAssembly, "{G}", encoder.GenerateGarbageAssembly())
return randomGarbageAssembly + ";"
Expand Down Expand Up @@ -171,13 +171,13 @@ func (encoder *Encoder) GetRandomOperandValue(operandType string) string {

switch operandType {
case "imm8":
return fmt.Sprintf("0x%x", RandomByte()%127)
return fmt.Sprintf("0x%x", GetRandomByte()%127)
case "imm16":
return fmt.Sprintf("0x%x", rand.Intn(32767))
case "imm32":
return fmt.Sprintf("0x%x", rand.Int31n((2147483647)))
case "imm64":
return fmt.Sprintf("0x%x", RandomBytes(8))
return fmt.Sprintf("0x%x", GetRandomBytes(8))
case "r8":
return encoder.GetRandomRegister(8)
case "r16":
Expand Down Expand Up @@ -300,7 +300,7 @@ func (encoder *Encoder) GetRandomFunctionAssembly() string {

prologue := fmt.Sprintf("PUSH %s;", bp)
prologue += fmt.Sprintf("MOV %s,%s;", bp, sp)
prologue += fmt.Sprintf("SUB %s,0x%x;", sp, RandomByte())
prologue += fmt.Sprintf("SUB %s,0x%x;", sp, GetRandomByte())

// Fill the function body with garbage instructions
garbage := encoder.GenerateGarbageAssembly()
Expand All @@ -313,8 +313,8 @@ func (encoder *Encoder) GetRandomFunctionAssembly() string {

// GenerateGarbageJump generates a JMP instruction over random bytes
func (encoder Encoder) GenerateGarbageJump() ([]byte, error) {
randomBytes := RandomBytes(encoder.ObfuscationLimit / 10)
garbageJmp, err := encoder.AddJmpOver(randomBytes)
GetRandomBytes := GetRandomBytes(encoder.ObfuscationLimit / 10)
garbageJmp, err := encoder.AddJmpOver(GetRandomBytes)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions lib/sgn.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ func (encoder Encoder) GetRandomRegister(size int) string {
func (encoder Encoder) GetRandomStackAddress() string {

if CoinFlip() {
return fmt.Sprintf("[%s+0x%x]", encoder.GetStackPointer(), RandomByte())
return fmt.Sprintf("[%s+0x%x]", encoder.GetStackPointer(), GetRandomByte())
}
return fmt.Sprintf("[%s-0x%x]", encoder.GetStackPointer(), RandomByte())
return fmt.Sprintf("[%s-0x%x]", encoder.GetStackPointer(), GetRandomByte())
}

// GetStackPointer returns the stack pointer register string based on the encoder architecture
Expand Down
Loading

0 comments on commit 98d40a9

Please sign in to comment.