From 32750edbf8a96a84b16df5708d4632adefdc732d Mon Sep 17 00:00:00 2001 From: razvangabriel16 Date: Fri, 12 Dec 2025 06:16:48 +0200 Subject: [PATCH 01/11] Create proposal.md Signed-off-by: razvangabriel16 --- malware-detection-with-llm/proposal.md | 166 +++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 malware-detection-with-llm/proposal.md diff --git a/malware-detection-with-llm/proposal.md b/malware-detection-with-llm/proposal.md new file mode 100644 index 00000000..a8b5ce30 --- /dev/null +++ b/malware-detection-with-llm/proposal.md @@ -0,0 +1,166 @@ +## How to do malware analysis on files to check if they are secure or not? + +We cannot risk running untrusted code directly on our machines because it may affect the system irreversibly, corrupt configuration files, steal credentials, or escape into the host environment. +Therefore, all analysis must be performed inside a sandbox environment. The sandbox should be isolated enough that even malicious code cannot break out. + +### Sandbox Strategy + +If the code appears lightweight and low-risk, we can execute it inside a Docker container. Docker provides OS isolation, namespace separation, cgroups etc. and allows us to disable networking, mount the repo read-only, and restrict capabilities. We can communicate with the container runtime though bind mounts, so we don't have to ensure active networking for protocols like scp etc. +If the code seems dangerous or highly suspicious, we must use a QEMU virtual machine, because QEMU provides full hardware virtualization and does not share the kernel with the host OS. This prevents kernel-level exploits or container-escape vulnerabilities. Though, this imply much more complexity overhead compared with the containerized solution. + +This approach balances speed (Docker) and security (QEMU), depending on threat level. + +### Is static analysis sufficient? + +Static analysis is useful, but entirely insufficient. There are famous cases where malware remained undetected until execution, that happened recently: +- Log4Shell in 2021: harmless-looking text strings triggered remote code execution inside the JVM at runtime. +- XZ Utils backdoor in 2024: the payload was deliberately hidden inside complex build scripts and bytecode, only visible during execution. +- Obfuscated Python malware: imports and payloads decrypted only at runtime, invisible to static AST parsing. + +Because malware can hide behavior behind: +obfuscated loaders, runtime-decrypted payloads, malicious environment-variable triggers, delayed execution, JIT-level behavior (Java/Python and other runtimes), +we must actually run the code in a sandbox and capture its system behavior. + +### Data we pass to the agent + +We will pass multiple files to the analysis agent, including: +The original source code (or binary) +strace logs (syscall-level activity) +ltrace logs (library-level calls) +network logs (if networking is allowed, usually not) +file-system activity logs +runtime exceptions and crash reports +metadata about the environment +This enables the agent to reason from both static and dynamic behavior. +Static checks depending on the runtime / language +Malware analysis depends a lot on the type of runtime. + +1. If we have a binary (C/C++/Rust/Go build or ELF executable) then we can examine it statically using: + +`readelf` - Parses ELF headers, detects suspicious sections (encrypted data blobs, RWX memory, injected segments) +`objdump` - Disassembles code, analysing the symbols, allows detecting: ROP gadgets, shellcode signatures, stack canaries missing, suspicious inline assembly, calls to dangerous libc functions (system, execve, popen) +`strings` - Reveals hidden URLs, IPs, commands, encryption keys +`ldd` - Shows dynamic link dependencies, can show linking to: unknown libraries, malicious preloads, LD_LIBRARY_PATH, dependency hijacking etc. +`Makefile` inspection -look for: custom build steps that download remote code, dynamic code generation, suspicious compiler flags (exmple: -z execstack) + +2. If the runtime includes Python + +Python is much more dangerous because it'ss extremely dynamic. Static AST parsing helps, but we must also check runtime behavior. +Static checks +Parse AST: detect eval, exec, compile, +detect __import__, dynamic imports +detect suspicious modules (subprocess, ctypes, socket) +Detect obfuscation (base64 payloads, XOR loops) +Detect tampering with builtins +Runtime (sandbox) checks +Inside container: +monitor file access, +monitor socket attempts, +detect heavy CPU loops (crypto-miners), +detect subprocess spawning, +intercept ctypes calls (native library loading). +Extra tools: +`pyinstaller` --debug + +`bandit` for static vulnerability scanning + +`python -X utf8 -X dev -v` for verbose import tracing + +3. If the runtime includes Java + +Java malware can hide inside: +.class files +.jar files +dynamic class loaders +remote class fetching (dangerous) +reflection +Static checks +Decompile bytecode with `javap` or CFR +Detect: Class.forName, custom classloaders, +JNI (native code), dynamic bytecode generation, +embedded shell commands +Runtime checks +Inside sandbox: +`strace` JVM monitor: network connections, file I/O, subprocess calls via Runtime.getRuntime.exec() + +Putting it together: the agent's skill +Your agent will have these components: +//To complete + +### Dynamic analysis flow ### + +After getting the scores of static analysis, the dynamic tests are launched within the sandbox environment: +we propose to capture: + +**Monitorization of the process** +Capture `strace` syscalls, `ltrace` libcalls, file access logs (`inotify` like), networking attempts (even if blocked), signals that were raised, resources usage (CPU + memory) + +**Seccomp** +Allows a process to define a filter that controls which +syscalls can execute (like a policy). We can collect all the syscalls denied attempts (strong malware indicators) + +### Arhitecture for dynamic analysis + +image + + +QEMU is a hosted virtual machine monitor: it emulates the machine's processor through dynamic binary translation and provides a set of different hardware and device models for the machine, enabling it to run a variety of guest operating systems. It also can be used with KVM to run virtual machines at near-native speed (by taking advantage of hardware extensions such as Intel VT-x). QEMU can also do emulation for user-level processes, allowing applications compiled for one architecture to run on another. +Qemu can use KVM or not. +If Qemu uses KVM, then Qemu emulates the peripherals (usb, mouse, keyboard, screen, disk, ...) and KVM runs the CPU code +If Qemu does not use KVM, then Qemu emulates the peripherals but also emulates the processor. That is, it runs the code by itself. +The advantage of using KVM is that it uses hardware acceleration provided by the CPU, because it is a kernel module and thus have privileges that Qemu alone wouldn't. +By the way, those hardware accelerations are related to being able to access peripherals (through pcie) in a secure way. +KVM is a “type 2” hypervisor, laying on the host OS. +The architecture of the test suite consists of a Quemu+KVM virtual machine running a Docker container inside it, both layers being equipped with reduced capabilities to encourage security. If we had chosen only one container, potentially dangerous instructions would have been run on the host kernel and therefore during the creation of logs during dynamic analysis we could have corrupted the system. although it is significantly more complex, we greatly reduce the risks. + +Hardening primitives deployed across both sandbox tiers include: ASLR, NX/DEP, PIE-compiled binaries, PaX-style W^X emulation and page-fault–based enforcement, ROP and return-to-libc heuristics, eBPF/JIT restrictions, and vendor-specific hardware protection extensions. +Additional defensive configurations include: +* Intel VMX leveraged for hardware-assisted virtualization of the analysis guest, ensuring that privileged instructions executed by the sample terminate safely within the hypervisor boundary. +* Memory Protection Keys (PKU) within the container to gate process memory accessibility on a per-page basis, minimizing the risk of intra-process memory abuse. +* IOMMU-backed DMA isolation to prevent peripheral-level or emulated-device–level direct memory access attacks from breaching the hypervisor or host. +* Confidential-computing enclaves (Intel SGX, AMD SEV, ARM TrustZone) not as an execution substrate for the specimen, but as a protection layer for sensitive components—such as cryptographic keys used for report attestation or proprietary analysis instrumentation—shielding them even in the presence of partial guest compromise. +This multi-layered, hardware-anchored isolation model substantially elevates the assurance level of the dynamic analysis pipeline while constraining adversarial behavior to strictly sandboxed domains. + +| Hardening Helper| Protection Target | Info | +|----------|----------|----------| +| ASLR | Memory Layout predictability | Makes the address to not be predictable for an attacker | +| NX/DEP | Executing injecting code | Prevents the execution from **.data** pages | +| PIE | Increases ASLR power | Allows randomization for the base of the addresses | +| PaX W^X | Write+Exec Memory | Forces strict separation, blocks injections | +| ROP heuristics | Code reuse exploits | detection of suspicious control flow | +| eBPF/JIT restrictions | Kernel Attack surface | prevents misusing eBPF for kernel compromise | +| RELRO | protect binaries from particularly GOT/PLT overwrites| startup performance cost because all symbols must be resolved at program startup | +| Intel VMX virt. | already used by KVM | nothing to do | + +**Unikernels** comparison: +Unikernels reduce very much the attack surface: no package manager, no shell, no users, no systemd(init processes), minimal syscalls, small code(base). This proposal described before includes Guest Linux kernel, Docker daemon, container runtime, linux fs, net. stack etc.So the security is exponentially boosted. But for this malware analysis the environment is focused on hardened sandbox analysis, virtualization boundaries, layers of mitigations and very important communication needed (maybe ssh etc.). Also, the toolchain would be too complex and not all the apps would run easily. + +---- + +A slash command in Gemini CLI is essentially a custom workflow or task you define for the AI agent. + +- example of slash command structure: +```yaml +name: malware-analysis-with-llm +description: "Analyze code for malware or suspicious behavior with LLM reasoning" +inputs: + - name: code_path + type: string + required: true +pre_scripts: + - ./scripts/static_analysis.sh {{code_path}} + - ./scripts/dynamic_analysis.sh {{code_path}} +llm_prompt: | + You are an AI security agent. + Analyze the following outputs from pre_scripts: + - Strace&Traces logs: {{dyn_analysis_log}} + - Python AST summary: {{python_ast}} + - Java decompiled report: {{java_report}} + Detect suspicious code patterns, unsafe system calls, and potential malware. + Output a risk level (SAFE / SUSPICIOUS / DANGEROUS) and reasoning report. +post_scripts: + - ./scripts/format_report.py {{llm_output}} +outputs: + - risk_level + - report_path +end From 82400d6d765547fe393df3c2a6c31aedd0914b83 Mon Sep 17 00:00:00 2001 From: razvangabriel16 Date: Sat, 13 Dec 2025 05:48:49 +0200 Subject: [PATCH 02/11] Create script.py Signed-off-by: razvangabriel16 --- .../static_analysis/script.py | 346 ++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 malware-detection-with-llm/static_analysis/script.py diff --git a/malware-detection-with-llm/static_analysis/script.py b/malware-detection-with-llm/static_analysis/script.py new file mode 100644 index 00000000..60086da3 --- /dev/null +++ b/malware-detection-with-llm/static_analysis/script.py @@ -0,0 +1,346 @@ +import os +import pathlib +import sys +import threading +import subprocess +import ast +import json +import astroid + +source_extensions = [".py", ".c", ".cpp", ".rs", ".sh", ".java"] + +def is_executable(path: str) -> bool: + return os.access(path, os.X_OK) + +#standard on Linux +def is_elf(path: str) -> bool: + try: + with open(path, "rb") as f: + header = f.read(16) + if len(header) < 16: + return False + if header[:4] != b"\x7fELF": + return False + if header[4] not in (1, 2): + return False + if header[5] not in (1, 2): + return False + return True + except Exception: + return False + +#standard on Windows +def is_pe(path: str) -> bool: + try: + with open(path, "rb") as f: + magic = f.read(2) + if magic != b"MZ": + return False + f.seek(0x3C) + pe_offset = int.from_bytes(f.read(4), "little") + f.seek(pe_offset) + pe_sig = f.read(4) + return pe_sig == b"PE\x00\x00" + except Exception: + return False + +#standard on macOS / iOS +def is_mach_o(path: str) -> bool: + try: + with open(path, "rb") as f: + header = f.read(4) + if len(header) < 4: + return False + mach_o_magics = [b"\xFE\xED\xFA\xCE", + b"\xFE\xED\xFA\xCF", + b"\xCA\xFE\xBA\xBE"] + return header in mach_o_magics + except Exception: + return False + +from abc import ABC, abstractmethod +from pathlib import Path + +#interface for static analysis tools with default run method +class StaticTool(ABC): + name: str + @abstractmethod + def command(self, path: str) -> list[str]: + #command to execute + pass + def run(self, path: str) -> None: + log_dir = "static" + os.makedirs(log_dir, exist_ok=True) + log_file = os.path.join(log_dir, f"{path}.{self.name}.log") + with open(log_file, "w") as f: + subprocess.run(self.command(path), stdout=f, stderr=f, check=False) + print(f"{self.name}:log saved to {log_file}") + +class ReadElf(StaticTool): + name = "readelf" + def command(self, path): + return ["readelf", "-h", "-S", "-l", path] +class ObjDump(StaticTool): + name = "objdump" + def command(self, path): + return ["objdump", "-d", path] +class Strings(StaticTool): + name = "strings" + def command(self, path): + return ["strings", "-a", path] +class NM(StaticTool): + name = "nm" + def command(self, path): + return ["nm", "-a", path] +class LddSafe(StaticTool): + name = "ldd" + def command(self, path): + return ["env", "LD_TRACE_LOADED_OBJECTS=1", "ldd", path] +class Checksec(StaticTool): + name = "checksec" + def command(self, path): + return ["checksec", "--file", path] +class FileCmd(StaticTool): + name = "file" + def command(self, path): + return ["file", path] +class Sha256(StaticTool): + name = "sha256sum" + def command(self, path): + return ["sha256sum", path] +class Md5(StaticTool): + name = "md5sum" + def command(self, path): + return ["md5sum", path] +class Ssdeep(StaticTool): + name = "ssdeep" + def command(self, path): + return ["ssdeep", path] +class Hexdump(StaticTool): + name = "hexdump" + def command(self, path): + return ["hexdump", "-C", path] +class Binwalk(StaticTool): + name = "binwalk" + def command(self, path): + return ["binwalk", path] +class ROPGadgetTool(StaticTool): + name = "ropgadget" + def command(self, path): + return ["ROPgadget", "--binary", path] +class Patchelf(StaticTool): + name = "patchelf" + def command(self, path): + return ["patchelf", "--print-rpath", path] + +DANGEROUS_CALLS = { + "eval", + "exec", + "compile", + "__import__", + "getattr", + "setattr", + "delattr", + "hasattr", + "globals", + "locals", + "vars", + "dir", + "system", + "popen", + "spawn", + "fork", + "execv", + "execve", + "execl", + "execlp", + "loads", + "load", + "dumps", + "open",#combined with exec/eval + "input", + "__builtins__", + "__dict__", +} + +class ASTScanner(ast.NodeVisitor): + def __init__(self): + self.findings = [] + + def visit_Call(self, node): + if isinstance(node.func, ast.Name): + if node.func.id in DANGEROUS_CALLS: + self.findings.append({ + "type": "dangerous_call", + "name": node.func.id, + "line": node.lineno + }) + self.generic_visit(node) + +def run_ast(src: Path, base: Path) -> None: + tree = ast.parse(src.read_text()) + scanner = ASTScanner() + scanner.visit(tree) + out1 = base.with_suffix(".ast.json") + out1.write_text(json.dumps(scanner.findings, indent=2)) + out2 = base.with_suffix(".ast.txt") + dump = ast.dump(tree, annotate_fields=False, include_attributes=False,indent=2) #Depending on True/False the file size varies a lot + with open(out2, "w", encoding="utf-8") as f: + f.write(dump) + +SUSPICIOUS_MODULES = { + "subprocess", + "os", + "pty", + "socket", + "ssl", + "http", + "urllib", + "urllib2", + "requests", + "websocket", + "ctypes", + "cffi", + "mmap", + "importlib", + "imp", + "pickle", + "marshal", + "shelve", + "sys", + "site", + "atexit", + "base64", + "zlib", + "bz2", + "lzma", + "codecs", + "hashlib", + "cryptography", + "Crypto", + "platform", + "getpass", + "pwd", + "grp", + "zipimport", + "pkgutil", + "runpy", +} + + +class Bandit(StaticTool): + name = "bandit" + def command(self, path: str) -> list[str]: + return [ + "bandit", + "-q", + "-f", "json", + path + ] + +def run_astroid(src: Path, base: Path): + mod = astroid.parse(src.read_text()) + findings = [] + for node in mod.body: + if isinstance(node, astroid.Import): + for name, _ in node.names: + if name in SUSPICIOUS_MODULES: + findings.append({ + "type": "suspicious_import", + "module": name, + "line": node.lineno + }) + + if isinstance(node, astroid.ImportFrom): + if node.modname in SUSPICIOUS_MODULES: + findings.append({ + "type": "suspicious_import", + "module": node.modname, + "line": node.lineno + }) + out = base.with_suffix(".astroid.json") + out.write_text(json.dumps(findings, indent=2)) + +def sourcecode(path: str)-> None: + #Todo + src = Path(path) + out_dir = Path("./static") + out_dir.mkdir(parents=True, exist_ok=True) + base = out_dir / src.stem + if path.endswith(".py"): + print(f"Detected Python source code: {path}") + threads = [] + t1 = threading.Thread(target=run_ast, args=(src, base), name="AST-thread") + t1.start() + threads.append(t1) + t2 = threading.Thread(target=run_astroid, args=(src, base), name="ASTROID-thread") + t2.start() + threads.append(t2) + bandit = Bandit() + t3 = threading.Thread(target=bandit.run, args=(path,), name=f"{bandit.name}-thread") + t3.start() + threads.append(t3) + strings = Strings() + t4 = threading.Thread(target=strings.run, args=(path,), name=f"{strings.name}-thread") + t4.start() + threads.append(t4) + for t in threads: + t.join() + elif path.endswith(".java"): + print(f"Detected Java source code: {path}") + #TODO + +""" +Only one thread at a time can execute Python bytecode in a process +even if we have multiple CPU cores (GIL). Paralelism is achieved using a sepparate thread +for each command runed. +""" +def binarycode(path: str) -> None: + if is_elf(path): + print(f"Detected ELF binary: {path}") + elif is_pe(path): + print(f"Detected PE binary: {path}") + elif is_mach_o(path): + print(f"Detected Mach-O binary: {path}") + else: + print(f"!Unknown binary format: {path}") + tools = [ + ReadElf(), ObjDump(), Strings(), + NM(), LddSafe(), Checksec(), FileCmd(), + ROPGadgetTool(), Hexdump(), Binwalk(), + Sha256(), Md5(), Ssdeep(), Patchelf()] + threads = [] + for tool in tools: + t = threading.Thread(target=tool.run, args=(path,), name=f"{tool.name}-thread") + t.start() + threads.append(t) + for t in threads: + t.join() + """ + @Ghidra integration (disabled for now) + binary = pathlib.Path(path) + project_dir = pathlib.Path("/tmp/ghidra_proj") + script_dir = pathlib.Path("/scripts") + ghidra_headless = "/opt/ghidra_10.3.5_PUBLIC/support/analyzeHeadless" + subprocess.run([ + ghidra_headless, + str(project_dir), + "MalwareDetect - cdl25", + "-import", str(binary), + "-scriptPath", str(script_dir), + "-postScript", "ExportDecompiled.java", + "-overwrite" + ], check=True) + """ + +def main(): + assert len(sys.argv) > 1, "The path of the code must be passed as an argument" + path = sys.argv[1] + if any(path.endswith(ext) for ext in source_extensions): + sourcecode(path) + elif is_executable(path): + binarycode(path) + + +if __name__ == "__main__": + main() From 6ef48c858693019311f8f8578456bd15a1836325 Mon Sep 17 00:00:00 2001 From: razvangabriel16 Date: Sat, 13 Dec 2025 05:50:09 +0200 Subject: [PATCH 03/11] Create requirements.txt Signed-off-by: razvangabriel16 --- malware-detection-with-llm/requirements.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 malware-detection-with-llm/requirements.txt diff --git a/malware-detection-with-llm/requirements.txt b/malware-detection-with-llm/requirements.txt new file mode 100644 index 00000000..c6b56733 --- /dev/null +++ b/malware-detection-with-llm/requirements.txt @@ -0,0 +1,10 @@ +astroid==4.0.2 +bandit==1.9.2 +capstone==5.0.6 +markdown-it-py==4.0.0 +mdurl==0.1.2 +Pygments==2.19.2 +PyYAML==6.0.3 +rich==14.2.0 +ROPGadget==7.7 +stevedore==5.6.0 From 5ebcf2811ad44f109e6b5579b2372572528be870 Mon Sep 17 00:00:00 2001 From: razvangabriel16 Date: Sat, 13 Dec 2025 05:51:10 +0200 Subject: [PATCH 04/11] Create indications.yaml Signed-off-by: razvangabriel16 --- .../static_analysis/indications.yaml | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 malware-detection-with-llm/static_analysis/indications.yaml diff --git a/malware-detection-with-llm/static_analysis/indications.yaml b/malware-detection-with-llm/static_analysis/indications.yaml new file mode 100644 index 00000000..03b5a669 --- /dev/null +++ b/malware-detection-with-llm/static_analysis/indications.yaml @@ -0,0 +1,88 @@ +name: static-binary-analysis-with-llm +description: "perform static binary security analysis and reason about anti-analysis: memory corruption and malware indicators with LLM" + +inputs: + - name: path + type: string + required: true + +pre_scripts: + - ./scripts/static_script.py {{path}} +static_path: ./static/ +llm_prompt: | + You are an AI security analyst specialized in static code malware detection. + Analyze the following static_script outputs for binaries or sourcecode: + - Binwalk scan (embedded files, compression, entropy): + {{static_path}}/{{path}}.binwalk.log + - Checksec report (RELRO, NX, PIE, stack canaries): + {{static_path}}/{{path}}.checksec.log + - File command output (binary type, architecture, stripping, linking): + {{static_path}}/{{path}}.file.log + - Hexdump and extracted strings (shellcode patterns, encoded blobs): + {{static_path}}/{{path}}.hexdump.log + - LDD output (runtime dependencies, loader hijacking potential): + {{static_path}}/{{path}}.ldd.log + - MD5 hash (basic fingerprinting / weak hash comparison): + {{static_path}}/{{path}}.md5sum.log + - NM symbols (exported/imported symbols, unsafe functions): + {{static_path}}/{{path}}.nm.log + - Objdump disassembly (instructions, syscalls, anti-analysis): + {{static_path}}/{{path}}.objdump.log + - Patchelf output (RPATH/RUNPATH, interpreter modification): + {{static_path}}/{{path}}.patchelf.log + - ROP gadget scan (available gadgets and syscall sequences): + {{static_path}}/{{path}}.ropgadget.log + - SHA256 hash (strong fingerprinting): + {{static_path}}/{{path}}.sha256sum.log + - SSDeep fuzzy hash (similarity to known malware families): + {{static_path}}/{{path}}.ssdeep.log + - ReadElf output (sections, headers, dynamic linking info): + {{static_path}}/{{path}}.readelf.log + - Strings extraction (potential shellcode, hidden strings): + {{static_path}}/{{path}}.strings.log + Correlate findings across tools. + Do not assume maliciousness from a single indicator. + Detect: + - Anti-debugging, anti-analysis, and obfuscation + - Unsafe or dangerous functions + - Shellcode, payloads, or embedded malicious content + - Exploit techniques (ROP, gadgets) + - Memory corruption risk (GOT/PLT issues) + - Environment hijacking risk + - Packing or self-extracting binaries + - Malware family correlations + + 1. **Instruction-level indicators (isa-instructions)** + Look for suspicious instructions like `rdtsc` (timing anti-debug), `cpuid` (VM/sandbox detection), raw syscalls (`int 0x80`, `syscall`, `sysenter`), `hlt`, interrupt manipulation (`cli`, `sti`), and I/O port access (`in`, `out`). Multiple such instructions or inline assembly in high-level code increases suspicion. + 2. **GOT/PLT / Dynamic Linking Checks** + Analyze RELRO, BIND_NOW, stack protection, and executable stack. Patterns like missing RELRO, partial RELRO with lazy binding, or RWX segments indicate runtime GOT overwrites, delayed symbol resolution, or critical memory corruption risk. + 3. **Sections and Binary Layout** + Examine section sizes, entropy, and naming. High entropy (>7) without readable strings suggests packing or encryption. Code in W sections or data in executable sections is highly suspicious. + 4. **Shellcode and Payload Indicators** + Look for `/bin/sh`, NOP sleds (`\x90\x90\x90`), raw syscalls, hardcoded IPs/domains, base64 or XOR blobs. Presence in `.text` or high-entropy sections increases severity. + 5. **Environment Hijacking / Loader Manipulation** + Check for risky LD_* variables (LD_PRELOAD, LD_LIBRARY_PATH, LD_AUDIT, LD_DEBUG) and unsafe RPATHs (`.`, `/tmp`, user-writable directories) that could allow code injection at load time. + 6. **Symbols and Functions** + Look for dangerous functions (`system`, `execve`, `popen`, `gets`, `strcpy`, `sprintf`) or exported internal symbols. Missing stack protection or obfuscated symbols are additional risk indicators. + 7. **ROP Gadgets** + Scan for high gadget density, `pop-ret` or `syscall-ret` sequences, or gadgets in writable/nonstandard sections. These indicate potential exploit techniques. + 8. **Packing and Embedded Content** + Identify compressed or encrypted blobs, embedded ELF files, or self-extracting content, often indicative of droppers or packed malware. + 9. **Multithreading / Concurrency** + Look for `pthread_create`, `clone`, `futex`, resource spinlocks, manual TLS, or lock-free primitives that may be used for anti-debugging or obfuscation. + 10. **Hash and Similarity Analysis** + Compare SHA256 and fuzzy hashes (ssdeep) to known malware. High similarity, minor variants, or known malware hashes suggest possible family classification. + Correlate findings across all these areas. Avoid relying on a single indicator. Output: + - **Severity**: INFORMATIONAL / MEDIUM / HIGH / CRITICAL + - **Category**: e.g., anti-analysis, memory-corruption, shellcode, unsafe-functions + - **Message**: describe the observed risk + - **Evidence**: relevant log snippets + + Provide a final risk level: SAFE / SUSPICIOUS / DANGEROUS + +post_scripts: + - ./scripts/format_findings_report.py {{llm_output}} + +outputs: + - risk_level + - findings_report_path From 7fd53cb6ba7fbac331999bd3925f219f0f92fe93 Mon Sep 17 00:00:00 2001 From: razvangabriel16 Date: Sat, 13 Dec 2025 05:52:56 +0200 Subject: [PATCH 05/11] Update proposal.md Signed-off-by: razvangabriel16 --- malware-detection-with-llm/proposal.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/malware-detection-with-llm/proposal.md b/malware-detection-with-llm/proposal.md index a8b5ce30..063fdaec 100644 --- a/malware-detection-with-llm/proposal.md +++ b/malware-detection-with-llm/proposal.md @@ -83,10 +83,6 @@ Runtime checks Inside sandbox: `strace` JVM monitor: network connections, file I/O, subprocess calls via Runtime.getRuntime.exec() -Putting it together: the agent's skill -Your agent will have these components: -//To complete - ### Dynamic analysis flow ### After getting the scores of static analysis, the dynamic tests are launched within the sandbox environment: From 8491a7cd20625361d98210397d828af6b037bfb5 Mon Sep 17 00:00:00 2001 From: razvangabriel16 Date: Sat, 13 Dec 2025 06:06:28 +0200 Subject: [PATCH 06/11] Create README.md Signed-off-by: razvangabriel16 --- .../static_analysis/README.md | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 malware-detection-with-llm/static_analysis/README.md diff --git a/malware-detection-with-llm/static_analysis/README.md b/malware-detection-with-llm/static_analysis/README.md new file mode 100644 index 00000000..f578a8c2 --- /dev/null +++ b/malware-detection-with-llm/static_analysis/README.md @@ -0,0 +1,145 @@ +# Static Binary & Source Code Analysis with LLM + +This project provides a **static code and binary security analysis framework** enhanced with **LLM reasoning**. It automates the extraction of indicators from binaries and source code, correlates findings, and produces a risk assessment. + +--- + +## Table of Contents + +- [Overview](#overview) +- [Architecture](#architecture) +- [Supported Analysis](#supported-analysis) +- [Agent & LLM Workflow](#agent--llm-workflow) +- [Directory Structure](#directory-structure) +- [Usage](#usage) + +--- + +## Overview + +The system analyzes both **compiled binaries** and **source code** to detect: + +- Anti-debugging and anti-analysis techniques +- Memory corruption vulnerabilities (GOT/PLT, RWX segments) +- Dangerous or unsafe functions +- Shellcode or embedded payloads +- Packing, obfuscation, or self-extracting binaries +- Malware family indicators + +It combines **classical static analysis tools** with **Python AST and ASTroid scans**, and optionally integrates **LLM reasoning** to summarize and correlate findings. + +--- + +## Architecture + +The framework is composed of: + +### 1. Static Analysis Scripts (`static_script.py`) +- Detects file type: source vs binary +- Runs multiple static tools in parallel threads +- Produces log files in a structured format (`./static/`) + +### 2. Tool Abstraction Layer +- Interface: `StaticTool` (run command, log results) +- Built-in implementations: + - `ReadElf`, `ObjDump`, `Strings`, `NM`, `LddSafe`, `Checksec`, `FileCmd` + - `ROPgadgetTool`, `Hexdump`, `Binwalk`, `Sha256`, `Md5`, `Ssdeep`, `Patchelf` +- Python-specific tools: + - `ASTScanner` (detect dangerous calls) + - `ASTroidScanner` (detect suspicious imports) + - `Bandit` (static vulnerability scan) + +### 3. LLM Agent Layer +- Orchestrated via YAML configuration (`static-binary-analysis-with-llm.yaml`) +- Inputs: paths to logs from the pre-scripts +- Prompt instructs the LLM to: + - Correlate findings across all static tools + - Detect suspicious behavior, obfuscation, anti-analysis + - Produce a risk level (**SAFE / SUSPICIOUS / DANGEROUS**) + - Output a structured findings report + +--- + +## Supported Analysis + +### Source Code +- **Python**: AST, ASTroid, Bandit, strings scan +- **Java**: (planned) AST parsing, import analysis, strings +- **Other languages**: C/C++, Rust, Shell scripts (basic detection) + +### Binaries +- ELF, PE, Mach-O detection +- Sections and segment layout +- Relocations (GOT/PLT, RWX segments) +- Executable stack, partial RELRO +- Strings and hexdump extraction +- ROP gadgets +- Hashing and fuzzy matching + +--- + +## Agent & LLM Workflow + +1. **Pre-scripts** + - The YAML file instructs the agent to run `static_script.py` for a given path. + +2. **Log generation** + - Each tool produces a log in the `./static/` directory (one file per tool per binary/source). + +3. **LLM reasoning** + - Reads all logs via paths defined in YAML (`{{static_path}}/{{path}}..log`) + - Correlates indicators (e.g., high-entropy sections + shellcode patterns) + - Produces: + - **Severity** (Informational / Medium / High / Critical) + - **Category** (anti-analysis, shellcode, unsafe-functions, etc.) + - **Evidence** (log snippets, line numbers, sections) + - Computes a **final risk level** for the artifact + +4. **Post-scripts** + - Formatting the LLM output into a structured report (`findings_report_path`) + +--- + +## Framework extends + +Add new static tools: subclass StaticTool and implement command() +Add new languages: implement run_ function similar to sourcecode() +Custom LLM prompts: adjust YAML llm_prompt to incorporate additional indicators +Ghidra integration: for C/C++ binaries, decompile and extract functions via analyzeHeadless + +## Usage + +```python +python3 scripts/static_script.py /path/artifact +``` +but not later than setting the virtual environment with the required modules +```python +python3 -m venv .venv +source .venv/bin/activate +pip install requirements.txt +``` +also system requirements (APT) + +```bash +sudo apt update +sudo apt install -y \ + python3 \ + python3-venv \ + python3-pip \ + binutils \ + file \ + coreutils \ + util-linux \ + libc-bin +sudo apt install -y \ + checksec \ + binwalk \ + ssdeep +sudo apt install -y ropgadget +#optionals +sudo apt install -y openjdk-17-jdk +sudo apt install -y openjdk-17-jdk unzip wget + +#for environment validation +which objdump nm readelf strings ldd checksec binwalk ROPgadget bandit ssdeep +``` From 36579c65fd4832f386949f4981508801699947fa Mon Sep 17 00:00:00 2001 From: razvangabriel16 Date: Sat, 13 Dec 2025 06:07:28 +0200 Subject: [PATCH 07/11] Update README.md Signed-off-by: razvangabriel16 --- malware-detection-with-llm/static_analysis/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/malware-detection-with-llm/static_analysis/README.md b/malware-detection-with-llm/static_analysis/README.md index f578a8c2..a5a1d168 100644 --- a/malware-detection-with-llm/static_analysis/README.md +++ b/malware-detection-with-llm/static_analysis/README.md @@ -36,7 +36,7 @@ The framework is composed of: ### 1. Static Analysis Scripts (`static_script.py`) - Detects file type: source vs binary -- Runs multiple static tools in parallel threads +- Runs multiple static tools in parallel threads for performance boost - Produces log files in a structured format (`./static/`) ### 2. Tool Abstraction Layer From 111d322267c97e21459bde72ee0f6483c9bf55e1 Mon Sep 17 00:00:00 2001 From: razvangabriel16 Date: Sat, 13 Dec 2025 12:40:30 +0200 Subject: [PATCH 08/11] Create script.py Signed-off-by: razvangabriel16 --- .../dynamic_analysis/script.py | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 malware-detection-with-llm/dynamic_analysis/script.py diff --git a/malware-detection-with-llm/dynamic_analysis/script.py b/malware-detection-with-llm/dynamic_analysis/script.py new file mode 100644 index 00000000..5fceaa96 --- /dev/null +++ b/malware-detection-with-llm/dynamic_analysis/script.py @@ -0,0 +1,59 @@ +import subprocess +import time +import os + +CLOUD_IMAGE = "noble-server-cloudimg-amd64.img" +USER_DATA = "user-data.yaml" +META_DATA = "meta-data.yaml" +SEED_ISO = "seed.iso" + +HOST_LOG_DIR = "logs_host" +VM_LOG_DIR = "/mnt/logs" + +QEMU_CMD = [ + "qemu-system-x86_64", + "-m", "4G", + "-smp", "2", + "-cpu", "qemu64", #"host", if you can access the host cpu features, otherwise qemu64 (much slower, but more compatible) + "-drive", f"file={CLOUD_IMAGE},format=qcow2", + "-drive", f"file={SEED_ISO},format=raw", + "-netdev", "user,id=net0", + "-device", "virtio-net-pci,netdev=net0", + "-virtfs", f"local,path={HOST_LOG_DIR},mount_tag=shared_logs,security_model=passthrough,id=logs", + "-nographic" +] + + +def create_seed_iso(): + print("Creating seed.iso cloud-init...") + if os.path.exists(SEED_ISO): + os.remove(SEED_ISO) + subprocess.check_call([ + "cloud-localds", + SEED_ISO, + USER_DATA, + META_DATA + ]) + + +def ensure_host_log_dir(): + print("Checkings!") + if not os.path.exists(HOST_LOG_DIR): + os.makedirs(HOST_LOG_DIR) + + +def start_qemu(): + print("Starting QEMU vm!") + return subprocess.Popen(QEMU_CMD) + + +def main(): + ensure_host_log_dir() + create_seed_iso() + vm = start_qemu() + print("The container inside the VM will write logs to:", HOST_LOG_DIR) + vm.wait() + + +if __name__ == "__main__": + main() From 9515aaee3ccaa760d4edb2e4b152927e646a9845 Mon Sep 17 00:00:00 2001 From: razvangabriel16 Date: Sat, 13 Dec 2025 12:41:24 +0200 Subject: [PATCH 09/11] Create meta-data.yaml Signed-off-by: razvangabriel16 --- malware-detection-with-llm/dynamic_analysis/meta-data.yaml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 malware-detection-with-llm/dynamic_analysis/meta-data.yaml diff --git a/malware-detection-with-llm/dynamic_analysis/meta-data.yaml b/malware-detection-with-llm/dynamic_analysis/meta-data.yaml new file mode 100644 index 00000000..cc37ab75 --- /dev/null +++ b/malware-detection-with-llm/dynamic_analysis/meta-data.yaml @@ -0,0 +1,2 @@ +instance-id: iid-local01 +local-hostname: autovm From 9620e6cfb8382df4758edd536397ba80abe1705a Mon Sep 17 00:00:00 2001 From: razvangabriel16 Date: Sat, 13 Dec 2025 12:42:34 +0200 Subject: [PATCH 10/11] Create user-data.yaml Signed-off-by: razvangabriel16 --- .../dynamic_analysis/user-data.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 malware-detection-with-llm/dynamic_analysis/user-data.yaml diff --git a/malware-detection-with-llm/dynamic_analysis/user-data.yaml b/malware-detection-with-llm/dynamic_analysis/user-data.yaml new file mode 100644 index 00000000..900394a8 --- /dev/null +++ b/malware-detection-with-llm/dynamic_analysis/user-data.yaml @@ -0,0 +1,17 @@ +hostname: autovm +package_update: true +package_upgrade: true + +packages: + - docker.io +#its a test only for communication through bind mounts, doesn't have logic yet +runcmd: + - mkdir -p /mnt/logs + - mount -t 9p -o trans=virtio,version=9p2000.L shared_logs /mnt/logs + - systemctl enable docker + - systemctl start docker + - docker run -d \ + --restart=always \ + --name logcollector \ + -v /mnt/logs:/var/log/myapp \ + bash -c "while true; do echo \"$(date) TEST LOG\" >> /var/log/myapp/test.log; sleep 1; done" From 36a0f58ac2048c6ecd1f285b167d2fd5cc6201cc Mon Sep 17 00:00:00 2001 From: razvangabriel16 Date: Sat, 13 Dec 2025 12:51:10 +0200 Subject: [PATCH 11/11] Create README.md Signed-off-by: razvangabriel16 --- .../dynamic_analysis/README.md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 malware-detection-with-llm/dynamic_analysis/README.md diff --git a/malware-detection-with-llm/dynamic_analysis/README.md b/malware-detection-with-llm/dynamic_analysis/README.md new file mode 100644 index 00000000..3d9955b6 --- /dev/null +++ b/malware-detection-with-llm/dynamic_analysis/README.md @@ -0,0 +1,23 @@ +# Dynamic Binary & Source Code Analysis with LLM + +This project provides a **dynamic code and binary security analysis framework** enhanced with **LLM reasoning**. It automates the extraction of indicators from binaries and source code, correlates findings, and produces a risk assessment. +For moment, the setup only tests how the logs are saved in the host machine, using bind mounts between container and virtual machine, and then virtfs between virtual machine and host. +--- + +## Table of Contents +- [Usage](#usage) + +--- + +### Currently issue +The issue i'm hitting with QEMU/KVM on WSL is that KVM requires hardware virtualization extensions (Intel VT-x/AMD-V) to be available to the Linux kernel, but WSL doesn't expose these to the guest Linux environment. +WSL itself is a virtualized environment: WSL2 runs Linux in a lightweight VM managed by Hyper-V. I am likely trying to run nested virtualization + +## Usage + +```bash +wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img +qemu-img resize noble-server-cloudimg-amd64.img +20G +cloud-localds seed.iso user-data.yaml meta-data.yaml +python3 ./script.py +```