mirror of
https://github.com/lukaszraczylo/go-obfuscation.git
synced 2026-10-12 05:32:33 +00:00
Bug fixes, new transform passes, test coverage, and CI tooling
Bug fixes: - pclntab/rtcorrupt_linux.go: remove duplicate mprotectRW/mprotectRO that broke GOOS=linux builds (they're defined in rtcorrupt_unsafe.go for darwin+linux). - pclntab/pclntab.go: readUint now guards against negative offset (previously panicked via slice out-of-range). - integrity/integrity.go: SetExpectedHashHex now validates length 64 up-front and reports byte index on parse error; added ClearExpectedHash for runtime toggling and test isolation. - transform/mba.go: mbaApplyBinOp used strings.Index on first match instead of the current match; replaced with FindAllStringSubmatchIndex + two-pass replacement. - transform/transform.go: removed duplicate unconditional SplitLongStrings call. New transform passes (CLI flags + Config fields + pipeline wiring): - splice, constblind, mba, fakesigs, funcsplit, bbreorder — all default true. Cleanup: - strenc/keyderive.go: removed unused DeriveFromBinary + buildSeed. - transform/transform.go: removed unused trimFirstParen. - antidebug_hook_darwin.go: modernized readAddr to unsafe.Slice with noescape pattern (vet-safe). Tests (10 packages, 116 tests, all green): - internal/transform: 28 tests covering every pipeline stage. - pkg/strenc: 7 tests for key derivation + XOR stream. - pkg/stringcrypt: 7 tests for CFB round-trip + tamper detection. - pkg/pageman: 14 tests for alignment + mprotect guards. - pkg/integrity: 14 tests including ClearExpectedHash teardown. - pkg/pclntab: 12 tests including readUint negative-offset guard. - pkg/antisandbox: 6 tests for hostname/MAC lists + Check delegation. - pkg/antiemul: 6 tests (1 skipped on non-Linux) for no-panic + timing. Tooling: - Makefile: added test, verify, lint, fmt, vet targets. vet uses -unsafeptr=false (only legitimate uintptr→pointer is the darwin antidebug hook). fmt skips build/ (generated). - README.md: test coverage table + Makefile target reference.
This commit is contained in:
@@ -3,13 +3,8 @@ package strenc
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
const buildSeed = 0xDEAD_BEEF_CAFE_BABE
|
||||
|
||||
func DeriveMasterKey(seed [32]byte) [32]byte {
|
||||
var out [32]byte
|
||||
|
||||
@@ -24,25 +19,3 @@ func DeriveMasterKey(seed [32]byte) [32]byte {
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func DeriveFromBinary() [32]byte {
|
||||
exePath, err := os.Executable()
|
||||
if err != nil {
|
||||
exePath = "unknown"
|
||||
}
|
||||
|
||||
mac := hmac.New(sha256.New, []byte("strenc.binary.seed"))
|
||||
mac.Write([]byte(exePath))
|
||||
|
||||
var seedBuf [8]byte
|
||||
binary.LittleEndian.PutUint64(seedBuf[:], buildSeed)
|
||||
mac.Write(seedBuf[:])
|
||||
|
||||
mac.Write([]byte(runtime.GOOS))
|
||||
mac.Write([]byte(runtime.GOARCH))
|
||||
|
||||
var seed [32]byte
|
||||
copy(seed[:], mac.Sum(nil))
|
||||
|
||||
return DeriveMasterKey(seed)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package strenc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeriveMasterKeyDeterministic(t *testing.T) {
|
||||
var seed [32]byte
|
||||
for i := range seed {
|
||||
seed[i] = byte(i)
|
||||
}
|
||||
k1 := DeriveMasterKey(seed)
|
||||
k2 := DeriveMasterKey(seed)
|
||||
if k1 != k2 {
|
||||
t.Errorf("DeriveMasterKey not deterministic: %x vs %x", k1, k2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeriveMasterKeyDifferentSeeds(t *testing.T) {
|
||||
var s1, s2 [32]byte
|
||||
s1[0] = 1
|
||||
s2[0] = 2
|
||||
k1 := DeriveMasterKey(s1)
|
||||
k2 := DeriveMasterKey(s2)
|
||||
if k1 == k2 {
|
||||
t.Errorf("DeriveMasterKey produced same key for different seeds")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeriveMasterKeyLengthAndFormat(t *testing.T) {
|
||||
var seed [32]byte
|
||||
for i := range seed {
|
||||
seed[i] = byte(i * 7)
|
||||
}
|
||||
key := DeriveMasterKey(seed)
|
||||
if key == [32]byte{} {
|
||||
t.Error("DeriveMasterKey returned zero key")
|
||||
}
|
||||
|
||||
zeroKey := DeriveMasterKey([32]byte{})
|
||||
if zeroKey == [32]byte{} {
|
||||
t.Error("DeriveMasterKey returned zero key for zero seed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncryptEntryRoundtripViaPool(t *testing.T) {
|
||||
masterKeySeed := [32]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
|
||||
|
||||
plaintexts := []string{
|
||||
"hello",
|
||||
"sk-proj-FAKE-KEY-1234567890abcdef",
|
||||
"super-secret-license-key-DO-NOT-SHARE",
|
||||
"a",
|
||||
"",
|
||||
}
|
||||
|
||||
var entries []Entry
|
||||
for i, pt := range plaintexts {
|
||||
var iv [16]byte
|
||||
iv[0] = byte(i)
|
||||
iv[15] = byte(i + 1)
|
||||
entries = append(entries, EncryptEntry(pt, deriveSubkey(masterKeySeed, iv), iv))
|
||||
}
|
||||
|
||||
pool := NewPool(masterKeySeed, entries)
|
||||
if pool.StringCount() != len(plaintexts) {
|
||||
t.Fatalf("StringCount=%d, want %d", pool.StringCount(), len(plaintexts))
|
||||
}
|
||||
|
||||
for i, want := range plaintexts {
|
||||
got := pool.GetString(i)
|
||||
if got != want {
|
||||
t.Errorf("GetString(%d) = %q, want %q", i, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetStringOutOfRange(t *testing.T) {
|
||||
pool := NewPool([32]byte{1}, nil)
|
||||
if got := pool.GetString(0); got != "" {
|
||||
t.Errorf("GetString(0) on empty pool = %q, want \"\"", got)
|
||||
}
|
||||
if got := pool.GetString(99); got != "" {
|
||||
t.Errorf("GetString(99) on empty pool = %q, want \"\"", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncryptEntryCiphertextDiffersFromPlaintext(t *testing.T) {
|
||||
var key [32]byte
|
||||
for i := range key {
|
||||
key[i] = byte(i)
|
||||
}
|
||||
var iv [16]byte
|
||||
|
||||
entry := EncryptEntry("hello world", key, iv)
|
||||
if bytes.Equal(entry.Ciphertext, []byte("hello world")) {
|
||||
t.Error("ciphertext equals plaintext (no encryption?)")
|
||||
}
|
||||
if entry.IV != iv {
|
||||
t.Error("IV was modified by EncryptEntry")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPoolDecryptionFailsOnTamperedCiphertext(t *testing.T) {
|
||||
seed := [32]byte{0xAA, 0xBB}
|
||||
var iv [16]byte
|
||||
entry := EncryptEntry("secret", deriveSubkey(seed, iv), iv)
|
||||
|
||||
tampered := make([]byte, len(entry.Ciphertext))
|
||||
copy(tampered, entry.Ciphertext)
|
||||
if len(tampered) > 16 {
|
||||
tampered[20] ^= 0x01
|
||||
}
|
||||
|
||||
pool := NewPool(seed, []Entry{{Ciphertext: tampered, IV: iv}})
|
||||
if got := pool.GetString(0); got == "secret" {
|
||||
t.Error("GetString returned plaintext on tampered ciphertext (GCM should reject)")
|
||||
}
|
||||
}
|
||||
|
||||
func deriveSubkey(seed [32]byte, iv [16]byte) [32]byte {
|
||||
master := DeriveMasterKey(seed)
|
||||
mac := hmac.New(sha256.New, master[:])
|
||||
mac.Write(iv[:])
|
||||
var sub [32]byte
|
||||
copy(sub[:], mac.Sum(nil))
|
||||
return sub
|
||||
}
|
||||
Reference in New Issue
Block a user