Files
2026-07-18 21:37:15 +03:00

60 lines
2.1 KiB
Go

package winpwn
import (
"bytes"
"fmt"
)
// FindXORKey finds a single byte k such that XORing data with the
// repeating key k produces no byte present in badChars -- the search step
// behind pwntools' encoders.xor, scoped to a single-byte key (the common
// case: avoiding \x00/\x0a/\x0d in a payload that itself gets typed/parsed
// as text before reaching the target). Returns an error if no byte in
// 0..255 works, which can happen if badChars is large enough that every
// possible key XORs at least one data byte into a forbidden value.
func FindXORKey(data []byte, badChars []byte) (byte, error) {
var bad [256]bool
for _, b := range badChars {
bad[b] = true
}
candidate:
for k := 0; k < 256; k++ {
key := byte(k)
if bad[key] {
continue // the key itself ends up nowhere in the output, but
// disallowing it too keeps the result usable as a literal
// byte elsewhere in the same payload (e.g. a decoder stub
// that embeds the key as an immediate).
}
for _, b := range data {
if bad[b^key] {
continue candidate
}
}
return key, nil
}
return 0, fmt.Errorf("no single-byte XOR key avoids all %d bad chars for this %d-byte input", len(badChars), len(data))
}
// EncodeXOR finds a single-byte XOR key avoiding badChars (via FindXORKey)
// and returns data encoded with it, plus the key itself. Decode by XORing
// again with the same key (see Xor in fiddling.go) -- this is the
// data-level half of pwntools' bad-character avoidance; it does not emit a
// self-decoding stub, so the receiving side needs to already know how to
// undo it (e.g. the target's own code does the XOR, or your script decodes
// a leaked buffer before parsing it).
func EncodeXOR(data []byte, badChars []byte) (encoded []byte, key byte, err error) {
key, err = FindXORKey(data, badChars)
if err != nil {
return nil, 0, err
}
return Xor(data, []byte{key}), key, nil
}
// HasBadChars reports whether data contains any byte in badChars -- the
// quick check before bothering with an encoder at all.
func HasBadChars(data []byte, badChars []byte) bool {
return bytes.ContainsAny(data, string(badChars))
}