Files
docker_file_analysis/scripts/fhelp
T
tobias e62a14dafc Add markdown wiki with 473 pages and zk browser
Generate interlinked wiki from master inventory: 397 tool pages,
15 workflow pages, 27 recipe pages, 33 category pages, plus index.
All pages use [[wiki-links]] for cross-navigation between tools,
workflows, recipes, and categories (1782 links total).

Install zk for interactive browsing with fzf search, tag filtering,
and backlink discovery. Add 'fhelp wiki' command and Makefile target.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 19:50:36 +01:00

574 lines
19 KiB
Bash
Executable File

#!/bin/bash
# Enhanced File Analysis Help System
# Integrates multiple help sources: custom cheat sheets, tldr, tool database, and workflows
# Color definitions
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
NC='\033[0m'
# Help system paths
TOOLS_DB="${TOOLS_DB:-/opt/remnux-docs/tools.db}"
CHEAT_DIR="${CHEAT_DIR:-/opt/cheatsheets}"
WORKFLOW_DIR="${WORKFLOW_DIR:-/opt/remnux-docs/workflows}"
TLDR_CACHE="${TLDR_CACHE:-/home/remnux/.local/share/tldr}"
WIKI_DIR="${WIKI_DIR:-/opt/wiki}"
# Resolve cheat file names from a user-provided tool name
# Tries several variants: exact, without .py, with .py, hyphen/underscore alternatives
resolve_cheat_file() {
local name="$1"
local base=$(echo "$name" | sed 's/\.[Pp][Yy]$//')
# candidates to try in order
local candidates=(
"$name"
"$base"
"${base}.py"
"${base//_/}"
"${base//-/_}"
"${base//_/-}"
)
for cand in "${candidates[@]}"; do
if [[ -f "$CHEAT_DIR/personal/$cand" ]]; then
echo "$CHEAT_DIR/personal/$cand"
return 0
fi
if [[ -f "$CHEAT_DIR/personal/${cand}.cheat" ]]; then
echo "$CHEAT_DIR/personal/${cand}.cheat"
return 0
fi
if [[ -f "$CHEAT_DIR/${cand}.cheat" ]]; then
echo "$CHEAT_DIR/${cand}.cheat"
return 0
fi
done
return 1
}
show_main_help() {
echo -e "${CYAN}REMnux Analysis Container Help System${NC}"
echo "======================================="
echo ""
echo -e "${GREEN}Getting Started:${NC}"
echo " fhelp start - Quick start guide (30 seconds)"
echo ""
echo -e "${GREEN}Find Tools:${NC}"
echo " fhelp tools <keyword> - Search by name or category"
echo " fhelp tools --interactive - Interactive browser (fzf)"
echo " Ctrl+G - Interactive cheatsheet browser (navi)"
echo ""
echo -e "${GREEN}Get Examples:${NC}"
echo " fhelp cheat <tool> - Usage examples for a specific tool"
echo " fhelp quick <command> - Quick tldr examples"
echo " F1 / Ctrl+/ - Help for command you're typing (zsh)"
echo ""
echo -e "${GREEN}Analysis Workflows:${NC}"
echo " fhelp workflow - List all 8 analysis workflows"
echo " fhelp workflow <name> - Show step-by-step workflow"
echo ""
echo -e "${GREEN}Wiki:${NC}"
echo " fhelp wiki - Browse the analysis wiki (zk)"
echo " fhelp wiki <tool> - Open a specific wiki page"
echo ""
echo -e "${GREEN}Other:${NC}"
echo " fhelp coverage - Help coverage statistics"
echo " fhelp examples - Browse all cheat sheets"
echo " fhelp --offline - Verify offline capabilities"
echo ""
echo -e "${YELLOW}Shortcuts:${NC} analyse, h, ? (all run fhelp)"
echo ""
echo -e "${YELLOW}Examples:${NC}"
echo " fhelp tools pdf # Find PDF analysis tools"
echo " fhelp cheat pdfid.py # pdfid.py usage examples"
echo " fhelp workflow static # Static analysis workflow"
}
show_start() {
echo -e "${CYAN}Quick Start Guide${NC}"
echo "================="
echo ""
# Count tools
local tool_count=0
local rich_count=0
if [[ -f "$TOOLS_DB" ]]; then
tool_count=$(wc -l < "$TOOLS_DB" 2>/dev/null || echo 0)
rich_count=$(grep -c '|rich$' "$TOOLS_DB" 2>/dev/null || echo 0)
fi
echo -e " This container has ${GREEN}${tool_count} analysis tools${NC} installed."
echo -e " ${GREEN}${rich_count}${NC} have detailed help with FOR610 lab examples."
echo ""
echo -e "${YELLOW}1. Find a tool:${NC}"
echo " fhelp tools pdf # search by keyword"
echo " fhelp tools --interactive # browse with fuzzy search"
echo ""
echo -e "${YELLOW}2. Get usage examples:${NC}"
echo " fhelp cheat pdfid.py # cheat sheet with examples"
echo " fhelp cheat oledump.py # Office document analysis"
echo " fhelp cheat capa # malware capabilities"
echo ""
echo -e "${YELLOW}3. Follow a workflow:${NC}"
echo " fhelp workflow # list all workflows"
echo " fhelp workflow static # static analysis steps"
echo " fhelp workflow document # document analysis steps"
echo ""
echo -e "${YELLOW}4. Interactive help:${NC}"
echo -e " ${GREEN}Ctrl+G${NC} # browse cheatsheets (navi)"
echo -e " ${GREEN}F1${NC} or ${GREEN}Ctrl+/${NC} # help for command you're typing (zsh)"
echo ""
echo -e "${YELLOW}5. Tool tiers:${NC}"
echo -e " ${GREEN}[FOR610]${NC} Rich help with lab examples and workflows"
echo -e " ${BLUE}[docs]${NC} Standard help from REMnux documentation"
echo -e " ${YELLOW}[basic]${NC} Minimal help (try: tool --help)"
echo ""
echo "Mount your files to /work/ and start analyzing!"
}
show_cheat() {
local tool="$1"
if [[ -z "$tool" ]]; then
echo -e "${RED}Please specify a tool name${NC}"
echo "Usage: fhelp cheat <tool>"
return 1
fi
# Check for specific workflow cheat sheets first
local cheat_file=""
case "$tool" in
"pdf"|"pdf-analysis")
cheat_file="$CHEAT_DIR/pdf-analysis.cheat"
;;
"malware"|"malware-analysis")
cheat_file="$CHEAT_DIR/malware-analysis.cheat"
;;
"system"|"system-utilities")
cheat_file="$CHEAT_DIR/system-utilities.cheat"
;;
*)
cheat_file=""
;;
esac
# If not a workflow cheat, try to resolve tool-specific cheat
if [[ -z "$cheat_file" || ! -f "$cheat_file" ]]; then
cheat_file=$(resolve_cheat_file "$tool") || cheat_file=""
fi
if [[ -n "$cheat_file" && -f "$cheat_file" ]]; then
echo -e "${CYAN}Cheat Sheet: ${YELLOW}$tool${NC}"
echo "$(printf '=%.0s' $(seq 1 $((${#tool} + 14))))"
echo ""
# Display cheat file content (skip YAML frontmatter if present)
awk '/^---$/{if(++c==2) start=1; next} start || !/^---$/ && c!=1' "$cheat_file"
elif command -v cheat >/dev/null 2>&1 && cheat "$tool" >/dev/null 2>&1; then
# Fallback: try the cheat command
echo -e "${CYAN}Cheat Sheet (cheat): ${YELLOW}$tool${NC}"
echo "$(printf '=%.0s' $(seq 1 $((${#tool} + 22))))"
echo ""
cheat "$tool"
elif command -v tldr >/dev/null 2>&1 && tldr "$tool" >/dev/null 2>&1; then
# Fallback: try tldr
echo -e "${CYAN}Quick Reference (tldr): ${YELLOW}$tool${NC}"
echo "$(printf '=%.0s' $(seq 1 $((${#tool} + 24))))"
echo ""
tldr "$tool"
else
echo -e "${YELLOW}No help found for '$tool'${NC}"
echo ""
# Suggest similar tools
if [[ -f "$TOOLS_DB" ]]; then
local matches=$(grep -i "$tool" "$TOOLS_DB" 2>/dev/null | head -5)
if [[ -n "$matches" ]]; then
echo "Did you mean one of these?"
echo "$matches" | while IFS='|' read -r name desc cat usage tier; do
local badge=""
case "$tier" in
rich) badge="${GREEN}[FOR610]${NC}" ;;
standard) badge="${BLUE}[docs]${NC}" ;;
*) badge="${YELLOW}[basic]${NC}" ;;
esac
echo -e " ${GREEN}$name${NC} $badge - $desc"
done
fi
fi
return 1
fi
}
show_quick() {
local command="$1"
if [[ -z "$command" ]]; then
echo -e "${RED}Please specify a command name${NC}"
echo "Usage: fhelp quick <command>"
return 1
fi
echo -e "${CYAN}Quick examples for: ${YELLOW}$command${NC}"
echo ""
if command -v tldr >/dev/null 2>&1; then
if ! tldr "$command" 2>/dev/null; then
echo -e "${YELLOW}No tldr page found for '$command'${NC}"
echo "Try: fhelp cheat $command"
fi
else
echo -e "${RED}tldr command not available${NC}"
return 1
fi
}
show_tools() {
local search_term="$1"
local option="$2"
case "$search_term" in
"--interactive")
if command -v find-tool >/dev/null 2>&1; then
find-tool --interactive
else
echo -e "${RED}find-tool not available${NC}"
fi
return
;;
"--list")
if command -v find-tool >/dev/null 2>&1; then
find-tool --list
else
echo -e "${RED}find-tool not available${NC}"
fi
return
;;
esac
if [[ -z "$search_term" ]]; then
echo -e "${RED}Please provide a search term${NC}"
echo "Usage: fhelp tools <search_term>"
echo " fhelp tools --interactive"
echo " fhelp tools --list"
return 1
fi
echo -e "${CYAN}Searching analysis tools for '${YELLOW}$search_term${CYAN}'...${NC}"
echo ""
if command -v find-tool >/dev/null 2>&1; then
find-tool "$search_term"
elif [[ -f "$TOOLS_DB" ]]; then
# Fallback: direct grep on tools.db
local results=$(grep -i "$search_term" "$TOOLS_DB" 2>/dev/null)
if [[ -n "$results" ]]; then
echo "$results" | while IFS='|' read -r name desc cat usage tier; do
local tier_badge=""
case "$tier" in
rich) tier_badge="${GREEN}[FOR610]${NC}" ;;
standard) tier_badge="${BLUE}[docs]${NC}" ;;
basic) tier_badge="${YELLOW}[basic]${NC}" ;;
*) tier_badge="" ;;
esac
echo -e " ${GREEN}$name${NC} $tier_badge"
echo " $desc"
echo " Usage: $usage"
echo ""
done
else
echo "No tools found matching '$search_term'"
fi
else
echo -e "${RED}No tools database available${NC}"
fi
}
show_examples() {
echo -e "${CYAN}Available Command Examples${NC}"
echo ""
if [[ -d "$CHEAT_DIR/personal" ]]; then
local count=$(ls -1 "$CHEAT_DIR/personal/"*.cheat 2>/dev/null | wc -l)
echo -e "${GREEN}Per-tool cheat sheets: $count${NC} (use: fhelp cheat <name>)"
echo ""
# Show a sample of tools grouped by first letter
ls -1 "$CHEAT_DIR/personal/"*.cheat 2>/dev/null | sed 's|.*/||; s|\.cheat$||' | head -30 | sed 's/^/ /'
if [[ $count -gt 30 ]]; then
echo " ... and $((count - 30)) more"
fi
echo ""
fi
if [[ -d "$CHEAT_DIR" ]]; then
echo -e "${GREEN}Workflow cheat sheets:${NC}"
ls -1 "$CHEAT_DIR"/*.cheat 2>/dev/null | sed 's|.*/||; s|\.cheat$||' | sed 's/^/ /'
echo ""
fi
echo -e "${GREEN}Analysis workflows:${NC} (use: fhelp workflow <name>)"
if [[ -d "$WORKFLOW_DIR" ]]; then
ls -1 "$WORKFLOW_DIR"/*.txt 2>/dev/null | sed 's|.*/||; s|\.txt$||' | grep -v index | sed 's/^/ /'
else
echo " static-analysis, behavioral-analysis, network-interception"
echo " document-analysis, javascript-deobfuscation, unpacking"
echo " code-injection, dotnet-analysis"
fi
}
show_workflow() {
local name="$1"
if [[ -z "$name" ]]; then
# Show workflow index
if [[ -f "$WORKFLOW_DIR/index.txt" ]]; then
cat "$WORKFLOW_DIR/index.txt"
else
echo -e "${CYAN}Available Analysis Workflows${NC}"
echo "=============================="
echo ""
echo " static-analysis-workflow Static Properties Analysis"
echo " behavioral-analysis-workflow Behavioral Analysis"
echo " network-interception-workflow Network Interception"
echo " document-analysis-workflow Malicious Document Analysis"
echo " javascript-deobfuscation-workflow JavaScript Deobfuscation"
echo " unpacking-workflow Unpacking Packed Executables"
echo " code-injection-workflow Code Injection Analysis"
echo " dotnet-analysis-workflow .NET Malware Analysis"
echo ""
echo "Usage: fhelp workflow <name>"
echo "Example: fhelp workflow static-analysis"
fi
return
fi
# Normalize name: allow partial matches
local wf_file=""
# Try exact match first
if [[ -f "$WORKFLOW_DIR/${name}.txt" ]]; then
wf_file="$WORKFLOW_DIR/${name}.txt"
elif [[ -f "$WORKFLOW_DIR/${name}-workflow.txt" ]]; then
wf_file="$WORKFLOW_DIR/${name}-workflow.txt"
else
# Fuzzy match: find workflow files containing the search term
if [[ -d "$WORKFLOW_DIR" ]]; then
wf_file=$(ls -1 "$WORKFLOW_DIR"/*.txt 2>/dev/null | grep -i "$name" | grep -v index | head -1)
fi
fi
if [[ -n "$wf_file" && -f "$wf_file" ]]; then
cat "$wf_file"
else
echo -e "${YELLOW}No workflow found matching '$name'${NC}"
echo ""
show_workflow # Show list
fi
}
show_coverage() {
echo -e "${CYAN}Help Coverage Statistics${NC}"
echo "========================"
echo ""
if [[ -f "$TOOLS_DB" ]]; then
local total=$(wc -l < "$TOOLS_DB" 2>/dev/null || echo 0)
local rich=$(grep -c '|rich$' "$TOOLS_DB" 2>/dev/null || echo 0)
local standard=$(grep -c '|standard$' "$TOOLS_DB" 2>/dev/null || echo 0)
local basic=$(grep -c '|basic$' "$TOOLS_DB" 2>/dev/null || echo 0)
echo -e " Tools in database: ${GREEN}$total${NC}"
echo -e " Rich help (FOR610): ${GREEN}$rich${NC}"
echo -e " Standard (docs): ${BLUE}$standard${NC}"
echo -e " Basic: ${YELLOW}$basic${NC}"
else
echo " Tools database not available"
fi
echo ""
if [[ -d "$CHEAT_DIR/personal" ]]; then
local cheats=$(ls -1 "$CHEAT_DIR/personal/"*.cheat 2>/dev/null | wc -l)
echo -e " Cheat sheets: ${GREEN}$cheats${NC}"
fi
if [[ -d "$WORKFLOW_DIR" ]]; then
local wfs=$(ls -1 "$WORKFLOW_DIR"/*.txt 2>/dev/null | grep -cv index 2>/dev/null || echo 0)
echo -e " Workflows: ${GREEN}$wfs${NC}"
fi
}
show_offline_status() {
echo -e "${CYAN}Offline Capability Check${NC}"
echo "==========================="
echo ""
echo "Documentation Tools:"
local tools=("find-tool" "cheat" "tldr")
for tool in "${tools[@]}"; do
if command -v "$tool" >/dev/null 2>&1; then
echo -e " ${GREEN}+ $tool - available${NC}"
else
echo -e " ${RED}- $tool - missing${NC}"
fi
done
echo ""
echo "Documentation Files:"
if [[ -f "$TOOLS_DB" ]]; then
local db_count=$(wc -l < "$TOOLS_DB" 2>/dev/null || echo 0)
echo -e " ${GREEN}+ tools.db - $db_count tools${NC}"
else
echo -e " ${RED}- tools.db - missing${NC}"
fi
if [[ -d "$CHEAT_DIR/personal" ]]; then
local cheat_count=$(ls -1 "$CHEAT_DIR/personal/"*.cheat 2>/dev/null | wc -l)
echo -e " ${GREEN}+ cheatsheets - $cheat_count files${NC}"
else
echo -e " ${RED}- cheatsheets - missing${NC}"
fi
if [[ -d "$WORKFLOW_DIR" ]]; then
local wf_count=$(ls -1 "$WORKFLOW_DIR"/*.txt 2>/dev/null | grep -cv index 2>/dev/null || echo 0)
echo -e " ${GREEN}+ workflows - $wf_count workflows${NC}"
else
echo -e " ${RED}- workflows - missing${NC}"
fi
echo ""
echo -e "${GREEN}Offline help system ready!${NC}"
}
show_wiki() {
local query="$1"
if [[ ! -d "$WIKI_DIR" ]]; then
echo -e "${RED}Wiki not installed at $WIKI_DIR${NC}"
return 1
fi
if [[ -z "$query" ]]; then
# Interactive browse
if command -v zk >/dev/null 2>&1; then
cd "$WIKI_DIR" && zk list --interactive
elif command -v fzf >/dev/null 2>&1; then
local selected
selected=$(find "$WIKI_DIR" -name '*.md' -not -path '*/.zk/*' | sort | fzf --preview "cat {}")
if [[ -n "$selected" ]]; then
cat "$selected"
fi
else
echo -e "${CYAN}Wiki pages:${NC}"
find "$WIKI_DIR" -name '*.md' -not -path '*/.zk/*' | sort | sed "s|$WIKI_DIR/||" | sed 's/^/ /'
fi
else
# Search for specific page
local found=""
local search_slug=$(echo "$query" | tr '[:upper:]' '[:lower:]' | sed 's/\.py$//' | sed 's/[^a-z0-9]/-/g' | sed 's/-$//')
# Try exact matches
for dir in tools workflows recipes categories; do
if [[ -f "$WIKI_DIR/$dir/$search_slug.md" ]]; then
found="$WIKI_DIR/$dir/$search_slug.md"
break
fi
done
# Try fuzzy match
if [[ -z "$found" ]]; then
found=$(find "$WIKI_DIR" -name "*${search_slug}*" -name '*.md' -not -path '*/.zk/*' | head -1)
fi
if [[ -n "$found" && -f "$found" ]]; then
echo -e "${CYAN}Wiki: ${YELLOW}$(basename "$found" .md)${NC}"
echo "$(printf '=%.0s' $(seq 1 60))"
echo ""
cat "$found"
else
echo -e "${YELLOW}No wiki page found for '$query'${NC}"
if command -v zk >/dev/null 2>&1; then
echo "Try: fhelp wiki (interactive browse)"
fi
fi
fi
}
show_all() {
echo -e "${CYAN}Complete Help System Overview${NC}"
echo "================================="
echo ""
show_coverage
echo ""
show_workflow
echo ""
show_offline_status
}
# Main command parsing
case "${1:-}" in
"start"|"quickstart"|"getting-started")
show_start
;;
"tools")
shift
show_tools "$@"
;;
"cheat")
shift
show_cheat "$@"
;;
"quick")
shift
show_quick "$@"
;;
"examples")
show_examples
;;
"workflow")
shift
show_workflow "$@"
;;
"pdf")
show_workflow "document-analysis"
;;
"malware")
show_workflow "static-analysis"
;;
"forensics")
show_workflow "behavioral-analysis"
;;
"wiki")
shift
show_wiki "$@"
;;
"coverage")
show_coverage
;;
"--offline")
show_offline_status
;;
"--all")
show_all
;;
"--help"|"-h"|"help"|"")
show_main_help
;;
*)
# Try as workflow name first, then show error
if [[ -d "$WORKFLOW_DIR" ]] && ls "$WORKFLOW_DIR"/*.txt 2>/dev/null | grep -qi "$1"; then
show_workflow "$1"
else
echo -e "${RED}Unknown option: $1${NC}"
echo ""
show_main_help
fi
;;
esac