Goal
In this lab we’ll replace the simple XOR function from Lab 6.1 with a rolling XOR implementation. This will once again be a standalone application to just illustrate its functionality, we’ll integrate it into our main application in the next lab.
Code
Once again feel free to replace plaintext
and key
with your own values.
package main
import (
"bytes"
"fmt"
"log"
)
// Here we XOR data with a key where the key byte is modified based on position.
// It is symmetric: calling it twice with the same key restores the original data.
func rollingXor(data []byte, key []byte) []byte {
keyBytes := []byte(key) // Ensure key is treated as bytes
keyLen := len(keyBytes)
result := make([]byte, len(data))
// Handle edge cases
if len(data) == 0 {
return []byte{}
}
if keyLen == 0 {
log.Println("[!] Warning: Rolling XOR key is empty. Returning original data.")
result := make([]byte, len(data))
copy(result, data)
return result
}
for i := 0; i < len(data); i++ {
// --- Rolling Key Calculation ---
// 1. Get the base key byte for this position (repeating key)
baseKeyByte := keyBytes[i%keyLen]
// 2. Get a modifier based on the current position (lower 8 bits of index)
positionByte := byte(i & 0xFF)
// 3. Calculate the effective key byte for this position
rollingKeyByte := baseKeyByte ^ positionByte
// --- End Rolling Key Calculation ---
// XOR the data byte with the *rolling* key byte
result[i] = data[i] ^ rollingKeyByte
}
return result
}
func main() {
fmt.Println("[+] Rolling XOR Obfuscation/Deobfuscation Demo")
// --- Define Sample Data and Key ---
plaintext := []byte("I am Lorde, YA YA YA!")
key := []byte{0xDE, 0xAD, 0xBE, 0xEF}
fmt.Printf("Original Plaintext : %s\n", string(plaintext))
fmt.Printf("Original Plaintext (Hex): %X\n", plaintext)
fmt.Printf("Key (Hex) : %X\n", key)
// --- Encrypt (Obfuscate) using Rolling XOR ---
fmt.Println("\n[+] Encrypting using ROLLING XOR...")
ciphertext := rollingXor(plaintext, key)
fmt.Printf("Ciphertext (Hex) : %X\n", ciphertext)
// --- Decrypt (Deobfuscate) using Rolling XOR ---
fmt.Println("\n[+] Decrypting using the SAME ROLLING XOR function and key...")
decryptedText := rollingXor(ciphertext, key)
fmt.Printf("Decrypted Text : %s\n", string(decryptedText))
fmt.Printf("Decrypted Text (Hex): %X\n", decryptedText)
// --- Verify Symmetry ---
fmt.Println("\n[+] Verifying decryption matches original plaintext...")
if bytes.Equal(plaintext, decryptedText) {
fmt.Println("[+] Success! Decrypted text matches original plaintext.")
} else {
fmt.Println("[-] Failure! Decrypted text does NOT match original plaintext.")
}
}
Code Breakdown
rollingXor
function
baseKeyByte := keyBytes[i % keyLen]
gets the standard repeating key byte.positionByte := byte(i & 0xFF)
gets a byte value based on the indexi
.rollingKeyByte := baseKeyByte ^ positionByte
combines these two to create the effective key for this position.result[i] = data[i] ^ rollingKeyByte
performs the XOR using this position-dependent key byte.
main
function
- This is structured identically to the
main
function in Lab 6.1. - It defines plaintext and a base key.
- It calls
rollingXor
for encryption. - It calls the same
rollingXor
function for decryption, demonstrating symmetry. - It verifies the result using
bytes.Equal
.
Instructions
- You can either use
go build
to compile, then run your application, or for simplicity usego run
. - Navigate to the directory containing your go file (make sure it’s the only one in this directory) and enter
go run .
Results
❯ go run .
[+] Rolling XOR Obfuscation/Deobfuscation Demo
Original Plaintext : I am Lorde, YA YA YA!
Original Plaintext (Hex): 4920616D204C6F7264652C20594120594120594121
Key (Hex) : DEADBEEF
[+] Encrypting using ROLLING XOR...
Ciphertext (Hex) : 978CDD81FAE4D79AB2C198C48BE190B98F9CF5BDEB
[+] Decrypting using the SAME ROLLING XOR function and key...
Decrypted Text : I am Lorde, YA YA YA!
Decrypted Text (Hex): 4920616D204C6F7264652C20594120594120594121
[+] Verifying decryption matches original plaintext...
[+] Success! Decrypted text matches original plaintext.
Discussion
Everything is pretty self-explanatory in our output, bit we can confirm of course that are pre-encrypted plaintext, and decrypted plaintext, match.
Conclusion
So that was not terribly exciting, but at least we confirmed that rolling XOR offered the same self-inverting ability as simple XOR did. Now let’s go and integrate this and key derivation logic into our reflective loader.