mirror of
https://github.com/lukaszraczylo/go-obfuscation.git
synced 2026-10-14 05:48:22 +00:00
v0.0.2
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type Instruction struct {
|
||||
@@ -15,7 +17,15 @@ type LabelledInstr struct {
|
||||
Target string
|
||||
}
|
||||
|
||||
type CompileOpts struct {
|
||||
NoJunk bool
|
||||
}
|
||||
|
||||
func Compile(program []LabelledInstr) []byte {
|
||||
return CompileWith(program, CompileOpts{})
|
||||
}
|
||||
|
||||
func CompileWith(program []LabelledInstr, opts CompileOpts) []byte {
|
||||
labelAddrs := make(map[string]int)
|
||||
|
||||
type fixup struct {
|
||||
@@ -26,11 +36,18 @@ func Compile(program []LabelledInstr) []byte {
|
||||
var fixups []fixup
|
||||
var bytecode []byte
|
||||
|
||||
junkOpcodes := []Opcode{opJunkA, opJunkB, opJunkC, opJunkD}
|
||||
|
||||
for _, entry := range program {
|
||||
if entry.Label != "" {
|
||||
labelAddrs[entry.Label] = len(bytecode)
|
||||
}
|
||||
|
||||
if !opts.NoJunk && shouldInsertJunk() {
|
||||
junkOp := junkOpcodes[randIntn(len(junkOpcodes))]
|
||||
bytecode = append(bytecode, encodeOp(junkOp))
|
||||
}
|
||||
|
||||
instr := entry.Instr
|
||||
isJump := instr.Op == OpJmp || instr.Op == OpJz || instr.Op == OpJnz
|
||||
|
||||
@@ -64,3 +81,18 @@ func Compile(program []LabelledInstr) []byte {
|
||||
|
||||
return bytecode
|
||||
}
|
||||
|
||||
func shouldInsertJunk() bool {
|
||||
return randIntn(3) == 0
|
||||
}
|
||||
|
||||
func randIntn(n int) int {
|
||||
if n <= 0 {
|
||||
return 0
|
||||
}
|
||||
b, err := rand.Int(rand.Reader, big.NewInt(int64(n)))
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return int(b.Int64())
|
||||
}
|
||||
|
||||
+27
-5
@@ -430,7 +430,7 @@ func TestStepwiseExecution(t *testing.T) {
|
||||
{Instr: Instruction{Op: OpHalt}},
|
||||
}
|
||||
|
||||
code := Compile(program)
|
||||
code := CompileWith(program, CompileOpts{NoJunk: true})
|
||||
vm := NewVM(code, nil)
|
||||
|
||||
steps := 0
|
||||
@@ -461,8 +461,13 @@ func TestXorObfuscationDeterminism(t *testing.T) {
|
||||
{Instr: Instruction{Op: OpHalt}},
|
||||
}
|
||||
|
||||
code1 := Compile(program)
|
||||
code2 := Compile(program)
|
||||
opts := CompileOpts{NoJunk: true}
|
||||
code1 := CompileWith(program, opts)
|
||||
code2 := CompileWith(program, opts)
|
||||
|
||||
if len(code1) != len(code2) {
|
||||
t.Fatalf("bytecode length differs: %d vs %d", len(code1), len(code2))
|
||||
}
|
||||
|
||||
for i := range code1 {
|
||||
if code1[i] != code2[i] {
|
||||
@@ -487,9 +492,8 @@ func TestBytecodeIsXORed(t *testing.T) {
|
||||
{Instr: Instruction{Op: OpHalt}},
|
||||
}
|
||||
|
||||
code := Compile(program)
|
||||
code := CompileWith(program, CompileOpts{NoJunk: true})
|
||||
|
||||
// First byte should be OpPush ^ dispatchKey, not OpPush itself
|
||||
rawPush := byte(OpPush) ^ dispatchKey
|
||||
if code[0] != rawPush {
|
||||
t.Errorf("expected bytecode[0]=0x%02X (XOR'd PUSH), got 0x%02X", rawPush, code[0])
|
||||
@@ -501,6 +505,24 @@ func TestBytecodeIsXORed(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestJunkOpcodesCorrectness(t *testing.T) {
|
||||
program := []LabelledInstr{
|
||||
{Instr: Instruction{Op: OpPush, Args: []int64{10}}},
|
||||
{Instr: Instruction{Op: OpPush, Args: []int64{20}}},
|
||||
{Instr: Instruction{Op: OpAdd}},
|
||||
{Instr: Instruction{Op: OpHalt}},
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
code := Compile(program)
|
||||
vm := NewVM(code, nil)
|
||||
result := vm.Run()
|
||||
if result != 30 {
|
||||
t.Fatalf("iteration %d: expected 30, got %d (bytecode len %d)", i, result, len(code))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrOp(t *testing.T) {
|
||||
// 0x0F OR 0xF0 = 0xFF
|
||||
program := []LabelledInstr{
|
||||
|
||||
Reference in New Issue
Block a user