mirror of
https://github.com/lukaszraczylo/go-obfuscation.git
synced 2026-10-12 05:32:33 +00:00
99 lines
1.8 KiB
Go
99 lines
1.8 KiB
Go
package vm
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"fmt"
|
|
"math/big"
|
|
)
|
|
|
|
type Instruction struct {
|
|
Op Opcode
|
|
Args []int64
|
|
}
|
|
|
|
type LabelledInstr struct {
|
|
Label string
|
|
Instr Instruction
|
|
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 {
|
|
offset int
|
|
op Opcode
|
|
target string
|
|
}
|
|
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
|
|
|
|
if isJump && entry.Target != "" {
|
|
fixups = append(fixups, fixup{
|
|
offset: len(bytecode),
|
|
op: instr.Op,
|
|
target: entry.Target,
|
|
})
|
|
ph := make([]byte, InstrSize(instr.Op))
|
|
ph[0] = encodeOp(instr.Op)
|
|
bytecode = append(bytecode, ph...)
|
|
continue
|
|
}
|
|
|
|
arg := int64(0)
|
|
if len(instr.Args) > 0 {
|
|
arg = instr.Args[0]
|
|
}
|
|
bytecode = append(bytecode, EncodeInstr(instr.Op, arg)...)
|
|
}
|
|
|
|
for _, f := range fixups {
|
|
addr, ok := labelAddrs[f.target]
|
|
if !ok {
|
|
panic(fmt.Sprintf("vm: undefined label %q", f.target))
|
|
}
|
|
enc := EncodeInstr(f.op, int64(addr))
|
|
copy(bytecode[f.offset:], enc)
|
|
}
|
|
|
|
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())
|
|
}
|