sometimes you don’t want to store the message, you want to embed it or somehow hide it in an ambient structure that only yields its contents when you apply the right ritual. the code above does exactly that: transforms a plaintext payload (print("hello world")) into a sparse sequence of integers (t_list) derived from the sign of a composite wave. the reconstruction is a one-liner that looks like a pythonic ritual incantation: a loop of lambdas, sign-tests, and binary joins collapsing into an exec.
import math
payload = 'print("hello world")'
def wave(t):
return math.cos(t) + math.sin(t) + 0.5*math.sin(3*t) # example: sines
bits = []
for c in payload:
bits.extend([int(x) for x in bin(ord(c))[2:].zfill(8)])
t_list = []
t = 0
for bit in bits:
while int(wave(t) > 0) != bit:
t += 1
t_list.append(t)
t += 1 # ensure uniqueness
one_liner = (
"import math; exec(''.join([chr(int(''.join(str(int(({wf})(t)>0)) "
"for t in {tl}[i:i+8]),2)) for i in range(0,len({tl}),8)]))"
).format(wf='lambda t: math.cos(t) + math.sin(t)+0.5*math.sin(3*t)', tl=t_list)
print("one-liner:\n", one_liner)
exec(one_liner)
Before you yell at me and say that “any exec can be made into a printf” remember that this is not the point, in the actual implementation I used bytecode compiling to ship the de-obfuscator with t_list.
the core mechanism
at heart, the method uses a simple bitmasking principle powered by the binary nature of sign operators, namely using them as a map from $\Re \rightarrow [0,1]$
\[b(t) = \mathbf{1}[\,f(t) > 0\,]\]where $ f(t) = \cos(t) + \sin(t) + \tfrac{1}{2}\sin(3t) $ (Or any arbitary periodic function really).
to encode a bitstream, we iterate t until the observed sign matches the next bit. every increment of t is effectively a brute-force search for alignment between the signal and the desired bit. the resulting sequence of ts is a record of those synchronization points.
the payload’s raw text is never stored directly. instead, each character’s ASCII binary expands into 8 bits, each bit into a “time index,” and only those times are preserved. the compression here is negative, but the obfuscation is maximal: a nonsensical list of integers that only regains meaning when placed in the context of the wave function.
reconstruction pipeline
the one-liner generated by the script is the demodulator. in expanded form:
- iterate over the integer sequence
t_listin chunks of 8. - for each
t, computeint(f(t) > 0). this yields one binary digit. - concatenate those 8 bits into a string, interpret it as base-2, and recover an ASCII code.
- map codes back to characters, join into a string, feed into
exec.
So basically we could -theoretically- just ship the function and this t_list if we were to use this method to obfuscate a malware payload.
signal-theoretic framing
from an information theory perspective, this is a toy modulation scheme:
- carrier: the periodic function $ f(t) $.
- symbol alphabet: sign(f(t)), i.e. {0,1}.
- encoding rule: for each desired bit, advance t until the carrier symbol matches.
- ciphertext: the ordered set of indices where matches occurred.
this is maybe-perhaps-please a form of time-domain encoding: we’re not storing the symbols directly, but the times at which the carrier assumes them. in communications, it resembles pulse-position modulation (PPM), except our pulses are synthetic wave crossings instead of actual signal spikes.
the redundancy is extreme: you need as many integers as there are bits, plus the shared knowledge of the waveform. but redundancy here is not a bug, it’s kind of the point, the payload is obfuscated inside the interaction between time and oscillation.
complexity and fragility
encoding is computationally ugly: O(n·m) where n = number of bits and m = average gap until the next matching sign. since wave(t) oscillates often, m is bounded, but still the process scales linearly with payload size and each increment is a costly float evaluation.
decoding is lightweight: a single pass through t_list, each step a few trig ops and a comparison. the asymmetry mirrors real-world crypto: heavy encode, light decode. in a practical application the encoding time complexity does not matter, since the decoding process is complex, but not slow.
fragility: change the waveform definition by a single coefficient, and the entire mapping collapses. even altering the inequality direction (>0 vs <0) flips the payload. this brittleness is both weakness (not robust) and strength (highly keyed).
cryptographic analogy
one could argue this construction is a degenerate cipher. the “key” is the waveform definition, and the “ciphertext” is t_list. without the key, reconstructing the payload is nontrivial. the search space of possible waveforms is infinite-dimensional, but in practice, with access to the code, it’s trivial. so cryptographically: worthless. but aesthetically: rich.
a neat extension would be to introduce parameterized chaos: let f(t) depend on a seed value (say, a logistic map parameter or a random Fourier series). then t_list is inert unless decoded with the correct seed. suddenly the trivial “decode by inspection” step requires brute-forcing a continuous parameter space.
extensions and escalation paths
- chaotic carriers: logistic, henon, or lorenz maps instead of sines. the zero-crossings become non-periodic, harder to model, but still deterministic given the seed.
- multi-channel embedding: split payload bits across several functions. only when all channels are recombined does the original byte stream appear.
- floating-point ciphertext: instead of advancing
tin integers, solve for the exact crossing time for each bit. ciphertext becomes irrational reals; decoding needs higher fidelity math. - cover traffic: blend valid
t_listvalues with dummies. only positions determined by a secondary rule (e.g. prime indices) actually contribute to the payload. - format camouflage: store
t_listinside image pixels, json config fields, or timestamp sequences. the list looks like harmless data until passed through the reconstruction pipeline.
cultural + maldev note
from a malware developer’s perspective, the strength isn’t in cryptographic hardness or in design or anywhere at all to be frankly honest, but maybe in cognitive overhead. analysts are trained to spot base64, xor, rot13—this forces them into the domain of signals and dynamical systems. every additional layer of unfamiliarity is time burned on triage.
this isn’t bulletproof obfuscation, but it is entropy injection: enough to break trivial detection pipelines and amuse anyone who thinks in both code and math. in practice you wouldn’t ship raw sines, you’d parameterize the wave with a secret, bury t_list in some innocuous structure, and let your de-obfuscator quietly reconstruct the payload at runtime.
anyways, check out the repo: