Tested with 10+ malicious PDFs, advance ones require parin ng double check.
0xDoc is a forensic tool not a scanner, so technically ikaw parin mag check pero it makes it very easier.
Features
Screenshots

7kb with malicious content

27kb with gibberish



0xDoc is a forensic tool not a scanner, so technically ikaw parin mag check pero it makes it very easier.
Features
- Some Awesome String Matchings
- Nice UI
- Safe File Reading
- Safe File Writing
- Very Fast
Screenshots

7kb with malicious content

27kb with gibberish



Code:
# Dependencies
import std/[os,strutils,re]
# Functions
proc log(a: string, b: string) =
let p = if a == "i": "\x1b[36m[0xDoc]\x1b[0m " elif a == "m": "\x1b[31m[0xDoc]\x1b[0m " elif a == "e": "\x1b[91m[0xDoc]\x1b[0m " else: ""
echo p & b
# Main
echo """
โโโ โโโโโโโโโโ โโโโโโ โโโโโโ
โโ โ โ โโโโโโ โโโโโโโ โโโโโโโ โโ
โโ โ โโโโ โโโโโโ โโโโโโ โ
โ โ โ โ โโโโ โโโโ โโโโโโโ โโโโ
โโโโ โโโโโโโโโโโ โ โโโโโโโโ โโโโโ โ
โโ โ โโ โ โโโ โ โ โโโโโโ โ โโ โ โ
โโ โโ โ โ โ โ โ โ โโ โ โ
โ โ โ โ โ โ โ โ โ โ
โ โ โ โ โ โ โ
โ โ
0xDoc
"""
if paramCount() > 0:
var a:string = paramStr(1)
if fileExists(a) and (a.endsWith(".pdf") or a.endsWith(".doc") or a.endsWith(".docx")):
var fI = getFileInfo(a)
log("i", "File has " & $fI.size & " length.")
log("i", "Safely allocating an area for the file content...")
var fC:ptr string = cast[ptr string](alloc0(fI.size+1))
log("i", "Safely reading the file content...")
copyMem(fC, cstring(readFile(a).replace(re"[^\x09\x0A\x0D\x20-\x7E]+", "")), fI.size)
log("i", "Safely writing the cleaned file content in advance...")
writeFile(a & ".cleaned.txt", $cast[cstring](fC))
log("i", "Printing the cleaned content...")
echo "========================================================================================"
echo $cast[cstring](fC)
echo "========================================================================================"
# Domains
var domains = findall($cast[cstring](fC), re"\w+.com")
log("i", $len(domains) & " domains found.")
if len(domains) != 0:
log("m", domains.join(", "))
# IPs
var ips = findall($cast[cstring](fC), re"\b(?:(?:2(?:[0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9])\.){3}(?:(?:2([0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9]))\b")
log("i", $len(ips) & " ips found.")
if len(ips) != 0:
log("m", ips.join(", "))
# HTTP(s)
var http = findall($cast[cstring](fC), re"""\bhttps?:\/\/[^\s"'<>]+""")
log("i", $len(http) & " http(s) found.")
if len(http) != 0:
log("m", http.join(", "))
# Suspicious Strings
var sS = findall($cast[cstring](fC), re"wscript|mshta|document\.write|ObjStm|ActiveXObject|ADODB\.Stream")
log("i", $len(sS) & " suspicious variables found.")
if len(sS) != 0:
log("m", sS.join(", "))
# Evaluators Strings
var sES = findall($cast[cstring](fC), re"Shell|Environ|Execute|Eval|Chr\(|StrReverse|CreateObject|target=")
log("i", $len(sES) & " suspicious functions found.")
if len(sES) != 0:
log("m", sES.join(", "))
# Execution Strings
var eS = findall($cast[cstring](fC), re"\/Javascript|\/JavaScript|\/JS|\/AA|\/OpenAction|\/Action|Launch|Action|\/SubmitForm|\<submit")
log("i", $len(eS) & " execution strings found.")
if len(eS) != 0:
log("m", eS.join(", "))
# Shells Strings
var slS = findall($cast[cstring](fC), re"powershell|cmd\.exe|cmd\s*/c|certutil|bitsadmin|mshta|this\.getURL")
log("i", $len(slS) & " shells strings found.")
if len(slS) != 0:
log("m", slS.join(", "))
# Evaluators Strings
var scS = findall($cast[cstring](fC), re"(eval|unescape|fromCharCode)\s*\(.*?\)")
log("i", $len(scS) & " evaluators strings found.")
if len(scS) != 0:
log("m", scS.join(", "))
# Base64 Strings
var b64S = findall($cast[cstring](fC), re"[a-zA-Z0-9+/=]{100,}")
log("i", $len(b64S) & " base64 strings found.")
if len(b64S) != 0:
log("m", b64S.join(", "))
# Hex Strings
var hS = findall($cast[cstring](fC), re"\x[0-9a-fA-F]{2,}")
log("i", $len(hS) & " hex strings found.")
if len(hS) != 0:
log("m", hS.join(", "))
# Warning Strings
var wS = findall($cast[cstring](fC), re"\/FlateDecode|hbbd")
log("i", $len(wS) & " warning strings found (this is not 100% always malicious, it's simply a headsup).")
if len(wS) != 0:
log("m", wS.join(", "))
# End
log("i", "Safely deallocating the file content...")
zeroMem(fC, fI.size)
dealloc(fC)
else:
log("e", "No valid file found.")
else:
log("i", "Usage: index <docFile>")