Add Android forensics, IOC threat-intel DB, Compose companion; scrub secrets from configs
This commit is contained in:
192
README.md
192
README.md
@@ -196,6 +196,198 @@ sudo systemctl enable --now autarch-daemon
|
|||||||
sudo systemctl enable --now autarch-web
|
sudo systemctl enable --now autarch-web
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
## Prerequisites & Required Tools
|
||||||
|
|
||||||
|
AUTARCH is a large platform with many optional features. The core web dashboard and AI agent require only Python dependencies (installed via pip). External system tools are needed for specific feature areas. Install only what you need.
|
||||||
|
|
||||||
|
### Core (Required)
|
||||||
|
|
||||||
|
Python 3.10+
|
||||||
|
Git
|
||||||
|
pip (Python package manager)
|
||||||
|
OpenSSL
|
||||||
|
|
||||||
|
Python dependencies are installed automatically by the setup script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/setup-venv.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Or manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Network Scanning & Analysis
|
||||||
|
|
||||||
|
nmap — Network scanner (port scanning, host discovery, service detection)
|
||||||
|
tshark — Terminal-based Wireshark (packet analysis, protocol decoding)
|
||||||
|
tcpdump — Packet capture
|
||||||
|
whois — Domain/IP WHOIS lookups
|
||||||
|
dig (dnsutils/bind-utils) — DNS enumeration
|
||||||
|
curl — HTTP requests
|
||||||
|
wget — File downloads
|
||||||
|
masscan — High-speed port scanner (optional)
|
||||||
|
|
||||||
|
Debian/Ubuntu:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt install nmap tshark tcpdump whois dnsutils curl wget
|
||||||
|
```
|
||||||
|
|
||||||
|
Fedora/RHEL:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dnf install nmap wireshark-cli tcpdump whois bind-utils curl wget
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wireless / WiFi Tools
|
||||||
|
|
||||||
|
iw — Wireless device configuration
|
||||||
|
iwconfig (wireless-tools) — Legacy wireless config
|
||||||
|
aircrack-ng suite — airmon-ng, airodump-ng, aireplay-ng, airbase-ng
|
||||||
|
reaver / wash — WPS attacks
|
||||||
|
mdk3 / mdk4 — Wireless denial-of-service testing
|
||||||
|
hostapd — Access point creation
|
||||||
|
dnsmasq — DHCP/DNS for rogue AP
|
||||||
|
bettercap — MITM and network attacks (optional)
|
||||||
|
|
||||||
|
Debian/Ubuntu:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt install iw wireless-tools aircrack-ng reaver mdk4 hostapd dnsmasq
|
||||||
|
```
|
||||||
|
|
||||||
|
### Penetration Testing
|
||||||
|
|
||||||
|
Metasploit Framework — msfrpcd, msfconsole, msfvenom (exploit framework)
|
||||||
|
RouterSploit — Router exploitation framework
|
||||||
|
hydra — Password brute-forcing
|
||||||
|
john (John the Ripper) — Password cracking
|
||||||
|
hashcat — GPU-accelerated password cracking
|
||||||
|
nikto — Web server scanner
|
||||||
|
gobuster — Directory/DNS brute-forcing
|
||||||
|
sqlmap — SQL injection (optional, manual install)
|
||||||
|
|
||||||
|
Metasploit install:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall
|
||||||
|
chmod 755 msfinstall
|
||||||
|
./msfinstall
|
||||||
|
```
|
||||||
|
|
||||||
|
### VPN & Firewall
|
||||||
|
|
||||||
|
wireguard-tools (wg, wg-quick) — VPN tunnel management
|
||||||
|
iptables or nftables (nft) — Firewall rules
|
||||||
|
fail2ban — Brute-force protection
|
||||||
|
ssh / sshd / ssh-keygen — SSH management
|
||||||
|
|
||||||
|
Debian/Ubuntu:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt install wireguard-tools iptables nftables fail2ban openssh-server
|
||||||
|
```
|
||||||
|
|
||||||
|
### Forensics & Reverse Engineering
|
||||||
|
|
||||||
|
file — File type identification
|
||||||
|
strings (binutils) — Extract printable strings from binaries
|
||||||
|
strace — System call tracer
|
||||||
|
ltrace — Library call tracer
|
||||||
|
|
||||||
|
Debian/Ubuntu:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt install file binutils strace ltrace
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hardware & Mobile
|
||||||
|
|
||||||
|
adb / fastboot (Android Platform Tools) — Android device management
|
||||||
|
scrcpy — Android screen mirroring
|
||||||
|
esptool — ESP32 firmware flashing (installed via pip)
|
||||||
|
proxmark3 / pm3 — RFID/NFC tools
|
||||||
|
nfc-list / nfc-mfclassic / nfc-poll (libnfc) — NFC tools
|
||||||
|
rtl_sdr — RTL-SDR software-defined radio
|
||||||
|
hackrf_transfer — HackRF SDR tools
|
||||||
|
|
||||||
|
Debian/Ubuntu:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt install android-tools-adb android-tools-fastboot scrcpy libnfc-bin
|
||||||
|
```
|
||||||
|
|
||||||
|
### Containers
|
||||||
|
|
||||||
|
docker — Container security auditing
|
||||||
|
|
||||||
|
### LLM Backends (AI Features)
|
||||||
|
|
||||||
|
For local LLM inference, you need at least one of:
|
||||||
|
|
||||||
|
llama.cpp (via llama-cpp-python, installed by pip) — GGUF model inference
|
||||||
|
HuggingFace Transformers (installed by pip) — SafeTensors model inference
|
||||||
|
PyTorch — Required for local transformers models. Install manually from https://pytorch.org/get-started/locally/
|
||||||
|
|
||||||
|
For cloud LLM backends, configure API keys in the vault:
|
||||||
|
|
||||||
|
Anthropic Claude API key
|
||||||
|
OpenAI-compatible API key
|
||||||
|
HuggingFace Inference API key
|
||||||
|
|
||||||
|
For GPU-accelerated llama.cpp:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CMAKE_ARGS="-DGGML_CUDA=on" pip install llama-cpp-python --force-reinstall --no-cache-dir
|
||||||
|
```
|
||||||
|
|
||||||
|
### Node.js (WebUSB Driver Compilation Only)
|
||||||
|
|
||||||
|
Node.js and npm are required ONLY if you need to recompile the WebUSB/Web Serial driver bundles. They are NOT needed at runtime. See the WebUSB Drivers section below.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## WebUSB Drivers (User-Compiled)
|
||||||
|
|
||||||
|
AUTARCH ships with pre-built WebUSB JavaScript bundles for ADB, Fastboot, and ESP32 flashing in web/static/js/lib/. These bundles enable direct browser-based hardware access through Chromium-based browsers without installing native drivers.
|
||||||
|
|
||||||
|
However, if you need to modify the WebUSB integration, update the library versions, or the pre-built bundles are missing or outdated, you MUST compile them yourself.
|
||||||
|
|
||||||
|
The WebUSB bundles are built from three entry points in src/:
|
||||||
|
|
||||||
|
src/adb-entry.js — ADB over WebUSB (@yume-chan/adb)
|
||||||
|
src/fastboot-entry.js — Fastboot over WebUSB (android-fastboot)
|
||||||
|
src/esptool-entry.js — ESP32 flashing over Web Serial (esptool-js)
|
||||||
|
|
||||||
|
To compile the WebUSB drivers:
|
||||||
|
|
||||||
|
1. Install Node.js (v18+ recommended) and npm
|
||||||
|
2. From the project root, install the build dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Run the build script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/build-hw-libs.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This uses esbuild to bundle the JavaScript libraries into browser-ready IIFE bundles and outputs them to web/static/js/lib/. The build produces three files:
|
||||||
|
|
||||||
|
adb-bundle.js — ADB over WebUSB
|
||||||
|
fastboot-bundle.js — Fastboot over WebUSB
|
||||||
|
esptool-bundle.js — ESP32 over Web Serial
|
||||||
|
|
||||||
|
IMPORTANT: WebUSB and Web Serial APIs require a Chromium-based browser (Chrome, Edge, Brave, etc.). Firefox and Safari do not support these APIs. The device must be connected via USB directly to the machine running the browser. WebUSB will NOT work over remote/forwarded connections.
|
||||||
|
|
||||||
|
If you do not need direct browser-based hardware access (ADB over WebUSB, Fastboot over WebUSB, or ESP32 Web Serial flashing), you can skip this step entirely. The rest of AUTARCH functions without these bundles. Standard ADB/Fastboot over the command line (via Android Platform Tools) works independently of WebUSB.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## The Daemon
|
## The Daemon
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvmToolchain(24)
|
jvmToolchain(21)
|
||||||
}
|
}
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
|
|||||||
BIN
autarch_companion/app/src/main/assets/bin/busybox
Normal file
BIN
autarch_companion/app/src/main/assets/bin/busybox
Normal file
Binary file not shown.
@@ -1,14 +1,26 @@
|
|||||||
|
// Copyright 2026 DarkHal
|
||||||
package com.darkhal.archon
|
package com.darkhal.archon
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.MenuItem
|
||||||
|
import androidx.appcompat.app.ActionBarDrawerToggle
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.GravityCompat
|
||||||
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.ui.setupWithNavController
|
|
||||||
import com.darkhal.archon.messaging.MessagingModule
|
import com.darkhal.archon.messaging.MessagingModule
|
||||||
import com.darkhal.archon.module.ModuleManager
|
import com.darkhal.archon.module.ModuleManager
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
|
import com.google.android.material.navigation.NavigationView
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
|
||||||
|
|
||||||
|
private lateinit var drawerLayout: DrawerLayout
|
||||||
|
private lateinit var navView: NavigationView
|
||||||
|
private lateinit var toolbar: MaterialToolbar
|
||||||
|
private lateinit var navController: NavController
|
||||||
|
private lateinit var toggle: ActionBarDrawerToggle
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -20,11 +32,62 @@ class MainActivity : AppCompatActivity() {
|
|||||||
// Register SMS/RCS messaging module
|
// Register SMS/RCS messaging module
|
||||||
ModuleManager.register(MessagingModule())
|
ModuleManager.register(MessagingModule())
|
||||||
|
|
||||||
|
// Setup toolbar
|
||||||
|
toolbar = findViewById(R.id.toolbar)
|
||||||
|
setSupportActionBar(toolbar)
|
||||||
|
|
||||||
|
// Setup drawer
|
||||||
|
drawerLayout = findViewById(R.id.drawer_layout)
|
||||||
|
navView = findViewById(R.id.nav_view)
|
||||||
|
|
||||||
|
toggle = ActionBarDrawerToggle(
|
||||||
|
this,
|
||||||
|
drawerLayout,
|
||||||
|
toolbar,
|
||||||
|
R.string.drawer_open,
|
||||||
|
R.string.drawer_close
|
||||||
|
)
|
||||||
|
drawerLayout.addDrawerListener(toggle)
|
||||||
|
toggle.syncState()
|
||||||
|
|
||||||
|
// Setup navigation controller
|
||||||
val navHostFragment = supportFragmentManager
|
val navHostFragment = supportFragmentManager
|
||||||
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
|
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
|
||||||
val navController = navHostFragment.navController
|
navController = navHostFragment.navController
|
||||||
|
|
||||||
val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav)
|
// Listen for drawer item clicks
|
||||||
bottomNav.setupWithNavController(navController)
|
navView.setNavigationItemSelectedListener(this)
|
||||||
|
|
||||||
|
// Highlight current destination in drawer
|
||||||
|
navController.addOnDestinationChangedListener { _, destination, _ ->
|
||||||
|
val menuItem = navView.menu.findItem(destination.id)
|
||||||
|
if (menuItem != null) {
|
||||||
|
navView.setCheckedItem(menuItem)
|
||||||
|
}
|
||||||
|
// Update toolbar title from destination label
|
||||||
|
supportActionBar?.title = destination.label ?: getString(R.string.drawer_app_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select Dashboard by default
|
||||||
|
navView.setCheckedItem(R.id.nav_dashboard)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
||||||
|
// Navigate to the selected destination
|
||||||
|
val currentDest = navController.currentDestination?.id
|
||||||
|
if (item.itemId != currentDest) {
|
||||||
|
navController.navigate(item.itemId)
|
||||||
|
}
|
||||||
|
drawerLayout.closeDrawer(GravityCompat.START)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
override fun onBackPressed() {
|
||||||
|
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
|
||||||
|
drawerLayout.closeDrawer(GravityCompat.START)
|
||||||
|
} else {
|
||||||
|
super.onBackPressed()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package com.darkhal.archon.ui
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.darkhal.archon.LoginActivity
|
||||||
|
import com.darkhal.archon.R
|
||||||
|
import com.darkhal.archon.util.AuthManager
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
|
||||||
|
class AboutFragment : Fragment() {
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||||
|
inflater.inflate(R.layout.fragment_about, container, false)
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
try {
|
||||||
|
val info = requireContext().packageManager.getPackageInfo(requireContext().packageName, 0)
|
||||||
|
view.findViewById<TextView>(R.id.about_version)?.text = "v${info.versionName}"
|
||||||
|
} catch (_: Exception) {}
|
||||||
|
|
||||||
|
view.findViewById<MaterialButton>(R.id.btn_logout)?.setOnClickListener {
|
||||||
|
AuthManager.logout(requireContext())
|
||||||
|
val intent = Intent(requireContext(), LoginActivity::class.java)
|
||||||
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
view.findViewById<MaterialButton>(R.id.btn_clear_data)?.setOnClickListener {
|
||||||
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
|
.setTitle("Clear App Data")
|
||||||
|
.setMessage("This will erase all settings, saved keys, and cached data. Are you sure?")
|
||||||
|
.setNegativeButton("Cancel", null)
|
||||||
|
.setPositiveButton("Clear") { _, _ ->
|
||||||
|
requireContext().getSharedPreferences("archon_prefs", 0).edit().clear().apply()
|
||||||
|
requireContext().getSharedPreferences("archon_adb_keys", 0).edit().clear().apply()
|
||||||
|
AuthManager.logout(requireContext())
|
||||||
|
val intent = Intent(requireContext(), LoginActivity::class.java)
|
||||||
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
// Copyright 2026 DarkHal
|
||||||
|
package com.darkhal.archon.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.inputmethod.EditorInfo
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.ImageButton
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.darkhal.archon.R
|
||||||
|
import com.darkhal.archon.messaging.ShizukuManager
|
||||||
|
import com.darkhal.archon.util.BusyboxInstaller
|
||||||
|
import com.darkhal.archon.service.LocalAdbClient
|
||||||
|
import com.darkhal.archon.util.PrivilegeManager
|
||||||
|
import com.darkhal.archon.util.ShellExecutor
|
||||||
|
import com.darkhal.archon.util.ShellResult
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interactive ADB shell terminal using RecyclerView for scrollable output.
|
||||||
|
* Connects through the privilege chain: Root > Shizuku > Local ADB > Archon Server
|
||||||
|
* Compatible with Shizuku AND our own privilege system simultaneously.
|
||||||
|
*/
|
||||||
|
class AdbShellFragment : Fragment() {
|
||||||
|
|
||||||
|
private lateinit var outputRecycler: RecyclerView
|
||||||
|
private lateinit var inputField: EditText
|
||||||
|
private lateinit var sendBtn: ImageButton
|
||||||
|
private lateinit var connectBtn: MaterialButton
|
||||||
|
private lateinit var clearBtn: MaterialButton
|
||||||
|
private lateinit var statusDot: View
|
||||||
|
private lateinit var statusText: TextView
|
||||||
|
|
||||||
|
private val adapter = ShellOutputAdapter()
|
||||||
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
private val commandHistory = mutableListOf<String>()
|
||||||
|
private var historyIndex = -1
|
||||||
|
|
||||||
|
private enum class ShellMethod { ROOT, SHIZUKU, LOCAL_ADB, SERVER_ADB, NONE }
|
||||||
|
private var activeMethod = ShellMethod.NONE
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||||
|
): View = inflater.inflate(R.layout.fragment_adb_shell, container, false)
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
outputRecycler = view.findViewById(R.id.shell_output)
|
||||||
|
inputField = view.findViewById(R.id.shell_input)
|
||||||
|
sendBtn = view.findViewById(R.id.btn_shell_send)
|
||||||
|
connectBtn = view.findViewById(R.id.btn_shell_connect)
|
||||||
|
clearBtn = view.findViewById(R.id.btn_shell_clear)
|
||||||
|
statusDot = view.findViewById(R.id.shell_status_dot)
|
||||||
|
statusText = view.findViewById(R.id.shell_status_text)
|
||||||
|
|
||||||
|
outputRecycler.layoutManager = LinearLayoutManager(requireContext())
|
||||||
|
outputRecycler.adapter = adapter
|
||||||
|
|
||||||
|
// Install busybox on first launch
|
||||||
|
Thread {
|
||||||
|
val installed = BusyboxInstaller.install(requireContext())
|
||||||
|
val version = if (installed) BusyboxInstaller.getVersion(requireContext()) else null
|
||||||
|
handler.post {
|
||||||
|
adapter.addSystem("AUTARCH ADB Shell v1.0")
|
||||||
|
if (version != null) {
|
||||||
|
adapter.addSystem("Busybox: $version")
|
||||||
|
}
|
||||||
|
adapter.addSystem("Type 'help' for available commands")
|
||||||
|
scrollToBottom()
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
|
||||||
|
sendBtn.setOnClickListener { executeCurrentInput() }
|
||||||
|
connectBtn.setOnClickListener { autoConnect() }
|
||||||
|
clearBtn.setOnClickListener {
|
||||||
|
adapter.clear()
|
||||||
|
adapter.addSystem("Terminal cleared")
|
||||||
|
}
|
||||||
|
|
||||||
|
inputField.setOnEditorActionListener { _, actionId, _ ->
|
||||||
|
if (actionId == EditorInfo.IME_ACTION_SEND || actionId == EditorInfo.IME_ACTION_DONE) {
|
||||||
|
executeCurrentInput()
|
||||||
|
true
|
||||||
|
} else false
|
||||||
|
}
|
||||||
|
|
||||||
|
autoConnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun executeCurrentInput() {
|
||||||
|
val cmd = inputField.text.toString().trim()
|
||||||
|
if (cmd.isEmpty()) return
|
||||||
|
|
||||||
|
inputField.setText("")
|
||||||
|
commandHistory.add(0, cmd)
|
||||||
|
historyIndex = -1
|
||||||
|
|
||||||
|
when (cmd.lowercase()) {
|
||||||
|
"clear" -> { adapter.clear(); return }
|
||||||
|
"help" -> {
|
||||||
|
adapter.addSystem("Built-in: clear, status, reconnect, history, exit")
|
||||||
|
adapter.addSystem("All other commands sent to device shell")
|
||||||
|
scrollToBottom()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
"status" -> {
|
||||||
|
adapter.addSystem("Method: ${activeMethod.name}")
|
||||||
|
adapter.addSystem("Privilege: ${PrivilegeManager.getAvailableMethod().label}")
|
||||||
|
scrollToBottom()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
"reconnect" -> { autoConnect(); return }
|
||||||
|
"history" -> {
|
||||||
|
if (commandHistory.isEmpty()) {
|
||||||
|
adapter.addSystem("No command history")
|
||||||
|
} else {
|
||||||
|
commandHistory.forEachIndexed { i, c -> adapter.addSystem(" ${i + 1}: $c") }
|
||||||
|
}
|
||||||
|
scrollToBottom()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
"exit" -> {
|
||||||
|
activeMethod = ShellMethod.NONE
|
||||||
|
updateStatus()
|
||||||
|
adapter.addSystem("Disconnected")
|
||||||
|
scrollToBottom()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.addCommand(cmd)
|
||||||
|
scrollToBottom()
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
val result = executeShellCommand(cmd)
|
||||||
|
handler.post {
|
||||||
|
if (result.stdout.isNotEmpty()) adapter.addStdout(result.stdout)
|
||||||
|
if (result.stderr.isNotEmpty()) adapter.addStderr(result.stderr)
|
||||||
|
if (result.exitCode != 0 && result.stdout.isEmpty() && result.stderr.isEmpty()) {
|
||||||
|
adapter.addStderr("Exit code: ${result.exitCode}")
|
||||||
|
}
|
||||||
|
scrollToBottom()
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun executeShellCommand(command: String): ShellResult {
|
||||||
|
return when (activeMethod) {
|
||||||
|
ShellMethod.ROOT -> ShellExecutor.execute("su -c '$command'")
|
||||||
|
ShellMethod.SHIZUKU -> {
|
||||||
|
try {
|
||||||
|
val output = ShizukuManager(requireContext()).executeCommand(command)
|
||||||
|
ShellResult(output, "", 0)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
ShellResult("", "Shizuku error: ${e.message}", -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ShellMethod.LOCAL_ADB -> LocalAdbClient.execute(command)
|
||||||
|
ShellMethod.SERVER_ADB -> PrivilegeManager.execute(command)
|
||||||
|
ShellMethod.NONE -> ShellResult("", "No shell access. Tap CONNECT.", -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun autoConnect() {
|
||||||
|
adapter.addSystem("Connecting...")
|
||||||
|
updateStatus("Connecting...", false)
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
val method = detectBestMethod()
|
||||||
|
handler.post {
|
||||||
|
activeMethod = method
|
||||||
|
updateStatus()
|
||||||
|
when (method) {
|
||||||
|
ShellMethod.ROOT -> adapter.addSystem("Connected via root (su)")
|
||||||
|
ShellMethod.SHIZUKU -> adapter.addSystem("Connected via Shizuku")
|
||||||
|
ShellMethod.LOCAL_ADB -> adapter.addSystem("Connected via wireless ADB")
|
||||||
|
ShellMethod.SERVER_ADB -> adapter.addSystem("Connected via Archon Server")
|
||||||
|
ShellMethod.NONE -> {
|
||||||
|
adapter.addSystem("No shell access available")
|
||||||
|
adapter.addSystem("Enable root, Shizuku, or Wireless Debugging")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scrollToBottom()
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun detectBestMethod(): ShellMethod {
|
||||||
|
val rootCheck = ShellExecutor.execute("su -c 'id'")
|
||||||
|
if (rootCheck.exitCode == 0 && rootCheck.stdout.contains("uid=0")) return ShellMethod.ROOT
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (ShizukuManager(requireContext()).getStatus() == ShizukuManager.ShizukuStatus.READY)
|
||||||
|
return ShellMethod.SHIZUKU
|
||||||
|
} catch (_: Exception) {}
|
||||||
|
|
||||||
|
if (LocalAdbClient.isConnected()) return ShellMethod.LOCAL_ADB
|
||||||
|
try {
|
||||||
|
if (LocalAdbClient.autoConnect(requireContext())) return ShellMethod.LOCAL_ADB
|
||||||
|
} catch (_: Exception) {}
|
||||||
|
|
||||||
|
if (PrivilegeManager.getAvailableMethod() != PrivilegeManager.Method.NONE) return ShellMethod.SERVER_ADB
|
||||||
|
|
||||||
|
return ShellMethod.NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateStatus(text: String? = null, connected: Boolean? = null) {
|
||||||
|
val isConnected = connected ?: (activeMethod != ShellMethod.NONE)
|
||||||
|
statusDot.setBackgroundColor(
|
||||||
|
if (isConnected) 0xFF98C379.toInt() else 0xFFE06C75.toInt()
|
||||||
|
)
|
||||||
|
statusText.text = text ?: when (activeMethod) {
|
||||||
|
ShellMethod.ROOT -> "Connected (root)"
|
||||||
|
ShellMethod.SHIZUKU -> "Connected (Shizuku)"
|
||||||
|
ShellMethod.LOCAL_ADB -> "Connected (wireless ADB)"
|
||||||
|
ShellMethod.SERVER_ADB -> "Connected (Archon Server)"
|
||||||
|
ShellMethod.NONE -> "Disconnected"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun scrollToBottom() {
|
||||||
|
if (adapter.itemCount > 0) {
|
||||||
|
outputRecycler.smoothScrollToPosition(adapter.itemCount - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2026 DarkHal
|
||||||
|
package com.darkhal.archon.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.darkhal.archon.R
|
||||||
|
import com.darkhal.archon.util.PrefsManager
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import com.google.android.material.slider.Slider
|
||||||
|
|
||||||
|
class AppearanceSettingsFragment : Fragment() {
|
||||||
|
|
||||||
|
private lateinit var fontSizeSlider: Slider
|
||||||
|
private lateinit var previewText: TextView
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||||
|
): View = inflater.inflate(R.layout.fragment_appearance_settings, container, false)
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
fontSizeSlider = view.findViewById(R.id.slider_font_size)
|
||||||
|
previewText = view.findViewById(R.id.font_size_preview)
|
||||||
|
|
||||||
|
// Load saved font size
|
||||||
|
val savedSize = PrefsManager.getFontSize(requireContext())
|
||||||
|
fontSizeSlider.value = savedSize.toFloat()
|
||||||
|
updatePreview(savedSize)
|
||||||
|
|
||||||
|
fontSizeSlider.addOnChangeListener { _, value, _ ->
|
||||||
|
updatePreview(value.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
view.findViewById<MaterialButton>(R.id.btn_save_appearance).setOnClickListener {
|
||||||
|
val size = fontSizeSlider.value.toInt()
|
||||||
|
PrefsManager.setFontSize(requireContext(), size)
|
||||||
|
Toast.makeText(requireContext(), "Appearance saved", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updatePreview(sizeSp: Int) {
|
||||||
|
previewText.setTextSize(TypedValue.COMPLEX_UNIT_SP, sizeSp.toFloat())
|
||||||
|
previewText.text = "Preview text (${sizeSp}sp)"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
package com.darkhal.archon.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.darkhal.archon.R
|
||||||
|
import com.darkhal.archon.service.DiscoveryManager
|
||||||
|
import com.darkhal.archon.util.PrefsManager
|
||||||
|
import com.darkhal.archon.util.ShellExecutor
|
||||||
|
import com.darkhal.archon.util.SslHelper
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
|
|
||||||
|
class ConnectionSettingsFragment : Fragment() {
|
||||||
|
|
||||||
|
private lateinit var inputServerIp: TextInputEditText
|
||||||
|
private lateinit var inputWebPort: TextInputEditText
|
||||||
|
private lateinit var inputAdbPort: TextInputEditText
|
||||||
|
private lateinit var inputUsbipPort: TextInputEditText
|
||||||
|
private lateinit var statusText: TextView
|
||||||
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||||
|
inflater.inflate(R.layout.fragment_settings_connection, container, false)
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
inputServerIp = view.findViewById(R.id.input_server_ip)
|
||||||
|
inputWebPort = view.findViewById(R.id.input_web_port)
|
||||||
|
inputAdbPort = view.findViewById(R.id.input_adb_port)
|
||||||
|
inputUsbipPort = view.findViewById(R.id.input_usbip_port)
|
||||||
|
statusText = view.findViewById(R.id.connection_status)
|
||||||
|
|
||||||
|
loadSettings()
|
||||||
|
|
||||||
|
view.findViewById<MaterialButton>(R.id.btn_save_connection).setOnClickListener { saveSettings() }
|
||||||
|
view.findViewById<MaterialButton>(R.id.btn_auto_detect).setOnClickListener { autoDetect(it as MaterialButton) }
|
||||||
|
view.findViewById<MaterialButton>(R.id.btn_test_connection).setOnClickListener { testConnection() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadSettings() {
|
||||||
|
val ctx = requireContext()
|
||||||
|
inputServerIp.setText(PrefsManager.getServerIp(ctx))
|
||||||
|
inputWebPort.setText(PrefsManager.getWebPort(ctx).toString())
|
||||||
|
inputAdbPort.setText(PrefsManager.getAdbPort(ctx).toString())
|
||||||
|
inputUsbipPort.setText(PrefsManager.getUsbIpPort(ctx).toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveSettings() {
|
||||||
|
val ctx = requireContext()
|
||||||
|
val ip = inputServerIp.text.toString().trim()
|
||||||
|
val webPort = inputWebPort.text.toString().trim().toIntOrNull() ?: 8181
|
||||||
|
val adbPort = inputAdbPort.text.toString().trim().toIntOrNull() ?: 5555
|
||||||
|
val usbipPort = inputUsbipPort.text.toString().trim().toIntOrNull() ?: 3240
|
||||||
|
|
||||||
|
if (ip.isEmpty()) {
|
||||||
|
statusText.text = "Error: Server IP cannot be empty"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
PrefsManager.setServerIp(ctx, ip)
|
||||||
|
PrefsManager.setWebPort(ctx, webPort)
|
||||||
|
PrefsManager.setAdbPort(ctx, adbPort)
|
||||||
|
PrefsManager.setUsbIpPort(ctx, usbipPort)
|
||||||
|
|
||||||
|
statusText.text = "Settings saved"
|
||||||
|
Toast.makeText(ctx, "Settings saved", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun autoDetect(btn: MaterialButton) {
|
||||||
|
statusText.text = "Scanning for AUTARCH server..."
|
||||||
|
btn.isEnabled = false
|
||||||
|
|
||||||
|
val discovery = DiscoveryManager(requireContext())
|
||||||
|
discovery.listener = object : DiscoveryManager.Listener {
|
||||||
|
override fun onServerFound(server: DiscoveryManager.DiscoveredServer) {
|
||||||
|
discovery.stopDiscovery()
|
||||||
|
handler.post {
|
||||||
|
if (server.ip.isNotEmpty()) inputServerIp.setText(server.ip)
|
||||||
|
if (server.port > 0) inputWebPort.setText(server.port.toString())
|
||||||
|
statusText.text = "Found ${server.hostname} at ${server.ip}:${server.port}"
|
||||||
|
btn.isEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun onDiscoveryStarted(method: DiscoveryManager.ConnectionMethod) {}
|
||||||
|
override fun onDiscoveryStopped(method: DiscoveryManager.ConnectionMethod) {
|
||||||
|
handler.post {
|
||||||
|
if (discovery.getDiscoveredServers().isEmpty()) {
|
||||||
|
statusText.text = "No server found on network"
|
||||||
|
}
|
||||||
|
btn.isEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun onDiscoveryError(method: DiscoveryManager.ConnectionMethod, error: String) {}
|
||||||
|
}
|
||||||
|
discovery.startDiscovery()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun testConnection() {
|
||||||
|
val ip = inputServerIp.text.toString().trim()
|
||||||
|
val port = inputWebPort.text.toString().trim().toIntOrNull() ?: 8181
|
||||||
|
if (ip.isEmpty()) { statusText.text = "Enter server IP first"; return }
|
||||||
|
|
||||||
|
statusText.text = "Testing $ip:$port..."
|
||||||
|
Thread {
|
||||||
|
val pingOk = ShellExecutor.execute("ping -c 1 -W 3 $ip").exitCode == 0
|
||||||
|
val httpOk = try {
|
||||||
|
val url = java.net.URL("https://$ip:$port/")
|
||||||
|
val conn = url.openConnection() as java.net.HttpURLConnection
|
||||||
|
SslHelper.trustSelfSigned(conn)
|
||||||
|
conn.connectTimeout = 5000
|
||||||
|
conn.readTimeout = 5000
|
||||||
|
val code = conn.responseCode
|
||||||
|
conn.disconnect()
|
||||||
|
code in 200..399
|
||||||
|
} catch (_: Exception) { false }
|
||||||
|
|
||||||
|
handler.post {
|
||||||
|
statusText.text = "Ping: ${if (pingOk) "OK" else "FAIL"}\nHTTPS: ${if (httpOk) "OK" else "FAIL"}"
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
package com.darkhal.archon.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.darkhal.archon.R
|
||||||
|
import com.darkhal.archon.messaging.ShizukuManager
|
||||||
|
import com.darkhal.archon.service.LocalAdbClient
|
||||||
|
import com.darkhal.archon.util.PrefsManager
|
||||||
|
import com.darkhal.archon.util.PrivilegeManager
|
||||||
|
import com.darkhal.archon.util.ShellExecutor
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import com.google.android.material.materialswitch.MaterialSwitch
|
||||||
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
|
|
||||||
|
class PrivilegeSettingsFragment : Fragment() {
|
||||||
|
|
||||||
|
private lateinit var currentMethodText: TextView
|
||||||
|
private lateinit var statusRoot: TextView
|
||||||
|
private lateinit var statusShizuku: TextView
|
||||||
|
private lateinit var statusAdb: TextView
|
||||||
|
private lateinit var statusServer: TextView
|
||||||
|
private lateinit var dotRoot: View
|
||||||
|
private lateinit var dotShizuku: View
|
||||||
|
private lateinit var dotAdb: View
|
||||||
|
private lateinit var dotServer: View
|
||||||
|
private lateinit var pairingCodeInput: TextInputEditText
|
||||||
|
private lateinit var switchAutoRestart: MaterialSwitch
|
||||||
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||||
|
inflater.inflate(R.layout.fragment_settings_privileges, container, false)
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
currentMethodText = view.findViewById(R.id.priv_current_method)
|
||||||
|
statusRoot = view.findViewById(R.id.status_root)
|
||||||
|
statusShizuku = view.findViewById(R.id.status_shizuku)
|
||||||
|
statusAdb = view.findViewById(R.id.status_adb)
|
||||||
|
statusServer = view.findViewById(R.id.status_server)
|
||||||
|
dotRoot = view.findViewById(R.id.dot_root)
|
||||||
|
dotShizuku = view.findViewById(R.id.dot_shizuku)
|
||||||
|
dotAdb = view.findViewById(R.id.dot_adb)
|
||||||
|
dotServer = view.findViewById(R.id.dot_server)
|
||||||
|
pairingCodeInput = view.findViewById(R.id.input_pairing_code)
|
||||||
|
switchAutoRestart = view.findViewById(R.id.switch_auto_restart_adb)
|
||||||
|
|
||||||
|
switchAutoRestart.isChecked = PrefsManager.isAutoRestartAdb(requireContext())
|
||||||
|
switchAutoRestart.setOnCheckedChangeListener { _, checked ->
|
||||||
|
PrefsManager.setAutoRestartAdb(requireContext(), checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
view.findViewById<MaterialButton>(R.id.btn_shizuku_request).setOnClickListener {
|
||||||
|
requestShizukuPermission()
|
||||||
|
}
|
||||||
|
|
||||||
|
view.findViewById<MaterialButton>(R.id.btn_adb_pair).setOnClickListener {
|
||||||
|
pairAdb()
|
||||||
|
}
|
||||||
|
|
||||||
|
view.findViewById<MaterialButton>(R.id.btn_refresh_status).setOnClickListener {
|
||||||
|
refreshStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshStatus() {
|
||||||
|
currentMethodText.text = "Detecting..."
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
val bestMethod = PrivilegeManager.getAvailableMethod()
|
||||||
|
|
||||||
|
// Root check
|
||||||
|
val rootResult = ShellExecutor.execute("su -c 'id'")
|
||||||
|
val hasRoot = rootResult.exitCode == 0 && rootResult.stdout.contains("uid=0")
|
||||||
|
|
||||||
|
// Shizuku check
|
||||||
|
val shizukuStatus = try {
|
||||||
|
ShizukuManager(requireContext()).getStatus()
|
||||||
|
} catch (_: Exception) {
|
||||||
|
ShizukuManager.ShizukuStatus.NOT_INSTALLED
|
||||||
|
}
|
||||||
|
|
||||||
|
// ADB check
|
||||||
|
val adbConnected = LocalAdbClient.isConnected()
|
||||||
|
val adbPaired = LocalAdbClient.isPaired(requireContext())
|
||||||
|
|
||||||
|
// Server check
|
||||||
|
val serverOk = bestMethod == PrivilegeManager.Method.ARCHON_SERVER ||
|
||||||
|
bestMethod == PrivilegeManager.Method.SERVER_ADB
|
||||||
|
|
||||||
|
handler.post {
|
||||||
|
currentMethodText.text = bestMethod.label
|
||||||
|
|
||||||
|
setDot(dotRoot, hasRoot)
|
||||||
|
statusRoot.text = if (hasRoot) "Root available (su)" else "No root access"
|
||||||
|
|
||||||
|
setDot(dotShizuku, shizukuStatus == ShizukuManager.ShizukuStatus.READY)
|
||||||
|
statusShizuku.text = shizukuStatus.label
|
||||||
|
|
||||||
|
setDot(dotAdb, adbConnected)
|
||||||
|
statusAdb.text = when {
|
||||||
|
adbConnected -> "Connected"
|
||||||
|
adbPaired -> "Paired, not connected"
|
||||||
|
else -> "Not paired"
|
||||||
|
}
|
||||||
|
|
||||||
|
setDot(dotServer, serverOk)
|
||||||
|
statusServer.text = if (serverOk) "Connected" else "Not connected"
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setDot(dot: View, active: Boolean) {
|
||||||
|
dot.setBackgroundColor(if (active) 0xFF98C379.toInt() else 0xFFE06C75.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requestShizukuPermission() {
|
||||||
|
try {
|
||||||
|
val mgr = ShizukuManager(requireContext())
|
||||||
|
val status = mgr.getStatus()
|
||||||
|
when (status) {
|
||||||
|
ShizukuManager.ShizukuStatus.NOT_INSTALLED ->
|
||||||
|
Toast.makeText(requireContext(), "Install Shizuku from Play Store first", Toast.LENGTH_LONG).show()
|
||||||
|
ShizukuManager.ShizukuStatus.INSTALLED_NOT_RUNNING ->
|
||||||
|
Toast.makeText(requireContext(), "Start Shizuku app first", Toast.LENGTH_LONG).show()
|
||||||
|
ShizukuManager.ShizukuStatus.RUNNING_NO_PERMISSION ->
|
||||||
|
Toast.makeText(requireContext(), "Requesting permission...", Toast.LENGTH_SHORT).show()
|
||||||
|
ShizukuManager.ShizukuStatus.READY ->
|
||||||
|
Toast.makeText(requireContext(), "Shizuku already ready", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(requireContext(), "Shizuku error: ${e.message}", Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
refreshStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pairAdb() {
|
||||||
|
val code = pairingCodeInput.text.toString().trim()
|
||||||
|
if (code.isEmpty()) {
|
||||||
|
Toast.makeText(requireContext(), "Enter the pairing code from Developer Options", Toast.LENGTH_LONG).show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Toast.makeText(requireContext(), "Discovering pairing service...", Toast.LENGTH_SHORT).show()
|
||||||
|
Thread {
|
||||||
|
val port = LocalAdbClient.discoverPairingPort(requireContext(), 15)
|
||||||
|
if (port == null) {
|
||||||
|
handler.post {
|
||||||
|
Toast.makeText(requireContext(), "Could not find pairing service. Is Wireless Debugging enabled?", Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
return@Thread
|
||||||
|
}
|
||||||
|
|
||||||
|
val success = LocalAdbClient.pair(requireContext(), "127.0.0.1", port, code)
|
||||||
|
handler.post {
|
||||||
|
if (success) {
|
||||||
|
Toast.makeText(requireContext(), "Paired successfully!", Toast.LENGTH_SHORT).show()
|
||||||
|
pairingCodeInput.setText("")
|
||||||
|
} else {
|
||||||
|
Toast.makeText(requireContext(), "Pairing failed. Check the code and try again.", Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
refreshStatus()
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
// Copyright 2026 DarkHal
|
||||||
|
package com.darkhal.archon.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.RadioButton
|
||||||
|
import android.widget.RadioGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import com.darkhal.archon.R
|
||||||
|
import com.darkhal.archon.util.PrefsManager
|
||||||
|
import com.darkhal.archon.util.PrivilegeManager
|
||||||
|
import com.darkhal.archon.util.ShellExecutor
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
|
||||||
|
class PrivilegesSettingsFragment : Fragment() {
|
||||||
|
|
||||||
|
private lateinit var radioGroup: RadioGroup
|
||||||
|
private lateinit var statusText: TextView
|
||||||
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||||
|
): View = inflater.inflate(R.layout.fragment_privileges_settings, container, false)
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
radioGroup = view.findViewById(R.id.radio_privilege_mode)
|
||||||
|
statusText = view.findViewById(R.id.privilege_status)
|
||||||
|
|
||||||
|
// Set current mode based on detected best method
|
||||||
|
view.findViewById<MaterialButton>(R.id.btn_save_privileges).setOnClickListener {
|
||||||
|
savePrivilegeMode()
|
||||||
|
}
|
||||||
|
|
||||||
|
checkPrivilegeStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkPrivilegeStatus() {
|
||||||
|
statusText.text = getString(R.string.privilege_status_checking)
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
val method = PrivilegeManager.getAvailableMethod()
|
||||||
|
|
||||||
|
// Check root
|
||||||
|
val rootAvailable = ShellExecutor.execute("su -c 'id'").exitCode == 0
|
||||||
|
|
||||||
|
// Check Shizuku (via our Archon Server)
|
||||||
|
val archonAvailable = method == PrivilegeManager.Method.ARCHON_SERVER
|
||||||
|
|
||||||
|
// Check local ADB
|
||||||
|
val adbAvailable = method == PrivilegeManager.Method.LOCAL_ADB ||
|
||||||
|
method == PrivilegeManager.Method.SERVER_ADB
|
||||||
|
|
||||||
|
handler.post {
|
||||||
|
val status = StringBuilder()
|
||||||
|
status.appendLine("Detected: ${method.label}")
|
||||||
|
status.appendLine()
|
||||||
|
status.appendLine("Root: ${if (rootAvailable) "Available" else "Not available"}")
|
||||||
|
status.appendLine("Archon Server: ${if (archonAvailable) "Running" else "Not running"}")
|
||||||
|
status.appendLine("ADB: ${if (adbAvailable) "Connected" else "Not connected"}")
|
||||||
|
statusText.text = status.toString()
|
||||||
|
|
||||||
|
// Select the radio matching current mode
|
||||||
|
when (method) {
|
||||||
|
PrivilegeManager.Method.ROOT ->
|
||||||
|
radioGroup.check(R.id.radio_root)
|
||||||
|
PrivilegeManager.Method.ARCHON_SERVER ->
|
||||||
|
radioGroup.check(R.id.radio_shizuku)
|
||||||
|
PrivilegeManager.Method.LOCAL_ADB, PrivilegeManager.Method.SERVER_ADB ->
|
||||||
|
radioGroup.check(R.id.radio_adb)
|
||||||
|
PrivilegeManager.Method.NONE ->
|
||||||
|
radioGroup.check(R.id.radio_none)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun savePrivilegeMode() {
|
||||||
|
val selected = when (radioGroup.checkedRadioButtonId) {
|
||||||
|
R.id.radio_root -> "root"
|
||||||
|
R.id.radio_shizuku -> "shizuku"
|
||||||
|
R.id.radio_adb -> "adb"
|
||||||
|
R.id.radio_none -> "none"
|
||||||
|
else -> "none"
|
||||||
|
}
|
||||||
|
|
||||||
|
PrefsManager.setPreferredPrivilegeMode(requireContext(), selected)
|
||||||
|
Toast.makeText(requireContext(), "Privilege mode saved: $selected", Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
|
// Re-check to show actual status
|
||||||
|
checkPrivilegeStatus()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package com.darkhal.archon.ui
|
||||||
|
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.darkhal.archon.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RecyclerView adapter for the ADB shell terminal output.
|
||||||
|
* Supports 4 line types with different colors:
|
||||||
|
* COMMAND - green, prefixed with >
|
||||||
|
* STDOUT - white/light gray
|
||||||
|
* STDERR - red
|
||||||
|
* SYSTEM - yellow italic (connection messages, errors, etc.)
|
||||||
|
*/
|
||||||
|
class ShellOutputAdapter : RecyclerView.Adapter<ShellOutputAdapter.LineViewHolder>() {
|
||||||
|
|
||||||
|
enum class LineType { COMMAND, STDOUT, STDERR, SYSTEM }
|
||||||
|
|
||||||
|
data class ShellLine(val text: String, val type: LineType)
|
||||||
|
|
||||||
|
private val lines = mutableListOf<ShellLine>()
|
||||||
|
|
||||||
|
fun addCommand(cmd: String) {
|
||||||
|
lines.add(ShellLine("> $cmd", LineType.COMMAND))
|
||||||
|
notifyItemInserted(lines.size - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addStdout(text: String) {
|
||||||
|
if (text.isBlank()) return
|
||||||
|
for (line in text.lines()) {
|
||||||
|
lines.add(ShellLine(line, LineType.STDOUT))
|
||||||
|
}
|
||||||
|
notifyItemRangeInserted(lines.size - text.lines().size, text.lines().size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addStderr(text: String) {
|
||||||
|
if (text.isBlank()) return
|
||||||
|
for (line in text.lines()) {
|
||||||
|
lines.add(ShellLine(line, LineType.STDERR))
|
||||||
|
}
|
||||||
|
notifyItemRangeInserted(lines.size - text.lines().size, text.lines().size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addSystem(text: String) {
|
||||||
|
lines.add(ShellLine(text, LineType.SYSTEM))
|
||||||
|
notifyItemInserted(lines.size - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
val count = lines.size
|
||||||
|
lines.clear()
|
||||||
|
notifyItemRangeRemoved(0, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = lines.size
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LineViewHolder {
|
||||||
|
val view = LayoutInflater.from(parent.context)
|
||||||
|
.inflate(R.layout.item_shell_output, parent, false)
|
||||||
|
return LineViewHolder(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: LineViewHolder, position: Int) {
|
||||||
|
val line = lines[position]
|
||||||
|
holder.textView.text = line.text
|
||||||
|
|
||||||
|
when (line.type) {
|
||||||
|
LineType.COMMAND -> {
|
||||||
|
holder.textView.setTextColor(0xFF98C379.toInt()) // green
|
||||||
|
holder.textView.setTypeface(Typeface.MONOSPACE, Typeface.BOLD)
|
||||||
|
}
|
||||||
|
LineType.STDOUT -> {
|
||||||
|
holder.textView.setTextColor(0xFFD4D4D4.toInt()) // light gray
|
||||||
|
holder.textView.setTypeface(Typeface.MONOSPACE, Typeface.NORMAL)
|
||||||
|
}
|
||||||
|
LineType.STDERR -> {
|
||||||
|
holder.textView.setTextColor(0xFFE06C75.toInt()) // red
|
||||||
|
holder.textView.setTypeface(Typeface.MONOSPACE, Typeface.NORMAL)
|
||||||
|
}
|
||||||
|
LineType.SYSTEM -> {
|
||||||
|
holder.textView.setTextColor(0xFFE5C07B.toInt()) // yellow
|
||||||
|
holder.textView.setTypeface(Typeface.MONOSPACE, Typeface.ITALIC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LineViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
val textView: TextView = view.findViewById(R.id.shell_line_text)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.darkhal.archon.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder fragment for pentesting tools that aren't implemented yet.
|
||||||
|
* Shows the tool name and a "coming soon" message.
|
||||||
|
* Pass the tool name via arguments bundle with key "tool_name".
|
||||||
|
*/
|
||||||
|
class ToolPlaceholderFragment : Fragment() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance(toolName: String): ToolPlaceholderFragment {
|
||||||
|
return ToolPlaceholderFragment().apply {
|
||||||
|
arguments = Bundle().apply {
|
||||||
|
putString("tool_name", toolName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
val toolName = arguments?.getString("tool_name") ?: "Tool"
|
||||||
|
|
||||||
|
val layout = LinearLayout(requireContext()).apply {
|
||||||
|
orientation = LinearLayout.VERTICAL
|
||||||
|
setPadding(48, 48, 48, 48)
|
||||||
|
}
|
||||||
|
|
||||||
|
val title = TextView(requireContext()).apply {
|
||||||
|
text = toolName
|
||||||
|
textSize = 24f
|
||||||
|
setTextColor(0xFFD4D4D4.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
val subtitle = TextView(requireContext()).apply {
|
||||||
|
text = "Implementation in progress"
|
||||||
|
textSize = 14f
|
||||||
|
setTextColor(0xFF858585.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.addView(title)
|
||||||
|
layout.addView(subtitle)
|
||||||
|
|
||||||
|
return layout
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
// Copyright 2026 DarkHal
|
||||||
|
package com.darkhal.archon.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the bundled busybox binary from APK assets to the app's
|
||||||
|
* private directory on first launch. Creates symlinks for all applets
|
||||||
|
* so they can be called by name (ls, grep, find, etc.).
|
||||||
|
*
|
||||||
|
* The binary is a static ARM64 build that works without root on any
|
||||||
|
* Android device. It provides 300+ Unix utilities in a single 2.7MB file.
|
||||||
|
*/
|
||||||
|
object BusyboxInstaller {
|
||||||
|
|
||||||
|
private const val TAG = "BusyboxInstaller"
|
||||||
|
private const val ASSET_PATH = "bin/busybox"
|
||||||
|
private const val BIN_DIR = "busybox"
|
||||||
|
private const val BUSYBOX_NAME = "busybox"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path to the busybox binary. Extracts from assets if needed.
|
||||||
|
* Returns null if extraction fails.
|
||||||
|
*/
|
||||||
|
fun getBusyboxPath(context: Context): String? {
|
||||||
|
val binDir = File(context.filesDir, BIN_DIR)
|
||||||
|
val busybox = File(binDir, BUSYBOX_NAME)
|
||||||
|
|
||||||
|
if (busybox.exists() && busybox.canExecute()) {
|
||||||
|
return busybox.absolutePath
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (install(context)) busybox.absolutePath else null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the bin directory containing busybox and its symlinks.
|
||||||
|
* Use this as a PATH prefix for shell sessions.
|
||||||
|
*/
|
||||||
|
fun getBinDir(context: Context): String {
|
||||||
|
val binDir = File(context.filesDir, BIN_DIR)
|
||||||
|
binDir.mkdirs()
|
||||||
|
return binDir.absolutePath
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install busybox from APK assets. Returns true on success.
|
||||||
|
*/
|
||||||
|
fun install(context: Context): Boolean {
|
||||||
|
val binDir = File(context.filesDir, BIN_DIR)
|
||||||
|
val busybox = File(binDir, BUSYBOX_NAME)
|
||||||
|
|
||||||
|
try {
|
||||||
|
binDir.mkdirs()
|
||||||
|
|
||||||
|
// Extract binary from assets
|
||||||
|
context.assets.open(ASSET_PATH).use { input ->
|
||||||
|
FileOutputStream(busybox).use { output ->
|
||||||
|
input.copyTo(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make executable
|
||||||
|
busybox.setExecutable(true, false)
|
||||||
|
|
||||||
|
if (!busybox.canExecute()) {
|
||||||
|
Log.e(TAG, "Failed to set execute permission on busybox")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "Extracted busybox to ${busybox.absolutePath} (${busybox.length()} bytes)")
|
||||||
|
|
||||||
|
// Create symlinks for all applets
|
||||||
|
createAppletSymlinks(busybox, binDir)
|
||||||
|
|
||||||
|
return true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Failed to install busybox", e)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create symlinks for all busybox applets.
|
||||||
|
* Runs "busybox --list" to get the applet names, then creates
|
||||||
|
* a symlink for each one pointing back to busybox.
|
||||||
|
*/
|
||||||
|
private fun createAppletSymlinks(busybox: File, binDir: File) {
|
||||||
|
try {
|
||||||
|
val process = ProcessBuilder(busybox.absolutePath, "--list")
|
||||||
|
.directory(binDir)
|
||||||
|
.redirectErrorStream(true)
|
||||||
|
.start()
|
||||||
|
|
||||||
|
val applets = process.inputStream.bufferedReader().readLines()
|
||||||
|
process.waitFor()
|
||||||
|
|
||||||
|
var created = 0
|
||||||
|
for (applet in applets) {
|
||||||
|
val name = applet.trim()
|
||||||
|
if (name.isEmpty() || name == BUSYBOX_NAME) continue
|
||||||
|
|
||||||
|
val link = File(binDir, name)
|
||||||
|
if (!link.exists()) {
|
||||||
|
try {
|
||||||
|
// Create symlink: applet -> busybox
|
||||||
|
Runtime.getRuntime().exec(arrayOf(
|
||||||
|
"ln", "-sf", busybox.absolutePath, link.absolutePath
|
||||||
|
)).waitFor()
|
||||||
|
created++
|
||||||
|
} catch (_: Exception) {
|
||||||
|
// Symlinks may not work on all filesystems.
|
||||||
|
// Fall back to a small shell wrapper script.
|
||||||
|
link.writeText("#!/system/bin/sh\nexec ${busybox.absolutePath} $name \"\$@\"\n")
|
||||||
|
link.setExecutable(true, false)
|
||||||
|
created++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "Created $created applet symlinks in ${binDir.absolutePath}")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Failed to create applet symlinks", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if busybox is installed and working.
|
||||||
|
*/
|
||||||
|
fun isInstalled(context: Context): Boolean {
|
||||||
|
val busybox = File(context.filesDir, "$BIN_DIR/$BUSYBOX_NAME")
|
||||||
|
return busybox.exists() && busybox.canExecute()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the version string of the installed busybox.
|
||||||
|
*/
|
||||||
|
fun getVersion(context: Context): String? {
|
||||||
|
val path = getBusyboxPath(context) ?: return null
|
||||||
|
return try {
|
||||||
|
val process = ProcessBuilder(path, "--help")
|
||||||
|
.redirectErrorStream(true)
|
||||||
|
.start()
|
||||||
|
val firstLine = process.inputStream.bufferedReader().readLine()
|
||||||
|
process.destroy()
|
||||||
|
firstLine
|
||||||
|
} catch (_: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all available applets.
|
||||||
|
*/
|
||||||
|
fun listApplets(context: Context): List<String> {
|
||||||
|
val path = getBusyboxPath(context) ?: return emptyList()
|
||||||
|
return try {
|
||||||
|
val process = ProcessBuilder(path, "--list")
|
||||||
|
.redirectErrorStream(true)
|
||||||
|
.start()
|
||||||
|
val applets = process.inputStream.bufferedReader().readLines()
|
||||||
|
.map { it.trim() }
|
||||||
|
.filter { it.isNotEmpty() }
|
||||||
|
process.waitFor()
|
||||||
|
applets
|
||||||
|
} catch (_: Exception) {
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,12 +13,16 @@ object PrefsManager {
|
|||||||
private const val KEY_USBIP_PORT = "usbip_port"
|
private const val KEY_USBIP_PORT = "usbip_port"
|
||||||
private const val KEY_AUTO_RESTART_ADB = "auto_restart_adb"
|
private const val KEY_AUTO_RESTART_ADB = "auto_restart_adb"
|
||||||
private const val KEY_BBS_ADDRESS = "bbs_address"
|
private const val KEY_BBS_ADDRESS = "bbs_address"
|
||||||
|
private const val KEY_PRIVILEGE_MODE = "privilege_mode"
|
||||||
|
private const val KEY_FONT_SIZE = "font_size"
|
||||||
|
|
||||||
private const val DEFAULT_SERVER_IP = ""
|
private const val DEFAULT_SERVER_IP = ""
|
||||||
private const val DEFAULT_WEB_PORT = 8181
|
private const val DEFAULT_WEB_PORT = 8181
|
||||||
private const val DEFAULT_ADB_PORT = 5555
|
private const val DEFAULT_ADB_PORT = 5555
|
||||||
private const val DEFAULT_USBIP_PORT = 3240
|
private const val DEFAULT_USBIP_PORT = 3240
|
||||||
private const val DEFAULT_BBS_ADDRESS = ""
|
private const val DEFAULT_BBS_ADDRESS = ""
|
||||||
|
private const val DEFAULT_PRIVILEGE_MODE = "none"
|
||||||
|
private const val DEFAULT_FONT_SIZE = 14
|
||||||
|
|
||||||
private fun prefs(context: Context): SharedPreferences {
|
private fun prefs(context: Context): SharedPreferences {
|
||||||
return context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
return context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||||
@@ -77,4 +81,20 @@ object PrefsManager {
|
|||||||
val port = getWebPort(context)
|
val port = getWebPort(context)
|
||||||
return "https://$ip:$port"
|
return "https://$ip:$port"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getPreferredPrivilegeMode(context: Context): String {
|
||||||
|
return prefs(context).getString(KEY_PRIVILEGE_MODE, DEFAULT_PRIVILEGE_MODE) ?: DEFAULT_PRIVILEGE_MODE
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setPreferredPrivilegeMode(context: Context, mode: String) {
|
||||||
|
prefs(context).edit().putString(KEY_PRIVILEGE_MODE, mode).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFontSize(context: Context): Int {
|
||||||
|
return prefs(context).getInt(KEY_FONT_SIZE, DEFAULT_FONT_SIZE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setFontSize(context: Context, size: Int) {
|
||||||
|
prefs(context).edit().putInt(KEY_FONT_SIZE, size).apply()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,64 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<androidx.drawerlayout.widget.DrawerLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/drawer_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
tools:openDrawer="start">
|
||||||
|
|
||||||
|
<!-- Main content area -->
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/background">
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:id="@+id/app_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/surface"
|
||||||
|
app:elevation="0dp">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="@color/surface"
|
||||||
|
app:titleTextColor="@color/terminal_green"
|
||||||
|
app:navigationIconTint="@color/terminal_green"
|
||||||
|
app:title="@string/drawer_app_name"
|
||||||
|
app:titleTextAppearance="@style/ToolbarTitle" />
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/nav_host_fragment"
|
android:id="@+id/nav_host_fragment"
|
||||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="match_parent"
|
||||||
app:defaultNavHost="true"
|
app:defaultNavHost="true"
|
||||||
app:layout_constraintBottom_toTopOf="@id/bottom_nav"
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:navGraph="@navigation/nav_graph" />
|
app:navGraph="@navigation/nav_graph" />
|
||||||
|
|
||||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
android:id="@+id/bottom_nav"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@color/surface"
|
|
||||||
app:itemIconTint="@color/nav_item_color"
|
|
||||||
app:itemTextColor="@color/nav_item_color"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:menu="@menu/bottom_nav" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
<!-- Navigation drawer -->
|
||||||
|
<com.google.android.material.navigation.NavigationView
|
||||||
|
android:id="@+id/nav_view"
|
||||||
|
android:layout_width="280dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="start"
|
||||||
|
android:background="@color/surface_dark"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
app:headerLayout="@layout/drawer_header"
|
||||||
|
app:menu="@menu/drawer_menu"
|
||||||
|
app:itemIconTint="@color/terminal_green"
|
||||||
|
app:itemTextColor="@color/text_primary"
|
||||||
|
app:subheaderColor="@color/terminal_green_dim"
|
||||||
|
app:subheaderTextAppearance="@style/DrawerSubheader" />
|
||||||
|
|
||||||
|
</androidx.drawerlayout.widget.DrawerLayout>
|
||||||
|
|||||||
48
autarch_companion/app/src/main/res/layout/drawer_header.xml
Normal file
48
autarch_companion/app/src/main/res/layout/drawer_header.xml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:paddingTop="32dp"
|
||||||
|
android:gravity="center_horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="64dp"
|
||||||
|
android:layout_height="64dp"
|
||||||
|
android:src="@drawable/ic_archon"
|
||||||
|
android:contentDescription="@string/app_name"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/drawer_app_name"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="22sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:letterSpacing="0.15"
|
||||||
|
android:layout_marginBottom="4dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/drawer_version"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="v2.0.0"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<!-- Separator line -->
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim"
|
||||||
|
android:layout_marginTop="8dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
93
autarch_companion/app/src/main/res/layout/fragment_about.xml
Normal file
93
autarch_companion/app/src/main/res/layout/fragment_about.xml
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="32dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="96dp"
|
||||||
|
android:layout_height="96dp"
|
||||||
|
android:src="@drawable/ic_archon"
|
||||||
|
android:contentDescription="@string/app_name"
|
||||||
|
android:layout_marginBottom="24dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/drawer_app_name"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="28sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:letterSpacing="0.2"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Companion"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="24dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/about_version"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="v2.0.0"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/about_copyright"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="32dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/about_description"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:gravity="center"
|
||||||
|
android:lineSpacingExtra="4dp"
|
||||||
|
android:layout_marginBottom="48dp" />
|
||||||
|
|
||||||
|
<!-- Logout -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_logout"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:text="LOGOUT"
|
||||||
|
android:textColor="@color/danger"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:strokeColor="@color/danger"
|
||||||
|
app:cornerRadius="4dp"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" />
|
||||||
|
|
||||||
|
<!-- Clear Data -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_clear_data"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="CLEAR APP DATA"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
129
autarch_companion/app/src/main/res/layout/fragment_adb_shell.xml
Normal file
129
autarch_companion/app/src/main/res/layout/fragment_adb_shell.xml
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<!-- Connection status bar -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/shell_status_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@color/surface">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/shell_status_dot"
|
||||||
|
android:layout_width="10dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:background="@color/danger" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/shell_status_text"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:text="Disconnected"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_shell_connect"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="CONNECT"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_shell_clear"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="CLEAR"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Separator -->
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim" />
|
||||||
|
|
||||||
|
<!-- Terminal output area -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/shell_output"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="4dp"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:background="@color/background" />
|
||||||
|
|
||||||
|
<!-- Separator -->
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim" />
|
||||||
|
|
||||||
|
<!-- Command input bar -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="4dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@color/surface">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="$"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="4dp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/shell_input"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textColorHint="@color/text_muted"
|
||||||
|
android:hint="@string/adb_shell_hint"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:inputType="text"
|
||||||
|
android:imeOptions="actionSend"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:importantForAutofill="no" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_shell_send"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:src="@android:drawable/ic_media_play"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="Send"
|
||||||
|
app:tint="@color/terminal_green" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Theme -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/appearance_theme_label"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<RadioGroup
|
||||||
|
android:id="@+id/radio_theme"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/radio_theme_dark"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/appearance_theme_dark"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:buttonTint="@color/terminal_green"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:checked="true" />
|
||||||
|
|
||||||
|
</RadioGroup>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Font Size -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/appearance_font_size"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.slider.Slider
|
||||||
|
android:id="@+id/slider_font_size"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:valueFrom="10"
|
||||||
|
android:valueTo="22"
|
||||||
|
android:value="14"
|
||||||
|
android:stepSize="1"
|
||||||
|
app:thumbColor="@color/terminal_green"
|
||||||
|
app:trackColorActive="@color/terminal_green"
|
||||||
|
app:trackColorInactive="@color/terminal_green_dim"
|
||||||
|
app:labelBehavior="floating" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/font_size_preview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Preview text (14sp)"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginTop="8dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Save -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_save_appearance"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/save_settings"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Privilege Mode Selection -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/privilege_mode_label"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<RadioGroup
|
||||||
|
android:id="@+id/radio_privilege_mode"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/radio_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/privilege_root"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:buttonTint="@color/terminal_green"
|
||||||
|
android:padding="8dp" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/radio_shizuku"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/privilege_shizuku"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:buttonTint="@color/terminal_green"
|
||||||
|
android:padding="8dp" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/radio_adb"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/privilege_adb"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:buttonTint="@color/terminal_green"
|
||||||
|
android:padding="8dp" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/radio_none"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/privilege_none"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:buttonTint="@color/terminal_green"
|
||||||
|
android:padding="8dp" />
|
||||||
|
|
||||||
|
</RadioGroup>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Privilege Status -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Status"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/privilege_status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/privilege_status_checking"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Save -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_save_privileges"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/save_settings"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Server Connection -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/server_connection"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:hint="@string/hint_server_ip"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_server_ip"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="text"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:hint="@string/hint_web_port"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_web_port"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="number"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Port Configuration -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/adb_configuration"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:hint="@string/hint_adb_port"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_adb_port"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="number"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:hint="@string/hint_usbip_port"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_usbip_port"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="number"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Auto-Detect -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_auto_detect"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:text="@string/auto_detect"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:icon="@android:drawable/ic_menu_search"
|
||||||
|
app:iconTint="@color/background"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="16dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_test_connection"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="@string/test_connection"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_save_connection"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/save_settings"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Status -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/connection_status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Privilege Settings"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
|
<!-- Current method display -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Active Privilege Method"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/priv_current_method"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Detecting..."
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Root status -->
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
|
android:text="ROOT" android:textColor="@color/accent" android:textSize="14sp"
|
||||||
|
android:textStyle="bold" android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal" android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="16dp">
|
||||||
|
<View android:id="@+id/dot_root" android:layout_width="10dp" android:layout_height="10dp" />
|
||||||
|
<TextView android:id="@+id/status_root" android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" android:layout_marginStart="8dp"
|
||||||
|
android:textColor="@color/text_secondary" android:text="Checking..." />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Shizuku status -->
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
|
android:text="SHIZUKU" android:textColor="@color/accent" android:textSize="14sp"
|
||||||
|
android:textStyle="bold" android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal" android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
<View android:id="@+id/dot_shizuku" android:layout_width="10dp" android:layout_height="10dp" />
|
||||||
|
<TextView android:id="@+id/status_shizuku" android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" android:layout_marginStart="8dp"
|
||||||
|
android:textColor="@color/text_secondary" android:text="Checking..." />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_shizuku_request"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="REQUEST SHIZUKU PERMISSION"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
style="@style/Widget.Material3.Button.OutlinedButton" />
|
||||||
|
|
||||||
|
<!-- Local ADB status -->
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
|
android:text="WIRELESS ADB" android:textColor="@color/accent" android:textSize="14sp"
|
||||||
|
android:textStyle="bold" android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal" android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
<View android:id="@+id/dot_adb" android:layout_width="10dp" android:layout_height="10dp" />
|
||||||
|
<TextView android:id="@+id/status_adb" android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" android:layout_marginStart="8dp"
|
||||||
|
android:textColor="@color/text_secondary" android:text="Checking..." />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Pairing Code"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_pairing_code"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="number" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_adb_pair"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="PAIR DEVICE"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
style="@style/Widget.Material3.Button.OutlinedButton" />
|
||||||
|
|
||||||
|
<!-- Archon Server status -->
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||||
|
android:text="ARCHON SERVER" android:textColor="@color/accent" android:textSize="14sp"
|
||||||
|
android:textStyle="bold" android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal" android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
<View android:id="@+id/dot_server" android:layout_width="10dp" android:layout_height="10dp" />
|
||||||
|
<TextView android:id="@+id/status_server" android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" android:layout_marginStart="8dp"
|
||||||
|
android:textColor="@color/text_secondary" android:text="Checking..." />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.materialswitch.MaterialSwitch
|
||||||
|
android:id="@+id/switch_auto_restart_adb"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Auto-restart ADB on boot"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:layout_marginTop="16dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_refresh_status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="REFRESH STATUS"
|
||||||
|
android:layout_marginTop="16dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_arp_scan"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="SCAN ARP TABLE"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/arp_count"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Warning banner for duplicate MACs -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/arp_warning"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="#33E06C75"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:textColor="#E06C75"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<!-- Results -->
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/arp_results"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textIsSelectable="true" />
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Header with copy button -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="DEVICE INFO"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_copy_all"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="COPY"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Device Section -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Device"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/section_device"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- System Section -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="System"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/section_system"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Hardware Section -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Hardware"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/section_hardware"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Network Section -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Network"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/section_network"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Security Section -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Security"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/section_security"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Storage Section -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Storage"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/section_storage"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Refresh Button -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_refresh"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="REFRESH"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp"
|
||||||
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
306
autarch_companion/app/src/main/res/layout/fragment_tool_dns.xml
Normal file
306
autarch_companion/app/src/main/res/layout/fragment_tool_dns.xml
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="DNS LOOKUP"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
|
<!-- Query Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Query"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:hint="Domain name or IP address"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_domain"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textUri"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- Record Type Selector -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Record Type"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
android:id="@+id/chip_group_record_type"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:singleSelection="true"
|
||||||
|
app:selectionRequired="true">
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_a"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="A"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:checked="true"
|
||||||
|
app:chipBackgroundColor="@color/surface_dark"
|
||||||
|
app:chipStrokeColor="@color/terminal_green_dim"
|
||||||
|
app:chipStrokeWidth="1dp"
|
||||||
|
app:checkedIconVisible="false"
|
||||||
|
android:textColor="@color/text_primary" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_aaaa"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="AAAA"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:chipBackgroundColor="@color/surface_dark"
|
||||||
|
app:chipStrokeColor="@color/terminal_green_dim"
|
||||||
|
app:chipStrokeWidth="1dp"
|
||||||
|
app:checkedIconVisible="false"
|
||||||
|
android:textColor="@color/text_primary" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_mx"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="MX"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:chipBackgroundColor="@color/surface_dark"
|
||||||
|
app:chipStrokeColor="@color/terminal_green_dim"
|
||||||
|
app:chipStrokeWidth="1dp"
|
||||||
|
app:checkedIconVisible="false"
|
||||||
|
android:textColor="@color/text_primary" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_ns"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="NS"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:chipBackgroundColor="@color/surface_dark"
|
||||||
|
app:chipStrokeColor="@color/terminal_green_dim"
|
||||||
|
app:chipStrokeWidth="1dp"
|
||||||
|
app:checkedIconVisible="false"
|
||||||
|
android:textColor="@color/text_primary" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_txt"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="TXT"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:chipBackgroundColor="@color/surface_dark"
|
||||||
|
app:chipStrokeColor="@color/terminal_green_dim"
|
||||||
|
app:chipStrokeWidth="1dp"
|
||||||
|
app:checkedIconVisible="false"
|
||||||
|
android:textColor="@color/text_primary" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_cname"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="CNAME"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:chipBackgroundColor="@color/surface_dark"
|
||||||
|
app:chipStrokeColor="@color/terminal_green_dim"
|
||||||
|
app:chipStrokeWidth="1dp"
|
||||||
|
app:checkedIconVisible="false"
|
||||||
|
android:textColor="@color/text_primary" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_soa"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="SOA"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:chipBackgroundColor="@color/surface_dark"
|
||||||
|
app:chipStrokeColor="@color/terminal_green_dim"
|
||||||
|
app:chipStrokeWidth="1dp"
|
||||||
|
app:checkedIconVisible="false"
|
||||||
|
android:textColor="@color/text_primary" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_ptr"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="PTR"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:chipBackgroundColor="@color/surface_dark"
|
||||||
|
app:chipStrokeColor="@color/terminal_green_dim"
|
||||||
|
app:chipStrokeWidth="1dp"
|
||||||
|
app:checkedIconVisible="false"
|
||||||
|
android:textColor="@color/text_primary" />
|
||||||
|
|
||||||
|
</com.google.android.material.chip.ChipGroup>
|
||||||
|
|
||||||
|
<!-- Custom DNS Server (optional) -->
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:hint="DNS Server (optional, e.g. 8.8.8.8)"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_dns_server"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textUri"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- Lookup Button -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_lookup"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="LOOKUP"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Results Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:cardBackgroundColor="@color/surface_dark"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="Results"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_copy_results"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:text="COPY"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_dns"
|
||||||
|
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:indeterminateTint="@color/terminal_green"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_results"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="120dp"
|
||||||
|
android:text="> ready_"
|
||||||
|
android:textColor="@color/terminal_green_dim"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:lineSpacingMultiplier="1.3" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
@@ -0,0 +1,304 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:paddingBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="FILE BROWSER"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="4dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/file_privilege_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Privilege: checking..."
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Breadcrumb path bar -->
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:id="@+id/breadcrumb_scroll"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="none"
|
||||||
|
android:background="@color/surface"
|
||||||
|
android:paddingTop="2dp"
|
||||||
|
android:paddingBottom="2dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/breadcrumb_container"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingBottom="8dp" />
|
||||||
|
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
<!-- Separator -->
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim" />
|
||||||
|
|
||||||
|
<!-- Action bar -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:background="@color/surface_dark">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_file_up"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="UP"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_file_root"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="/"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_file_data"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="/data"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_file_system"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="/system"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_file_sdcard"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="/sdcard"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_file_refresh"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="REFRESH"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Separator -->
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim" />
|
||||||
|
|
||||||
|
<!-- Column header -->
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="none"
|
||||||
|
android:background="@color/surface">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingBottom="6dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="PERMISSIONS"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="OWNER"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="GROUP"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="SIZE"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="DATE"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="200dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="NAME"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
<!-- Separator -->
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim" />
|
||||||
|
|
||||||
|
<!-- File list -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/file_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingBottom="8dp" />
|
||||||
|
|
||||||
|
<!-- Status bar -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:background="@color/surface_dark">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/file_status"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="> /"
|
||||||
|
android:textColor="@color/terminal_green_dim"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="start" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/file_count_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="0 items"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<!-- Tab selector for chains -->
|
||||||
|
<com.google.android.material.tabs.TabLayout
|
||||||
|
android:id="@+id/firewall_tabs"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/surface"
|
||||||
|
app:tabTextColor="@color/text_muted"
|
||||||
|
app:tabSelectedTextColor="@color/terminal_green"
|
||||||
|
app:tabIndicatorColor="@color/terminal_green"
|
||||||
|
app:tabMode="scrollable" />
|
||||||
|
|
||||||
|
<!-- Action buttons -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_fw_refresh"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="REFRESH"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_fw_add"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="ADD RULE"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Rules display -->
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/firewall_output"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textIsSelectable="true" />
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,374 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="HTTP HEADERS"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
|
<!-- Input Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Request"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green"
|
||||||
|
app:boxBackgroundColor="@color/surface_dark"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_url"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="https://example.com"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textColorHint="@color/text_muted"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:inputType="textUri"
|
||||||
|
android:imeOptions="actionDone" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- Method Selector -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Method: "
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginEnd="8dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
android:id="@+id/chip_group_method"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:singleSelection="true"
|
||||||
|
app:selectionRequired="true">
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_get"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="GET"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:checked="true"
|
||||||
|
app:chipBackgroundColor="@color/surface_dark"
|
||||||
|
app:chipStrokeColor="@color/terminal_green_dim"
|
||||||
|
app:chipStrokeWidth="1dp"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
style="@style/Widget.Material3.Chip.Filter" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_head"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="HEAD"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp"
|
||||||
|
app:chipBackgroundColor="@color/surface_dark"
|
||||||
|
app:chipStrokeColor="@color/terminal_green_dim"
|
||||||
|
app:chipStrokeWidth="1dp"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
style="@style/Widget.Material3.Chip.Filter" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_post"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="POST"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp"
|
||||||
|
app:chipBackgroundColor="@color/surface_dark"
|
||||||
|
app:chipStrokeColor="@color/terminal_green_dim"
|
||||||
|
app:chipStrokeWidth="1dp"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
style="@style/Widget.Material3.Chip.Filter" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_options"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="OPTIONS"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp"
|
||||||
|
app:chipBackgroundColor="@color/surface_dark"
|
||||||
|
app:chipStrokeColor="@color/terminal_green_dim"
|
||||||
|
app:chipStrokeWidth="1dp"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
style="@style/Widget.Material3.Chip.Filter" />
|
||||||
|
</com.google.android.material.chip.ChipGroup>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Custom Headers -->
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green"
|
||||||
|
app:boxBackgroundColor="@color/surface_dark"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_custom_headers"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Custom headers (Key: Value, one per line)"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textColorHint="@color/text_muted"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:minLines="2"
|
||||||
|
android:maxLines="4"
|
||||||
|
android:gravity="top" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- Follow redirects toggle + send -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.materialswitch.MaterialSwitch
|
||||||
|
android:id="@+id/switch_follow_redirects"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Follow redirects"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:checked="false"
|
||||||
|
app:thumbTint="@color/terminal_green"
|
||||||
|
app:trackTint="@color/surface_dark"
|
||||||
|
android:layout_marginEnd="8dp" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_send"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="SEND"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Progress -->
|
||||||
|
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
|
android:id="@+id/progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:indicatorColor="@color/terminal_green"
|
||||||
|
app:trackColor="@color/surface_dark"
|
||||||
|
app:trackThickness="3dp" />
|
||||||
|
|
||||||
|
<!-- Response Info Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/card_response"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/response_status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="4dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/response_time"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="4dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/response_url"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textIsSelectable="true" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Redirect Chain Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/card_redirects"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/warning"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="REDIRECT CHAIN"
|
||||||
|
android:textColor="@color/warning"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/redirect_chain_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textIsSelectable="true" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Security Headers Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/card_security"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="SECURITY HEADERS"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/security_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- All Headers -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/card_headers"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:cardBackgroundColor="@color/surface_dark"
|
||||||
|
app:cardCornerRadius="8dp">
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/headers_output"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:textColor="@color/terminal_green_dim"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textIsSelectable="true" />
|
||||||
|
</ScrollView>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:paddingBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="KEYSTORE DUMP"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="4dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/ks_privilege_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Privilege: checking..."
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="4dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Recon tool — enumerates key material, does not extract secrets"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<!-- Action buttons -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="4dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_ks_scan_all"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="SCAN ALL"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
style="@style/Widget.Material3.Button"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_ks_keystore"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="KEYSTORE"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_ks_keymaster"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="KEYMASTER"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_ks_samsung"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="SAMSUNG EFS"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_ks_certs"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="CERTIFICATES"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_ks_clear"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="CLEAR"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Status line -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/ks_status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="> idle"
|
||||||
|
android:textColor="@color/terminal_green_dim"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="4dp"
|
||||||
|
android:background="@color/surface_dark" />
|
||||||
|
|
||||||
|
<!-- Separator -->
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim" />
|
||||||
|
|
||||||
|
<!-- Results output -->
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/ks_scroll"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/ks_output"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:text="> Tap SCAN ALL to enumerate key material\n> Requires root or Archon Server privileges"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:lineSpacingExtra="2dp" />
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
<!-- Bottom info bar -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:background="@color/surface_dark">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/ks_entry_count"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="0 entries found"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/ks_scan_time"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,343 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:paddingBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="LOGCAT VIEWER"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="4dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/logcat_privilege_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Privilege: checking..."
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<!-- Control buttons row -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_logcat_start"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="START"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
style="@style/Widget.Material3.Button"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_logcat_stop"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="STOP"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_logcat_clear"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="CLEAR"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_logcat_save"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="SAVE"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Filter row -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="TAG:"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginEnd="6dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_logcat_tag"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:hint="filter tag..."
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textColorHint="@color/text_muted"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:inputType="text"
|
||||||
|
android:background="@color/surface_dark"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:singleLine="true" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="MSG:"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="6dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_logcat_msg"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:hint="filter text..."
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textColorHint="@color/text_muted"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:inputType="text"
|
||||||
|
android:background="@color/surface_dark"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:singleLine="true" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Log level filter buttons -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="LVL:"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginEnd="6dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_level_v"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="V"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/logcat_verbose"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_level_d"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="D"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/logcat_debug"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_level_i"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="I"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button"
|
||||||
|
app:backgroundTint="@color/logcat_info"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_level_w"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="W"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button"
|
||||||
|
app:backgroundTint="@color/logcat_warn"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_level_e"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="E"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button"
|
||||||
|
app:backgroundTint="@color/logcat_error"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_level_f"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="F"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button"
|
||||||
|
app:backgroundTint="@color/logcat_fatal"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_logcat_autoscroll"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="AUTO"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
style="@style/Widget.Material3.Button"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Status line -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/logcat_status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="> stopped"
|
||||||
|
android:textColor="@color/terminal_green_dim"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="4dp"
|
||||||
|
android:background="@color/surface_dark" />
|
||||||
|
|
||||||
|
<!-- Separator -->
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim" />
|
||||||
|
|
||||||
|
<!-- Log output -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/logcat_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingBottom="8dp" />
|
||||||
|
|
||||||
|
<!-- Bottom info bar -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:background="@color/surface_dark">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/logcat_line_count"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="0 lines"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/logcat_filter_info"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="min: V"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="WiFi Monitor Mode"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
|
<!-- Status card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/monitor_chip_info"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:text="Detecting WiFi chip..." />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/monitor_status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:text="Status: Unknown" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/monitor_firmware"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Controls -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_monitor_enable"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="ENABLE MONITOR MODE"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
app:cornerRadius="4dp"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_monitor_disable"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="DISABLE MONITOR MODE"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:cornerRadius="4dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:enabled="false" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_monitor_check"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="CHECK STATUS"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:cornerRadius="4dp"
|
||||||
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
|
<!-- Log output -->
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/monitor_log"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textIsSelectable="true" />
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:paddingBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="NETWORK SCANNER"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="4dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/netscan_subtitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Local network device discovery"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<!-- Subnet input row -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="SUBNET:"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginEnd="8dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_subnet"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:hint="192.168.1"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textColorHint="@color/text_muted"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:inputType="text"
|
||||||
|
android:background="@color/surface_dark"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:singleLine="true" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text=".0/24"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginStart="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Action buttons row -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="4dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_scan"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="SCAN"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
style="@style/Widget.Material3.Button"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_arp_only"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="ARP CACHE"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_clear"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="CLEAR"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Progress bar -->
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/scan_progress"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
android:max="254"
|
||||||
|
android:progress="0"
|
||||||
|
android:progressTint="@color/terminal_green"
|
||||||
|
android:progressBackgroundTint="@color/surface"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<!-- Status line -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/scan_status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="> idle"
|
||||||
|
android:textColor="@color/terminal_green_dim"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="4dp"
|
||||||
|
android:background="@color/surface_dark" />
|
||||||
|
|
||||||
|
<!-- Separator -->
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim" />
|
||||||
|
|
||||||
|
<!-- Results count header -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:background="@color/surface">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/results_count"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="0 devices found"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/scan_time"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Separator -->
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim" />
|
||||||
|
|
||||||
|
<!-- Device list -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/device_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingBottom="16dp" />
|
||||||
|
|
||||||
|
<!-- Bottom log area -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
app:cardBackgroundColor="@color/surface_dark"
|
||||||
|
app:cardCornerRadius="4dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/scan_log"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:maxHeight="96dp"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:text="> ready"
|
||||||
|
android:textColor="@color/terminal_green_dim"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
android:lineSpacingExtra="1dp" />
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
106
autarch_companion/app/src/main/res/layout/fragment_tool_pcap.xml
Normal file
106
autarch_companion/app/src/main/res/layout/fragment_tool_pcap.xml
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<!-- Interface and filter -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/pcap_interface"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/pcap_filter"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:hint="Filter (e.g. port 80, host 10.0.0.1)"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textColorHint="@color/text_muted"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:layout_marginStart="8dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Controls -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_pcap_start"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:text="START"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_pcap_stop"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:text="STOP"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
app:cornerRadius="4dp"
|
||||||
|
android:enabled="false" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/pcap_count"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:text="0 packets" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim"
|
||||||
|
android:layout_marginTop="4dp" />
|
||||||
|
|
||||||
|
<!-- Packet output -->
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/pcap_scroll"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/pcap_output"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textIsSelectable="true" />
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:paddingBottom="0dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="PORT SCANNER"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
|
<!-- Target Host Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Target"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:hint="Host / IP address"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_target_host"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textUri"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- Port Range Row -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:hint="Start port"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_port_start"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="number"
|
||||||
|
android:text="1"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:hint="End port"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_port_end"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="number"
|
||||||
|
android:text="1024"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_common_ports"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="COMMON"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp"
|
||||||
|
app:strokeColor="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Scan / Stop Buttons -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_scan"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="SCAN"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_stop"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="STOP"
|
||||||
|
android:textColor="@color/danger"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:enabled="false"
|
||||||
|
app:strokeColor="@color/danger"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Progress Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/card_progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_progress_label"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="Scanning..."
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_progress_count"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="0 / 0"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_bar"
|
||||||
|
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="0"
|
||||||
|
android:progressTint="@color/terminal_green"
|
||||||
|
android:progressBackgroundTint="@color/surface_dark" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_open_count"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
android:text="Open: 0"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Results List -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler_results"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingBottom="16dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:background="@color/background" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,359 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:paddingBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="PROCESS INSPECTOR"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="4dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/proc_privilege_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Privilege: checking..."
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<!-- Search bar -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_proc_search"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:hint="Filter processes..."
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textColorHint="@color/text_muted"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:inputType="text"
|
||||||
|
android:background="@color/surface_dark"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:singleLine="true" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_proc_refresh"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:text="REFRESH"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
style="@style/Widget.Material3.Button"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Sort buttons row -->
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="none">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_sort_pid"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="PID"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_sort_user"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="USER"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_sort_cpu"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="CPU%"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_sort_mem"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="MEM%"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_sort_vsz"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="VSZ"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_sort_rss"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="RSS"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_sort_cmd"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:text="CMD"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
app:backgroundTint="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Status line -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/proc_status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="> idle"
|
||||||
|
android:textColor="@color/terminal_green_dim"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="4dp"
|
||||||
|
android:background="@color/surface_dark" />
|
||||||
|
|
||||||
|
<!-- Separator -->
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim" />
|
||||||
|
|
||||||
|
<!-- Column header row -->
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="none"
|
||||||
|
android:background="@color/surface">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingBottom="6dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="PID"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="90dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="USER"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="55dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="CPU%"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="55dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="MEM%"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="VSZ"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="RSS"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="STAT"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="200dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="COMMAND"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
<!-- Separator -->
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/terminal_green_dim" />
|
||||||
|
|
||||||
|
<!-- Process list -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/proc_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingBottom="8dp" />
|
||||||
|
|
||||||
|
<!-- Bottom status bar -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:background="@color/surface_dark">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/proc_count_text"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="0 processes"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/proc_sort_indicator"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="sort: PID"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
273
autarch_companion/app/src/main/res/layout/fragment_tool_ssl.xml
Normal file
273
autarch_companion/app/src/main/res/layout/fragment_tool_ssl.xml
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="SSL/TLS CHECK"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
|
<!-- Input Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Target"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green"
|
||||||
|
app:boxBackgroundColor="@color/surface_dark"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_hostname"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="hostname (e.g. example.com)"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textColorHint="@color/text_muted"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:inputType="textUri"
|
||||||
|
android:imeOptions="actionDone" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green"
|
||||||
|
app:boxBackgroundColor="@color/surface_dark"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_port"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="port (443)"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textColorHint="@color/text_muted"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:inputType="number" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_check"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="CHECK"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Status Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/card_status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/status_dot"
|
||||||
|
android:layout_width="10dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:background="@color/status_offline"
|
||||||
|
android:layout_marginEnd="8dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/status_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Checking..."
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/status_protocol"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="2dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/status_cipher"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="2dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/status_time"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Issues Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/card_issues"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/danger"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="ISSUES"
|
||||||
|
android:textColor="@color/danger"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/issues_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/danger"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Certificate Chain -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/card_chain"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="CERTIFICATE CHAIN"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/chain_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Progress -->
|
||||||
|
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
|
android:id="@+id/progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:indeterminate="true"
|
||||||
|
app:indicatorColor="@color/terminal_green"
|
||||||
|
app:trackColor="@color/surface_dark"
|
||||||
|
app:trackThickness="3dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="WHOIS LOOKUP"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
|
<!-- Input Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Domain / IP"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:boxStrokeColor="@color/terminal_green"
|
||||||
|
app:hintTextColor="@color/terminal_green"
|
||||||
|
app:boxBackgroundColor="@color/surface_dark"
|
||||||
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/input_domain"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="example.com or 93.184.216.34"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textColorHint="@color/text_muted"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:inputType="textUri"
|
||||||
|
android:imeOptions="actionDone" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_lookup"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="LOOKUP"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.materialswitch.MaterialSwitch
|
||||||
|
android:id="@+id/switch_raw"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="RAW"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:thumbTint="@color/terminal_green"
|
||||||
|
app:trackTint="@color/surface_dark" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Progress -->
|
||||||
|
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
|
android:id="@+id/progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:indicatorColor="@color/terminal_green"
|
||||||
|
app:trackColor="@color/surface_dark"
|
||||||
|
app:trackThickness="3dp" />
|
||||||
|
|
||||||
|
<!-- Parsed Results Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/card_parsed"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="PARSED"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/parsed_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Raw Output -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/card_raw"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:cardBackgroundColor="@color/surface_dark"
|
||||||
|
app:cardCornerRadius="8dp">
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/raw_output"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:textColor="@color/terminal_green_dim"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textIsSelectable="true" />
|
||||||
|
</ScrollView>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
326
autarch_companion/app/src/main/res/layout/fragment_tool_wifi.xml
Normal file
326
autarch_companion/app/src/main/res/layout/fragment_tool_wifi.xml
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/background"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="WIFI ANALYZER"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
|
<!-- Current Connection Card -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:id="@+id/card_current_connection"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:strokeColor="@color/terminal_green"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Current Connection"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:layout_marginBottom="12dp" />
|
||||||
|
|
||||||
|
<!-- SSID -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="4dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="SSID"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_conn_ssid"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="--"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- BSSID -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="4dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="BSSID"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_conn_bssid"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="--"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Frequency -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="4dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Frequency"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_conn_freq"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="--"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Channel -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="4dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Channel"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_conn_channel"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="--"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Signal Strength -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="4dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Signal"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_conn_signal"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="--"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Signal Bar -->
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/pb_conn_signal"
|
||||||
|
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="0"
|
||||||
|
android:progressTint="@color/terminal_green"
|
||||||
|
android:progressBackgroundTint="@color/surface_dark"
|
||||||
|
android:layout_marginBottom="4dp" />
|
||||||
|
|
||||||
|
<!-- Link Speed -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="4dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Link Speed"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_conn_speed"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="--"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- IP Address -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="IP Address"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_conn_ip"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="--"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
<!-- Scan Controls -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="12dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_scan"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="SCAN"
|
||||||
|
android:textColor="@color/background"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
app:backgroundTint="@color/terminal_green"
|
||||||
|
app:cornerRadius="4dp"
|
||||||
|
android:layout_marginEnd="8dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_sort_signal"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="dBm"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp"
|
||||||
|
android:layout_marginEnd="4dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_sort_channel"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="CH"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:cornerRadius="4dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Network Count -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_network_count"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Nearby Networks (0)"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<!-- Scan Results List -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv_networks"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:nestedScrollingEnabled="false" />
|
||||||
|
|
||||||
|
<!-- Status Text -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_status"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="> WiFi analyzer ready_"
|
||||||
|
android:textColor="@color/terminal_green_dim"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginTop="12dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:background="?android:attr/selectableItemBackground">
|
||||||
|
|
||||||
|
<!-- Status dot -->
|
||||||
|
<View
|
||||||
|
android:id="@+id/device_status_dot"
|
||||||
|
android:layout_width="10dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:layout_marginEnd="12dp" />
|
||||||
|
|
||||||
|
<!-- Device info -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- IP address -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/device_ip"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:singleLine="true" />
|
||||||
|
|
||||||
|
<!-- Hostname -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/device_hostname"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:layout_marginTop="2dp" />
|
||||||
|
|
||||||
|
<!-- MAC + Vendor -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/device_mac"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:layout_marginTop="1dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Vendor badge -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/device_vendor"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:gravity="end"
|
||||||
|
android:maxWidth="100dp"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:ellipsize="end" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/shell_line_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingTop="1dp"
|
||||||
|
android:paddingBottom="1dp"
|
||||||
|
android:textColor="#D4D4D4"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:textIsSelectable="true" />
|
||||||
126
autarch_companion/app/src/main/res/layout/item_wifi_network.xml
Normal file
126
autarch_companion/app/src/main/res/layout/item_wifi_network.xml
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="6dp"
|
||||||
|
app:cardBackgroundColor="@color/surface"
|
||||||
|
app:cardCornerRadius="6dp"
|
||||||
|
app:strokeColor="@color/terminal_green_dim"
|
||||||
|
app:strokeWidth="1dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<!-- Signal bar column -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginEnd="12dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_signal_dbm"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="-50"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:gravity="center" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/pb_signal"
|
||||||
|
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="50"
|
||||||
|
android:progressTint="@color/terminal_green"
|
||||||
|
android:progressBackgroundTint="@color/surface_dark"
|
||||||
|
android:layout_marginTop="2dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Network info column -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_ssid"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="NetworkName"
|
||||||
|
android:textColor="@color/text_primary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_bssid"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="00:00:00:00:00:00"
|
||||||
|
android:textColor="@color/text_muted"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginTop="4dp">
|
||||||
|
|
||||||
|
<!-- Security badge -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_security"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="WPA2"
|
||||||
|
android:textColor="@color/terminal_green"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:background="@color/surface_dark"
|
||||||
|
android:paddingStart="6dp"
|
||||||
|
android:paddingEnd="6dp"
|
||||||
|
android:paddingTop="1dp"
|
||||||
|
android:paddingBottom="1dp"
|
||||||
|
android:layout_marginEnd="8dp" />
|
||||||
|
|
||||||
|
<!-- Channel -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_channel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="CH 6"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:layout_marginEnd="8dp" />
|
||||||
|
|
||||||
|
<!-- Frequency band -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_band"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="2.4 GHz"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:textSize="11sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
153
autarch_companion/app/src/main/res/menu/drawer_menu.xml
Normal file
153
autarch_companion/app/src/main/res/menu/drawer_menu.xml
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<group android:id="@+id/group_main"
|
||||||
|
android:checkableBehavior="single">
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_dashboard"
|
||||||
|
android:icon="@android:drawable/ic_menu_compass"
|
||||||
|
android:title="@string/nav_dashboard" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_adb_shell"
|
||||||
|
android:icon="@android:drawable/ic_menu_sort_by_size"
|
||||||
|
android:title="@string/nav_adb_shell" />
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<item android:title="@string/drawer_header_tools">
|
||||||
|
<menu>
|
||||||
|
<group android:id="@+id/group_tools"
|
||||||
|
android:checkableBehavior="single">
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_modules"
|
||||||
|
android:icon="@android:drawable/ic_menu_manage"
|
||||||
|
android:title="@string/nav_modules" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_messaging"
|
||||||
|
android:icon="@android:drawable/ic_dialog_email"
|
||||||
|
android:title="@string/nav_messaging" />
|
||||||
|
</group>
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item android:title="NON-ROOTED TOOLS">
|
||||||
|
<menu>
|
||||||
|
<group android:id="@+id/group_noroot_tools"
|
||||||
|
android:checkableBehavior="single">
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_netscan"
|
||||||
|
android:icon="@android:drawable/ic_menu_mapmode"
|
||||||
|
android:title="Network Scanner" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_portscan"
|
||||||
|
android:icon="@android:drawable/ic_menu_sort_by_size"
|
||||||
|
android:title="Port Scanner" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_wifi"
|
||||||
|
android:icon="@android:drawable/ic_menu_compass"
|
||||||
|
android:title="WiFi Analyzer" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_dns"
|
||||||
|
android:icon="@android:drawable/ic_menu_search"
|
||||||
|
android:title="DNS Lookup" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_whois"
|
||||||
|
android:icon="@android:drawable/ic_menu_info_details"
|
||||||
|
android:title="Whois" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_ssl"
|
||||||
|
android:icon="@android:drawable/ic_secure"
|
||||||
|
android:title="SSL/TLS Check" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_headers"
|
||||||
|
android:icon="@android:drawable/ic_menu_recent_history"
|
||||||
|
android:title="HTTP Headers" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_devinfo"
|
||||||
|
android:icon="@android:drawable/ic_menu_myplaces"
|
||||||
|
android:title="Device Info" />
|
||||||
|
</group>
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item android:title="ROOTED TOOLS">
|
||||||
|
<menu>
|
||||||
|
<group android:id="@+id/group_root_tools"
|
||||||
|
android:checkableBehavior="single">
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_pcap"
|
||||||
|
android:icon="@android:drawable/ic_menu_upload"
|
||||||
|
android:title="Packet Capture" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_monitor"
|
||||||
|
android:icon="@android:drawable/ic_menu_view"
|
||||||
|
android:title="WiFi Monitor" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_arp"
|
||||||
|
android:icon="@android:drawable/ic_menu_mapmode"
|
||||||
|
android:title="ARP Scanner" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_firewall"
|
||||||
|
android:icon="@android:drawable/ic_lock_lock"
|
||||||
|
android:title="Firewall Rules" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_processes"
|
||||||
|
android:icon="@android:drawable/ic_menu_manage"
|
||||||
|
android:title="Process Inspector" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_files"
|
||||||
|
android:icon="@android:drawable/ic_menu_agenda"
|
||||||
|
android:title="File Browser" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_logcat"
|
||||||
|
android:icon="@android:drawable/ic_menu_sort_alphabetically"
|
||||||
|
android:title="Logcat Viewer" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_tool_keystore"
|
||||||
|
android:icon="@android:drawable/ic_menu_close_clear_cancel"
|
||||||
|
android:title="Keystore Dump" />
|
||||||
|
</group>
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item android:title="@string/drawer_header_setup">
|
||||||
|
<menu>
|
||||||
|
<group android:id="@+id/group_setup"
|
||||||
|
android:checkableBehavior="single">
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_setup"
|
||||||
|
android:icon="@drawable/ic_setup"
|
||||||
|
android:title="@string/nav_device_setup" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_links"
|
||||||
|
android:icon="@android:drawable/ic_menu_share"
|
||||||
|
android:title="@string/nav_links" />
|
||||||
|
</group>
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item android:title="@string/drawer_header_settings">
|
||||||
|
<menu>
|
||||||
|
<group android:id="@+id/group_settings"
|
||||||
|
android:checkableBehavior="single">
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_settings_connection"
|
||||||
|
android:icon="@android:drawable/ic_menu_preferences"
|
||||||
|
android:title="@string/nav_settings_connection" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_settings_privileges"
|
||||||
|
android:icon="@android:drawable/ic_lock_lock"
|
||||||
|
android:title="@string/nav_settings_privileges" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_settings_appearance"
|
||||||
|
android:icon="@android:drawable/ic_menu_view"
|
||||||
|
android:title="@string/nav_settings_appearance" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_about"
|
||||||
|
android:icon="@android:drawable/ic_menu_info_details"
|
||||||
|
android:title="@string/nav_about" />
|
||||||
|
</group>
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</menu>
|
||||||
@@ -1,38 +1,131 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
<navigation
|
<navigation
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/nav_graph"
|
android:id="@+id/nav_graph"
|
||||||
app:startDestination="@id/nav_dashboard">
|
app:startDestination="@id/nav_dashboard">
|
||||||
|
|
||||||
|
<!-- MAIN -->
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_dashboard"
|
android:id="@+id/nav_dashboard"
|
||||||
android:name="com.darkhal.archon.ui.DashboardFragment"
|
android:name="com.darkhal.archon.ui.DashboardFragment"
|
||||||
android:label="@string/nav_dashboard" />
|
android:label="@string/nav_dashboard" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_messaging"
|
android:id="@+id/nav_adb_shell"
|
||||||
android:name="com.darkhal.archon.ui.MessagingFragment"
|
android:name="com.darkhal.archon.ui.AdbShellFragment"
|
||||||
android:label="@string/nav_messaging" />
|
android:label="@string/nav_adb_shell" />
|
||||||
|
|
||||||
<fragment
|
|
||||||
android:id="@+id/nav_links"
|
|
||||||
android:name="com.darkhal.archon.ui.LinksFragment"
|
|
||||||
android:label="@string/nav_links" />
|
|
||||||
|
|
||||||
|
<!-- TOOLS -->
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_modules"
|
android:id="@+id/nav_modules"
|
||||||
android:name="com.darkhal.archon.ui.ModulesFragment"
|
android:name="com.darkhal.archon.ui.ModulesFragment"
|
||||||
android:label="@string/nav_modules" />
|
android:label="@string/nav_modules" />
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_messaging"
|
||||||
|
android:name="com.darkhal.archon.ui.MessagingFragment"
|
||||||
|
android:label="@string/nav_messaging" />
|
||||||
|
|
||||||
|
<!-- NON-ROOTED TOOLS -->
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_netscan"
|
||||||
|
android:name="com.darkhal.archon.ui.tools.NetworkScannerFragment"
|
||||||
|
android:label="Network Scanner" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_portscan"
|
||||||
|
android:name="com.darkhal.archon.ui.tools.PortScannerFragment"
|
||||||
|
android:label="Port Scanner" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_wifi"
|
||||||
|
android:name="com.darkhal.archon.ui.tools.WifiAnalyzerFragment"
|
||||||
|
android:label="WiFi Analyzer" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_dns"
|
||||||
|
android:name="com.darkhal.archon.ui.tools.DnsLookupFragment"
|
||||||
|
android:label="DNS Lookup" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_whois"
|
||||||
|
android:name="com.darkhal.archon.ui.tools.WhoisFragment"
|
||||||
|
android:label="Whois" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_ssl"
|
||||||
|
android:name="com.darkhal.archon.ui.tools.SslCheckFragment"
|
||||||
|
android:label="SSL/TLS Check" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_headers"
|
||||||
|
android:name="com.darkhal.archon.ui.tools.HttpHeadersFragment"
|
||||||
|
android:label="HTTP Headers" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_devinfo"
|
||||||
|
android:name="com.darkhal.archon.ui.tools.DeviceInfoFragment"
|
||||||
|
android:label="Device Info" />
|
||||||
|
|
||||||
|
<!-- ROOTED TOOLS -->
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_pcap"
|
||||||
|
android:name="com.darkhal.archon.ui.ToolPlaceholderFragment"
|
||||||
|
android:label="Packet Capture" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_monitor"
|
||||||
|
android:name="com.darkhal.archon.ui.ToolPlaceholderFragment"
|
||||||
|
android:label="WiFi Monitor" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_arp"
|
||||||
|
android:name="com.darkhal.archon.ui.ToolPlaceholderFragment"
|
||||||
|
android:label="ARP Scanner" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_firewall"
|
||||||
|
android:name="com.darkhal.archon.ui.ToolPlaceholderFragment"
|
||||||
|
android:label="Firewall Rules" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_processes"
|
||||||
|
android:name="com.darkhal.archon.ui.tools.ProcessInspectorFragment"
|
||||||
|
android:label="Process Inspector" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_files"
|
||||||
|
android:name="com.darkhal.archon.ui.tools.FileBrowserFragment"
|
||||||
|
android:label="File Browser" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_logcat"
|
||||||
|
android:name="com.darkhal.archon.ui.tools.LogcatViewerFragment"
|
||||||
|
android:label="Logcat Viewer" />
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_tool_keystore"
|
||||||
|
android:name="com.darkhal.archon.ui.tools.KeystoreDumpFragment"
|
||||||
|
android:label="Keystore Dump" />
|
||||||
|
|
||||||
|
<!-- SETUP -->
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_setup"
|
android:id="@+id/nav_setup"
|
||||||
android:name="com.darkhal.archon.ui.SetupFragment"
|
android:name="com.darkhal.archon.ui.SetupFragment"
|
||||||
android:label="@string/nav_setup" />
|
android:label="@string/nav_device_setup" />
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_settings"
|
android:id="@+id/nav_links"
|
||||||
android:name="com.darkhal.archon.ui.SettingsFragment"
|
android:name="com.darkhal.archon.ui.LinksFragment"
|
||||||
android:label="@string/nav_settings" />
|
android:label="@string/nav_links" />
|
||||||
|
|
||||||
|
<!-- SETTINGS -->
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_settings_connection"
|
||||||
|
android:name="com.darkhal.archon.ui.ConnectionSettingsFragment"
|
||||||
|
android:label="@string/nav_settings_connection" />
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_settings_privileges"
|
||||||
|
android:name="com.darkhal.archon.ui.PrivilegesSettingsFragment"
|
||||||
|
android:label="@string/nav_settings_privileges" />
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_settings_appearance"
|
||||||
|
android:name="com.darkhal.archon.ui.AppearanceSettingsFragment"
|
||||||
|
android:label="@string/nav_settings_appearance" />
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_about"
|
||||||
|
android:name="com.darkhal.archon.ui.AboutFragment"
|
||||||
|
android:label="@string/nav_about" />
|
||||||
|
|
||||||
</navigation>
|
</navigation>
|
||||||
|
|||||||
@@ -15,4 +15,17 @@
|
|||||||
<color name="warning">#FFFFAA00</color>
|
<color name="warning">#FFFFAA00</color>
|
||||||
<color name="black">#FF000000</color>
|
<color name="black">#FF000000</color>
|
||||||
<color name="nav_item_color">#FF00FF41</color>
|
<color name="nav_item_color">#FF00FF41</color>
|
||||||
|
|
||||||
|
<!-- Logcat level colors -->
|
||||||
|
<color name="logcat_verbose">#FF888888</color>
|
||||||
|
<color name="logcat_debug">#FF5599FF</color>
|
||||||
|
<color name="logcat_info">#FF00CC44</color>
|
||||||
|
<color name="logcat_warn">#FFFFAA00</color>
|
||||||
|
<color name="logcat_error">#FFFF4444</color>
|
||||||
|
<color name="logcat_fatal">#FFFF2222</color>
|
||||||
|
|
||||||
|
<!-- File browser -->
|
||||||
|
<color name="file_directory">#FF00CCFF</color>
|
||||||
|
<color name="file_symlink">#FFCC66FF</color>
|
||||||
|
<color name="file_executable">#FF00FF41</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -2,13 +2,31 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Archon</string>
|
<string name="app_name">Archon</string>
|
||||||
|
|
||||||
<!-- Navigation -->
|
<!-- Navigation - Drawer -->
|
||||||
<string name="nav_dashboard">Dashboard</string>
|
<string name="nav_dashboard">Dashboard</string>
|
||||||
<string name="nav_links">Links</string>
|
<string name="nav_adb_shell">ADB Shell</string>
|
||||||
<string name="nav_modules">Modules</string>
|
<string name="nav_modules">Modules</string>
|
||||||
|
<string name="nav_device_setup">Device Setup</string>
|
||||||
|
<string name="nav_links">Links</string>
|
||||||
|
<string name="nav_settings_connection">Connection</string>
|
||||||
|
<string name="nav_settings_privileges">Privileges</string>
|
||||||
|
<string name="nav_settings_appearance">Appearance</string>
|
||||||
|
<string name="nav_about">About</string>
|
||||||
|
|
||||||
|
<!-- Legacy (kept for bottom_nav.xml compatibility) -->
|
||||||
<string name="nav_setup">Setup</string>
|
<string name="nav_setup">Setup</string>
|
||||||
<string name="nav_settings">Settings</string>
|
<string name="nav_settings">Settings</string>
|
||||||
|
|
||||||
|
<!-- Drawer section headers -->
|
||||||
|
<string name="drawer_header_tools">TOOLS</string>
|
||||||
|
<string name="drawer_header_setup">SETUP</string>
|
||||||
|
<string name="drawer_header_settings">SETTINGS</string>
|
||||||
|
|
||||||
|
<!-- Drawer header -->
|
||||||
|
<string name="drawer_app_name">AUTARCH</string>
|
||||||
|
<string name="drawer_open">Open navigation</string>
|
||||||
|
<string name="drawer_close">Close navigation</string>
|
||||||
|
|
||||||
<!-- Discovery -->
|
<!-- Discovery -->
|
||||||
<string name="server_discovery">Server Discovery</string>
|
<string name="server_discovery">Server Discovery</string>
|
||||||
<string name="discovery_idle">Tap SCAN to find AUTARCH</string>
|
<string name="discovery_idle">Tap SCAN to find AUTARCH</string>
|
||||||
@@ -87,4 +105,32 @@
|
|||||||
<string name="auto_detect">AUTO-DETECT SERVER</string>
|
<string name="auto_detect">AUTO-DETECT SERVER</string>
|
||||||
<string name="test_connection">TEST</string>
|
<string name="test_connection">TEST</string>
|
||||||
<string name="save_settings">SAVE</string>
|
<string name="save_settings">SAVE</string>
|
||||||
|
|
||||||
|
<!-- ADB Shell -->
|
||||||
|
<string name="adb_shell_title">ADB SHELL</string>
|
||||||
|
<string name="adb_shell_hint">Enter command...</string>
|
||||||
|
<string name="adb_shell_run">RUN</string>
|
||||||
|
<string name="adb_shell_clear">CLEAR</string>
|
||||||
|
<string name="adb_shell_welcome">> ADB shell ready. Type a command.\n</string>
|
||||||
|
|
||||||
|
<!-- Privileges -->
|
||||||
|
<string name="privileges_title">PRIVILEGES</string>
|
||||||
|
<string name="privilege_mode_label">Privilege Mode</string>
|
||||||
|
<string name="privilege_root">Root</string>
|
||||||
|
<string name="privilege_shizuku">Shizuku</string>
|
||||||
|
<string name="privilege_adb">ADB</string>
|
||||||
|
<string name="privilege_none">None (standard)</string>
|
||||||
|
<string name="privilege_status_checking">Checking privilege status...</string>
|
||||||
|
|
||||||
|
<!-- Appearance -->
|
||||||
|
<string name="appearance_title">APPEARANCE</string>
|
||||||
|
<string name="appearance_theme_label">Theme</string>
|
||||||
|
<string name="appearance_theme_dark">Terminal Dark</string>
|
||||||
|
<string name="appearance_font_size">Font Size</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_title">ABOUT</string>
|
||||||
|
<string name="about_version_label">Version</string>
|
||||||
|
<string name="about_copyright">Copyright 2026 DarkHal</string>
|
||||||
|
<string name="about_description">AUTARCH Companion\nRemote device management and security toolkit.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 DarkHal -->
|
||||||
<resources>
|
<resources>
|
||||||
<style name="Theme.Archon" parent="Theme.Material3.Dark.NoActionBar">
|
<style name="Theme.Archon" parent="Theme.Material3.Dark.NoActionBar">
|
||||||
<item name="colorPrimary">@color/terminal_green</item>
|
<item name="colorPrimary">@color/terminal_green</item>
|
||||||
@@ -12,5 +13,27 @@
|
|||||||
<item name="android:statusBarColor">@color/background</item>
|
<item name="android:statusBarColor">@color/background</item>
|
||||||
<item name="android:navigationBarColor">@color/surface</item>
|
<item name="android:navigationBarColor">@color/surface</item>
|
||||||
<item name="android:windowBackground">@color/background</item>
|
<item name="android:windowBackground">@color/background</item>
|
||||||
|
<item name="drawerLayoutStyle">@style/Widget.Archon.DrawerLayout</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Toolbar title style -->
|
||||||
|
<style name="ToolbarTitle" parent="TextAppearance.Material3.TitleLarge">
|
||||||
|
<item name="android:fontFamily">monospace</item>
|
||||||
|
<item name="android:textSize">18sp</item>
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
<item name="android:letterSpacing">0.1</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Drawer subheader text style -->
|
||||||
|
<style name="DrawerSubheader" parent="TextAppearance.Material3.LabelSmall">
|
||||||
|
<item name="android:fontFamily">monospace</item>
|
||||||
|
<item name="android:textSize">11sp</item>
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
<item name="android:letterSpacing">0.15</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- DrawerLayout scrim -->
|
||||||
|
<style name="Widget.Archon.DrawerLayout" parent="Widget.Material3.DrawerLayout">
|
||||||
|
<item name="scrimColor">#CC000000</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
256
autarch_companion/gitea_module.md
Normal file
256
autarch_companion/gitea_module.md
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
# Linking Archon as a Git Submodule of AUTARCH
|
||||||
|
|
||||||
|
This guide walks through setting up Archon (the Android companion app) as a git submodule inside the AUTARCH repository, hosted on a self-hosted Gitea instance.
|
||||||
|
|
||||||
|
**Assumed URLs:**
|
||||||
|
- AUTARCH: `https://gitea.example.com/you/autarch`
|
||||||
|
- Archon: `https://gitea.example.com/you/archon`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Initial Setup — Create Both Repos on Gitea
|
||||||
|
|
||||||
|
### Create the repos on Gitea
|
||||||
|
|
||||||
|
Log into your Gitea instance and create two repositories:
|
||||||
|
|
||||||
|
1. Go to `https://gitea.example.com` → **+** → **New Repository**
|
||||||
|
2. Create `autarch` (do not initialize with README if you already have local files)
|
||||||
|
3. Repeat for `archon`
|
||||||
|
|
||||||
|
### Push AUTARCH
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /path/to/autarch
|
||||||
|
git init # if not already a git repo
|
||||||
|
git remote add origin https://gitea.example.com/you/autarch.git
|
||||||
|
git add .
|
||||||
|
git commit -m "Initial commit"
|
||||||
|
git push -u origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
### Push Archon
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /path/to/archon
|
||||||
|
git init
|
||||||
|
git remote add origin https://gitea.example.com/you/archon.git
|
||||||
|
git add .
|
||||||
|
git commit -m "Initial commit"
|
||||||
|
git push -u origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Add Archon as a Submodule
|
||||||
|
|
||||||
|
From the **AUTARCH repository root**, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /path/to/autarch
|
||||||
|
git submodule add https://gitea.example.com/you/archon.git Archon
|
||||||
|
```
|
||||||
|
|
||||||
|
This does three things:
|
||||||
|
- Clones the Archon repo into `autarch/Archon/`
|
||||||
|
- Creates (or updates) `.gitmodules` in the AUTARCH root
|
||||||
|
- Stages both `.gitmodules` and the new `Archon` directory pointer
|
||||||
|
|
||||||
|
If you prefer SSH instead of HTTPS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git submodule add git@gitea.example.com:you/archon.git Archon
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Commit the Submodule Reference
|
||||||
|
|
||||||
|
After adding the submodule, two things are staged:
|
||||||
|
|
||||||
|
- `.gitmodules` — a config file mapping the submodule path to its URL
|
||||||
|
- `Archon` — not the Archon files themselves, but a **pointer** (a specific commit hash) to the Archon repo
|
||||||
|
|
||||||
|
Commit both:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git status
|
||||||
|
# On branch main
|
||||||
|
# Changes to be committed:
|
||||||
|
# new file: .gitmodules
|
||||||
|
# new file: Archon
|
||||||
|
|
||||||
|
git commit -m "Add Archon as git submodule"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
AUTARCH's repo now contains a reference to a specific commit in Archon — not the Archon files directly. This is intentional: submodules are pinned to a commit, not a branch.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. `.gitmodules` Example
|
||||||
|
|
||||||
|
After running `git submodule add`, your `.gitmodules` file will look like this:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[submodule "Archon"]
|
||||||
|
path = Archon
|
||||||
|
url = https://gitea.example.com/you/archon.git
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to track a specific branch (optional, see pitfalls):
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[submodule "Archon"]
|
||||||
|
path = Archon
|
||||||
|
url = https://gitea.example.com/you/archon.git
|
||||||
|
branch = main
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Cloning AUTARCH with Archon
|
||||||
|
|
||||||
|
### Option A — Clone everything at once (recommended)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --recurse-submodules https://gitea.example.com/you/autarch.git
|
||||||
|
```
|
||||||
|
|
||||||
|
This clones AUTARCH and immediately initializes and checks out Archon at the pinned commit.
|
||||||
|
|
||||||
|
### Option B — Clone AUTARCH first, pull Archon later
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://gitea.example.com/you/autarch.git
|
||||||
|
cd autarch
|
||||||
|
git submodule update --init
|
||||||
|
```
|
||||||
|
|
||||||
|
`--init` is needed the first time because the submodule isn't initialized yet. After that, use `git submodule update` without `--init`.
|
||||||
|
|
||||||
|
To also pull nested submodules (if Archon ever gains its own submodules):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git submodule update --init --recursive
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Updating Archon to a Newer Commit
|
||||||
|
|
||||||
|
The submodule is pinned to a specific commit. To move AUTARCH's pointer to a newer Archon commit:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Step into the submodule
|
||||||
|
cd Archon
|
||||||
|
git checkout main
|
||||||
|
git pull origin main
|
||||||
|
|
||||||
|
# Step back out to AUTARCH
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# The submodule pointer has changed — stage and commit it
|
||||||
|
git add Archon
|
||||||
|
git commit -m "Update Archon submodule to latest"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
After this, anyone who runs `git submodule update` in their AUTARCH clone will get the newer Archon commit.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Gitea UI — How Submodules Are Displayed
|
||||||
|
|
||||||
|
When you browse to `https://gitea.example.com/you/autarch` in the Gitea web UI, the `Archon` directory will appear in the file list with a special icon and a label like:
|
||||||
|
|
||||||
|
```
|
||||||
|
Archon @ a3f92c1
|
||||||
|
```
|
||||||
|
|
||||||
|
The `@ a3f92c1` is a clickable link that takes you directly to that commit in the `archon` repository. Gitea resolves the link automatically as long as both repos are on the same Gitea instance and the URL in `.gitmodules` matches.
|
||||||
|
|
||||||
|
If the submodule URL points to an external host (e.g., GitHub), Gitea will still show the `@ hash` label but the link will point to the external URL.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. CI/CD — Checking Out Submodules in Gitea Actions
|
||||||
|
|
||||||
|
If you use Gitea Actions (workflow syntax is identical to GitHub Actions), the default `actions/checkout` step does **not** pull submodules. Add `submodules: true` to fix this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: AUTARCH CI
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout AUTARCH with submodules
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true # fetches Archon at the pinned commit
|
||||||
|
# submodules: recursive # use this if submodules have their own submodules
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: make build
|
||||||
|
```
|
||||||
|
|
||||||
|
For private submodules on the same Gitea instance, you may need to configure an SSH key or access token in the workflow secrets and set the submodule URL to use SSH.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Common Pitfalls
|
||||||
|
|
||||||
|
### Detached HEAD in the submodule
|
||||||
|
|
||||||
|
When you run `git submodule update`, the submodule is checked out at a specific commit — not a branch. This is called a **detached HEAD** state. If you `cd Archon` and make commits while in detached HEAD, those commits are not on any branch and can be lost.
|
||||||
|
|
||||||
|
Fix: before making changes inside the submodule, always check out a branch first:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd Archon
|
||||||
|
git checkout main
|
||||||
|
# now make changes, commit, push
|
||||||
|
```
|
||||||
|
|
||||||
|
### Forgot to commit after updating the submodule
|
||||||
|
|
||||||
|
Running `cd Archon && git pull` updates the Archon files locally but does **not** automatically update AUTARCH's pointer to the new commit. You must come back to the AUTARCH root and commit:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ..
|
||||||
|
git add Archon
|
||||||
|
git commit -m "Update Archon submodule"
|
||||||
|
```
|
||||||
|
|
||||||
|
If you push AUTARCH without doing this, the pointer still points to the old Archon commit and collaborators won't get the update.
|
||||||
|
|
||||||
|
### SSH vs HTTPS
|
||||||
|
|
||||||
|
Choose one scheme and be consistent. If your team uses SSH keys for Gitea authentication, use the SSH URL in `.gitmodules`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
url = git@gitea.example.com:you/archon.git
|
||||||
|
```
|
||||||
|
|
||||||
|
If you use HTTPS with a token, use the HTTPS URL. Mixing them causes authentication failures for people whose environment only has one configured.
|
||||||
|
|
||||||
|
You can override the URL locally (without touching `.gitmodules`) using:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git config submodule.Archon.url git@gitea.example.com:you/archon.git
|
||||||
|
```
|
||||||
|
|
||||||
|
This writes to `.git/config` and is not committed, so it only affects your local clone.
|
||||||
|
|
||||||
|
### Cloning without `--recurse-submodules`
|
||||||
|
|
||||||
|
If someone clones AUTARCH normally and then tries to build, the `Archon/` directory will exist but be **empty**. They need to run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git submodule update --init
|
||||||
|
```
|
||||||
|
|
||||||
|
Document this in your project README so contributors know to expect it.
|
||||||
@@ -2,3 +2,4 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
|||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
android.nonTransitiveRClass=true
|
android.nonTransitiveRClass=true
|
||||||
|
android.aapt2FromMavenOverride=/home/snake/android-sdk/build-tools/36.0.0/aapt2
|
||||||
|
|||||||
0
autarch_companion/gradlew.bat
vendored
Normal file → Executable file
0
autarch_companion/gradlew.bat
vendored
Normal file → Executable file
@@ -1 +1 @@
|
|||||||
sdk.dir=C:/Users/mdavi/AppData/Local/Android/Sdk
|
sdk.dir=/home/snake/android-sdk
|
||||||
|
|||||||
16
autarch_companion_compose/settings.gradle.kts
Normal file
16
autarch_companion_compose/settings.gradle.kts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dependencyResolution {
|
||||||
|
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rootProject.name = "ArchonCompose"
|
||||||
|
include(":app")
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
[llama]
|
[llama]
|
||||||
model_path = C:\she\autarch\models\darkHal.gguf
|
model_path = C:\Track 1\model\sssnake7070\HauhauCS\Qwen3.5-9B-Uncensored-HauhauCS-Aggressive\Qwen3.5-9B-Uncensored-HauhauCS-Aggressive-Q4_K_M.gguf
|
||||||
n_ctx = 2048
|
n_ctx = 2048
|
||||||
n_threads = 4
|
n_threads = 4
|
||||||
n_gpu_layers = -1
|
n_gpu_layers = -1
|
||||||
@@ -29,7 +29,7 @@ no_banner = false
|
|||||||
host = 127.0.0.1
|
host = 127.0.0.1
|
||||||
port = 55553
|
port = 55553
|
||||||
username = msf
|
username = msf
|
||||||
password = msdf
|
password = msf
|
||||||
ssl = true
|
ssl = true
|
||||||
|
|
||||||
[osint]
|
[osint]
|
||||||
@@ -76,7 +76,7 @@ default_port = 80
|
|||||||
execution_timeout = 120
|
execution_timeout = 120
|
||||||
|
|
||||||
[upnp]
|
[upnp]
|
||||||
enabled = true
|
enabled = false
|
||||||
internal_ip = 10.0.0.26
|
internal_ip = 10.0.0.26
|
||||||
refresh_hours = 12
|
refresh_hours = 12
|
||||||
mappings = 443:TCP,51820:UDP,8080:TCP
|
mappings = 443:TCP,51820:UDP,8080:TCP
|
||||||
@@ -108,7 +108,7 @@ bt_require_security = true
|
|||||||
[web]
|
[web]
|
||||||
host = 0.0.0.0
|
host = 0.0.0.0
|
||||||
port = 8181
|
port = 8181
|
||||||
secret_key = 23088243f11ce0b135c64413073c8c9fc0ecf83711d5f892b68f95b348a54007
|
secret_key =
|
||||||
mcp_port = 8081
|
mcp_port = 8081
|
||||||
|
|
||||||
[revshell]
|
[revshell]
|
||||||
@@ -150,18 +150,18 @@ threat_threshold_auto_respond = 40
|
|||||||
log_max_entries = 1000
|
log_max_entries = 1000
|
||||||
|
|
||||||
[agents]
|
[agents]
|
||||||
backend = local
|
backend = claude
|
||||||
local_max_steps = 20
|
local_max_steps = 200
|
||||||
local_verbose = true
|
local_verbose = true
|
||||||
claude_enabled = false
|
claude_enabled = false
|
||||||
claude_model = claude-sonnet-4-6
|
claude_model = claude-sonnet-4-6
|
||||||
claude_max_tokens = 16384
|
claude_max_tokens = 16384
|
||||||
claude_max_steps = 30
|
claude_max_steps = 200
|
||||||
openai_enabled = false
|
openai_enabled = false
|
||||||
openai_model = gpt-4o
|
openai_model = gpt-4o
|
||||||
openai_base_url = https://api.openai.com/v1
|
openai_base_url = https://api.openai.com/v1
|
||||||
openai_max_tokens = 16384
|
openai_max_tokens = 16384
|
||||||
openai_max_steps = 30
|
openai_max_steps = 200
|
||||||
|
|
||||||
[mcp]
|
[mcp]
|
||||||
enabled = false
|
enabled = false
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ PARAMS: {{"question": "your question"}}
|
|||||||
self,
|
self,
|
||||||
llm: LLM = None,
|
llm: LLM = None,
|
||||||
tools: ToolRegistry = None,
|
tools: ToolRegistry = None,
|
||||||
max_steps: int = 20,
|
max_steps: int = 200,
|
||||||
verbose: bool = True
|
verbose: bool = True
|
||||||
):
|
):
|
||||||
"""Initialize the agent.
|
"""Initialize the agent.
|
||||||
|
|||||||
871
core/android_forensics.py
Normal file
871
core/android_forensics.py
Normal file
@@ -0,0 +1,871 @@
|
|||||||
|
"""
|
||||||
|
Autarch Android Forensics — forensic acquisition and IOC scanning for Android devices.
|
||||||
|
by: SsSnake
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
_manager = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_android_forensics_manager():
|
||||||
|
global _manager
|
||||||
|
if _manager is None:
|
||||||
|
_manager = AutarchAndroidManager()
|
||||||
|
return _manager
|
||||||
|
|
||||||
|
|
||||||
|
class AutarchAndroidManager:
|
||||||
|
"""Forensic acquisition and IOC scanning for Android devices."""
|
||||||
|
|
||||||
|
IOC_DATA_DIR = Path(__file__).parent.parent / 'data' / 'ioc'
|
||||||
|
ACQ_DATA_DIR = Path(__file__).parent.parent / 'data' / 'android_forensics'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._ioc_db = None # lazy-loaded
|
||||||
|
|
||||||
|
# ── Helpers ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def _hw(self):
|
||||||
|
from core.hardware import get_hardware_manager
|
||||||
|
return get_hardware_manager()
|
||||||
|
|
||||||
|
def _adb(self, serial, cmd, timeout=60):
|
||||||
|
"""Run an ADB shell command, return stdout string."""
|
||||||
|
result = self._hw().adb_shell_raw(serial, cmd, timeout=timeout)
|
||||||
|
if isinstance(result, dict):
|
||||||
|
return result.get('output', '') or ''
|
||||||
|
return str(result or '')
|
||||||
|
|
||||||
|
def _acq_dir(self, serial, acq_id):
|
||||||
|
d = self.ACQ_DATA_DIR / serial / acq_id
|
||||||
|
d.mkdir(parents=True, exist_ok=True)
|
||||||
|
return d
|
||||||
|
|
||||||
|
def _new_acq_id(self):
|
||||||
|
return datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||||
|
|
||||||
|
# ── IOC Database ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def load_ioc_database(self, force=False):
|
||||||
|
"""Lazy-load and merge all IOC data from data/ioc/. Returns merged dict."""
|
||||||
|
if self._ioc_db is not None and not force:
|
||||||
|
return self._ioc_db
|
||||||
|
|
||||||
|
db = {
|
||||||
|
'packages': {}, # pkg_name -> {name, source, severity}
|
||||||
|
'certs': {}, # sha1/sha256 -> {name, source}
|
||||||
|
'domains': {}, # domain -> {name, source}
|
||||||
|
'ips': set(),
|
||||||
|
'file_paths': {}, # path -> {name, source}
|
||||||
|
'processes': {}, # proc_name -> {name, source}
|
||||||
|
'hashes': {}, # sha256 -> {name, source}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 1. Stalkerware ioc.yaml + watchware.yaml
|
||||||
|
for fname in ('ioc.yaml', 'watchware.yaml'):
|
||||||
|
fpath = self.IOC_DATA_DIR / 'stalkerware' / fname
|
||||||
|
if fpath.exists():
|
||||||
|
self._parse_stalkerware_yaml(fpath, db)
|
||||||
|
|
||||||
|
# 2. Amnesty investigations
|
||||||
|
amnesty_dir = self.IOC_DATA_DIR / 'spyware' / 'amnesty'
|
||||||
|
if amnesty_dir.exists():
|
||||||
|
for campaign_dir in sorted(amnesty_dir.iterdir()):
|
||||||
|
if campaign_dir.is_dir():
|
||||||
|
self._parse_investigation(campaign_dir, db)
|
||||||
|
|
||||||
|
# 3. MVT indicators
|
||||||
|
mvt_dir = self.IOC_DATA_DIR / 'spyware' / 'mvt'
|
||||||
|
if mvt_dir.exists():
|
||||||
|
for campaign_dir in sorted(mvt_dir.iterdir()):
|
||||||
|
if campaign_dir.is_dir():
|
||||||
|
self._parse_investigation(campaign_dir, db)
|
||||||
|
|
||||||
|
# 4. Citizen Lab campaigns
|
||||||
|
cl_dir = self.IOC_DATA_DIR / 'spyware' / 'citizen_lab'
|
||||||
|
if cl_dir.exists():
|
||||||
|
for campaign_dir in sorted(cl_dir.iterdir()):
|
||||||
|
if campaign_dir.is_dir():
|
||||||
|
self._parse_investigation(campaign_dir, db)
|
||||||
|
|
||||||
|
# 5. iMazing indicators (recursive)
|
||||||
|
imazing_dir = self.IOC_DATA_DIR / 'spyware' / 'imazing'
|
||||||
|
if imazing_dir.exists():
|
||||||
|
for item in imazing_dir.rglob('*'):
|
||||||
|
if item.is_dir():
|
||||||
|
self._parse_investigation(item, db)
|
||||||
|
|
||||||
|
# 6. Existing stalkerware_signatures.json
|
||||||
|
sigs_path = Path(__file__).parent.parent / 'data' / 'stalkerware_signatures.json'
|
||||||
|
if sigs_path.exists():
|
||||||
|
self._parse_sigs_json(sigs_path, db)
|
||||||
|
|
||||||
|
# Convert ips set to list for JSON serialisation
|
||||||
|
db['ips'] = list(db['ips'])
|
||||||
|
|
||||||
|
self._ioc_db = db
|
||||||
|
self._save_index(db)
|
||||||
|
return db
|
||||||
|
|
||||||
|
def _parse_stalkerware_yaml(self, path, db):
|
||||||
|
"""Parse stalkerware/watchware ioc.yaml into db."""
|
||||||
|
try:
|
||||||
|
import yaml
|
||||||
|
except ImportError:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
with open(path, encoding='utf-8', errors='ignore') as f:
|
||||||
|
data = yaml.safe_load(f)
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
return
|
||||||
|
for vendor, info in data.items():
|
||||||
|
if not isinstance(info, dict):
|
||||||
|
continue
|
||||||
|
source = f'stalkerware/{path.name}:{vendor}'
|
||||||
|
for pkg in info.get('packages', []) or []:
|
||||||
|
if pkg:
|
||||||
|
db['packages'][pkg] = {'name': vendor, 'source': source, 'severity': 'high'}
|
||||||
|
for cert in info.get('certificates', []) or []:
|
||||||
|
if cert:
|
||||||
|
db['certs'][cert.lower()] = {'name': vendor, 'source': source}
|
||||||
|
for domain in (info.get('domains', []) or []) + (info.get('c2', []) or []) + (info.get('website', []) or []):
|
||||||
|
if domain:
|
||||||
|
db['domains'][domain.lower()] = {'name': vendor, 'source': source}
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _parse_investigation(self, campaign_dir, db):
|
||||||
|
"""Parse a campaign directory for IOC text files and STIX2."""
|
||||||
|
name = campaign_dir.name
|
||||||
|
source = f'spyware/{campaign_dir.parent.name}/{name}'
|
||||||
|
|
||||||
|
for f in campaign_dir.iterdir():
|
||||||
|
if not f.is_file():
|
||||||
|
continue
|
||||||
|
fname = f.name.lower()
|
||||||
|
|
||||||
|
if fname in ('domains.txt', 'domains'):
|
||||||
|
self._load_txt_lines(f, db['domains'], name, source)
|
||||||
|
elif fname in ('package_names.txt', 'package_names'):
|
||||||
|
self._load_txt_lines(f, db['packages'], name, source, extra={'severity': 'critical'})
|
||||||
|
elif fname in ('processes.txt', 'processes'):
|
||||||
|
self._load_txt_lines(f, db['processes'], name, source)
|
||||||
|
elif fname in ('file_paths.txt', 'file_paths'):
|
||||||
|
self._load_txt_lines(f, db['file_paths'], name, source)
|
||||||
|
elif fname in ('ips.txt', 'ip_addresses.txt', 'ip-addresses.txt'):
|
||||||
|
self._load_txt_set(f, db['ips'])
|
||||||
|
elif fname.endswith('.stix2') or fname.endswith('_stix.json'):
|
||||||
|
self._parse_stix(f, db, name, source)
|
||||||
|
elif fname in ('sha256.txt', 'sha256.csv'):
|
||||||
|
self._load_hashes(f, db['hashes'], name, source)
|
||||||
|
elif fname == 'package_cert_hashes.txt':
|
||||||
|
self._load_txt_lines(f, db['certs'], name, source)
|
||||||
|
elif fname.endswith('.json') and 'ioc' in fname:
|
||||||
|
self._parse_ioc_json(f, db, name, source)
|
||||||
|
elif fname.endswith('.csv') and 'ioc' in fname:
|
||||||
|
self._parse_ioc_csv(f, db, name, source)
|
||||||
|
|
||||||
|
def _load_txt_lines(self, path, target_dict, name, source, extra=None):
|
||||||
|
"""Load one-indicator-per-line text file into a dict."""
|
||||||
|
try:
|
||||||
|
with open(path, encoding='utf-8', errors='ignore') as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip().lower()
|
||||||
|
if line and not line.startswith('#'):
|
||||||
|
entry = {'name': name, 'source': source}
|
||||||
|
if extra:
|
||||||
|
entry.update(extra)
|
||||||
|
target_dict[line] = entry
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _load_txt_set(self, path, target_set):
|
||||||
|
try:
|
||||||
|
with open(path, encoding='utf-8', errors='ignore') as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
if line and not line.startswith('#'):
|
||||||
|
target_set.add(line)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _load_hashes(self, path, target_dict, name, source):
|
||||||
|
try:
|
||||||
|
with open(path, encoding='utf-8', errors='ignore') as f:
|
||||||
|
for line in f:
|
||||||
|
parts = line.strip().split(',')
|
||||||
|
h = parts[0].strip().lower()
|
||||||
|
if h and len(h) in (32, 40, 64):
|
||||||
|
target_dict[h] = {'name': name, 'source': source}
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _parse_stix(self, path, db, name, source):
|
||||||
|
"""Parse a STIX2 JSON file for indicators."""
|
||||||
|
try:
|
||||||
|
with open(path, encoding='utf-8', errors='ignore') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
objects = data.get('objects', []) if isinstance(data, dict) else []
|
||||||
|
for obj in objects:
|
||||||
|
if obj.get('type') != 'indicator':
|
||||||
|
continue
|
||||||
|
pattern = obj.get('pattern', '')
|
||||||
|
for m in re.findall(r"domain-name:value\s*=\s*'([^']+)'", pattern):
|
||||||
|
db['domains'][m.lower()] = {'name': name, 'source': source}
|
||||||
|
for m in re.findall(r"file:hashes\.'[^']+'\s*=\s*'([a-fA-F0-9]+)'", pattern):
|
||||||
|
db['hashes'][m.lower()] = {'name': name, 'source': source}
|
||||||
|
for m in re.findall(r"process:name\s*=\s*'([^']+)'", pattern):
|
||||||
|
db['processes'][m.lower()] = {'name': name, 'source': source}
|
||||||
|
for m in re.findall(r"(?:file:name|directory:path)\s*=\s*'([^']+)'", pattern):
|
||||||
|
db['file_paths'][m] = {'name': name, 'source': source}
|
||||||
|
for m in re.findall(r"ipv[46]-addr:value\s*=\s*'([^']+)'", pattern):
|
||||||
|
db['ips'].add(m)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _parse_ioc_json(self, path, db, name, source):
|
||||||
|
try:
|
||||||
|
with open(path, encoding='utf-8', errors='ignore') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
items = data.get('items', data.get('iocs', [])) if isinstance(data, dict) else data
|
||||||
|
if not isinstance(items, list):
|
||||||
|
return
|
||||||
|
for item in items:
|
||||||
|
if not isinstance(item, dict):
|
||||||
|
continue
|
||||||
|
itype = item.get('type', '').lower()
|
||||||
|
val = str(item.get('value', item.get('indicator', ''))).strip().lower()
|
||||||
|
if not val:
|
||||||
|
continue
|
||||||
|
if 'domain' in itype:
|
||||||
|
db['domains'][val] = {'name': name, 'source': source}
|
||||||
|
elif 'ip' in itype:
|
||||||
|
db['ips'].add(val)
|
||||||
|
elif 'hash' in itype or 'sha' in itype or 'md5' in itype:
|
||||||
|
db['hashes'][val] = {'name': name, 'source': source}
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _parse_ioc_csv(self, path, db, name, source):
|
||||||
|
try:
|
||||||
|
import csv
|
||||||
|
with open(path, encoding='utf-8', errors='ignore', newline='') as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
for row in reader:
|
||||||
|
val = (row.get('value') or row.get('indicator') or row.get('domain') or '').strip().lower()
|
||||||
|
itype = (row.get('type') or row.get('indicator_type') or '').lower()
|
||||||
|
if not val:
|
||||||
|
continue
|
||||||
|
if 'domain' in itype:
|
||||||
|
db['domains'][val] = {'name': name, 'source': source}
|
||||||
|
elif 'hash' in itype or 'sha256' in itype:
|
||||||
|
db['hashes'][val] = {'name': name, 'source': source}
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _parse_sigs_json(self, path, db):
|
||||||
|
"""Merge existing stalkerware_signatures.json into db."""
|
||||||
|
try:
|
||||||
|
with open(path, encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
for vendor, info in data.get('stalkerware', {}).items():
|
||||||
|
source = f'stalkerware_signatures.json:{vendor}'
|
||||||
|
sev = info.get('severity', 'high')
|
||||||
|
for pkg in info.get('packages', []):
|
||||||
|
if pkg and pkg not in db['packages']:
|
||||||
|
db['packages'][pkg] = {'name': vendor, 'source': source, 'severity': sev}
|
||||||
|
for spyware in data.get('government_spyware', []):
|
||||||
|
name = spyware.get('name', 'unknown')
|
||||||
|
source = f'stalkerware_signatures.json:{name}'
|
||||||
|
for ind in spyware.get('indicators', []):
|
||||||
|
itype = ind.get('type', '')
|
||||||
|
val = ind.get('value', '')
|
||||||
|
if not val:
|
||||||
|
continue
|
||||||
|
if itype == 'process':
|
||||||
|
db['processes'][val.lower()] = {'name': name, 'source': source}
|
||||||
|
elif itype == 'domain':
|
||||||
|
db['domains'][val.lower()] = {'name': name, 'source': source, 'severity': 'critical'}
|
||||||
|
elif itype == 'file_path':
|
||||||
|
db['file_paths'][val] = {'name': name, 'source': source}
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _save_index(self, db):
|
||||||
|
try:
|
||||||
|
def _count_dirs(d):
|
||||||
|
return sum(1 for p in d.iterdir() if p.is_dir()) if d.exists() else 0
|
||||||
|
|
||||||
|
ips = db.get('ips', [])
|
||||||
|
index = {
|
||||||
|
'generated': datetime.now().isoformat(),
|
||||||
|
'counts': {
|
||||||
|
'packages': len(db.get('packages', {})),
|
||||||
|
'certs': len(db.get('certs', {})),
|
||||||
|
'domains': len(db.get('domains', {})),
|
||||||
|
'ips': len(ips) if not isinstance(ips, set) else len(ips),
|
||||||
|
'file_paths': len(db.get('file_paths', {})),
|
||||||
|
'processes': len(db.get('processes', {})),
|
||||||
|
'hashes': len(db.get('hashes', {})),
|
||||||
|
},
|
||||||
|
'sources': {
|
||||||
|
'stalkerware_ioc_yaml': (self.IOC_DATA_DIR / 'stalkerware' / 'ioc.yaml').exists(),
|
||||||
|
'amnesty_investigations': _count_dirs(self.IOC_DATA_DIR / 'spyware' / 'amnesty'),
|
||||||
|
'mvt_campaigns': _count_dirs(self.IOC_DATA_DIR / 'spyware' / 'mvt'),
|
||||||
|
'citizen_lab_campaigns': _count_dirs(self.IOC_DATA_DIR / 'spyware' / 'citizen_lab'),
|
||||||
|
'yara_rules': sum(1 for _ in (self.IOC_DATA_DIR / 'yara').rglob('*.yar*'))
|
||||||
|
if (self.IOC_DATA_DIR / 'yara').exists() else 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.IOC_DATA_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(self.IOC_DATA_DIR / 'index.json', 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(index, f, indent=2)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_ioc_stats(self):
|
||||||
|
"""Return IOC database statistics (from index.json if available)."""
|
||||||
|
idx_path = self.IOC_DATA_DIR / 'index.json'
|
||||||
|
if idx_path.exists():
|
||||||
|
try:
|
||||||
|
with open(idx_path, encoding='utf-8') as f:
|
||||||
|
return json.load(f)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
db = self.load_ioc_database()
|
||||||
|
return {'counts': {k: len(v) for k, v in db.items() if isinstance(v, (dict, list))}}
|
||||||
|
|
||||||
|
def reload_ioc_database(self):
|
||||||
|
"""Force reload all IOC data from disk."""
|
||||||
|
self._ioc_db = None
|
||||||
|
return self.load_ioc_database(force=True)
|
||||||
|
|
||||||
|
# ── Acquisition Methods ─────────────────────────────────────────
|
||||||
|
|
||||||
|
def acquire_packages(self, serial):
|
||||||
|
"""Get list of installed packages with paths and system/user classification."""
|
||||||
|
try:
|
||||||
|
all_out = self._adb(serial, 'pm list packages -f', timeout=30)
|
||||||
|
sys_out = self._adb(serial, 'pm list packages -s', timeout=30)
|
||||||
|
|
||||||
|
# Build system package set from -s output (format: "package:com.pkg.name")
|
||||||
|
sys_pkgs = set()
|
||||||
|
for line in sys_out.splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith('package:'):
|
||||||
|
sys_pkgs.add(line[8:].strip())
|
||||||
|
|
||||||
|
# Parse -f output (format: "package:/path/to/base.apk=com.pkg.name")
|
||||||
|
packages = []
|
||||||
|
for line in all_out.splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if not line.startswith('package:'):
|
||||||
|
continue
|
||||||
|
line = line[8:] # strip "package:"
|
||||||
|
# Split on last '=' to handle paths that may contain '='
|
||||||
|
eq_pos = line.rfind('=')
|
||||||
|
if eq_pos == -1:
|
||||||
|
pkg_name = line
|
||||||
|
apk_path = ''
|
||||||
|
else:
|
||||||
|
apk_path = line[:eq_pos]
|
||||||
|
pkg_name = line[eq_pos + 1:]
|
||||||
|
pkg_name = pkg_name.strip()
|
||||||
|
if pkg_name:
|
||||||
|
packages.append({
|
||||||
|
'package': pkg_name,
|
||||||
|
'path': apk_path.strip(),
|
||||||
|
'system': pkg_name in sys_pkgs,
|
||||||
|
})
|
||||||
|
return {'ok': True, 'packages': packages, 'total': len(packages)}
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'packages': []}
|
||||||
|
|
||||||
|
def acquire_processes(self, serial):
|
||||||
|
"""Get list of running processes."""
|
||||||
|
try:
|
||||||
|
out = self._adb(serial, 'ps -A', timeout=30)
|
||||||
|
lines = [l for l in out.splitlines() if l.strip()]
|
||||||
|
return {'ok': True, 'output': out, 'count': max(0, len(lines) - 1)}
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'output': ''}
|
||||||
|
|
||||||
|
def acquire_getprop(self, serial):
|
||||||
|
"""Get all system properties via getprop."""
|
||||||
|
try:
|
||||||
|
out = self._adb(serial, 'getprop', timeout=30)
|
||||||
|
props = {}
|
||||||
|
for line in out.splitlines():
|
||||||
|
m = re.match(r'\[(.+)\]:\s*\[(.*)\]\s*$', line)
|
||||||
|
if m:
|
||||||
|
props[m.group(1)] = m.group(2)
|
||||||
|
return {'ok': True, 'props': props, 'output': out}
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'props': {}}
|
||||||
|
|
||||||
|
def acquire_settings(self, serial):
|
||||||
|
"""Get global, secure, and system settings."""
|
||||||
|
try:
|
||||||
|
result = {}
|
||||||
|
for ns in ('global', 'secure', 'system'):
|
||||||
|
out = self._adb(serial, f'settings list {ns}', timeout=30)
|
||||||
|
settings = {}
|
||||||
|
for line in out.splitlines():
|
||||||
|
if '=' in line:
|
||||||
|
k, _, v = line.partition('=')
|
||||||
|
settings[k.strip()] = v.strip()
|
||||||
|
result[ns] = settings
|
||||||
|
return {'ok': True, 'settings': result}
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'settings': {}}
|
||||||
|
|
||||||
|
def acquire_services(self, serial):
|
||||||
|
"""List all running Android services."""
|
||||||
|
try:
|
||||||
|
out = self._adb(serial, 'service list', timeout=30)
|
||||||
|
return {'ok': True, 'output': out, 'count': len(out.splitlines())}
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'output': ''}
|
||||||
|
|
||||||
|
def acquire_dumpsys(self, serial):
|
||||||
|
"""Full dumpsys output (may be large)."""
|
||||||
|
try:
|
||||||
|
out = self._adb(serial, 'dumpsys', timeout=180)
|
||||||
|
return {'ok': True, 'output': out, 'size': len(out)}
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'output': ''}
|
||||||
|
|
||||||
|
def acquire_logcat(self, serial):
|
||||||
|
"""Recent logcat entries (last 1000 lines)."""
|
||||||
|
try:
|
||||||
|
out = self._adb(serial, 'logcat -d -t 1000', timeout=60)
|
||||||
|
return {'ok': True, 'output': out, 'lines': len(out.splitlines())}
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'output': ''}
|
||||||
|
|
||||||
|
def acquire_tmp_files(self, serial):
|
||||||
|
"""List files in /data/local/tmp/."""
|
||||||
|
try:
|
||||||
|
out = self._adb(serial, 'ls -la /data/local/tmp/ 2>/dev/null', timeout=15)
|
||||||
|
return {'ok': True, 'output': out, 'lines': len(out.splitlines())}
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'output': ''}
|
||||||
|
|
||||||
|
def acquire_files(self, serial, max_depth=5):
|
||||||
|
"""Recursive file listing from common paths."""
|
||||||
|
try:
|
||||||
|
paths = ['/data/local/tmp', '/sdcard/Android/data', '/data/data',
|
||||||
|
'/system/app', '/data/app']
|
||||||
|
results = []
|
||||||
|
for base in paths:
|
||||||
|
out = self._adb(
|
||||||
|
serial,
|
||||||
|
f'find {base} -maxdepth {max_depth} -type f 2>/dev/null | head -500',
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
for line in out.splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if line:
|
||||||
|
results.append({'path': line})
|
||||||
|
return {'ok': True, 'files': results, 'total': len(results)}
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'files': []}
|
||||||
|
|
||||||
|
def acquire_logs(self, serial):
|
||||||
|
"""Full logcat with thread-time format (last 2000 lines)."""
|
||||||
|
try:
|
||||||
|
out = self._adb(serial, 'logcat -d -v threadtime -t 2000', timeout=90)
|
||||||
|
return {'ok': True, 'output': out, 'lines': len(out.splitlines())}
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'output': ''}
|
||||||
|
|
||||||
|
def acquire_bugreport_info(self, serial):
|
||||||
|
"""Collect bugreport header info (device state, battery, memory) without full zip."""
|
||||||
|
try:
|
||||||
|
sections = {}
|
||||||
|
for name, cmd in [
|
||||||
|
('memory', 'cat /proc/meminfo'),
|
||||||
|
('cpuinfo', 'cat /proc/cpuinfo | head -40'),
|
||||||
|
('uptime', 'cat /proc/uptime'),
|
||||||
|
('mounts', 'cat /proc/mounts'),
|
||||||
|
]:
|
||||||
|
sections[name] = self._adb(serial, cmd, timeout=15)
|
||||||
|
return {'ok': True, 'sections': sections}
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'sections': {}}
|
||||||
|
|
||||||
|
# ── IOC Scanning ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def scan_packages(self, serial, packages_data=None):
|
||||||
|
"""Match installed packages against IOC package names."""
|
||||||
|
db = self.load_ioc_database()
|
||||||
|
if packages_data is None:
|
||||||
|
result = self.acquire_packages(serial)
|
||||||
|
if not result.get('ok'):
|
||||||
|
return {'ok': False, 'error': result.get('error'), 'findings': []}
|
||||||
|
packages_data = result['packages']
|
||||||
|
|
||||||
|
findings = []
|
||||||
|
for pkg_info in packages_data:
|
||||||
|
pkg = pkg_info.get('package', '').strip()
|
||||||
|
if pkg and pkg in db['packages']:
|
||||||
|
match = db['packages'][pkg]
|
||||||
|
findings.append({
|
||||||
|
'package': pkg,
|
||||||
|
'path': pkg_info.get('path', ''),
|
||||||
|
'system': pkg_info.get('system', False),
|
||||||
|
'threat_name': match['name'],
|
||||||
|
'source': match['source'],
|
||||||
|
'severity': match.get('severity', 'high'),
|
||||||
|
'type': 'package_match',
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
'ok': True,
|
||||||
|
'total_scanned': len(packages_data),
|
||||||
|
'findings': findings,
|
||||||
|
'clean': len(findings) == 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
def scan_certificates(self, serial):
|
||||||
|
"""Check APK signing cert hashes against known-bad certs in IOC database."""
|
||||||
|
db = self.load_ioc_database()
|
||||||
|
findings = []
|
||||||
|
if not db.get('certs'):
|
||||||
|
return {'ok': True, 'findings': [], 'note': 'No cert IOCs loaded'}
|
||||||
|
try:
|
||||||
|
pkg_result = self.acquire_packages(serial)
|
||||||
|
# Only check user-installed (non-system) packages; limit to 100 for speed
|
||||||
|
packages = [p for p in pkg_result.get('packages', []) if not p.get('system')][:100]
|
||||||
|
for pkg_info in packages:
|
||||||
|
pkg = pkg_info.get('package', '')
|
||||||
|
if not pkg:
|
||||||
|
continue
|
||||||
|
out = self._adb(serial, f'pm dump {pkg} 2>/dev/null | grep -A2 "Signing"', timeout=15)
|
||||||
|
for line in out.splitlines():
|
||||||
|
m = re.search(r'([a-fA-F0-9]{40,64})', line)
|
||||||
|
if m:
|
||||||
|
cert_hash = m.group(1).lower()
|
||||||
|
if cert_hash in db['certs']:
|
||||||
|
match = db['certs'][cert_hash]
|
||||||
|
findings.append({
|
||||||
|
'package': pkg,
|
||||||
|
'cert_hash': cert_hash,
|
||||||
|
'threat_name': match['name'],
|
||||||
|
'source': match['source'],
|
||||||
|
'severity': 'critical',
|
||||||
|
'type': 'cert_match',
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'findings': findings}
|
||||||
|
return {'ok': True, 'findings': findings, 'clean': len(findings) == 0}
|
||||||
|
|
||||||
|
def scan_network_indicators(self, serial):
|
||||||
|
"""Check DNS/proxy settings and active TCP connections against IOC domains/IPs."""
|
||||||
|
db = self.load_ioc_database()
|
||||||
|
findings = []
|
||||||
|
try:
|
||||||
|
props = self.acquire_getprop(serial).get('props', {})
|
||||||
|
for key, val in props.items():
|
||||||
|
if 'dns' in key.lower() and val and val.lower() in db['domains']:
|
||||||
|
match = db['domains'][val.lower()]
|
||||||
|
findings.append({
|
||||||
|
'type': 'dns_property', 'key': key, 'value': val,
|
||||||
|
'threat_name': match['name'], 'source': match['source'], 'severity': 'high',
|
||||||
|
})
|
||||||
|
|
||||||
|
ioc_ips = set(db.get('ips', []))
|
||||||
|
if ioc_ips:
|
||||||
|
tcp_out = self._adb(serial, 'cat /proc/net/tcp 2>/dev/null', timeout=15)
|
||||||
|
for line in tcp_out.splitlines()[1:]:
|
||||||
|
parts = line.strip().split()
|
||||||
|
if len(parts) < 3:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
remote_hex = parts[2]
|
||||||
|
ip_hex, port_hex = remote_hex.split(':')
|
||||||
|
# /proc/net/tcp stores IPs in little-endian hex
|
||||||
|
ip = '.'.join(str(int(ip_hex[i:i+2], 16)) for i in (6, 4, 2, 0))
|
||||||
|
port = int(port_hex, 16)
|
||||||
|
if ip not in ('0.0.0.0', '127.0.0.1') and ip in ioc_ips:
|
||||||
|
findings.append({
|
||||||
|
'type': 'tcp_connection', 'remote_ip': ip, 'remote_port': port,
|
||||||
|
'severity': 'critical', 'source': 'network_scan',
|
||||||
|
'threat_name': 'Known malicious IP',
|
||||||
|
})
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'findings': findings}
|
||||||
|
return {'ok': True, 'findings': findings, 'clean': len(findings) == 0}
|
||||||
|
|
||||||
|
def scan_file_indicators(self, serial):
|
||||||
|
"""Check device for known spyware artifact file paths."""
|
||||||
|
db = self.load_ioc_database()
|
||||||
|
if not db.get('file_paths'):
|
||||||
|
return {'ok': True, 'findings': [], 'note': 'No file path IOCs loaded'}
|
||||||
|
findings = []
|
||||||
|
try:
|
||||||
|
for fpath, match in list(db['file_paths'].items())[:200]:
|
||||||
|
out = self._adb(serial, f'ls "{fpath}" 2>/dev/null', timeout=5)
|
||||||
|
if out.strip() and 'No such file' not in out:
|
||||||
|
findings.append({
|
||||||
|
'type': 'file_path',
|
||||||
|
'path': fpath,
|
||||||
|
'threat_name': match['name'],
|
||||||
|
'source': match['source'],
|
||||||
|
'severity': 'critical',
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'findings': findings}
|
||||||
|
return {'ok': True, 'findings': findings, 'clean': len(findings) == 0}
|
||||||
|
|
||||||
|
def scan_process_indicators(self, serial):
|
||||||
|
"""Cross-reference running processes against known spyware process names."""
|
||||||
|
db = self.load_ioc_database()
|
||||||
|
if not db.get('processes'):
|
||||||
|
return {'ok': True, 'findings': [], 'note': 'No process IOCs loaded'}
|
||||||
|
findings = []
|
||||||
|
try:
|
||||||
|
proc_output = self.acquire_processes(serial).get('output', '').lower()
|
||||||
|
for proc_name, match in db['processes'].items():
|
||||||
|
if proc_name and proc_name in proc_output:
|
||||||
|
findings.append({
|
||||||
|
'type': 'process_match',
|
||||||
|
'process': proc_name,
|
||||||
|
'threat_name': match['name'],
|
||||||
|
'source': match['source'],
|
||||||
|
'severity': 'critical',
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e), 'findings': findings}
|
||||||
|
return {'ok': True, 'findings': findings, 'clean': len(findings) == 0}
|
||||||
|
|
||||||
|
# ── SLM Heuristic Scanner ────────────────────────────────────────
|
||||||
|
|
||||||
|
def _heuristic_scan(self, data_type, items, threshold=0.65):
|
||||||
|
"""Run SLM heuristic pass on a list of items via the local LLM.
|
||||||
|
data_type: 'packages' | 'processes' | 'network' | 'files'
|
||||||
|
Returns list of {item, score, reason, category} for items scoring >= threshold."""
|
||||||
|
if not items:
|
||||||
|
return []
|
||||||
|
try:
|
||||||
|
from core.llm import get_llm, LLMError
|
||||||
|
llm = get_llm()
|
||||||
|
if not llm or not llm.is_loaded:
|
||||||
|
return []
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
|
||||||
|
prompts = {
|
||||||
|
'packages': (
|
||||||
|
'Classify each Android package name for stalkerware/spyware/adware risk. '
|
||||||
|
'Score 0.0-1.0. High risk: names impersonating system apps, random strings, '
|
||||||
|
'unknown publishers with device-admin-sounding names. '
|
||||||
|
'Return only a JSON array: [{"item":"...","score":0.0,"reason":"...","category":"stalkerware|adware|suspicious|clean"}]'
|
||||||
|
),
|
||||||
|
'processes': (
|
||||||
|
'Classify each Android process name for malware risk. Score 0.0-1.0. '
|
||||||
|
'Suspicious: random hex strings, names mimicking system processes with slight misspellings. '
|
||||||
|
'Return only a JSON array: [{"item":"...","score":0.0,"reason":"...","category":"malware|suspicious|clean"}]'
|
||||||
|
),
|
||||||
|
'network': (
|
||||||
|
'Classify each domain or IP for C2/malware beacon risk. Score 0.0-1.0. '
|
||||||
|
'High risk: DGA-looking names, dynamic DNS (duckdns, no-ip, ddns), unusual TLDs, high-entropy subdomains. '
|
||||||
|
'Return only a JSON array: [{"item":"...","score":0.0,"reason":"...","category":"c2_beacon|dga_domain|suspicious|clean"}]'
|
||||||
|
),
|
||||||
|
'files': (
|
||||||
|
'Classify each Android file path for spyware/stalkerware artifact risk. Score 0.0-1.0. '
|
||||||
|
'High risk: hidden directories, paths in /data/local/tmp, surveillance-sounding names. '
|
||||||
|
'Return only a JSON array: [{"item":"...","score":0.0,"reason":"...","category":"spyware|suspicious|clean"}]'
|
||||||
|
),
|
||||||
|
}
|
||||||
|
base_prompt = prompts.get(data_type, prompts['packages'])
|
||||||
|
|
||||||
|
findings = []
|
||||||
|
# Process in chunks of 50 (on-device SLM token budget)
|
||||||
|
for i in range(0, len(items), 50):
|
||||||
|
chunk = items[i:i + 50]
|
||||||
|
prompt = f'{base_prompt}\n\nItems:\n' + '\n'.join(str(x) for x in chunk)
|
||||||
|
try:
|
||||||
|
raw = get_llm().generate(prompt, max_tokens=800)
|
||||||
|
# Extract JSON array from response
|
||||||
|
m = re.search(r'\[.*\]', raw, re.DOTALL)
|
||||||
|
if not m:
|
||||||
|
continue
|
||||||
|
parsed = json.loads(m.group(0))
|
||||||
|
for entry in parsed:
|
||||||
|
if isinstance(entry, dict) and float(entry.get('score', 0)) >= threshold:
|
||||||
|
findings.append({
|
||||||
|
'item': str(entry.get('item', '')),
|
||||||
|
'score': float(entry.get('score', 0)),
|
||||||
|
'reason': str(entry.get('reason', '')),
|
||||||
|
'category': str(entry.get('category', 'suspicious')),
|
||||||
|
'confidence': float(entry.get('score', 0)),
|
||||||
|
'heuristic': True,
|
||||||
|
'data_type': data_type,
|
||||||
|
})
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
return findings
|
||||||
|
|
||||||
|
# ── Composite Operations ─────────────────────────────────────────
|
||||||
|
|
||||||
|
def full_acquisition(self, serial):
|
||||||
|
"""Run all acquisition modules and all IOC scans. Save results to disk."""
|
||||||
|
acq_id = self._new_acq_id()
|
||||||
|
acq_dir = self._acq_dir(serial, acq_id)
|
||||||
|
|
||||||
|
report = {
|
||||||
|
'acq_id': acq_id,
|
||||||
|
'serial': serial,
|
||||||
|
'timestamp': datetime.now().isoformat(),
|
||||||
|
'modules': {},
|
||||||
|
'ioc_findings': [],
|
||||||
|
}
|
||||||
|
|
||||||
|
module_map = {
|
||||||
|
'packages': self.acquire_packages,
|
||||||
|
'processes': self.acquire_processes,
|
||||||
|
'getprop': self.acquire_getprop,
|
||||||
|
'settings': self.acquire_settings,
|
||||||
|
'services': self.acquire_services,
|
||||||
|
'logcat': self.acquire_logcat,
|
||||||
|
'tmp_files': self.acquire_tmp_files,
|
||||||
|
'files': self.acquire_files,
|
||||||
|
'logs': self.acquire_logs,
|
||||||
|
'bugreport': self.acquire_bugreport_info,
|
||||||
|
}
|
||||||
|
|
||||||
|
for mod_name, func in module_map.items():
|
||||||
|
try:
|
||||||
|
result = func(serial)
|
||||||
|
report['modules'][mod_name] = result
|
||||||
|
with open(acq_dir / f'{mod_name}.json', 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(result, f, indent=2, default=str)
|
||||||
|
except Exception as e:
|
||||||
|
report['modules'][mod_name] = {'ok': False, 'error': str(e)}
|
||||||
|
|
||||||
|
# IOC scans — reuse already-acquired package list
|
||||||
|
packages_data = report['modules'].get('packages', {}).get('packages', [])
|
||||||
|
all_findings = []
|
||||||
|
for scan_name, scan_func in [
|
||||||
|
('packages', lambda s: self.scan_packages(s, packages_data)),
|
||||||
|
('network', self.scan_network_indicators),
|
||||||
|
('files', self.scan_file_indicators),
|
||||||
|
('processes', self.scan_process_indicators),
|
||||||
|
]:
|
||||||
|
try:
|
||||||
|
scan_result = scan_func(serial)
|
||||||
|
for finding in scan_result.get('findings', []):
|
||||||
|
finding['scan_type'] = scan_name
|
||||||
|
all_findings.append(finding)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
report['ioc_findings'] = all_findings
|
||||||
|
report['scan_summary'] = {
|
||||||
|
'total_findings': len(all_findings),
|
||||||
|
'critical': sum(1 for f in all_findings if f.get('severity') == 'critical'),
|
||||||
|
'high': sum(1 for f in all_findings if f.get('severity') == 'high'),
|
||||||
|
'clean': len(all_findings) == 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(acq_dir / 'report.json', 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(report, f, indent=2, default=str)
|
||||||
|
|
||||||
|
return report
|
||||||
|
|
||||||
|
def get_acquisition_list(self, serial):
|
||||||
|
"""List past acquisitions for a device."""
|
||||||
|
device_dir = self.ACQ_DATA_DIR / serial
|
||||||
|
if not device_dir.exists():
|
||||||
|
return []
|
||||||
|
acquisitions = []
|
||||||
|
for acq_dir in sorted(device_dir.iterdir(), reverse=True):
|
||||||
|
if not acq_dir.is_dir():
|
||||||
|
continue
|
||||||
|
report_path = acq_dir / 'report.json'
|
||||||
|
entry = {'acq_id': acq_dir.name, 'has_report': report_path.exists()}
|
||||||
|
if report_path.exists():
|
||||||
|
try:
|
||||||
|
with open(report_path, encoding='utf-8') as f:
|
||||||
|
r = json.load(f)
|
||||||
|
entry['timestamp'] = r.get('timestamp', acq_dir.name)
|
||||||
|
entry['modules'] = list(r.get('modules', {}).keys())
|
||||||
|
entry['findings'] = r.get('scan_summary', {}).get('total_findings', 0)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
acquisitions.append(entry)
|
||||||
|
return acquisitions
|
||||||
|
|
||||||
|
def export_report(self, serial, acq_id):
|
||||||
|
"""Load a saved acquisition report from disk."""
|
||||||
|
report_path = self.ACQ_DATA_DIR / serial / acq_id / 'report.json'
|
||||||
|
if not report_path.exists():
|
||||||
|
return {'ok': False, 'error': 'Report not found'}
|
||||||
|
try:
|
||||||
|
with open(report_path, encoding='utf-8') as f:
|
||||||
|
return {'ok': True, 'report': json.load(f), 'path': str(report_path)}
|
||||||
|
except Exception as e:
|
||||||
|
return {'ok': False, 'error': str(e)}
|
||||||
|
|
||||||
|
# ── Direct (WebUSB) Mode ─────────────────────────────────────────
|
||||||
|
|
||||||
|
def get_direct_commands(self, operation):
|
||||||
|
"""Return ADB shell commands for browser-side WebUSB execution."""
|
||||||
|
commands = {
|
||||||
|
'packages': 'pm list packages -f',
|
||||||
|
'packages_sys': 'pm list packages -s',
|
||||||
|
'processes': 'ps -A',
|
||||||
|
'getprop': 'getprop',
|
||||||
|
'settings_global': 'settings list global',
|
||||||
|
'settings_secure': 'settings list secure',
|
||||||
|
'settings_system': 'settings list system',
|
||||||
|
'services': 'service list',
|
||||||
|
'logcat': 'logcat -d -t 1000',
|
||||||
|
'tmp_files': 'ls -la /data/local/tmp/ 2>/dev/null',
|
||||||
|
'tcp_connections': 'cat /proc/net/tcp 2>/dev/null',
|
||||||
|
}
|
||||||
|
if operation == 'full':
|
||||||
|
return commands
|
||||||
|
cmd = commands.get(operation)
|
||||||
|
return {operation: cmd} if cmd else {}
|
||||||
|
|
||||||
|
def parse_direct_output(self, operation, raw_output):
|
||||||
|
"""Parse raw ADB output returned from a WebUSB browser client."""
|
||||||
|
if operation == 'packages':
|
||||||
|
packages = []
|
||||||
|
for line in raw_output.splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if not line.startswith('package:'):
|
||||||
|
continue
|
||||||
|
line = line[8:]
|
||||||
|
eq_pos = line.rfind('=')
|
||||||
|
if eq_pos == -1:
|
||||||
|
pkg_name, apk_path = line, ''
|
||||||
|
else:
|
||||||
|
apk_path, pkg_name = line[:eq_pos], line[eq_pos + 1:]
|
||||||
|
pkg_name = pkg_name.strip()
|
||||||
|
if pkg_name:
|
||||||
|
packages.append({'package': pkg_name, 'path': apk_path.strip(), 'system': False})
|
||||||
|
return {'ok': True, 'packages': packages, 'total': len(packages)}
|
||||||
|
|
||||||
|
elif operation == 'processes':
|
||||||
|
lines = [l for l in raw_output.splitlines() if l.strip()]
|
||||||
|
return {'ok': True, 'output': raw_output, 'count': max(0, len(lines) - 1)}
|
||||||
|
|
||||||
|
elif operation == 'getprop':
|
||||||
|
props = {}
|
||||||
|
for line in raw_output.splitlines():
|
||||||
|
m = re.match(r'\[(.+)\]:\s*\[(.*)\]\s*$', line)
|
||||||
|
if m:
|
||||||
|
props[m.group(1)] = m.group(2)
|
||||||
|
return {'ok': True, 'props': props, 'output': raw_output}
|
||||||
|
|
||||||
|
else:
|
||||||
|
return {'ok': True, 'output': raw_output}
|
||||||
@@ -405,10 +405,18 @@ class AutonomyDaemon:
|
|||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# Read step limit from config based on the active LLM backend
|
||||||
|
from core.config import Config
|
||||||
|
cfg = Config()
|
||||||
|
backend = cfg.get('autarch', 'llm_backend', fallback='local')
|
||||||
|
step_key = f'{backend}_max_steps'
|
||||||
|
agent_settings = cfg.get_agent_settings()
|
||||||
|
max_steps = agent_settings.get(step_key, agent_settings.get('local_max_steps', 200))
|
||||||
|
|
||||||
agent = Agent(
|
agent = Agent(
|
||||||
llm=llm_inst,
|
llm=llm_inst,
|
||||||
tools=get_tool_registry(),
|
tools=get_tool_registry(),
|
||||||
max_steps=15,
|
max_steps=max_steps,
|
||||||
verbose=False,
|
verbose=False,
|
||||||
)
|
)
|
||||||
result = agent.run(task)
|
result = agent.run(task)
|
||||||
|
|||||||
@@ -140,17 +140,17 @@ class Config:
|
|||||||
},
|
},
|
||||||
'agents': {
|
'agents': {
|
||||||
'backend': 'local',
|
'backend': 'local',
|
||||||
'local_max_steps': '20',
|
'local_max_steps': '200',
|
||||||
'local_verbose': 'true',
|
'local_verbose': 'true',
|
||||||
'claude_enabled': 'false',
|
'claude_enabled': 'false',
|
||||||
'claude_model': 'claude-sonnet-4-6',
|
'claude_model': 'claude-sonnet-4-6',
|
||||||
'claude_max_tokens': '16384',
|
'claude_max_tokens': '16384',
|
||||||
'claude_max_steps': '30',
|
'claude_max_steps': '200',
|
||||||
'openai_enabled': 'false',
|
'openai_enabled': 'false',
|
||||||
'openai_model': 'gpt-4o',
|
'openai_model': 'gpt-4o',
|
||||||
'openai_base_url': 'https://api.openai.com/v1',
|
'openai_base_url': 'https://api.openai.com/v1',
|
||||||
'openai_max_tokens': '16384',
|
'openai_max_tokens': '16384',
|
||||||
'openai_max_steps': '30',
|
'openai_max_steps': '200',
|
||||||
},
|
},
|
||||||
'hal_memory': {
|
'hal_memory': {
|
||||||
'max_bytes': str(4 * 1024 * 1024 * 1024), # 4GB default
|
'max_bytes': str(4 * 1024 * 1024 * 1024), # 4GB default
|
||||||
@@ -539,17 +539,17 @@ class Config:
|
|||||||
"""Get agent configuration settings."""
|
"""Get agent configuration settings."""
|
||||||
return {
|
return {
|
||||||
'backend': self.get('agents', 'backend', 'local'),
|
'backend': self.get('agents', 'backend', 'local'),
|
||||||
'local_max_steps': self.get_int('agents', 'local_max_steps', 20),
|
'local_max_steps': self.get_int('agents', 'local_max_steps', 200),
|
||||||
'local_verbose': self.get_bool('agents', 'local_verbose', True),
|
'local_verbose': self.get_bool('agents', 'local_verbose', True),
|
||||||
'claude_enabled': self.get_bool('agents', 'claude_enabled', False),
|
'claude_enabled': self.get_bool('agents', 'claude_enabled', False),
|
||||||
'claude_model': self.get('agents', 'claude_model', 'claude-sonnet-4-6'),
|
'claude_model': self.get('agents', 'claude_model', 'claude-sonnet-4-6'),
|
||||||
'claude_max_tokens': self.get_int('agents', 'claude_max_tokens', 16384),
|
'claude_max_tokens': self.get_int('agents', 'claude_max_tokens', 16384),
|
||||||
'claude_max_steps': self.get_int('agents', 'claude_max_steps', 30),
|
'claude_max_steps': self.get_int('agents', 'claude_max_steps', 200),
|
||||||
'openai_enabled': self.get_bool('agents', 'openai_enabled', False),
|
'openai_enabled': self.get_bool('agents', 'openai_enabled', False),
|
||||||
'openai_model': self.get('agents', 'openai_model', 'gpt-4o'),
|
'openai_model': self.get('agents', 'openai_model', 'gpt-4o'),
|
||||||
'openai_base_url': self.get('agents', 'openai_base_url', 'https://api.openai.com/v1'),
|
'openai_base_url': self.get('agents', 'openai_base_url', 'https://api.openai.com/v1'),
|
||||||
'openai_max_tokens': self.get_int('agents', 'openai_max_tokens', 16384),
|
'openai_max_tokens': self.get_int('agents', 'openai_max_tokens', 16384),
|
||||||
'openai_max_steps': self.get_int('agents', 'openai_max_steps', 30),
|
'openai_max_steps': self.get_int('agents', 'openai_max_steps', 200),
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
258
core/cve_db.py
Normal file
258
core/cve_db.py
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
"""
|
||||||
|
Autarch CVE Database — CVE lookup for Android packages via OSV.dev.
|
||||||
|
by: SsSnake
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import threading
|
||||||
|
import urllib.request
|
||||||
|
import urllib.error
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
_db_instance = None
|
||||||
|
_db_lock = threading.Lock()
|
||||||
|
|
||||||
|
|
||||||
|
def get_cve_db():
|
||||||
|
global _db_instance
|
||||||
|
if _db_instance is None:
|
||||||
|
with _db_lock:
|
||||||
|
if _db_instance is None:
|
||||||
|
_db_instance = CveDatabase()
|
||||||
|
return _db_instance
|
||||||
|
|
||||||
|
|
||||||
|
class CveDatabase:
|
||||||
|
"""CVE lookup for Android packages. Uses OSV.dev as primary data source."""
|
||||||
|
|
||||||
|
DATA_DIR = Path(__file__).parent.parent / 'data' / 'ioc' / 'cve'
|
||||||
|
OSV_QUERY_URL = 'https://api.osv.dev/v1/query'
|
||||||
|
OSV_BATCH_URL = 'https://api.osv.dev/v1/querybatch'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.DATA_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
self._cache = {} # package_name -> [vuln_dicts]
|
||||||
|
self._stats_cache = None
|
||||||
|
self._lock = threading.Lock()
|
||||||
|
self._last_query = None
|
||||||
|
|
||||||
|
def get_cve_for_package(self, package_name, version=None) -> list:
|
||||||
|
"""Query OSV.dev for CVEs affecting an Android package."""
|
||||||
|
with self._lock:
|
||||||
|
if package_name in self._cache:
|
||||||
|
return self._cache[package_name]
|
||||||
|
|
||||||
|
try:
|
||||||
|
body = {
|
||||||
|
"package": {
|
||||||
|
"name": package_name,
|
||||||
|
"ecosystem": "Android"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if version is not None:
|
||||||
|
body["version"] = version
|
||||||
|
|
||||||
|
response = self._query_osv(body)
|
||||||
|
vulns = response.get("vulns", [])
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for vuln in vulns:
|
||||||
|
parsed = self._parse_vuln(vuln, package_name)
|
||||||
|
results.append(parsed)
|
||||||
|
|
||||||
|
with self._lock:
|
||||||
|
self._cache[package_name] = results
|
||||||
|
self._last_query = datetime.now(timezone.utc).isoformat()
|
||||||
|
|
||||||
|
return results
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_cve_for_android_sdk(self, sdk_version) -> list:
|
||||||
|
"""Query OSV.dev for CVEs affecting a specific Android SDK version."""
|
||||||
|
package_name = f"android:{sdk_version}"
|
||||||
|
try:
|
||||||
|
body = {
|
||||||
|
"package": {
|
||||||
|
"name": package_name,
|
||||||
|
"ecosystem": "Android"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = self._query_osv(body)
|
||||||
|
vulns = response.get("vulns", [])
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for vuln in vulns:
|
||||||
|
parsed = self._parse_vuln(vuln, package_name)
|
||||||
|
results.append(parsed)
|
||||||
|
|
||||||
|
with self._lock:
|
||||||
|
self._cache[package_name] = results
|
||||||
|
self._last_query = datetime.now(timezone.utc).isoformat()
|
||||||
|
|
||||||
|
return results
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def check_packages_batch(self, packages: list) -> dict:
|
||||||
|
"""Query OSV.dev for CVEs affecting multiple Android packages at once."""
|
||||||
|
if not packages:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
results = {}
|
||||||
|
# Split into chunks of 50
|
||||||
|
chunk_size = 50
|
||||||
|
for i in range(0, len(packages), chunk_size):
|
||||||
|
chunk = packages[i:i + chunk_size]
|
||||||
|
queries = [
|
||||||
|
{"package": {"name": p["name"], "ecosystem": "Android"}}
|
||||||
|
for p in chunk
|
||||||
|
]
|
||||||
|
body = {"queries": queries}
|
||||||
|
|
||||||
|
data = json.dumps(body).encode("utf-8")
|
||||||
|
req = urllib.request.Request(
|
||||||
|
self.OSV_BATCH_URL,
|
||||||
|
data=data,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"User-Agent": "Autarch/1.0"
|
||||||
|
},
|
||||||
|
method="POST"
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req, timeout=10) as resp:
|
||||||
|
response = json.loads(resp.read().decode("utf-8"))
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
batch_results = response.get("results", [])
|
||||||
|
for idx, result in enumerate(batch_results):
|
||||||
|
if idx >= len(chunk):
|
||||||
|
break
|
||||||
|
pkg_name = chunk[idx]["name"]
|
||||||
|
vulns = result.get("vulns", [])
|
||||||
|
parsed_vulns = [self._parse_vuln(v, pkg_name) for v in vulns]
|
||||||
|
results[pkg_name] = parsed_vulns
|
||||||
|
|
||||||
|
with self._lock:
|
||||||
|
self._cache[pkg_name] = parsed_vulns
|
||||||
|
|
||||||
|
with self._lock:
|
||||||
|
if results:
|
||||||
|
self._last_query = datetime.now(timezone.utc).isoformat()
|
||||||
|
|
||||||
|
return results
|
||||||
|
except Exception:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def get_stats(self) -> dict:
|
||||||
|
"""Return basic stats about the CVE database cache."""
|
||||||
|
with self._lock:
|
||||||
|
return {
|
||||||
|
"total_cached": len(self._cache),
|
||||||
|
"last_query": self._last_query,
|
||||||
|
"data_dir": str(self.DATA_DIR)
|
||||||
|
}
|
||||||
|
|
||||||
|
def _query_osv(self, body: dict) -> dict:
|
||||||
|
"""POST a JSON body to the OSV.dev query endpoint. Returns parsed JSON or {}."""
|
||||||
|
try:
|
||||||
|
data = json.dumps(body).encode("utf-8")
|
||||||
|
req = urllib.request.Request(
|
||||||
|
self.OSV_QUERY_URL,
|
||||||
|
data=data,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"User-Agent": "Autarch/1.0"
|
||||||
|
},
|
||||||
|
method="POST"
|
||||||
|
)
|
||||||
|
with urllib.request.urlopen(req, timeout=10) as resp:
|
||||||
|
return json.loads(resp.read().decode("utf-8"))
|
||||||
|
except Exception:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def _parse_vuln(self, vuln: dict, package_name: str) -> dict:
|
||||||
|
"""Extract standardised CVE fields from an OSV vulnerability object."""
|
||||||
|
# cve_id: prefer alias starting with "CVE-", else use vuln id
|
||||||
|
cve_id = vuln.get("id", "UNKNOWN")
|
||||||
|
for alias in vuln.get("aliases", []):
|
||||||
|
if alias.startswith("CVE-"):
|
||||||
|
cve_id = alias
|
||||||
|
break
|
||||||
|
|
||||||
|
# severity: try database_specific first, then severity array score, normalise
|
||||||
|
raw_severity = (
|
||||||
|
vuln.get("database_specific", {}).get("severity")
|
||||||
|
or vuln.get("severity", [{}])[0].get("score", "UNKNOWN")
|
||||||
|
)
|
||||||
|
severity = self._normalise_severity(raw_severity)
|
||||||
|
|
||||||
|
# description: summary or details, capped at 500 chars
|
||||||
|
description = vuln.get("summary", vuln.get("details", ""))[:500]
|
||||||
|
|
||||||
|
# patched_version: look for a "fixed" event in affected ranges
|
||||||
|
patched_version = "unknown"
|
||||||
|
affected_list = vuln.get("affected", [{}])
|
||||||
|
if affected_list:
|
||||||
|
ranges = affected_list[0].get("ranges", [])
|
||||||
|
for r in ranges:
|
||||||
|
for event in r.get("events", []):
|
||||||
|
if "fixed" in event:
|
||||||
|
patched_version = event["fixed"]
|
||||||
|
break
|
||||||
|
if patched_version != "unknown":
|
||||||
|
break
|
||||||
|
|
||||||
|
return {
|
||||||
|
"package": package_name,
|
||||||
|
"cve_id": cve_id,
|
||||||
|
"severity": severity,
|
||||||
|
"description": description,
|
||||||
|
"patched_version": patched_version,
|
||||||
|
"source": "osv.dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
def _normalise_severity(self, raw) -> str:
|
||||||
|
"""Map a raw severity string or CVSS score to critical/high/medium/low."""
|
||||||
|
if raw is None or raw == "UNKNOWN":
|
||||||
|
return "medium"
|
||||||
|
|
||||||
|
raw_str = str(raw).strip().upper()
|
||||||
|
|
||||||
|
# Direct label match
|
||||||
|
label_map = {
|
||||||
|
"CRITICAL": "critical",
|
||||||
|
"HIGH": "high",
|
||||||
|
"MEDIUM": "medium",
|
||||||
|
"MODERATE": "medium",
|
||||||
|
"LOW": "low",
|
||||||
|
"NONE": "low"
|
||||||
|
}
|
||||||
|
if raw_str in label_map:
|
||||||
|
return label_map[raw_str]
|
||||||
|
|
||||||
|
# Try numeric CVSS score
|
||||||
|
try:
|
||||||
|
score = float(raw_str)
|
||||||
|
if score >= 9.0:
|
||||||
|
return "critical"
|
||||||
|
elif score >= 7.0:
|
||||||
|
return "high"
|
||||||
|
elif score >= 4.0:
|
||||||
|
return "medium"
|
||||||
|
else:
|
||||||
|
return "low"
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# CVSS vector strings often start with digits after the last colon
|
||||||
|
# e.g. "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
|
||||||
|
# Fall back to medium if we can't parse it
|
||||||
|
return "medium"
|
||||||
259
core/keystore.py
Normal file
259
core/keystore.py
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
"""
|
||||||
|
AUTARCH Encrypted Keystore
|
||||||
|
Per-user encrypted storage for API keys, passwords, and credentials.
|
||||||
|
|
||||||
|
Stores secrets in keystore.xml in the user data directory using AES-256-CBC
|
||||||
|
encryption from the existing vault module. Secrets are separated by user
|
||||||
|
account so multi-user deployments don't leak across accounts.
|
||||||
|
|
||||||
|
The keystore file format is XML for human-inspectability of the structure
|
||||||
|
(though all values are encrypted). Each entry has:
|
||||||
|
- A unique key name
|
||||||
|
- The encrypted value (base64-encoded)
|
||||||
|
- The user who owns it
|
||||||
|
- A timestamp
|
||||||
|
- An optional category (api_key, password, token, certificate, etc.)
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
from core.keystore import get_keystore
|
||||||
|
|
||||||
|
ks = get_keystore()
|
||||||
|
|
||||||
|
# Store a secret for the current user
|
||||||
|
ks.set('claude_api_key', 'sk-ant-...', category='api_key')
|
||||||
|
|
||||||
|
# Retrieve it
|
||||||
|
key = ks.get('claude_api_key') # Returns '' if not set
|
||||||
|
|
||||||
|
# List all keys for the current user
|
||||||
|
ks.keys() # ['claude_api_key', 'openai_api_key']
|
||||||
|
|
||||||
|
# Store for a specific user
|
||||||
|
ks.set('shodan_key', 'abc123', user='admin', category='api_key')
|
||||||
|
|
||||||
|
# Delete
|
||||||
|
ks.delete('old_key')
|
||||||
|
"""
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
from xml.dom import minidom
|
||||||
|
|
||||||
|
_log = logging.getLogger('autarch.keystore')
|
||||||
|
|
||||||
|
# Import encryption functions from the existing vault
|
||||||
|
from core.vault import _derive_key, _encrypt, _decrypt
|
||||||
|
|
||||||
|
|
||||||
|
def _get_default_user() -> str:
|
||||||
|
"""Get the current user identity for key ownership."""
|
||||||
|
from core.paths import get_user_profile_path
|
||||||
|
profile_path = get_user_profile_path()
|
||||||
|
if profile_path.exists():
|
||||||
|
try:
|
||||||
|
with open(profile_path) as f:
|
||||||
|
profile = json.load(f)
|
||||||
|
return profile.get('username', 'default')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return 'default'
|
||||||
|
|
||||||
|
|
||||||
|
class Keystore:
|
||||||
|
"""Encrypted per-user secrets keystore backed by XML."""
|
||||||
|
|
||||||
|
def __init__(self, keystore_path: Path = None, master_password: str = ''):
|
||||||
|
from core.paths import get_keystore_path
|
||||||
|
self._path = keystore_path or get_keystore_path()
|
||||||
|
self._master = master_password
|
||||||
|
self._salt = None
|
||||||
|
self._entries: Dict[str, Dict] = {} # key -> {value, user, category, timestamp, salt}
|
||||||
|
self._load()
|
||||||
|
|
||||||
|
def _load(self):
|
||||||
|
"""Load and decrypt the keystore from disk."""
|
||||||
|
if not self._path.exists():
|
||||||
|
_log.info(f'No keystore found at {self._path}, starting fresh')
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
tree = ET.parse(str(self._path))
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
self._salt = base64.b64decode(root.get('salt', ''))
|
||||||
|
|
||||||
|
for entry in root.findall('entry'):
|
||||||
|
key_name = entry.get('name', '')
|
||||||
|
if not key_name:
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._entries[key_name] = {
|
||||||
|
'encrypted_value': entry.get('value', ''),
|
||||||
|
'user': entry.get('user', 'default'),
|
||||||
|
'category': entry.get('category', ''),
|
||||||
|
'timestamp': entry.get('timestamp', ''),
|
||||||
|
'iv': entry.get('iv', ''),
|
||||||
|
}
|
||||||
|
|
||||||
|
_log.info(f'Loaded keystore with {len(self._entries)} entries')
|
||||||
|
except Exception as e:
|
||||||
|
_log.error(f'Failed to load keystore: {e}')
|
||||||
|
|
||||||
|
def _save(self):
|
||||||
|
"""Encrypt and save the keystore to disk."""
|
||||||
|
try:
|
||||||
|
root = ET.Element('keystore')
|
||||||
|
root.set('version', '1')
|
||||||
|
|
||||||
|
if self._salt is None:
|
||||||
|
self._salt = os.urandom(32)
|
||||||
|
root.set('salt', base64.b64encode(self._salt).decode())
|
||||||
|
root.set('updated', str(int(time.time())))
|
||||||
|
|
||||||
|
for key_name, data in sorted(self._entries.items()):
|
||||||
|
entry = ET.SubElement(root, 'entry')
|
||||||
|
entry.set('name', key_name)
|
||||||
|
entry.set('value', data.get('encrypted_value', ''))
|
||||||
|
entry.set('iv', data.get('iv', ''))
|
||||||
|
entry.set('user', data.get('user', 'default'))
|
||||||
|
entry.set('category', data.get('category', ''))
|
||||||
|
entry.set('timestamp', data.get('timestamp', ''))
|
||||||
|
|
||||||
|
# Pretty-print the XML
|
||||||
|
rough = ET.tostring(root, encoding='unicode')
|
||||||
|
parsed = minidom.parseString(rough)
|
||||||
|
pretty = parsed.toprettyxml(indent=' ', encoding='utf-8')
|
||||||
|
|
||||||
|
self._path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(self._path, 'wb') as f:
|
||||||
|
f.write(pretty)
|
||||||
|
|
||||||
|
_log.info(f'Saved keystore with {len(self._entries)} entries')
|
||||||
|
except Exception as e:
|
||||||
|
_log.error(f'Failed to save keystore: {e}')
|
||||||
|
|
||||||
|
def set(self, key: str, value: str, user: str = None, category: str = ''):
|
||||||
|
"""Store an encrypted secret."""
|
||||||
|
if user is None:
|
||||||
|
user = _get_default_user()
|
||||||
|
|
||||||
|
if self._salt is None:
|
||||||
|
self._salt = os.urandom(32)
|
||||||
|
|
||||||
|
# Derive encryption key from salt + master password
|
||||||
|
enc_key = _derive_key(self._salt, self._master)
|
||||||
|
|
||||||
|
# Encrypt the value
|
||||||
|
iv, ciphertext = _encrypt(value.encode('utf-8'), enc_key)
|
||||||
|
|
||||||
|
self._entries[key] = {
|
||||||
|
'encrypted_value': base64.b64encode(ciphertext).decode(),
|
||||||
|
'iv': base64.b64encode(iv).decode(),
|
||||||
|
'user': user,
|
||||||
|
'category': category,
|
||||||
|
'timestamp': str(int(time.time())),
|
||||||
|
}
|
||||||
|
|
||||||
|
self._save()
|
||||||
|
_log.info(f'Stored secret: {key} (user={user}, category={category})')
|
||||||
|
|
||||||
|
def get(self, key: str, user: str = None) -> str:
|
||||||
|
"""Retrieve a decrypted secret. Returns '' if not found."""
|
||||||
|
if user is None:
|
||||||
|
user = _get_default_user()
|
||||||
|
|
||||||
|
entry = self._entries.get(key)
|
||||||
|
if not entry:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
# Check user ownership
|
||||||
|
if entry['user'] != user and entry['user'] != 'shared':
|
||||||
|
_log.warning(f'Access denied: {key} belongs to {entry["user"]}, not {user}')
|
||||||
|
return ''
|
||||||
|
|
||||||
|
try:
|
||||||
|
enc_key = _derive_key(self._salt, self._master)
|
||||||
|
iv = base64.b64decode(entry['iv'])
|
||||||
|
ciphertext = base64.b64decode(entry['encrypted_value'])
|
||||||
|
plaintext = _decrypt(iv, ciphertext, enc_key)
|
||||||
|
return plaintext.decode('utf-8')
|
||||||
|
except Exception as e:
|
||||||
|
_log.error(f'Failed to decrypt {key}: {e}')
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def delete(self, key: str, user: str = None):
|
||||||
|
"""Delete a secret."""
|
||||||
|
if user is None:
|
||||||
|
user = _get_default_user()
|
||||||
|
|
||||||
|
entry = self._entries.get(key)
|
||||||
|
if entry and (entry['user'] == user or entry['user'] == 'shared'):
|
||||||
|
del self._entries[key]
|
||||||
|
self._save()
|
||||||
|
_log.info(f'Deleted secret: {key}')
|
||||||
|
|
||||||
|
def keys(self, user: str = None, category: str = None) -> List[str]:
|
||||||
|
"""List key names for a user, optionally filtered by category."""
|
||||||
|
if user is None:
|
||||||
|
user = _get_default_user()
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for key, data in self._entries.items():
|
||||||
|
if data['user'] != user and data['user'] != 'shared':
|
||||||
|
continue
|
||||||
|
if category and data.get('category', '') != category:
|
||||||
|
continue
|
||||||
|
result.append(key)
|
||||||
|
return sorted(result)
|
||||||
|
|
||||||
|
def get_all_for_user(self, user: str = None) -> Dict[str, str]:
|
||||||
|
"""Get all decrypted secrets for a user as a dict."""
|
||||||
|
if user is None:
|
||||||
|
user = _get_default_user()
|
||||||
|
return {k: self.get(k, user) for k in self.keys(user)}
|
||||||
|
|
||||||
|
def get_metadata(self, key: str) -> Optional[Dict]:
|
||||||
|
"""Get metadata (user, category, timestamp) for a key without decrypting."""
|
||||||
|
entry = self._entries.get(key)
|
||||||
|
if not entry:
|
||||||
|
return None
|
||||||
|
return {
|
||||||
|
'user': entry['user'],
|
||||||
|
'category': entry.get('category', ''),
|
||||||
|
'timestamp': entry.get('timestamp', ''),
|
||||||
|
}
|
||||||
|
|
||||||
|
def migrate_from_vault(self):
|
||||||
|
"""Import secrets from the old vault.enc into the new keystore."""
|
||||||
|
from core.vault import get_vault
|
||||||
|
vault = get_vault()
|
||||||
|
migrated = 0
|
||||||
|
for key in vault.keys():
|
||||||
|
value = vault.get(key)
|
||||||
|
if value and key not in self._entries:
|
||||||
|
# Guess category from key name
|
||||||
|
category = 'api_key' if 'api_key' in key else 'credential'
|
||||||
|
self.set(key, value, user='default', category=category)
|
||||||
|
migrated += 1
|
||||||
|
if migrated:
|
||||||
|
_log.info(f'Migrated {migrated} secrets from vault to keystore')
|
||||||
|
return migrated
|
||||||
|
|
||||||
|
|
||||||
|
# Singleton
|
||||||
|
_keystore_instance: Optional[Keystore] = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_keystore(master_password: str = '') -> Keystore:
|
||||||
|
"""Get the global keystore instance."""
|
||||||
|
global _keystore_instance
|
||||||
|
if _keystore_instance is None:
|
||||||
|
_keystore_instance = Keystore(master_password=master_password)
|
||||||
|
return _keystore_instance
|
||||||
280
core/local_agent.py
Normal file
280
core/local_agent.py
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
"""
|
||||||
|
AUTARCH Local Agent
|
||||||
|
Lightweight client that runs on the user's machine and executes
|
||||||
|
commands locally, streaming results back to the AUTARCH server.
|
||||||
|
|
||||||
|
This makes the web UI feel like AUTARCH is running on the user's
|
||||||
|
machine — scans, tool output, file operations all happen locally.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python3 autarch-agent.py --server https://10.0.0.1:8181
|
||||||
|
|
||||||
|
The agent:
|
||||||
|
1. Connects to the AUTARCH server via WebSocket
|
||||||
|
2. Authenticates with the user's token
|
||||||
|
3. Receives command requests from the server
|
||||||
|
4. Executes them locally (subprocess)
|
||||||
|
5. Streams stdout/stderr back in real-time
|
||||||
|
6. Reports system info (OS, arch, hostname, IP) on connect
|
||||||
|
|
||||||
|
Protocol:
|
||||||
|
Server -> Agent: {"type": "exec", "id": "xxx", "command": "nmap -sV 10.0.0.1"}
|
||||||
|
Agent -> Server: {"type": "output", "id": "xxx", "stream": "stdout", "data": "..."}
|
||||||
|
Agent -> Server: {"type": "output", "id": "xxx", "stream": "stderr", "data": "..."}
|
||||||
|
Agent -> Server: {"type": "done", "id": "xxx", "exit_code": 0}
|
||||||
|
Agent -> Server: {"type": "sysinfo", "hostname": "...", "os": "...", ...}
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import shutil
|
||||||
|
import socket
|
||||||
|
import subprocess
|
||||||
|
import ssl
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
try:
|
||||||
|
import websockets
|
||||||
|
except ImportError:
|
||||||
|
print("Installing websockets...")
|
||||||
|
subprocess.check_call([sys.executable, "-m", "pip", "install", "websockets", "-q"])
|
||||||
|
import websockets
|
||||||
|
|
||||||
|
|
||||||
|
def get_system_info():
|
||||||
|
"""Collect local system information to send on connect."""
|
||||||
|
info = {
|
||||||
|
"hostname": socket.gethostname(),
|
||||||
|
"os": platform.system(),
|
||||||
|
"os_version": platform.version(),
|
||||||
|
"arch": platform.machine(),
|
||||||
|
"python": platform.python_version(),
|
||||||
|
"username": os.getenv("USER", os.getenv("USERNAME", "unknown")),
|
||||||
|
"home": str(Path.home()),
|
||||||
|
"cwd": os.getcwd(),
|
||||||
|
"pid": os.getpid(),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Network interfaces
|
||||||
|
try:
|
||||||
|
info["ip"] = socket.gethostbyname(socket.gethostname())
|
||||||
|
except Exception:
|
||||||
|
info["ip"] = "unknown"
|
||||||
|
|
||||||
|
# Available tools
|
||||||
|
tools = {}
|
||||||
|
for tool in ["nmap", "tcpdump", "wireshark", "python3", "git", "curl",
|
||||||
|
"wget", "ssh", "netstat", "ss", "ip", "ifconfig", "arp",
|
||||||
|
"dig", "nslookup", "traceroute", "ping", "whois",
|
||||||
|
"openssl", "nikto", "sqlmap", "hydra", "john", "hashcat"]:
|
||||||
|
path = shutil.which(tool)
|
||||||
|
if path:
|
||||||
|
tools[tool] = path
|
||||||
|
info["tools"] = tools
|
||||||
|
|
||||||
|
# Disk usage
|
||||||
|
try:
|
||||||
|
usage = shutil.disk_usage("/")
|
||||||
|
info["disk_total"] = usage.total
|
||||||
|
info["disk_free"] = usage.free
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
async def execute_command(command, cmd_id, websocket):
|
||||||
|
"""Execute a command locally and stream output back."""
|
||||||
|
try:
|
||||||
|
process = await asyncio.create_subprocess_shell(
|
||||||
|
command,
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.PIPE,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Stream stdout
|
||||||
|
async def read_stream(stream, name):
|
||||||
|
while True:
|
||||||
|
line = await stream.readline()
|
||||||
|
if not line:
|
||||||
|
break
|
||||||
|
await websocket.send(json.dumps({
|
||||||
|
"type": "output",
|
||||||
|
"id": cmd_id,
|
||||||
|
"stream": name,
|
||||||
|
"data": line.decode("utf-8", errors="replace"),
|
||||||
|
}))
|
||||||
|
|
||||||
|
# Run both streams concurrently
|
||||||
|
await asyncio.gather(
|
||||||
|
read_stream(process.stdout, "stdout"),
|
||||||
|
read_stream(process.stderr, "stderr"),
|
||||||
|
)
|
||||||
|
|
||||||
|
exit_code = await process.wait()
|
||||||
|
|
||||||
|
await websocket.send(json.dumps({
|
||||||
|
"type": "done",
|
||||||
|
"id": cmd_id,
|
||||||
|
"exit_code": exit_code,
|
||||||
|
}))
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
await websocket.send(json.dumps({
|
||||||
|
"type": "error",
|
||||||
|
"id": cmd_id,
|
||||||
|
"message": str(e),
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
async def read_file(path, cmd_id, websocket):
|
||||||
|
"""Read a file and send its contents back."""
|
||||||
|
try:
|
||||||
|
p = Path(path).expanduser()
|
||||||
|
if not p.exists():
|
||||||
|
await websocket.send(json.dumps({
|
||||||
|
"type": "error", "id": cmd_id,
|
||||||
|
"message": f"File not found: {path}"
|
||||||
|
}))
|
||||||
|
return
|
||||||
|
|
||||||
|
if p.is_dir():
|
||||||
|
# List directory
|
||||||
|
entries = []
|
||||||
|
for entry in sorted(p.iterdir()):
|
||||||
|
stat = entry.stat()
|
||||||
|
entries.append({
|
||||||
|
"name": entry.name,
|
||||||
|
"is_dir": entry.is_dir(),
|
||||||
|
"size": stat.st_size,
|
||||||
|
"modified": stat.st_mtime,
|
||||||
|
})
|
||||||
|
await websocket.send(json.dumps({
|
||||||
|
"type": "dirlist", "id": cmd_id,
|
||||||
|
"path": str(p), "entries": entries,
|
||||||
|
}))
|
||||||
|
else:
|
||||||
|
# Read file (limit to 10MB)
|
||||||
|
size = p.stat().st_size
|
||||||
|
if size > 10 * 1024 * 1024:
|
||||||
|
await websocket.send(json.dumps({
|
||||||
|
"type": "error", "id": cmd_id,
|
||||||
|
"message": f"File too large: {size} bytes"
|
||||||
|
}))
|
||||||
|
return
|
||||||
|
|
||||||
|
content = p.read_text(encoding="utf-8", errors="replace")
|
||||||
|
await websocket.send(json.dumps({
|
||||||
|
"type": "file", "id": cmd_id,
|
||||||
|
"path": str(p), "content": content,
|
||||||
|
"size": size,
|
||||||
|
}))
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
await websocket.send(json.dumps({
|
||||||
|
"type": "error", "id": cmd_id,
|
||||||
|
"message": str(e),
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
async def agent_loop(server_url, token):
|
||||||
|
"""Main agent loop - connect to server and process commands."""
|
||||||
|
# Allow self-signed certs
|
||||||
|
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||||
|
ssl_context.check_hostname = False
|
||||||
|
ssl_context.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
|
ws_url = server_url.replace("https://", "wss://").replace("http://", "ws://")
|
||||||
|
ws_url = f"{ws_url}/ws/agent"
|
||||||
|
|
||||||
|
print(f"Connecting to {ws_url}...")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
async with websockets.connect(ws_url, ssl=ssl_context,
|
||||||
|
extra_headers={"Authorization": f"Bearer {token}"}) as ws:
|
||||||
|
print("Connected to AUTARCH server")
|
||||||
|
|
||||||
|
# Send system info on connect
|
||||||
|
sysinfo = get_system_info()
|
||||||
|
sysinfo["type"] = "sysinfo"
|
||||||
|
await ws.send(json.dumps(sysinfo))
|
||||||
|
|
||||||
|
# Send heartbeat periodically
|
||||||
|
async def heartbeat():
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(30)
|
||||||
|
try:
|
||||||
|
await ws.send(json.dumps({"type": "heartbeat", "time": time.time()}))
|
||||||
|
except Exception:
|
||||||
|
break
|
||||||
|
|
||||||
|
heartbeat_task = asyncio.create_task(heartbeat())
|
||||||
|
|
||||||
|
# Process commands
|
||||||
|
try:
|
||||||
|
async for message in ws:
|
||||||
|
try:
|
||||||
|
msg = json.loads(message)
|
||||||
|
msg_type = msg.get("type", "")
|
||||||
|
cmd_id = msg.get("id", "")
|
||||||
|
|
||||||
|
if msg_type == "exec":
|
||||||
|
command = msg.get("command", "")
|
||||||
|
if command:
|
||||||
|
print(f" Executing: {command[:80]}")
|
||||||
|
asyncio.create_task(execute_command(command, cmd_id, ws))
|
||||||
|
|
||||||
|
elif msg_type == "read":
|
||||||
|
path = msg.get("path", "")
|
||||||
|
if path:
|
||||||
|
asyncio.create_task(read_file(path, cmd_id, ws))
|
||||||
|
|
||||||
|
elif msg_type == "ping":
|
||||||
|
await ws.send(json.dumps({"type": "pong", "id": cmd_id}))
|
||||||
|
|
||||||
|
elif msg_type == "kill":
|
||||||
|
# Server wants us to disconnect
|
||||||
|
print("Server requested disconnect")
|
||||||
|
break
|
||||||
|
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
finally:
|
||||||
|
heartbeat_task.cancel()
|
||||||
|
|
||||||
|
except (websockets.exceptions.ConnectionClosed,
|
||||||
|
ConnectionRefusedError, OSError) as e:
|
||||||
|
print(f"Connection lost: {e}. Reconnecting in 5s...")
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\nAgent stopped")
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="AUTARCH Local Agent")
|
||||||
|
parser.add_argument("--server", "-s", required=True,
|
||||||
|
help="AUTARCH server URL (e.g. https://10.0.0.1:8181)")
|
||||||
|
parser.add_argument("--token", "-t", default="",
|
||||||
|
help="Authentication token")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
print("AUTARCH Local Agent")
|
||||||
|
print(f"Server: {args.server}")
|
||||||
|
print(f"System: {platform.system()} {platform.machine()}")
|
||||||
|
print(f"Host: {socket.gethostname()}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
asyncio.run(agent_loop(args.server, args.token))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -76,6 +76,49 @@ def get_data_dir() -> Path:
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_data_dir() -> Path:
|
||||||
|
"""Return the platform-specific user data directory.
|
||||||
|
Created as a hidden folder on first call.
|
||||||
|
|
||||||
|
Windows: %APPDATA%/Autarch/
|
||||||
|
Linux: ~/.autarch/
|
||||||
|
macOS: ~/Library/Application Support/Autarch/
|
||||||
|
"""
|
||||||
|
system = platform.system()
|
||||||
|
if system == 'Windows':
|
||||||
|
base = os.environ.get('APPDATA', '')
|
||||||
|
if base:
|
||||||
|
d = Path(base) / 'Autarch'
|
||||||
|
else:
|
||||||
|
d = Path.home() / 'AppData' / 'Roaming' / 'Autarch'
|
||||||
|
elif system == 'Darwin':
|
||||||
|
d = Path.home() / 'Library' / 'Application Support' / 'Autarch'
|
||||||
|
else:
|
||||||
|
# Linux and others - hidden dotfolder in home
|
||||||
|
d = Path.home() / '.autarch'
|
||||||
|
|
||||||
|
d.mkdir(parents=True, exist_ok=True)
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def get_keystore_path() -> Path:
|
||||||
|
"""Return the path to the encrypted keystore file.
|
||||||
|
Stored in the user data directory, separate from the app install."""
|
||||||
|
return get_user_data_dir() / 'keystore.xml'
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_profile_path() -> Path:
|
||||||
|
"""Return the path to the user profile file."""
|
||||||
|
return get_user_data_dir() / 'profile.json'
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_sessions_dir() -> Path:
|
||||||
|
"""Return the directory for user session data (chat history, agent memory)."""
|
||||||
|
d = get_user_data_dir() / 'sessions'
|
||||||
|
d.mkdir(parents=True, exist_ok=True)
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
def get_config_path() -> Path:
|
def get_config_path() -> Path:
|
||||||
"""Return config path. Writable copy lives next to the exe;
|
"""Return config path. Writable copy lives next to the exe;
|
||||||
falls back to the bundled default if the writable copy doesn't exist yet."""
|
falls back to the bundled default if the writable copy doesn't exist yet."""
|
||||||
|
|||||||
184
core/sites_db.py
184
core/sites_db.py
@@ -49,6 +49,12 @@ class SitesDatabase:
|
|||||||
self._conn = None
|
self._conn = None
|
||||||
self._lock = threading.Lock()
|
self._lock = threading.Lock()
|
||||||
|
|
||||||
|
# Ensure the schema exists, then seed from the master dh.json the first
|
||||||
|
# time (or whenever the cache is empty). dh.json is the source of truth;
|
||||||
|
# dh_sites.db is a fast local query cache rebuilt from it automatically.
|
||||||
|
self._ensure_schema()
|
||||||
|
self._auto_populate()
|
||||||
|
|
||||||
def _get_connection(self) -> sqlite3.Connection:
|
def _get_connection(self) -> sqlite3.Connection:
|
||||||
"""Get thread-safe database connection."""
|
"""Get thread-safe database connection."""
|
||||||
if self._conn is None:
|
if self._conn is None:
|
||||||
@@ -56,6 +62,48 @@ class SitesDatabase:
|
|||||||
self._conn.row_factory = sqlite3.Row
|
self._conn.row_factory = sqlite3.Row
|
||||||
return self._conn
|
return self._conn
|
||||||
|
|
||||||
|
def _ensure_schema(self) -> None:
|
||||||
|
"""Create the sites table and indexes if they don't already exist."""
|
||||||
|
with self._lock:
|
||||||
|
conn = self._get_connection()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS sites (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL UNIQUE,
|
||||||
|
url_template TEXT NOT NULL,
|
||||||
|
category TEXT DEFAULT 'other',
|
||||||
|
source TEXT DEFAULT 'dh',
|
||||||
|
nsfw INTEGER DEFAULT 0,
|
||||||
|
enabled INTEGER DEFAULT 1,
|
||||||
|
error_type TEXT,
|
||||||
|
error_code INTEGER,
|
||||||
|
error_string TEXT,
|
||||||
|
match_code INTEGER,
|
||||||
|
match_string TEXT
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_sites_category ON sites(category)")
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_sites_source ON sites(source)")
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_sites_enabled ON sites(enabled)")
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_sites_nsfw ON sites(nsfw)")
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
def _auto_populate(self) -> None:
|
||||||
|
"""Seed the cache from the master dh.json when the sites table is empty."""
|
||||||
|
with self._lock:
|
||||||
|
conn = self._get_connection()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM sites")
|
||||||
|
count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
if count > 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
json_path = self.data_dir / "dh.json"
|
||||||
|
if json_path.exists():
|
||||||
|
self.load_from_json(json_path)
|
||||||
|
|
||||||
def get_stats(self) -> Dict[str, Any]:
|
def get_stats(self) -> Dict[str, Any]:
|
||||||
"""Get database statistics."""
|
"""Get database statistics."""
|
||||||
with self._lock:
|
with self._lock:
|
||||||
@@ -390,6 +438,142 @@ class SitesDatabase:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def add_sites_bulk(self, sites: List[Dict], overwrite: bool = False) -> Dict[str, int]:
|
||||||
|
"""Bulk-insert sites in a single transaction.
|
||||||
|
|
||||||
|
By default only sites with a NOT-yet-seen name are added; existing
|
||||||
|
names are left untouched (INSERT OR IGNORE). Pass overwrite=True to
|
||||||
|
replace existing rows instead.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sites: List of site dicts. Recognised keys: name, url_template
|
||||||
|
(or url), category, source, nsfw, enabled, error_type,
|
||||||
|
error_code, error_string, match_code, match_string.
|
||||||
|
overwrite: Replace existing rows sharing the same name.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Stats dict: {'total', 'added', 'skipped', 'errors'}.
|
||||||
|
"""
|
||||||
|
stats = {'total': len(sites), 'added': 0, 'skipped': 0, 'errors': 0}
|
||||||
|
verb = "INSERT OR REPLACE" if overwrite else "INSERT OR IGNORE"
|
||||||
|
|
||||||
|
with self._lock:
|
||||||
|
conn = self._get_connection()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
for site in sites:
|
||||||
|
name = site.get('name')
|
||||||
|
url = site.get('url_template') or site.get('url')
|
||||||
|
if not name or not url:
|
||||||
|
stats['errors'] += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
cursor.execute(f"""
|
||||||
|
{verb} INTO sites
|
||||||
|
(name, url_template, category, source, nsfw, enabled,
|
||||||
|
error_type, error_code, error_string, match_code, match_string)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
""", (
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
site.get('category', 'other'),
|
||||||
|
site.get('source', 'custom'),
|
||||||
|
1 if site.get('nsfw') else 0,
|
||||||
|
0 if site.get('enabled', 1) in (0, False) else 1,
|
||||||
|
site.get('error_type'),
|
||||||
|
site.get('error_code'),
|
||||||
|
site.get('error_string'),
|
||||||
|
site.get('match_code'),
|
||||||
|
site.get('match_string'),
|
||||||
|
))
|
||||||
|
if cursor.rowcount > 0:
|
||||||
|
stats['added'] += 1
|
||||||
|
else:
|
||||||
|
stats['skipped'] += 1
|
||||||
|
except Exception:
|
||||||
|
stats['errors'] += 1
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
return stats
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _normalize_url(url: str) -> str:
|
||||||
|
"""Normalise a URL template for duplicate detection.
|
||||||
|
|
||||||
|
Strips scheme, leading www., case, and trailing slash so that
|
||||||
|
http/https, www/non-www and case variants of the same profile URL
|
||||||
|
collapse to one key.
|
||||||
|
"""
|
||||||
|
if not url:
|
||||||
|
return ''
|
||||||
|
u = url.strip().lower()
|
||||||
|
for scheme in ('https://', 'http://'):
|
||||||
|
if u.startswith(scheme):
|
||||||
|
u = u[len(scheme):]
|
||||||
|
break
|
||||||
|
if u.startswith('www.'):
|
||||||
|
u = u[4:]
|
||||||
|
return u.rstrip('/')
|
||||||
|
|
||||||
|
def deduplicate(self) -> Dict[str, int]:
|
||||||
|
"""Remove duplicate sites that share the same (normalised) URL template.
|
||||||
|
|
||||||
|
Names are already unique via the schema constraint; this collapses rows
|
||||||
|
whose URL templates point at the same profile page. For each duplicate
|
||||||
|
group the best row is kept (prefer enabled, then having a detection
|
||||||
|
pattern, then the oldest/lowest id) and the rest are deleted.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Stats dict: {'duplicate_groups', 'removed', 'remaining'}.
|
||||||
|
"""
|
||||||
|
with self._lock:
|
||||||
|
conn = self._get_connection()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
cursor.execute(
|
||||||
|
"SELECT id, url_template, error_type, error_string, match_string, enabled FROM sites"
|
||||||
|
)
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
|
groups: Dict[str, list] = {}
|
||||||
|
for r in rows:
|
||||||
|
key = self._normalize_url(r['url_template'])
|
||||||
|
if not key:
|
||||||
|
continue
|
||||||
|
groups.setdefault(key, []).append(r)
|
||||||
|
|
||||||
|
def score(r):
|
||||||
|
has_detection = bool(r['error_string'] or r['match_string'] or r['error_type'])
|
||||||
|
# Higher tuple wins; -id keeps the lowest (oldest) id.
|
||||||
|
return (1 if r['enabled'] else 0, 1 if has_detection else 0, -r['id'])
|
||||||
|
|
||||||
|
to_delete = []
|
||||||
|
dup_groups = 0
|
||||||
|
for members in groups.values():
|
||||||
|
if len(members) < 2:
|
||||||
|
continue
|
||||||
|
dup_groups += 1
|
||||||
|
members_sorted = sorted(members, key=score, reverse=True)
|
||||||
|
to_delete.extend(r['id'] for r in members_sorted[1:])
|
||||||
|
|
||||||
|
for i in range(0, len(to_delete), 500):
|
||||||
|
chunk = to_delete[i:i + 500]
|
||||||
|
placeholders = ','.join('?' * len(chunk))
|
||||||
|
cursor.execute(f"DELETE FROM sites WHERE id IN ({placeholders})", chunk)
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM sites")
|
||||||
|
remaining = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
return {
|
||||||
|
'duplicate_groups': dup_groups,
|
||||||
|
'removed': len(to_delete),
|
||||||
|
'remaining': remaining,
|
||||||
|
}
|
||||||
|
|
||||||
def update_detection(
|
def update_detection(
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
|
|||||||
159
core/user_profile.py
Normal file
159
core/user_profile.py
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
"""
|
||||||
|
AUTARCH User Profile Manager
|
||||||
|
Handles user identity, preferences, and session management.
|
||||||
|
|
||||||
|
On first launch, creates a default profile in the user data directory.
|
||||||
|
Supports multiple users for shared deployments.
|
||||||
|
|
||||||
|
The profile stores non-sensitive user info (username, display name, role, etc.)
|
||||||
|
Sensitive data (API keys, passwords) goes in the keystore.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict, Optional
|
||||||
|
|
||||||
|
_log = logging.getLogger('autarch.user_profile')
|
||||||
|
|
||||||
|
|
||||||
|
class UserProfile:
|
||||||
|
"""User profile and preferences."""
|
||||||
|
|
||||||
|
def __init__(self, profile_path: Path = None):
|
||||||
|
from core.paths import get_user_profile_path
|
||||||
|
self._path = profile_path or get_user_profile_path()
|
||||||
|
self._data: Dict = {}
|
||||||
|
self._load()
|
||||||
|
|
||||||
|
def _load(self):
|
||||||
|
"""Load profile from disk, or create default."""
|
||||||
|
if self._path.exists():
|
||||||
|
try:
|
||||||
|
with open(self._path) as f:
|
||||||
|
self._data = json.load(f)
|
||||||
|
_log.info(f'Loaded profile for {self._data.get("username", "unknown")}')
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
_log.error(f'Failed to load profile: {e}')
|
||||||
|
|
||||||
|
# Create default profile
|
||||||
|
self._data = self._create_default()
|
||||||
|
self._save()
|
||||||
|
_log.info('Created default user profile')
|
||||||
|
|
||||||
|
def _create_default(self) -> Dict:
|
||||||
|
"""Create the default user profile."""
|
||||||
|
username = os.getenv('USER', os.getenv('USERNAME', 'operator'))
|
||||||
|
return {
|
||||||
|
'username': username,
|
||||||
|
'display_name': username.capitalize(),
|
||||||
|
'role': 'admin',
|
||||||
|
'created': int(time.time()),
|
||||||
|
'last_login': int(time.time()),
|
||||||
|
'preferences': {
|
||||||
|
'theme': 'dark',
|
||||||
|
'llm_backend': 'local',
|
||||||
|
'hal_auto_analyze': True,
|
||||||
|
'hal_max_steps': 200,
|
||||||
|
'verbose': False,
|
||||||
|
'default_scan_target': 'local', # 'local' scans user device, 'server' scans server
|
||||||
|
'chat_memory_enabled': True,
|
||||||
|
},
|
||||||
|
'session': {
|
||||||
|
'last_module': '',
|
||||||
|
'last_target': '',
|
||||||
|
'last_scan_type': '',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def _save(self):
|
||||||
|
"""Save profile to disk."""
|
||||||
|
try:
|
||||||
|
self._path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(self._path, 'w') as f:
|
||||||
|
json.dump(self._data, f, indent=2)
|
||||||
|
except Exception as e:
|
||||||
|
_log.error(f'Failed to save profile: {e}')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def username(self) -> str:
|
||||||
|
return self._data.get('username', 'default')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def display_name(self) -> str:
|
||||||
|
return self._data.get('display_name', self.username)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def role(self) -> str:
|
||||||
|
return self._data.get('role', 'user')
|
||||||
|
|
||||||
|
def get_preference(self, key: str, default=None):
|
||||||
|
"""Get a user preference value."""
|
||||||
|
return self._data.get('preferences', {}).get(key, default)
|
||||||
|
|
||||||
|
def set_preference(self, key: str, value):
|
||||||
|
"""Set a user preference and save."""
|
||||||
|
if 'preferences' not in self._data:
|
||||||
|
self._data['preferences'] = {}
|
||||||
|
self._data['preferences'][key] = value
|
||||||
|
self._save()
|
||||||
|
|
||||||
|
def get_session(self, key: str, default='') -> str:
|
||||||
|
"""Get a session value (non-persistent state hints)."""
|
||||||
|
return self._data.get('session', {}).get(key, default)
|
||||||
|
|
||||||
|
def set_session(self, key: str, value: str):
|
||||||
|
"""Set a session value."""
|
||||||
|
if 'session' not in self._data:
|
||||||
|
self._data['session'] = {}
|
||||||
|
self._data['session'][key] = value
|
||||||
|
self._save()
|
||||||
|
|
||||||
|
def update_last_login(self):
|
||||||
|
"""Record login timestamp."""
|
||||||
|
self._data['last_login'] = int(time.time())
|
||||||
|
self._save()
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict:
|
||||||
|
"""Export profile as a dict (for API/display)."""
|
||||||
|
return {
|
||||||
|
'username': self.username,
|
||||||
|
'display_name': self.display_name,
|
||||||
|
'role': self.role,
|
||||||
|
'created': self._data.get('created', 0),
|
||||||
|
'last_login': self._data.get('last_login', 0),
|
||||||
|
'preferences': self._data.get('preferences', {}),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Singleton
|
||||||
|
_profile_instance: Optional[UserProfile] = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_profile() -> UserProfile:
|
||||||
|
"""Get the global user profile instance."""
|
||||||
|
global _profile_instance
|
||||||
|
if _profile_instance is None:
|
||||||
|
_profile_instance = UserProfile()
|
||||||
|
return _profile_instance
|
||||||
|
|
||||||
|
|
||||||
|
def init_profile_on_launch():
|
||||||
|
"""Called at app startup to ensure profile exists and update login time."""
|
||||||
|
profile = get_profile()
|
||||||
|
profile.update_last_login()
|
||||||
|
|
||||||
|
# Migrate old vault secrets to new keystore if needed
|
||||||
|
from core.paths import get_keystore_path
|
||||||
|
ks_path = get_keystore_path()
|
||||||
|
if not ks_path.exists():
|
||||||
|
from core.keystore import get_keystore
|
||||||
|
ks = get_keystore()
|
||||||
|
migrated = ks.migrate_from_vault()
|
||||||
|
if migrated:
|
||||||
|
_log.info(f'Migrated {migrated} secrets from vault to keystore on first run')
|
||||||
|
|
||||||
|
return profile
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"listen_dns": "10.0.0.56:53",
|
"listen_dns": "420.420.420.420:53",
|
||||||
"listen_api": "127.0.0.1:5380",
|
"listen_api": "127.0.0.1:5380",
|
||||||
"api_token": "5ed79350fed2490d2aca6f3b29776365",
|
"api_token": "",
|
||||||
"upstream": [],
|
"upstream": [],
|
||||||
"cache_ttl": 300,
|
"cache_ttl": 300,
|
||||||
"zones_dir": "C:\\she\\autarch\\data\\dns\\zones",
|
"zones_dir": "/home/snake/autarch/data/dns/zones",
|
||||||
"dnssec_keys_dir": "C:\\she\\autarch\\data\\dns\\keys",
|
"dnssec_keys_dir": "/home/snake/autarch/data/dns/keys",
|
||||||
"log_queries": true
|
"log_queries": true
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,7 @@ You are Hal, the AI security agent for AUTARCH — built by darkHal Security Gro
|
|||||||
3. DETECT THE OS FIRST before running any command. Use the shell tool to run "uname -s" or check if you're on Windows. Then ONLY run commands for THAT operating system. Never list commands for multiple distros or platforms in one response.
|
3. DETECT THE OS FIRST before running any command. Use the shell tool to run "uname -s" or check if you're on Windows. Then ONLY run commands for THAT operating system. Never list commands for multiple distros or platforms in one response.
|
||||||
4. On Linux: detect the distro (cat /etc/os-release). Use apt for Debian/Ubuntu, dnf for Fedora, pacman for Arch. Do NOT guess — check first.
|
4. On Linux: detect the distro (cat /etc/os-release). Use apt for Debian/Ubuntu, dnf for Fedora, pacman for Arch. Do NOT guess — check first.
|
||||||
5. On Windows: use PowerShell or cmd commands. Do NOT mix in Linux commands.
|
5. On Windows: use PowerShell or cmd commands. Do NOT mix in Linux commands.
|
||||||
6. For commands that need root/admin: use the shell tool directly — the system has a privileged daemon that handles elevation automatically. NEVER prefix commands with "sudo". Just run the command.
|
6. For commands that need root/admin: you CAN use sudo. The system has a privileged daemon that handles elevation, so sudo will work without password prompts. Use sudo when commands require elevated privileges.
|
||||||
7. Run ONE command at a time. Verify it worked before running the next one.
|
7. Run ONE command at a time. Verify it worked before running the next one.
|
||||||
8. Keep responses short and direct. No filler, no preamble.
|
8. Keep responses short and direct. No filler, no preamble.
|
||||||
9. When asked to do something, DO IT. Don't explain how it would be done on 5 different OSes.
|
9. When asked to do something, DO IT. Don't explain how it would be done on 5 different OSes.
|
||||||
@@ -19,15 +19,15 @@ You can read files, write files, execute shell commands, search the codebase, an
|
|||||||
## Common Commands by OS
|
## Common Commands by OS
|
||||||
|
|
||||||
Linux (Debian/Ubuntu):
|
Linux (Debian/Ubuntu):
|
||||||
apt update && apt install <package>
|
sudo apt update && sudo apt install <package>
|
||||||
systemctl start/stop/status <service>
|
sudo systemctl start/stop/status <service>
|
||||||
iptables -A INPUT -s <ip> -j DROP
|
sudo iptables -A INPUT -s <ip> -j DROP
|
||||||
ip addr / ip route / ip neigh / ss -tunap
|
ip addr / ip route / ip neigh / ss -tunap
|
||||||
|
|
||||||
Linux (Fedora/RHEL):
|
Linux (Fedora/RHEL):
|
||||||
dnf install <package>
|
sudo dnf install <package>
|
||||||
systemctl start/stop/status <service>
|
sudo systemctl start/stop/status <service>
|
||||||
firewall-cmd --add-rich-rule='rule family=ipv4 source address=<ip> drop'
|
sudo firewall-cmd --add-rich-rule='rule family=ipv4 source address=<ip> drop'
|
||||||
|
|
||||||
Windows:
|
Windows:
|
||||||
Get-NetFirewallRule / New-NetFirewallRule
|
Get-NetFirewallRule / New-NetFirewallRule
|
||||||
@@ -55,8 +55,8 @@ For tasks: use tools. Run one command, check the result, then continue.
|
|||||||
For module creation: use create_module tool.
|
For module creation: use create_module tool.
|
||||||
|
|
||||||
When running shell commands — ALWAYS detect OS first, then:
|
When running shell commands — ALWAYS detect OS first, then:
|
||||||
CORRECT: iptables -L -n (after confirming Linux)
|
CORRECT: sudo iptables -L -n (after confirming Linux)
|
||||||
WRONG: sudo iptables -L -n
|
CORRECT: iptables -L -n (also works, daemon handles elevation)
|
||||||
WRONG: Here's how to do it on Linux, Windows, and macOS...
|
WRONG: Here's how to do it on Linux, Windows, and macOS...
|
||||||
|
|
||||||
When explaining results:
|
When explaining results:
|
||||||
|
|||||||
19
data/ioc/index.json
Normal file
19
data/ioc/index.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"generated": "2026-07-13T15:40:17.978877",
|
||||||
|
"counts": {
|
||||||
|
"packages": 300,
|
||||||
|
"certs": 11,
|
||||||
|
"domains": 5793,
|
||||||
|
"ips": 65,
|
||||||
|
"file_paths": 19,
|
||||||
|
"processes": 84,
|
||||||
|
"hashes": 318
|
||||||
|
},
|
||||||
|
"sources": {
|
||||||
|
"stalkerware_ioc_yaml": true,
|
||||||
|
"amnesty_investigations": 16,
|
||||||
|
"mvt_campaigns": 8,
|
||||||
|
"citizen_lab_campaigns": 21,
|
||||||
|
"yara_rules": 52
|
||||||
|
}
|
||||||
|
}
|
||||||
605
data/ioc/spyware/amnesty/2018-08-01_nso/indicators.csv
Normal file
605
data/ioc/spyware/amnesty/2018-08-01_nso/indicators.csv
Normal file
@@ -0,0 +1,605 @@
|
|||||||
|
domain_name,ip_address
|
||||||
|
"14-tracking.com","191.101.31.25"
|
||||||
|
"1minto-start.com","185.94.190.203"
|
||||||
|
"24-7clinic.com","46.183.219.79"
|
||||||
|
"3driving.com","185.106.120.130"
|
||||||
|
"456h612i458g.com","81.22.255.180"
|
||||||
|
"7style.org","109.200.24.106"
|
||||||
|
"800health.net","185.189.112.199"
|
||||||
|
"access.dynamic-dns.net","95.183.51.199"
|
||||||
|
"accountnotify.com","185.130.184.35"
|
||||||
|
"activate-discount.com","200.7.97.228"
|
||||||
|
"actorsshop.net","31.184.198.149"
|
||||||
|
"actu24.online","185.156.175.219"
|
||||||
|
"addmyid.net","46.22.223.209"
|
||||||
|
"adeal4u.co","217.112.131.120"
|
||||||
|
"afriquenouvelle.com","185.94.191.69"
|
||||||
|
"aircraftsxhibition.com","108.170.31.100"
|
||||||
|
"ajelnews.net","109.200.24.72"
|
||||||
|
"akhbara-aalawsat.com","185.243.115.100"
|
||||||
|
"akhbar-aliqtisad.com","185.94.191.23"
|
||||||
|
"akhbar-arabia.com","200.7.97.216"
|
||||||
|
"albumphotopro.biz","185.45.192.134"
|
||||||
|
"alive2plunge.com","173.254.248.104"
|
||||||
|
"allafricaninfo.com","5.102.146.87"
|
||||||
|
"allbeautifularts.com","185.94.191.73"
|
||||||
|
"alldaycooking.co","217.112.131.103"
|
||||||
|
"allfadiha.co","217.64.113.254"
|
||||||
|
"allladiesloveme.com","38.132.118.108"
|
||||||
|
"all-sales.info","88.119.179.165"
|
||||||
|
"allthecolorsyoulike.com","185.225.68.6"
|
||||||
|
"allthegamesyouneed.com","185.195.200.43"
|
||||||
|
"allthemakeupyouneed.com","185.195.200.51"
|
||||||
|
"allthesongsyoulike.com","46.183.216.141"
|
||||||
|
"alluneed4home.net","109.200.24.48"
|
||||||
|
"android-core.org","109.200.24.112"
|
||||||
|
"android-updates.net","185.225.68.229"
|
||||||
|
"apiapple.com","185.141.26.50"
|
||||||
|
"apiwacdn.com","206.189.108.245"
|
||||||
|
"appointments-online.com","88.150.227.120"
|
||||||
|
"arabnews365.com","88.119.179.166"
|
||||||
|
"arab-share.com","46.21.147.141"
|
||||||
|
"arabworld.biz","46.21.147.224"
|
||||||
|
"arabworldnews.info","185.230.124.235"
|
||||||
|
"around-theglobe.co","185.82.202.32"
|
||||||
|
"ar-tweets.com","109.200.24.76"
|
||||||
|
"atlaslions.info","82.211.31.177"
|
||||||
|
"autodiscount.info","88.150.227.105"
|
||||||
|
"banca-movil.com","149.255.36.138"
|
||||||
|
"bargainservice.online","83.221.132.157"
|
||||||
|
"beautifulhousesaroundme.com","185.225.68.2"
|
||||||
|
"beethoventopsymphonies.com","80.255.12.246"
|
||||||
|
"benjamin-taganga.info","217.112.131.176"
|
||||||
|
"bestadventures4u.com","93.158.203.142"
|
||||||
|
"bestcandyever.com","5.149.250.2"
|
||||||
|
"bestfoods.co","200.7.98.133"
|
||||||
|
"bestfriendneedshelp.com","88.150.138.66"
|
||||||
|
"bestheadphones4u.com","93.158.203.140"
|
||||||
|
"besthotelsaroundme.com","5.149.252.157"
|
||||||
|
"bestperfumesnow.com","89.249.65.165"
|
||||||
|
"bestpresents4all.net","94.177.236.235"
|
||||||
|
"bestsalesaroundme.com","89.33.246.112"
|
||||||
|
"beststores4u.com","185.94.189.198"
|
||||||
|
"bestsushiever.com","88.150.138.106"
|
||||||
|
"better-deal.info","217.112.131.147"
|
||||||
|
"bicyclerentalnow.com","5.149.254.5"
|
||||||
|
"biggunsarefun.com","200.7.105.3"
|
||||||
|
"blackwhitebags.com","185.206.224.41"
|
||||||
|
"blcheck.utensils.pro","164.132.138.55"
|
||||||
|
"blue.911hig11carcay959454.com","54.37.104.101"
|
||||||
|
"booking-tables.com","109.200.24.59"
|
||||||
|
"boysrbabies.co","38.132.118.111"
|
||||||
|
"breakfastisgood.com","5.102.147.114"
|
||||||
|
"breaking-extranews.online","185.141.27.124"
|
||||||
|
"breakingnewsasia.com","200.7.111.156"
|
||||||
|
"breaking-news.co","88.150.189.108"
|
||||||
|
"breakthenews.net","81.95.5.165"
|
||||||
|
"br-hashtags.com","191.101.31.21"
|
||||||
|
"brighttooth.net","185.189.112.200"
|
||||||
|
"brownandblueeyes.com","185.29.11.165"
|
||||||
|
"browser-update.online","191.101.31.114"
|
||||||
|
"br-travels.com","81.95.7.58"
|
||||||
|
"buildurlife.net","5.149.255.198"
|
||||||
|
"bunchi.club","5.149.249.174"
|
||||||
|
"businesssupportme.com","5.149.255.69"
|
||||||
|
"bussybeesallover.com","195.12.48.42"
|
||||||
|
"buymanuel.co","185.117.75.84"
|
||||||
|
"buypresent4me.net","94.177.239.30"
|
||||||
|
"calendarsapp.com","185.117.72.120"
|
||||||
|
"captcha.bl33pon6373.com","88.99.107.18"
|
||||||
|
"carrefour-des-affaires.com","5.102.146.126"
|
||||||
|
"cars-to-buy.com","217.112.131.146"
|
||||||
|
"cashandlife.com","185.82.200.233"
|
||||||
|
"casia-news.info","185.198.58.158"
|
||||||
|
"catfoodstorage.net","217.61.5.131"
|
||||||
|
"catsndogsproducts.com","88.119.179.226"
|
||||||
|
"cdnupdateweb.com","190.97.165.115"
|
||||||
|
"cdnwa.com","185.141.25.30"
|
||||||
|
"cell-abonnes.com","5.102.147.82"
|
||||||
|
"cellphonesprices.com","93.158.200.205"
|
||||||
|
"cellular-updates.com","176.223.111.159"
|
||||||
|
"cellularupdates.info","185.77.129.136"
|
||||||
|
"cellular-updates.online","154.16.37.40"
|
||||||
|
"centrasia-news.com","185.225.68.125"
|
||||||
|
"cheapapartmentsaroundme.com","88.119.179.140"
|
||||||
|
"cheaphostingtoday.com","5.102.146.49"
|
||||||
|
"cheapmotelz.net","185.106.120.173"
|
||||||
|
"cheapsolutions4u.com","141.255.161.88"
|
||||||
|
"cheaptransporting.net","185.156.173.118"
|
||||||
|
"check-my-internetspeed.com","200.7.97.229"
|
||||||
|
"chocolateicecreamlovers.com","88.150.138.74"
|
||||||
|
"chocollife.me","185.94.191.123"
|
||||||
|
"chubaka.org","185.225.68.124"
|
||||||
|
"classic-furnitures.com","185.183.107.43"
|
||||||
|
"clickrighthere.online","138.59.17.76"
|
||||||
|
"coffecups.online","31.3.232.125"
|
||||||
|
"coffee2go.org","86.105.18.222"
|
||||||
|
"colorfulnotebooks.com","185.195.200.38"
|
||||||
|
"colorsoflife.online","62.113.232.221"
|
||||||
|
"columbus-parking.com","154.16.37.39"
|
||||||
|
"coolasiankitchen.com","5.102.146.91"
|
||||||
|
"coolbbqtools.net","217.112.131.108"
|
||||||
|
"coolmath4us.net","217.112.131.227"
|
||||||
|
"cool-smartphone-apps.com","217.112.131.58"
|
||||||
|
"coupedumondepro.com","188.215.229.213"
|
||||||
|
"couponshops.info","37.220.31.114"
|
||||||
|
"cpr-appointments.com","88.150.227.121"
|
||||||
|
"cryptocurrecny.com","185.225.68.77"
|
||||||
|
"cryptokoinz.com","5.149.254.24"
|
||||||
|
"cryptopcoinz.com","217.61.7.152"
|
||||||
|
"csomagodjott.com","200.7.97.238"
|
||||||
|
"daily-sport.news","200.7.97.214"
|
||||||
|
"dancinglife.co","89.249.65.206"
|
||||||
|
"deal4unow.com","185.134.29.146"
|
||||||
|
"delivery-24-7.com","81.92.202.222"
|
||||||
|
"dental-care-spa.net","185.225.68.202"
|
||||||
|
"deportesinfo.com","149.255.35.115"
|
||||||
|
"diaspora-news.com","81.95.5.144"
|
||||||
|
"dinneraroundyou.com","217.112.131.208"
|
||||||
|
"discountmarkets.info","88.150.138.69"
|
||||||
|
"discountstores.info","109.200.24.73"
|
||||||
|
"discoveredworld-news.com","185.236.202.184"
|
||||||
|
"dogfoodstorage.net","217.61.104.60"
|
||||||
|
"dogopics.com","5.102.145.183"
|
||||||
|
"doitformom.com","89.34.111.212"
|
||||||
|
"doitforthefame-now.com","88.150.138.82"
|
||||||
|
"do-itonyour-own.com","5.102.145.64"
|
||||||
|
"domain-redirect.com","109.200.24.122"
|
||||||
|
"domainsearching.net","185.117.89.251"
|
||||||
|
"domainsearching.net","80.211.250.229"
|
||||||
|
"domain-security.org","109.200.24.2"
|
||||||
|
"donateabox.co","5.102.146.82"
|
||||||
|
"donateaflower.com","104.216.8.34"
|
||||||
|
"done.events","130.185.250.200"
|
||||||
|
"dowhatyouneed.com","5.102.145.130"
|
||||||
|
"easybett.online","46.183.221.185"
|
||||||
|
"easy-pay.info","89.249.65.193"
|
||||||
|
"ecommerce-ads.org","46.183.223.249"
|
||||||
|
"economic-news.co","185.230.124.234"
|
||||||
|
"editorscolumn.net","89.238.138.141"
|
||||||
|
"egov-online.com","88.150.227.122"
|
||||||
|
"egov-segek.info","185.195.200.47"
|
||||||
|
"egov-sergek.info","185.195.200.47"
|
||||||
|
"ehistorybooks.com","185.109.168.29"
|
||||||
|
"ehistorybooks.com","78.142.25.30"
|
||||||
|
"elitecarz.net","5.102.147.163"
|
||||||
|
"eltiempo-news.com","38.84.132.165"
|
||||||
|
"emonitoring-paczki.pl","86.105.18.121"
|
||||||
|
"entertainmentinat.com","5.149.254.12"
|
||||||
|
"e-prokuror.info","5.102.145.72"
|
||||||
|
"e-sveiciens.com","5.149.254.14"
|
||||||
|
"eura-cell.com","88.150.227.98"
|
||||||
|
"eurasianupdate.com","88.150.227.110"
|
||||||
|
"eurosportnews.info","217.64.114.179"
|
||||||
|
"event-reg.info","185.77.131.10"
|
||||||
|
"ex-forexlive.com","5.102.147.73"
|
||||||
|
"extrahoney.net","77.245.76.109"
|
||||||
|
"ezdropshipping.net","23.107.197.107"
|
||||||
|
"fabric-shops.com","185.225.68.176"
|
||||||
|
"face-image.com","185.225.68.128"
|
||||||
|
"fadi7apress.com","5.102.145.26"
|
||||||
|
"fantastic-gardens.com","185.94.189.208"
|
||||||
|
"fashion-live.net","37.220.31.78"
|
||||||
|
"fashion-online.net","217.112.131.136"
|
||||||
|
"fashionpark.info","185.94.191.124"
|
||||||
|
"fastfixs.net","37.220.31.80"
|
||||||
|
"femmedaffaire.com","5.102.146.93"
|
||||||
|
"fiestamaghreb.com","188.215.229.216"
|
||||||
|
"files-downloads.com","217.61.96.219"
|
||||||
|
"findavoucher.online","185.198.58.196"
|
||||||
|
"findgoodfood.co","185.94.189.207"
|
||||||
|
"finditout-now.com","5.102.147.51"
|
||||||
|
"findmyass.org","8.39.147.100"
|
||||||
|
"findmyfriendsnow.com","179.43.169.41"
|
||||||
|
"findmylunch.org","38.132.118.116"
|
||||||
|
"findmymind.co","185.230.124.241"
|
||||||
|
"findmyplants.com","46.21.147.65"
|
||||||
|
"findouthere.org","83.221.132.104"
|
||||||
|
"fishingtrickz.com","185.244.150.68"
|
||||||
|
"fitness-for-ever.com","185.77.131.109"
|
||||||
|
"flights-report.com","217.112.131.42"
|
||||||
|
"flights-todays.com","88.150.227.103"
|
||||||
|
"flying-free.online","154.16.37.35"
|
||||||
|
"fofopiko.org","217.112.131.158"
|
||||||
|
"foodforyou.info","88.150.138.78"
|
||||||
|
"foodiez.online","46.183.221.187"
|
||||||
|
"foto-top.info","185.225.68.133"
|
||||||
|
"foudefoot.live","185.45.193.210"
|
||||||
|
"freedominfo.net","46.21.147.123"
|
||||||
|
"freelancers-team.org","5.102.147.106"
|
||||||
|
"free-local-events.info","185.225.68.207"
|
||||||
|
"freshandsoftbread.com","188.215.229.222"
|
||||||
|
"freshsaladtoday.com","200.7.97.254"
|
||||||
|
"fundum8430.com","163.172.140.159"
|
||||||
|
"funinat.com","46.21.147.46"
|
||||||
|
"funinthesun4u.com","185.198.58.144"
|
||||||
|
"funintheuk.com","185.117.75.228"
|
||||||
|
"funnytvclips.com","200.7.111.155"
|
||||||
|
"fwupdating.com","5.135.199.22"
|
||||||
|
"gadgetsshop.info","185.225.68.158"
|
||||||
|
"getagift.info","185.225.68.159"
|
||||||
|
"getoutofyourmind.com","5.149.254.18"
|
||||||
|
"getphotosinstant.net","5.102.147.51"
|
||||||
|
"glassesofwine.com","38.132.118.117"
|
||||||
|
"globalsupporteam.com","80.255.6.24"
|
||||||
|
"golf-news.live","167.88.5.222"
|
||||||
|
"goodcookingonline.com","5.102.146.90"
|
||||||
|
"goodflowersinside.com","37.220.31.19"
|
||||||
|
"good-games.org","80.255.3.111"
|
||||||
|
"goodthoughts4u.com","5.102.147.254"
|
||||||
|
"goroskop.co","5.149.255.19"
|
||||||
|
"gostatspro.com","81.17.30.45"
|
||||||
|
"go-trip.online","200.7.111.11"
|
||||||
|
"gulfca.net","88.150.227.115"
|
||||||
|
"gulf-financials.com","82.211.30.122"
|
||||||
|
"gulf-news.info","185.230.124.233"
|
||||||
|
"hairdresseraroundme.com","31.3.232.116"
|
||||||
|
"halal-place.com","89.249.65.234"
|
||||||
|
"handcreamforyou.com","185.81.113.105"
|
||||||
|
"handymanwood.com","77.73.65.47"
|
||||||
|
"happiness4us.com","5.149.254.20"
|
||||||
|
"hdsoccerstream.com","195.12.50.179"
|
||||||
|
"health-club.online","86.105.18.212"
|
||||||
|
"hellomydaddy.com","200.7.97.168"
|
||||||
|
"hellomymommy.com","200.7.97.167"
|
||||||
|
"highclassdining.net","109.200.24.58"
|
||||||
|
"holiday4u.work","5.102.146.184"
|
||||||
|
"homeishere.co","31.3.232.126"
|
||||||
|
"homemadecandies.net","195.12.50.177"
|
||||||
|
"host-one-more.com","185.156.173.70"
|
||||||
|
"hotelsauto.co","185.198.57.144"
|
||||||
|
"hotels-review.org","217.112.131.90"
|
||||||
|
"hotelstax.co","188.215.229.205"
|
||||||
|
"hotelsurvey.info","185.225.68.205"
|
||||||
|
"hothdwallpaperz.com","5.102.145.37"
|
||||||
|
"hotinfosource.com","217.112.131.111"
|
||||||
|
"hot-motors.com","185.117.89.231"
|
||||||
|
"housesfurniture.com","185.94.192.106"
|
||||||
|
"housing-update.com","88.150.227.117"
|
||||||
|
"howisurday.com","185.198.58.195"
|
||||||
|
"howtoexplorebirds.com","88.150.227.99"
|
||||||
|
"howtomakeavocadotoastandegg.com","84.38.129.195"
|
||||||
|
"hracingtips.com","185.117.89.220"
|
||||||
|
"icecreamlovesme.com","155.94.160.126"
|
||||||
|
"igiheonline.com","5.102.147.250"
|
||||||
|
"ilovemybeatifulnails.com","109.200.24.10"
|
||||||
|
"ilovemymilf.com","5.102.146.72"
|
||||||
|
"income-tax.online","103.199.16.153"
|
||||||
|
"indrive.info","185.225.68.141"
|
||||||
|
"ineediscounts.com","185.117.72.113"
|
||||||
|
"info24.live","185.141.27.116"
|
||||||
|
"infospotpro.com","217.112.131.20"
|
||||||
|
"infospress.com","5.102.146.241"
|
||||||
|
"insta-foto.net","185.141.26.39"
|
||||||
|
"internetmobilespeed.com","91.219.238.77"
|
||||||
|
"intim-media.net","185.225.68.126"
|
||||||
|
"investigationews.com","185.82.200.187"
|
||||||
|
"in-weather.com","103.199.17.206"
|
||||||
|
"islamic-news-today.com","103.199.16.88"
|
||||||
|
"islamiyaat.com","89.249.65.146"
|
||||||
|
"islam-today.info","185.198.58.151"
|
||||||
|
"islam-world.net","200.7.97.242"
|
||||||
|
"istgr-foto.com","185.225.68.131"
|
||||||
|
"iwantitallnow.com","173.254.248.105"
|
||||||
|
"jaimelire.net","185.183.97.196"
|
||||||
|
"just-one-left.com","46.21.147.14"
|
||||||
|
"karbalaeyat.com","191.101.31.29"
|
||||||
|
"kaspi-payment.com","185.94.191.114"
|
||||||
|
"keyindoors.com","66.85.157.84"
|
||||||
|
"kingdom-deals.com","200.7.97.212"
|
||||||
|
"kingdom-news.com","191.101.31.118"
|
||||||
|
"klientuserviss.com","185.198.58.178"
|
||||||
|
"koramaghreb.com","188.215.229.214"
|
||||||
|
"kurjerserviss.com","185.198.58.177"
|
||||||
|
"labonneforme.net","185.183.97.194"
|
||||||
|
"leadersnews.org","5.102.147.105"
|
||||||
|
"leggingsjustforyou.com","5.149.250.18"
|
||||||
|
"legyelvodas.com","185.117.89.252"
|
||||||
|
"legyelvodas.com","80.211.254.70"
|
||||||
|
"legyelvodas.net","185.117.89.253"
|
||||||
|
"leleader.org","185.106.120.35"
|
||||||
|
"leprotestant.com","185.106.120.34"
|
||||||
|
"lesbonnesaffaires.online","5.102.146.123"
|
||||||
|
"lesportail.biz","185.117.75.165"
|
||||||
|
"liam-ryan.co","185.141.26.49"
|
||||||
|
"lifedonor.net","88.150.138.111"
|
||||||
|
"like-the-rest.com","185.225.68.68"
|
||||||
|
"live-once.net","185.183.97.117"
|
||||||
|
"loading-images.com","5.102.147.172"
|
||||||
|
"loading-pag.net","8.28.175.73"
|
||||||
|
"localgreenflowers.com","185.225.68.198"
|
||||||
|
"loisiragogo.com","5.102.146.128"
|
||||||
|
"lonely-place.com","5.102.146.116"
|
||||||
|
"looking-for-two.com","5.102.145.8"
|
||||||
|
"lookitupnow.website","185.81.113.81"
|
||||||
|
"look-outsidenow.com","89.33.246.113"
|
||||||
|
"loschismescalientes.com","149.255.35.106"
|
||||||
|
"losnegocios.biz","23.227.207.174"
|
||||||
|
"lost-n-found.net","185.183.96.140"
|
||||||
|
"loveandhatenow.com","5.102.147.219"
|
||||||
|
"maghrebfoot.com","185.117.75.169"
|
||||||
|
"maghrebfunny.biz","185.94.189.214"
|
||||||
|
"mamba-live.com","217.112.131.106"
|
||||||
|
"mapupdatezone.com","185.193.38.159"
|
||||||
|
"massagetax.co","5.102.145.98"
|
||||||
|
"maymknch2026.co","188.215.229.212"
|
||||||
|
"medical-updates.com","185.77.129.103"
|
||||||
|
"megacenter.info","217.112.131.95"
|
||||||
|
"mercedesbenz-vip.com","185.77.131.103"
|
||||||
|
"mideast-today.com","88.119.179.176"
|
||||||
|
"miles-club.com","217.112.131.91"
|
||||||
|
"miralo-rapidamente.com","46.21.150.144"
|
||||||
|
"mobile-softs.com","5.149.255.18"
|
||||||
|
"mobile-update.online","185.198.57.43"
|
||||||
|
"mobile-updates.info","217.112.131.61"
|
||||||
|
"mobileweatherweb.com","185.44.105.35"
|
||||||
|
"mobi-up.net","81.92.202.215"
|
||||||
|
"moh-followup.com","88.150.227.118"
|
||||||
|
"moh-online.com","109.200.24.71"
|
||||||
|
"mondaymornings.co","176.223.111.231"
|
||||||
|
"moneycoincurrency.com","185.225.68.201"
|
||||||
|
"moneydigitalcurrency.com","185.225.68.200"
|
||||||
|
"moneyxchanges.com","109.200.24.19"
|
||||||
|
"mosque-salah.com","109.200.24.64"
|
||||||
|
"mosque-salah.net","185.225.68.5"
|
||||||
|
"mosquesfinder.com","194.187.249.106"
|
||||||
|
"motordeal.info","88.150.227.104"
|
||||||
|
"movie-tickets.online","103.199.16.11"
|
||||||
|
"moyfoto.net","185.141.26.18"
|
||||||
|
"m-resume.com","185.225.68.135"
|
||||||
|
"muftyat.com","217.112.131.16"
|
||||||
|
"muslim-world.info","200.7.97.215"
|
||||||
|
"muzicclips.com","200.7.97.248"
|
||||||
|
"mybrightidea.co","185.117.72.10"
|
||||||
|
"mydailycooking.net","89.249.65.138"
|
||||||
|
"myfiles.photos","130.185.250.199"
|
||||||
|
"myfreecharge.online","103.199.16.111"
|
||||||
|
"mygreathat.com","109.200.24.126"
|
||||||
|
"mykaspi.com","217.112.131.39"
|
||||||
|
"mylovelypet.net","62.113.232.197"
|
||||||
|
"mymobile-cell.com","217.61.4.34"
|
||||||
|
"mypostservice.online","192.52.243.110"
|
||||||
|
"my-privacy.co","103.199.16.15"
|
||||||
|
"mysadaga.com","31.3.232.108"
|
||||||
|
"myshoesforever.com","185.225.68.177"
|
||||||
|
"myshop4u.net","77.73.65.210"
|
||||||
|
"mystulchik.com","5.102.145.14"
|
||||||
|
"mysuperheadphones.co","179.43.169.8"
|
||||||
|
"mysuperheadphones.co","52.54.37.95"
|
||||||
|
"myukadventures.com","185.94.189.204"
|
||||||
|
"nation24.info","5.102.147.235"
|
||||||
|
"nationalleagues.net","5.102.146.124"
|
||||||
|
"nbrowser.org","109.200.24.102"
|
||||||
|
"newandfresh.com","185.82.202.29"
|
||||||
|
"newandroidapps.net","185.181.10.64"
|
||||||
|
"newarrivals.club","185.109.168.12"
|
||||||
|
"newarrivals.club","88.119.179.102"
|
||||||
|
"newcooking.org","109.200.24.11"
|
||||||
|
"newdailycoupons.com","88.150.227.77"
|
||||||
|
"newmodel.online","185.109.168.18"
|
||||||
|
"newmodel.online","88.119.179.168"
|
||||||
|
"newnhotapps.com","217.112.131.137"
|
||||||
|
"news-alert.org","200.7.111.124"
|
||||||
|
"newscurrent.info","185.134.29.144"
|
||||||
|
"newsdirect.online","185.243.112.77"
|
||||||
|
"news-gazette.info","88.119.179.164"
|
||||||
|
"newsofficial.info","87.121.98.39"
|
||||||
|
"newsofgames.com","154.16.37.11"
|
||||||
|
"newsofthemoment.net","38.132.118.114"
|
||||||
|
"newworld-news.com","89.40.181.124"
|
||||||
|
"nightevents.info","185.225.68.206"
|
||||||
|
"noextramoney.com","192.161.48.122"
|
||||||
|
"noloveforyou.com","38.132.114.168"
|
||||||
|
"nomorewarnow.com","185.198.58.143"
|
||||||
|
"noonstore.sale","130.185.250.201"
|
||||||
|
"noor-alhedaya.com","89.249.65.149"
|
||||||
|
"normal-brain.com","103.199.16.12"
|
||||||
|
"nosalternatives.com","185.141.27.123"
|
||||||
|
"nothernkivu.com","89.40.181.125"
|
||||||
|
"noti-global.com","38.84.132.168"
|
||||||
|
"noti-hot.com","8.28.175.78"
|
||||||
|
"notresante-infos.com","5.102.145.169"
|
||||||
|
"nouveau-president.com","185.106.120.246"
|
||||||
|
"nouvelles247.com","200.7.97.213"
|
||||||
|
"novosti247.com","109.200.24.32"
|
||||||
|
"nuevaidea.co","173.254.248.115"
|
||||||
|
"odnoklass-profile.com","185.225.68.132"
|
||||||
|
"offresimmobilier.com","5.102.145.12"
|
||||||
|
"ok-group.org","185.225.68.134"
|
||||||
|
"one-isnot-enough.com","5.102.147.13"
|
||||||
|
"onetreeinheaven.com","37.220.31.107"
|
||||||
|
"online-dailynews.com","88.150.227.125"
|
||||||
|
"onlinefreework.com","200.7.105.39"
|
||||||
|
"onlineshopzm.com","185.225.68.60"
|
||||||
|
"onlygossip.info","185.117.89.198"
|
||||||
|
"only-news.net","5.102.147.162"
|
||||||
|
"onlytoday.biz","109.200.24.104"
|
||||||
|
"onthegoodtime.com","185.225.68.69"
|
||||||
|
"operatingnews.com","46.21.147.173"
|
||||||
|
"orange-updates.com","5.104.105.200"
|
||||||
|
"ourorder.info","185.225.68.127"
|
||||||
|
"outletsaroundme.com","78.142.25.37"
|
||||||
|
"outletstore.tech","87.121.98.38"
|
||||||
|
"papers2go.co","176.223.111.206"
|
||||||
|
"park4free.info","185.144.83.116"
|
||||||
|
"passwd.privo7799add.net","188.40.155.240"
|
||||||
|
"pastesbin.com","185.195.200.56"
|
||||||
|
"pathtogo.net","5.149.255.3"
|
||||||
|
"pay-city.com","154.16.37.105"
|
||||||
|
"paynfly.info","185.144.83.114"
|
||||||
|
"paywithcrytpo.com","200.7.111.154"
|
||||||
|
"phonering4you.com","5.149.250.19"
|
||||||
|
"photo-my.net","5.149.255.16"
|
||||||
|
"pickcard.info","5.102.147.138"
|
||||||
|
"picture4us.com","46.183.221.149"
|
||||||
|
"pi.license-updater.com","91.219.28.21"
|
||||||
|
"pine-sales.com","92.222.208.251"
|
||||||
|
"pizzatoyourplace.com","5.149.249.19"
|
||||||
|
"playwithusonline.com","200.7.111.102"
|
||||||
|
"pochta-info.com","185.29.11.203"
|
||||||
|
"politica504.com","149.255.36.132"
|
||||||
|
"politicalpress.org","5.102.145.99"
|
||||||
|
"politiques-infos.info","5.102.145.17"
|
||||||
|
"postainf.net","200.7.98.117"
|
||||||
|
"posta.news","185.29.11.200"
|
||||||
|
"ppcisdead.com","88.150.189.121"
|
||||||
|
"prikol-girls.com","5.149.249.189"
|
||||||
|
"promosdereve.com","88.119.179.105"
|
||||||
|
"promotionlove.co","185.117.75.165"
|
||||||
|
"promotionlove.co","185.94.192.101"
|
||||||
|
"puffyteddybear.com","84.38.130.107"
|
||||||
|
"purple-enveloppe.com","66.85.157.71"
|
||||||
|
"quitmyjob.xyz","103.199.16.47"
|
||||||
|
"quran-quote.com","84.200.32.211"
|
||||||
|
"rainingcats.net","38.132.118.110"
|
||||||
|
"readingbooksnow.com","109.200.24.7"
|
||||||
|
"regionews.net","5.102.145.90"
|
||||||
|
"reklamas.info","5.149.254.2"
|
||||||
|
"rentmotors.net","88.150.138.99"
|
||||||
|
"research-archive.com","5.102.146.59"
|
||||||
|
"reseausocialsolutions.co","185.82.200.143"
|
||||||
|
"reservationszone.com","88.150.138.85"
|
||||||
|
"reseufun.com","188.215.229.215"
|
||||||
|
"resolutionsbox.com","38.132.118.107"
|
||||||
|
"restaurantsstar.com","185.225.68.75"
|
||||||
|
"rewards-club.info","176.223.111.137"
|
||||||
|
"rockmusic4u.com","185.82.200.164"
|
||||||
|
"rockstarpony.com","94.177.234.8"
|
||||||
|
"rosegoldjewerly.com","185.195.200.44"
|
||||||
|
"rosesforus.com","88.150.189.111"
|
||||||
|
"russian4u.net","95.213.193.40"
|
||||||
|
"saladsaroundme.com","89.33.246.119"
|
||||||
|
"same-old.net","37.220.31.46"
|
||||||
|
"savemoretime.co","185.225.68.64"
|
||||||
|
"saveurday.net","37.72.175.179"
|
||||||
|
"securesmsing.com","109.200.24.14"
|
||||||
|
"sergek.info","185.195.200.46"
|
||||||
|
"services-sync.com","46.21.147.237"
|
||||||
|
"service-update.online","185.94.191.59"
|
||||||
|
"shia-voice.com","52.54.37.95"
|
||||||
|
"shia-voice.com","89.249.65.148"
|
||||||
|
"shoppingdailydeals.net","109.200.24.18"
|
||||||
|
"shortfb.com","37.220.31.108"
|
||||||
|
"shuturl.com","185.117.72.117"
|
||||||
|
"signpetition.co","200.7.111.125"
|
||||||
|
"site-redirecting.com","109.200.24.20"
|
||||||
|
"smarttarfi.com","45.76.42.111"
|
||||||
|
"snoweverywhere.com","46.21.147.21"
|
||||||
|
"soccerstreamingstars.com","185.183.96.131"
|
||||||
|
"social-life.info","185.183.96.131"
|
||||||
|
"somuchrain.com","5.102.145.39"
|
||||||
|
"so-this-is.com","159.89.193.231"
|
||||||
|
"specialgifts4all.com","200.7.97.225"
|
||||||
|
"sportupdates.info","185.225.68.86"
|
||||||
|
"sportupdates.online","89.33.246.118"
|
||||||
|
"sputnik-news.info","185.198.58.182"
|
||||||
|
"starbuckscoffeeweb.com","217.112.131.109"
|
||||||
|
"stars4sale.co","185.225.68.65"
|
||||||
|
"start2playnow.com","5.102.145.248"
|
||||||
|
"starting-from0.com","185.94.189.219"
|
||||||
|
"statisticsdb.net","185.93.183.231"
|
||||||
|
"stopmysms.com","191.101.31.222"
|
||||||
|
"stopsms.biz","185.198.58.154"
|
||||||
|
"sunday-deals.com","88.119.179.169"
|
||||||
|
"supportonline4me.com","185.80.53.199"
|
||||||
|
"surprising-sites.com","217.112.131.67"
|
||||||
|
"sync-cdn.com","185.183.96.150"
|
||||||
|
"syncmap.org","185.117.89.145"
|
||||||
|
"tablereservation.info","109.200.24.66"
|
||||||
|
"takethat.co","209.250.247.96"
|
||||||
|
"tastyteaflavors.com","5.149.248.27"
|
||||||
|
"telecom-info.com","185.225.68.61"
|
||||||
|
"tengrinews.co","81.95.5.168"
|
||||||
|
"theastafrican.com","185.156.173.104"
|
||||||
|
"thebestclassicalmusic.net","217.64.113.250"
|
||||||
|
"thecoffeeilove.com","185.225.68.199"
|
||||||
|
"thehighesttemple.com","185.183.107.49"
|
||||||
|
"thehoteloffers.com","185.225.68.203"
|
||||||
|
"the-only-way-out.com","185.230.124.228"
|
||||||
|
"theshopclub.org","185.225.68.160"
|
||||||
|
"thespaclub.net","88.150.138.83"
|
||||||
|
"theway2get.com","88.119.179.156"
|
||||||
|
"ticket-aviata.info","185.94.191.14"
|
||||||
|
"tiketon.info","185.94.191.120"
|
||||||
|
"tlgr-me.org","185.225.68.130"
|
||||||
|
"tobepure.com","88.119.179.205"
|
||||||
|
"tommyfame.com","77.245.76.110"
|
||||||
|
"top100vidz.com","62.113.232.207"
|
||||||
|
"top10gifts4men.com","5.102.145.180"
|
||||||
|
"top10leadsgen.com","200.7.97.230"
|
||||||
|
"topbraingames4u.com","185.183.96.169"
|
||||||
|
"topten-news.info","185.94.191.67"
|
||||||
|
"touristvaca.com","185.198.57.200"
|
||||||
|
"tradeexchanging.com","81.95.5.164"
|
||||||
|
"traffic-pay.com","88.150.227.119"
|
||||||
|
"traffic-updates.info","217.112.131.156"
|
||||||
|
"travel-foryou.online","5.102.145.113"
|
||||||
|
"travelight.online","81.95.5.147"
|
||||||
|
"traveltogether.link","5.102.147.114"
|
||||||
|
"tricksinswiss.com","89.238.138.136"
|
||||||
|
"trililihihi.com","5.102.145.14"
|
||||||
|
"t-support.net","109.200.24.15"
|
||||||
|
"turismo-aqui.com","38.84.132.172"
|
||||||
|
"tvshowcusting.com","31.184.198.150"
|
||||||
|
"un-limitededitions.com","185.225.68.97"
|
||||||
|
"unsubscribed.co","191.101.31.213"
|
||||||
|
"untoldinfo.net","5.102.147.41"
|
||||||
|
"updateapps.net","80.255.3.107"
|
||||||
|
"upgrade-sim-card.com","217.112.131.150"
|
||||||
|
"upload-now.net","88.150.227.116"
|
||||||
|
"uptownfun.co","46.246.1.12"
|
||||||
|
"urbestfriends.com","77.73.65.199"
|
||||||
|
"url-redirect.com","66.172.10.189"
|
||||||
|
"urlsync.com","185.141.25.210"
|
||||||
|
"urspanishteacher.net","95.213.188.35"
|
||||||
|
"vanillaandcream.com","77.245.76.113"
|
||||||
|
"vastdealsnow.com","191.101.31.214"
|
||||||
|
"verify-app.online","185.82.202.42"
|
||||||
|
"videosdownload.co","5.102.146.66"
|
||||||
|
"vider-image.com","185.225.68.123"
|
||||||
|
"viedechretien.org","5.102.145.122"
|
||||||
|
"vie-en-islam.com","5.102.147.234"
|
||||||
|
"viewhdvideos.com","200.7.111.118"
|
||||||
|
"vipmasajes.com","38.84.132.174"
|
||||||
|
"viva-droid.com","5.102.146.64"
|
||||||
|
"vivrechezsoi.info","5.102.147.236"
|
||||||
|
"vkan-profile.com","185.225.68.129"
|
||||||
|
"volcanosregion.com","5.102.146.85"
|
||||||
|
"waffleswithnutella.com","66.85.157.83"
|
||||||
|
"watersport4u.net","77.73.68.160"
|
||||||
|
"weather4free.com","88.119.179.134"
|
||||||
|
"weatherapi.co","206.189.51.151"
|
||||||
|
"web-config.org","109.200.24.121"
|
||||||
|
"websites4yourhost.com","185.234.73.10"
|
||||||
|
"web-viewer.online","217.112.131.189"
|
||||||
|
"welovebigcakes.com","185.117.75.82"
|
||||||
|
"welovelollipops.com","185.45.192.144"
|
||||||
|
"welovemorningcoffees.com","179.43.169.36"
|
||||||
|
"wewantflowersnow.com","185.225.68.3"
|
||||||
|
"whatcanidowithbirds.com","88.150.189.106"
|
||||||
|
"whats-new.org","46.22.223.252"
|
||||||
|
"whereismybonus.com","5.149.252.241"
|
||||||
|
"whereismyhand.com","38.132.114.167"
|
||||||
|
"whereisthehat.com","8.28.175.71"
|
||||||
|
"windyone.net","200.7.105.24"
|
||||||
|
"wintertimes.co","46.246.1.14"
|
||||||
|
"wonderfulinsights.com","217.112.131.207"
|
||||||
|
"woodhome4u.com","77.73.65.48"
|
||||||
|
"xchange4u.net","185.183.107.44"
|
||||||
|
"xchangerates247.net","185.183.96.139"
|
||||||
|
"xn--nissn-3jc.com","89.238.132.249"
|
||||||
|
"xn--noki-t5b.com","86.105.18.11"
|
||||||
|
"xn--telegrm-qbd.com","185.225.68.136"
|
||||||
|
"xtremelivesupport.com","5.102.146.237"
|
||||||
|
"youcantpass.com","37.220.31.28"
|
||||||
|
"yourbestclothes.com","46.21.147.197"
|
||||||
|
"yourbestefforts.com","46.21.147.196"
|
||||||
|
"yourbestvaca.com","104.216.8.38"
|
||||||
|
"yourgreatestsmartphone.com","88.150.227.83"
|
||||||
|
"yourhotelreservation.info","185.225.68.204"
|
||||||
|
"yummyfoodallover.com","37.72.175.143"
|
||||||
|
"zednewszm.com","217.64.113.251"
|
||||||
|
"zm-banks.com","217.64.113.252"
|
||||||
|
"zm-banks.com","89.43.60.103"
|
||||||
|
"zm-weather.com","89.43.60.103"
|
||||||
|
"zsports-info.com","89.43.60.104"
|
||||||
|
216
data/ioc/spyware/amnesty/2018-12-19_best_practice/domains.txt
Normal file
216
data/ioc/spyware/amnesty/2018-12-19_best_practice/domains.txt
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
account-facebook.com
|
||||||
|
account-mysecure.com
|
||||||
|
account-privacy.com
|
||||||
|
account-privcay.com
|
||||||
|
account-servics.com
|
||||||
|
account-servicse.com
|
||||||
|
accounts-mysecure.com
|
||||||
|
accounts-mysecures.com
|
||||||
|
accounts-secuirty.com
|
||||||
|
accounts-securtiy.com
|
||||||
|
accounts-servicse.com
|
||||||
|
accounts-settings.com
|
||||||
|
alert-newmail02.pro
|
||||||
|
application-secure.com
|
||||||
|
applications-secure.com
|
||||||
|
applications-security.com
|
||||||
|
authorize-myaccount.com
|
||||||
|
blu142-live.com
|
||||||
|
blu160-live.com
|
||||||
|
blu162-live.com
|
||||||
|
blu165-live.com
|
||||||
|
blu167-live.com
|
||||||
|
blu175-live.com
|
||||||
|
blu176-live.com
|
||||||
|
blu178-live.com
|
||||||
|
blu179-live.com
|
||||||
|
blu187-live.com
|
||||||
|
browser-checked.com
|
||||||
|
browsering-check.com
|
||||||
|
browsering-checked.com
|
||||||
|
browsers-checked.com
|
||||||
|
browser-secures.com
|
||||||
|
browsers-secure.com
|
||||||
|
browsers-secures.com
|
||||||
|
bul174-live.com
|
||||||
|
check-activities.com
|
||||||
|
check-browser.com
|
||||||
|
check-browsering.com
|
||||||
|
check-browsers.com
|
||||||
|
checking-browser.com
|
||||||
|
connected-myaccount.com
|
||||||
|
connect-myaccount.com
|
||||||
|
data-center17.website
|
||||||
|
documents-view.com
|
||||||
|
documents-viewer.com
|
||||||
|
document-viewer.com
|
||||||
|
go2myprofile.info
|
||||||
|
go2profiles.info
|
||||||
|
googledriveservice.com
|
||||||
|
gotolinks.top
|
||||||
|
goto-newmail01.pro
|
||||||
|
idmsa-login.com
|
||||||
|
inbox01-email.pro
|
||||||
|
inbox01-gomail.com
|
||||||
|
inbox01-mails.icu
|
||||||
|
inbox01-mails.pro
|
||||||
|
inbox02-accounts.pro
|
||||||
|
inbox02-mails.icu
|
||||||
|
inbox02-mails.pro
|
||||||
|
inbox03-accounts.pro
|
||||||
|
inbox03-mails.icu
|
||||||
|
inbox03-mails.pro
|
||||||
|
inbox04-accounts.pro
|
||||||
|
inbox04-mails.icu
|
||||||
|
inbox04-mails.pro
|
||||||
|
inbox05-accounts.pro
|
||||||
|
inbox05-mails.icu
|
||||||
|
inbox05-mails.pro
|
||||||
|
inbox06-accounts.pro
|
||||||
|
inbox06-mails.pro
|
||||||
|
inbox07-accounts.pro
|
||||||
|
inbox101-account.com
|
||||||
|
inbox101-accounts.com
|
||||||
|
inbox101-accounts.info
|
||||||
|
inbox101-accounts.pro
|
||||||
|
inbox101-live.com
|
||||||
|
inbox102-account.com
|
||||||
|
inbox102-live.com
|
||||||
|
inbox102-mail.pro
|
||||||
|
inbox103-account.com
|
||||||
|
inbox103-mail.pro
|
||||||
|
inbox104-accounts.pro
|
||||||
|
inbox105-accounts.pro
|
||||||
|
inbox106-accounts.pro
|
||||||
|
inbox107-accounts.pro
|
||||||
|
inbox108-accounts.pro
|
||||||
|
inbox109-accounts.pro
|
||||||
|
inbox169-live.com
|
||||||
|
inbox171-live.com
|
||||||
|
inbox171-live.pro
|
||||||
|
inbox172-live.com
|
||||||
|
inbox173-live.com
|
||||||
|
inbox174-live.com
|
||||||
|
inbox-live.com
|
||||||
|
inbox-mail01.pro
|
||||||
|
inbox-mail02.pro
|
||||||
|
inbox-myaccount.com
|
||||||
|
mail01-inbox.pro
|
||||||
|
mail02-inbox.com
|
||||||
|
mail02-inbox.pro
|
||||||
|
mail03-inbox.com
|
||||||
|
mail03-inbox.pro
|
||||||
|
mail04-inbox.com
|
||||||
|
mail04-inbox.pro
|
||||||
|
mail05-inbox.pro
|
||||||
|
mail06-inbox.pro
|
||||||
|
mail07-inbox.pro
|
||||||
|
mail08-inbox.pro
|
||||||
|
mail09-inbox.pro
|
||||||
|
mail101-inbox.com
|
||||||
|
mail101-inbox.pro
|
||||||
|
mail103-inbox.com
|
||||||
|
mail103-inbox.pro
|
||||||
|
mail104-inbox.com
|
||||||
|
mail104-inbox.pro
|
||||||
|
mail105-inbox.com
|
||||||
|
mail105-inbox.pro
|
||||||
|
mail106-inbox.pro
|
||||||
|
mail107-inbox.pro
|
||||||
|
mail108-inbox.pro
|
||||||
|
mail109-inbox.pro
|
||||||
|
mail10-inbox.pro
|
||||||
|
mail110-inbox.pro
|
||||||
|
mail12-inbox.pro
|
||||||
|
mail13-inbox.pro
|
||||||
|
mail14-inbox.pro
|
||||||
|
mail15-inbox.pro
|
||||||
|
mail16-inbox.pro
|
||||||
|
mail17-inbox.pro
|
||||||
|
mail18-inbox.pro
|
||||||
|
mail19-inbox.pro
|
||||||
|
mail201-inbox.pro
|
||||||
|
mail20-inbox.pro
|
||||||
|
mail21-inbox.pro
|
||||||
|
mail-inbox.pro
|
||||||
|
mailings-noreply.pro
|
||||||
|
myaccountes-setting.com
|
||||||
|
myaccountes-settings.com
|
||||||
|
myaccount-inbox.pro
|
||||||
|
myaccount-logins.com
|
||||||
|
myaccount-redirects.com
|
||||||
|
myaccount-setting.com
|
||||||
|
myaccount-settinges.com
|
||||||
|
myaccount-setup1.com
|
||||||
|
myaccount-setup.com
|
||||||
|
myaccount-setups.com
|
||||||
|
myaccounts-login.com
|
||||||
|
myaccounts-profile.com
|
||||||
|
myaccounts-secuirty.com
|
||||||
|
myaccounts-secures.com
|
||||||
|
myaccounts-settings.com
|
||||||
|
myaccounts-settinq.com
|
||||||
|
myaccounts-settinqes.com
|
||||||
|
myaccounts-transfer.com
|
||||||
|
myaccount-transfer.com
|
||||||
|
myaccount.verification-approve.com
|
||||||
|
myaccount.verification-approves.com
|
||||||
|
myaccuont-settings.com
|
||||||
|
mysecure-account.com
|
||||||
|
mysecure-accounts.com
|
||||||
|
mysecures-accounts.com
|
||||||
|
newinbox01-accounts.pro
|
||||||
|
newinbox01-mails.pro
|
||||||
|
newinbox02-accounts.pro
|
||||||
|
newinbox03-accounts.pro
|
||||||
|
newinbox05-accounts.pro
|
||||||
|
newinbox06-accounts.pro
|
||||||
|
newinbox07-accounts.pro
|
||||||
|
newinbox08-accounts.pro
|
||||||
|
newinbox-account.info
|
||||||
|
newinbox-accounts.pro
|
||||||
|
noreply.ac
|
||||||
|
noreply-accounts.site
|
||||||
|
noreply-mailer.pro
|
||||||
|
noreply-mailers.com
|
||||||
|
noreply-mailers.pro
|
||||||
|
noreply-myaccount.com
|
||||||
|
privacy-myaccount.com
|
||||||
|
privcay-setting.com
|
||||||
|
profile-settings.com
|
||||||
|
protonemail.ch
|
||||||
|
recovery-settings.info
|
||||||
|
redirection-login.com
|
||||||
|
redirection-logins.com
|
||||||
|
redirections-login.com
|
||||||
|
redirections-login.info
|
||||||
|
redirects-myaccount.com
|
||||||
|
royalk-uae.com
|
||||||
|
secure-browsre.com
|
||||||
|
secures-applications.com
|
||||||
|
secures-browser.com
|
||||||
|
secure-settinqes.com
|
||||||
|
secures-inbox.com
|
||||||
|
secures-inbox.info
|
||||||
|
securesmails-alerts.pro
|
||||||
|
secures-settinqes.com
|
||||||
|
secures-transfer.com
|
||||||
|
secures-transfers.com
|
||||||
|
security-settinges.com
|
||||||
|
securtiy-settings.com
|
||||||
|
services-securtiy.com
|
||||||
|
setting-privcay.com
|
||||||
|
settings-secuity.com
|
||||||
|
settinq-myaccounts.com
|
||||||
|
settinqs-myaccount.com
|
||||||
|
thx-me.website
|
||||||
|
transfer-click.com
|
||||||
|
transfer-clicks.com
|
||||||
|
truecaller.services
|
||||||
|
tutanota.org
|
||||||
|
urllink.xyz
|
||||||
|
verification-approve.com
|
||||||
|
verification-approves.com
|
||||||
|
verifications-approve.com
|
||||||
|
xn--mxamya0a.ccn
|
||||||
|
yahoo.llc
|
||||||
34
data/ioc/spyware/amnesty/2019-03-06_egypt_oauth/domains.txt
Normal file
34
data/ioc/spyware/amnesty/2019-03-06_egypt_oauth/domains.txt
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
account-login.site
|
||||||
|
adminmail.online
|
||||||
|
email-secure.online
|
||||||
|
login-acc.email
|
||||||
|
login-network.space
|
||||||
|
login-service.email
|
||||||
|
login-service.online
|
||||||
|
m4r3zb2ci0-noreply.pw
|
||||||
|
mail-log.pw
|
||||||
|
mail-secure.online
|
||||||
|
mail-secure.tech
|
||||||
|
mail-verify.live
|
||||||
|
maillogin.pw
|
||||||
|
mailverify.live
|
||||||
|
my-mail-inbox.com
|
||||||
|
redirect-secure.pw
|
||||||
|
safebrowsing.website
|
||||||
|
secure-accounts.online
|
||||||
|
secure-conn.pw
|
||||||
|
secure-email.site
|
||||||
|
secure-emails.online
|
||||||
|
secure-login.services
|
||||||
|
service-login.online
|
||||||
|
signin-aouth2.pw
|
||||||
|
signin-verify.pw
|
||||||
|
user-members.pro
|
||||||
|
verify-mail.pro
|
||||||
|
verifymail.live
|
||||||
|
vers.pw
|
||||||
|
weblive.pw
|
||||||
|
whatsuppweb.me
|
||||||
|
wi-fi.email
|
||||||
|
www.secure-email.site
|
||||||
|
xbz.pw
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
accounts@m4r3zb2ci0-noreply.pw
|
||||||
|
noreply-team.googelsupport@verify-mail.pro
|
||||||
|
secuirty.center.google.accounts@m4r3zb2ci0-noreply.pw
|
||||||
|
support-team@m4r3zb2ci0-noreply.pw
|
||||||
|
mails@m4r3zb2ci0-noreply.pw
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
srf-goolge.site
|
||||||
|
gmailusercontent.site
|
||||||
|
protect-outlook.com
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
admin@microsoftstore.com
|
||||||
|
google.com@localhost
|
||||||
|
google@script
|
||||||
|
noreply750@mailgoogle.ccm
|
||||||
|
noreply@gmailusercontent.site
|
||||||
|
noreply@mailgoogle.ccm
|
||||||
|
googlecommunityteam-noreply@srf-goolge.site
|
||||||
|
noreply-accounts@goolge.cm
|
||||||
|
noreply@accounts-goolge.com
|
||||||
|
noreply@accounts-goolgeemail.site
|
||||||
|
accounts-noreply@google.ccm
|
||||||
|
noreply-accounts@google.ccm
|
||||||
|
alerts@valabs.info
|
||||||
|
google@noreply-accounts.com
|
||||||
|
no-reply@goolge.email
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
stopsms.biz
|
||||||
|
revolution-news.co
|
||||||
|
videosdownload.co
|
||||||
|
infospress.com
|
||||||
|
business-today.info
|
||||||
|
hmizat.co
|
||||||
|
free247downloads.com
|
||||||
|
bun54l2b67.get1tn0w.free247downloads.com
|
||||||
|
|
||||||
71
data/ioc/spyware/amnesty/2020-03-12_uzbekistan/domains.txt
Normal file
71
data/ioc/spyware/amnesty/2020-03-12_uzbekistan/domains.txt
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
acccountsgoog1e.com
|
||||||
|
account-mail.info
|
||||||
|
accountapp.xyz
|
||||||
|
accountsgoog1e.com
|
||||||
|
alexandr01299.xyz
|
||||||
|
auth-google.site
|
||||||
|
auth-mail.email
|
||||||
|
badoo-account-security.com
|
||||||
|
chrome-redirect.top
|
||||||
|
com-auth.site
|
||||||
|
com-enter.site
|
||||||
|
com-gm.site
|
||||||
|
com-google.site
|
||||||
|
check-activity.com.ru
|
||||||
|
comericac.com
|
||||||
|
desktest1.xyz
|
||||||
|
desktest5.xyz
|
||||||
|
desktest9.xyz
|
||||||
|
dokerest.xyz
|
||||||
|
dokertest.xyz
|
||||||
|
droinjoin.xyz
|
||||||
|
emails-support.site
|
||||||
|
fedortest.xyz
|
||||||
|
freekremlin.com
|
||||||
|
frosdank.com
|
||||||
|
frostdank.com
|
||||||
|
garant-help.com
|
||||||
|
gmail-warning.top
|
||||||
|
google-activity.pw
|
||||||
|
gvoice8765.online
|
||||||
|
hpphhpph.com
|
||||||
|
id-support-email.com
|
||||||
|
joindroin.xyz
|
||||||
|
lamatrest.xyz
|
||||||
|
mail-auth.email
|
||||||
|
mail-auth.online
|
||||||
|
mail-google.email
|
||||||
|
my-short.com
|
||||||
|
myaccount-support.top
|
||||||
|
mycabinet.xyz
|
||||||
|
mynavvfedera1.org
|
||||||
|
mynavyfedera1.org
|
||||||
|
mynavyfedral.org
|
||||||
|
mynevyfedera1.org
|
||||||
|
navyfedara1.org
|
||||||
|
navyfedera1.com
|
||||||
|
navyfedera1.org
|
||||||
|
navyfederai.org
|
||||||
|
nayfedera1.org
|
||||||
|
nevyfedera1.org
|
||||||
|
nitroqensports.eu
|
||||||
|
nsdns.xyz
|
||||||
|
poxypoxy.xyz
|
||||||
|
rc-room.com
|
||||||
|
support-emails.host
|
||||||
|
t1bank.xyz
|
||||||
|
testdhome1.xyz
|
||||||
|
testdhome4.xyz
|
||||||
|
testdom1.xyz
|
||||||
|
testdom3.xyz
|
||||||
|
testfor7.xyz
|
||||||
|
vkontak1e.com
|
||||||
|
voice98765.online
|
||||||
|
xn--avyfedera-yubm.org
|
||||||
|
xn--bckchain-v3a30f.com
|
||||||
|
xn--blckchain-17c.com
|
||||||
|
xn--blockcain-lmb.com
|
||||||
|
xn--mynavyfedera-occ.org
|
||||||
|
xn--navyfderal-36a.com
|
||||||
|
xn--navyfedera-j0b.org
|
||||||
|
yandex-account-security.com
|
||||||
22
data/ioc/spyware/amnesty/2020-03-12_uzbekistan/ips.txt
Normal file
22
data/ioc/spyware/amnesty/2020-03-12_uzbekistan/ips.txt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
51.15.100.189
|
||||||
|
51.15.114.133
|
||||||
|
51.15.134.115
|
||||||
|
51.15.253.174
|
||||||
|
51.15.116.52
|
||||||
|
212.47.244.155
|
||||||
|
167.99.208.115
|
||||||
|
142.93.219.124
|
||||||
|
51.158.108.37
|
||||||
|
51.158.168.110
|
||||||
|
51.83.97.40
|
||||||
|
134.209.86.7
|
||||||
|
68.183.66.192
|
||||||
|
167.71.93.148
|
||||||
|
134.209.193.198
|
||||||
|
217.61.0.148
|
||||||
|
165.227.153.226
|
||||||
|
68.183.49.14
|
||||||
|
45.86.65.167
|
||||||
|
208.68.39.124
|
||||||
|
51.254.221.192
|
||||||
|
217.61.17.175
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
279c70f2da2c361b62353bdaa388372adc14929b3be83571b1347d890fd6279c
|
||||||
|
902c5f46ac101b6f30032d4c5c86ecec115add3605fb0d66057130b6e11c57e6
|
||||||
|
ba1990b5e38191512718180d0de1ad2123e18330449b8c12877c4db60aeb05e4
|
||||||
3
data/ioc/spyware/amnesty/2020-06-15_india/README.md
Normal file
3
data/ioc/spyware/amnesty/2020-06-15_india/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# India: Human Rights Defenders Targeted by a Coordinated Spyware Operation
|
||||||
|
|
||||||
|
Indicators of the report [India: Human Rights Defenders Targeted by a Coordinated Spyware Operation](https://www.amnesty.org/en/latest/research/2020/06/india-human-rights-defenders-targeted-by-a-coordinated-spyware-operation/)
|
||||||
3
data/ioc/spyware/amnesty/2020-06-15_india/domains.txt
Normal file
3
data/ioc/spyware/amnesty/2020-06-15_india/domains.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
researchplanet.zapto.org
|
||||||
|
socialstatistics.zapto.org
|
||||||
|
duniaenewsportal.ddns.net
|
||||||
5
data/ioc/spyware/amnesty/2020-06-15_india/emails.txt
Normal file
5
data/ioc/spyware/amnesty/2020-06-15_india/emails.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
jagdish.meshraam@gmail.com
|
||||||
|
drsnehapatil64@gmail.com
|
||||||
|
sinhamuskaan04@gmail.com
|
||||||
|
jennifergonzales789@gmail.com
|
||||||
|
payalshastri79@gmail.com
|
||||||
5
data/ioc/spyware/amnesty/2020-06-15_india/ips.txt
Normal file
5
data/ioc/spyware/amnesty/2020-06-15_india/ips.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
185.82.202.155
|
||||||
|
185.117.66.188
|
||||||
|
185.117.74.47
|
||||||
|
185.117.74.28
|
||||||
|
185.45.193.14
|
||||||
12
data/ioc/spyware/amnesty/2020-06-15_india/sha256.txt
Normal file
12
data/ioc/spyware/amnesty/2020-06-15_india/sha256.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
e3dea449bf74434ee1c9cdc04ca68b8f3c9bac357768e07df303433f257d3b9a
|
||||||
|
21d24e08889f75461a7ce6f21fc612a701bca35da1a218cf3cdd6e23f613bb4d
|
||||||
|
16b5c74fb55f52ae0ae4328f65b2bf3bbe3e5ee34268c1d32a247a0a1dfa3186
|
||||||
|
5a4aca57541954195953066a4be96dfb19776ba099d72f8f1d3677581594606e
|
||||||
|
11cef331557eb693e718d27b6a7211a98d3982117a03ec1491db8098ea3cec00
|
||||||
|
88b92d985b7d616c93c391731c1e4a6d3c8323fdcbf31cfc4d340e27253913a7
|
||||||
|
b1b6e133aa320669c772ec7e5fd6fbe4cb3edca13ad5351f14df3c1f13939d09
|
||||||
|
ea5f37e1feab670171963aa83b235c772202b2d4bb7289dd45302c3851dbd6f9
|
||||||
|
de302a61e5f07b0e65753355d44d22181a2742ac3a92aa058bdcd00cc4dab788
|
||||||
|
b09ca9d48a0455ed5e02a56aabeb397c41fb63320244719749e0741da72e79c4
|
||||||
|
095ec879f323a0a3eceb97013125880d49ac701eef568e3b010fdddb1333941f
|
||||||
|
ac4d5d938009fd44b2f7587986862ab2278887a17d32f748278445b625b3efd9
|
||||||
25
data/ioc/spyware/amnesty/2020-09-25_finfisher/README.md
Normal file
25
data/ioc/spyware/amnesty/2020-09-25_finfisher/README.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Technical Report
|
||||||
|
|
||||||
|
This repository contains indicators of compromise and scripts related to the report [German-made FinSpy spyware found in Egypt, and Mac and Linux versions revealed ](https://www.amnesty.org/en/latest/research/2020/09/german-made-finspy-spyware-found-in-egypt-and-mac-and-linux-versions-revealed/) published by Amnesty Tech in September 2020.
|
||||||
|
|
||||||
|
Indicators:
|
||||||
|
|
||||||
|
* `domains.txt` : domains identified
|
||||||
|
* `ips.txt` : IPv4 addresses identified
|
||||||
|
* `sha256.csv` : sha256 of samples identified
|
||||||
|
* `rules.yar` : Yara rules
|
||||||
|
|
||||||
|
Tools in the script folder:
|
||||||
|
|
||||||
|
* `decode_modules.py` : decode encrypted modules of Linux and MacOs
|
||||||
|
* `read_config.py` : read FinSpy configuration
|
||||||
|
* `android/extract_config.py` : extract configuration from FinSpy Android samples
|
||||||
|
* `android/java_parser.py` : extract obfuscated strings from decompiled java code
|
||||||
|
* `android/string_decoder.py` : decode obfuscated strings
|
||||||
|
* `linux/extract_config.py` : extract configuration files from a Linux FinSpy installer
|
||||||
|
* `cobaltstrike/cobaltstrike_config.py`: extract the configuration of a Cobalt Strike payload
|
||||||
|
* `cobaltstrike/cobaltstrike_decode.py`: decode an obfuscated Cobalt Strike payload
|
||||||
|
|
||||||
|
Additional files:
|
||||||
|
|
||||||
|
* `android_tlv_list.csv` : list of TLV values extracted from the Android sample
|
||||||
@@ -0,0 +1,813 @@
|
|||||||
|
Group ID,Group name,TLV value,Known TLV,TLV name,Function
|
||||||
|
64,drives all get,131488,✔,TlvTypeGetAllDrivesRequest,
|
||||||
|
64,drives all get,131744,✔,TlvTypeGetAllDrivesReply,
|
||||||
|
66,contents folder get,135328,✔,TlvTypeGetFolderContentsRequest,
|
||||||
|
66,contents folder get,135584,✔,TlvTypeGetFolderContentsReply,
|
||||||
|
66,contents folder get,135840,✔,TlvTypeGetFolderContentsNext,
|
||||||
|
66,contents folder get,136096,✔,TlvTypeGetFolderContentsEnd,
|
||||||
|
68,download file,139424,✔,TlvTypeDownloadFileRequest,
|
||||||
|
68,download file,139680,✔,TlvTypeCancelDownloadFileRequest,
|
||||||
|
68,download file,139936,✔,TlvTypeDownloadFileReply,
|
||||||
|
68,download file,140192,✔,TlvTypeDownloadFileNext,
|
||||||
|
68,download file,140448,✔,TlvTypeDownloadFileEnd,
|
||||||
|
68,download file,140704,✔,TlvTypeCancelDownloadFileReply,
|
||||||
|
70,upload file,143520,✔,TlvTypeUploadFileRequest,
|
||||||
|
70,upload file,143776,✔,TlvTypeCancelUploadFileRequest,
|
||||||
|
70,upload file,144032,✔,TlvTypeUploadFileReply,
|
||||||
|
70,upload file,144288,✔,TlvTypeUploadFileNext,
|
||||||
|
70,upload file,144544,✔,TlvTypeUploadFileEnd,
|
||||||
|
70,upload file,144800,✔,TlvTypeUploadFileCompleted,
|
||||||
|
70,upload file,145056,✔,TlvTypeCancelUploadFileReply,
|
||||||
|
72,delete file,147616,✔,TlvTypeDeleteFileRequest,
|
||||||
|
72,delete file,147872,✔,TlvTypeDeleteFileReply,
|
||||||
|
74,search file,151968,✔,TlvTypeSearchFileRequest,
|
||||||
|
74,search file,152224,✔,TlvTypeSearchFileReply,
|
||||||
|
74,search file,152480,✔,TlvTypeSearchFileNext,
|
||||||
|
74,search file,152736,✔,TlvTypeSearchFileEnd,
|
||||||
|
74,search file,152992,✔,TlvTypeCancelSearchFileRequest,
|
||||||
|
74,search file,153248,✔,TlvTypeCancelSearchFileReply,
|
||||||
|
78,fs,159888,✔,TlvTypeFSFileDataChunk,"Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/d, L/org/xmlpush/v3/o/h, L/org/xmlpush/v3/h/c"
|
||||||
|
78,fs,160128,✔,TlvTypeFSDiskDrive,Lorg/xmlpush/v3/o/e
|
||||||
|
78,fs,160384,✔,TlvTypeFSFullPath,"Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/d, Lorg/xmlpush/v3/o/d, Lorg/xmlpush/v3/o/d, Lorg/xmlpush/v3/o/d, Lorg/xmlpush/v3/f/b, L/org/xmlpush/v3/o/h, L/org/xmlpush/v3/h/c"
|
||||||
|
78,fs,160640,✔,TlvTypeFSFilename,"Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, L/org/xmlpush/v3/h/c"
|
||||||
|
78,fs,160896,✔,TlvTypeFSFileExtension,
|
||||||
|
78,fs,161088,✔,TlvTypeFSDiskDriveType,Lorg/xmlpush/v3/o/e
|
||||||
|
78,fs,161408,✔,TlvTypeFSFileSize,"Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e"
|
||||||
|
78,fs,161584,✔,TlvTypeFSIsFolder,"Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e"
|
||||||
|
79,fs,161840,✔,TlvTypeFSReadOnly,"Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e"
|
||||||
|
79,fs,162096,✔,TlvTypeFSHidden,"Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e"
|
||||||
|
79,fs,162352,✔,TlvTypeFSSystem,"Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e"
|
||||||
|
79,fs,162688,✔,TlvTypeFSFileCreationTime,"Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e"
|
||||||
|
79,fs,162944,✔,TlvTypeFSFileLastAccessTime,"Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e"
|
||||||
|
79,fs,163200,✔,TlvTypeFSFileLastWriteTime,"Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e"
|
||||||
|
79,fs,163472,✔,TlvTypeFSFullPathM,"Lorg/xmlpush/v3/o/d, Lorg/xmlpush/v3/o/d, Lorg/xmlpush/v3/o/d, L/org/xmlpush/v3/h/c"
|
||||||
|
79,fs,163632,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
82,system config file,168096,✔,TlvTypeGetFileSystemConfigRequest,
|
||||||
|
82,system config file,168352,✔,TlvTypeFileSystemConfigReply,
|
||||||
|
82,system config file,168608,✔,TlvTypeSetFileSystemConfigRequest,
|
||||||
|
128,line cmd,262560,✔,TlvTypeStartCmdLineSessionRequest,
|
||||||
|
128,line cmd,262816,✔,TlvTypeStartCmdLineSessionReply,
|
||||||
|
128,line cmd,263072,✔,TlvTypeStopCmdLineSessionRequest,
|
||||||
|
128,line cmd,263328,✔,TlvTypeCmdLineSessionStoppedReply,
|
||||||
|
128,line cmd,263584,✔,TlvTypeCmdLineExecute,
|
||||||
|
128,line cmd,263840,✔,TlvTypeCmdLineExecutionResult,
|
||||||
|
130,line cmd execute,266352,✔,TlvTypeCmdLineExecuteCommand,
|
||||||
|
130,line cmd execute,266560,✔,TlvTypeCmdLineExecuteAnswerID,
|
||||||
|
130,line cmd execute,266864,✔,TlvTypeCmdLineExecuteAnswerData,
|
||||||
|
146,line config cmd,299168,✔,TlvTypeGetCmdLineConfigRequest,
|
||||||
|
146,line config cmd,299424,✔,TlvTypeCmdLineConfigReply,
|
||||||
|
146,line config cmd,299680,✔,TlvTypeSetCmdLineConfigRequest,
|
||||||
|
160,config scheduler,328096,✔,TlvTypeGetSchedulerConfigRequest,
|
||||||
|
160,config scheduler,328352,✔,TlvTypeSchedulerConfigReply,
|
||||||
|
160,config scheduler,328608,✔,TlvTypeSetSchedulerConfigRequest,
|
||||||
|
162,task scheduler,331920,✔,TlvTypeSchedulerTask,
|
||||||
|
162,task scheduler,332192,✔,TlvTypeSchedulerTaskRecordByTime,
|
||||||
|
162,task scheduler,332448,✔,TlvTypeSchedulerTaskRecordScreenWhenAppRuns,
|
||||||
|
162,task scheduler,332704,✔,TlvTypeSchedulerTaskRecordMicWhenAppUsesIt,
|
||||||
|
162,task scheduler,332960,✔,TlvTypeSchedulerTaskRecordWebCamWhenAppUsesIt,
|
||||||
|
176,sch,360592,✔,TlvTypeSCHTaskConfiguration,L/org/xmlpush/v3/h/c
|
||||||
|
176,sch,360752,✔,TlvTypeSCHTaskEnabled,L/org/xmlpush/v3/h/c
|
||||||
|
176,sch,361344,✔,TlvTypeSCHTaskStartDateTime,L/org/xmlpush/v3/h/c
|
||||||
|
176,sch,361600,✔,TlvTypeSCHTaskStopDateTime,L/org/xmlpush/v3/h/c
|
||||||
|
176,sch,362112,✔,TlvTypeSCHApplicationName,
|
||||||
|
176,sch,362288,✔,TlvTypeSCHApplicationWindowOnly,
|
||||||
|
512,microphone,1048992,✔,TlvTypeStartMicrophoneRequest,
|
||||||
|
512,microphone,1049248,✔,TlvTypeStartMicrophoneReply,
|
||||||
|
512,microphone,1049504,✔,TlvTypeMicrophoneFrame,
|
||||||
|
512,microphone,1049760,✔,TlvTypeStopMicrophoneRequest,
|
||||||
|
512,microphone,1050016,✔,TlvTypeMicrophoneStoppedReply,
|
||||||
|
512,microphone,1050272,✔,TlvTypeStartMicrophoneRecording,
|
||||||
|
514,,1052736,✔,TlvTypeMICFrameID,"Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/n"
|
||||||
|
514,,1053072,✔,TlvTypeMICFrameData,"Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/n"
|
||||||
|
514,,1053312,✔,TlvTypeAudioSessionType,
|
||||||
|
514,,1053568,✔,TlvTypeAudioEncodingType,
|
||||||
|
518,audio config,1061024,✔,TlvTypeGetAudioConfigRequest,
|
||||||
|
518,audio config,1061280,✔,TlvTypeAudioConfigReply,
|
||||||
|
518,audio config,1061536,✔,TlvTypeSetAudioConfigRequest,
|
||||||
|
520,type video,1066112,✔,TlvTypeVideoSessionType,"Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/b, Lorg/xmlpush/v3/o/b"
|
||||||
|
520,type video,1066368,✔,TlvTypeVideoEncodingType,"Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/b, Lorg/xmlpush/v3/o/b"
|
||||||
|
544,screen,1114528,✔,TlvTypeStartScreenRequest,
|
||||||
|
544,screen,1114784,✔,TlvTypeStartScreenReply,
|
||||||
|
544,screen,1115040,✔,TlvTypeScreenFrame,
|
||||||
|
544,screen,1115296,✔,TlvTypeStopScreenRequest,
|
||||||
|
544,screen,1115552,✔,TlvTypeScreenStoppedReply,
|
||||||
|
544,screen,1115808,✔,TlvTypeStartScreenRecording,
|
||||||
|
548,cam web,1122720,✔,TlvTypeStartWebCamRequest,
|
||||||
|
548,cam web,1122976,✔,TlvTypeStartWebCamReply,
|
||||||
|
548,cam web,1123232,✔,TlvTypeWebCamFrame,
|
||||||
|
548,cam web,1123488,✔,TlvTypeStopWebCamRequest,
|
||||||
|
548,cam web,1123744,✔,TlvTypeWebCamStoppedReply,
|
||||||
|
548,cam web,1124000,✔,TlvTypeStartWebCamRecording,
|
||||||
|
550,config video,1126560,✔,TlvTypeGetVideoConfigRequest,
|
||||||
|
550,config video,1126816,✔,TlvTypeVideoConfigReply,
|
||||||
|
550,config video,1127072,✔,TlvTypeSetVideoConfigRequest,
|
||||||
|
552,,1130560,✔,TlvTypeVDFrameID,"Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/b"
|
||||||
|
552,,1130896,✔,TlvTypeVDFrameData,"Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/b"
|
||||||
|
552,,1131136,✔,TlvTypeOriginalVideoResolution,"Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/b, Lorg/xmlpush/v3/o/b"
|
||||||
|
552,,1131392,✔,TlvTypeVideoResolution,"Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/b, Lorg/xmlpush/v3/o/b"
|
||||||
|
552,,1132160,✔,TlvTypeAutomaticRecordingUID,
|
||||||
|
576,key logging,1180064,✔,TlvTypeStartKeyLoggingRequest,
|
||||||
|
576,key logging,1180320,✔,TlvTypeStartKeyLoggingReply,
|
||||||
|
576,key logging,1180576,✔,TlvTypeKeyLoggingFrame,
|
||||||
|
576,key logging,1180832,✔,TlvTypeStopKeyLoggingRequest,
|
||||||
|
576,key logging,1181088,✔,TlvTypeKeyLoggingStoppedReply,
|
||||||
|
582,config keylogger,1192096,✔,TlvTypeGetKeyloggerConfigRequest,
|
||||||
|
582,config keylogger,1192352,✔,TlvTypeKeyloggerConfigReply,
|
||||||
|
582,config keylogger,1192608,✔,TlvTypeSetKeyloggerConfigRequest,
|
||||||
|
584,kl frame data,1196416,✔,TlvTypeKLFrameData,Lorg/xmlpush/v3/o/i
|
||||||
|
640,skype,1311136,✔,TlvTypeSkypeAudioMetaInfo,
|
||||||
|
640,skype,1311376,✔,TlvTypeSkypeAudioRecording,
|
||||||
|
640,skype,1311648,✔,TlvTypeSkypeTextRecording,
|
||||||
|
640,skype,1311904,✔,TlvTypeSkypeFileMetaInfo,
|
||||||
|
640,skype,1312144,✔,TlvTypeSkypeFileRecording,
|
||||||
|
640,skype,1312416,✔,TlvTypeSkypeContactsRecording,
|
||||||
|
640,skype,1312640,✔,TlvTypeSkypeContactsUserData,
|
||||||
|
646,config skype,1323168,✔,TlvTypeGetSkypeConfigRequest,
|
||||||
|
646,config skype,1323424,✔,TlvTypeSkypeConfigReply,
|
||||||
|
646,config skype,1323680,✔,TlvTypeSetSkypeConfigRequest,
|
||||||
|
646,config skype,1324336,✔,TlvTypeConfigSkypeAudioEnable,
|
||||||
|
646,config skype,1324592,✔,TlvTypeConfigSkypeTextEnable,
|
||||||
|
646,config skype,1324848,✔,TlvTypeConfigSkypeFileEnable,
|
||||||
|
647,config contacts enable list skype,1325104,✔,TlvTypeConfigSkypeContactsListEnable,
|
||||||
|
648,skype,1327232,✔,TlvTypeSkypeAudioEncodingType,
|
||||||
|
648,skype,1327488,✔,TlvTypeSkypeLoggedInUserAccountName,
|
||||||
|
648,skype,1327744,✔,TlvTypeSkypeConversationPartnerAccountName,
|
||||||
|
648,skype,1328000,✔,TlvTypeSkypeConversationPartnerDisplayName,
|
||||||
|
648,skype,1328256,✔,TlvTypeSkypeChatMembers,
|
||||||
|
648,skype,1328512,✔,TlvTypeSkypeTextMessage,
|
||||||
|
648,skype,1328768,✔,TlvTypeSkypeChatID,
|
||||||
|
648,skype,1329024,✔,TlvTypeSkypeSenderAccountName,
|
||||||
|
649,skype,1329280,✔,TlvTypeSkypeSenderDisplayName,
|
||||||
|
649,skype,1329536,✔,TlvTypeSkypeIncoming,
|
||||||
|
649,skype,1329792,✔,TlvTypeSkypeSessionType,
|
||||||
|
704,changed file,1442208,✔,TlvTypeChangedFileMetaInfo,
|
||||||
|
704,changed file,1442432,✔,TlvTypeChangedFileChangeTime,
|
||||||
|
704,changed file,1442688,✔,TlvTypeChangedFileChangeEvent,
|
||||||
|
704,changed file,1442960,✔,TlvTypeChangedFileRecording,
|
||||||
|
710,config changed,1454240,✔,TlvTypeGetChangedConfigRequest,
|
||||||
|
710,config changed,1454496,✔,TlvTypeChangedConfigReply,
|
||||||
|
710,config changed,1454752,✔,TlvTypeSetChangedConfigRequest,
|
||||||
|
710,config changed,1454912,✔,TlvTypeConfigChangedEvents,
|
||||||
|
736,,1507744,✔,TlvTypeAccessedFileMetaInfo,
|
||||||
|
736,,1507968,✔,TlvTypeAccessedFileAccessTime,
|
||||||
|
736,,1508224,✔,TlvTypeAccessedFileAccessEvent,
|
||||||
|
736,,1508496,✔,TlvTypeAccessedFileRecording,
|
||||||
|
736,,1508736,✔,TlvTypeAccessedApplicationName,
|
||||||
|
736,,1508912,✔,TlvTypeConfigRecordImagesFromExplorer,
|
||||||
|
742,accessed config,1519776,✔,TlvTypeGetAccessedConfigRequest,
|
||||||
|
742,accessed config,1520032,✔,TlvTypeAccessedConfigReply,
|
||||||
|
742,accessed config,1520288,✔,TlvTypeSetAccessedConfigRequest,
|
||||||
|
742,accessed config,1520448,✔,TlvTypeConfigAccessedEvents,
|
||||||
|
768,print,1573280,✔,TlvTypePrintFileMetaInfo,
|
||||||
|
768,print,1573520,✔,TlvTypePrintFrame,
|
||||||
|
772,print,1581184,✔,TlvTypePrintApplicationName,
|
||||||
|
772,print,1581440,✔,TlvTypePrintFilename,
|
||||||
|
772,print,1581696,✔,TlvTypePrintEncodingType,
|
||||||
|
774,print config,1585312,✔,TlvTypeGetPrintConfigRequest,
|
||||||
|
774,print config,1585568,✔,TlvTypePrintConfigReply,
|
||||||
|
774,print config,1585824,✔,TlvTypeSetPrintConfigRequest,
|
||||||
|
800,deleted,1638816,✔,TlvTypeDeletedFileMetaInfo,
|
||||||
|
800,deleted,1639296,✔,TlvTypeDeletedFileDeletionTime,
|
||||||
|
800,deleted,1639552,✔,TlvTypeDeletedFileRecycleBin,
|
||||||
|
800,deleted,1639808,✔,TlvTypeDeletedMethod,
|
||||||
|
800,deleted,1640064,✔,TlvTypeDeletedApplicationName,
|
||||||
|
800,deleted,1640336,✔,TlvTypeDeletedFileRecording,
|
||||||
|
806,config deleted,1650848,✔,TlvTypeGetDeletedConfigRequest,
|
||||||
|
806,config deleted,1651104,✔,TlvTypeDeletedConfigReply,
|
||||||
|
806,config deleted,1651360,✔,TlvTypeSetDeletedConfigRequest,
|
||||||
|
1024,application upload forensics,2097568,✔,TlvTypeUploadForensicsApplicationRequest,
|
||||||
|
1024,application upload forensics,2097824,✔,TlvTypeUploadForensicsApplicationReply,
|
||||||
|
1024,application upload forensics,2098080,✔,TlvTypeUploadForensicsApplicationChunk,
|
||||||
|
1024,application upload forensics,2098336,✔,TlvTypeUploadForensicsApplicationDoneRequest,
|
||||||
|
1024,application upload forensics,2098592,✔,TlvTypeUploadForensicsApplicationDoneReply,
|
||||||
|
1026,application remove forensics,2101664,✔,TlvTypeRemoveForensicsApplicationRequest,
|
||||||
|
1026,application remove forensics,2101920,✔,TlvTypeRemoveForensicsApplicationReply,
|
||||||
|
1028,app forensics execute,2105760,✔,TlvTypeForensicsAppExecuteRequest,
|
||||||
|
1028,app forensics execute,2106016,✔,TlvTypeForensicsAppExecuteReply,
|
||||||
|
1028,app forensics execute,2106272,✔,TlvTypeForensicsAppExecuteResult,
|
||||||
|
1028,app forensics execute,2106528,✔,TlvTypeForensicsAppExecuteResultChunk,
|
||||||
|
1028,app forensics execute,2106784,✔,TlvTypeForensicsAppExecuteResultDone,
|
||||||
|
1028,app forensics execute,2107040,✔,TlvTypeForensicsCancelAppExecuteRequest,
|
||||||
|
1028,app forensics execute,2107296,✔,TlvTypeForensicsCancelAppExecuteReply,
|
||||||
|
1030,config forensics,2109600,✔,TlvTypeGetForensicsConfigRequest,
|
||||||
|
1030,config forensics,2109856,✔,TlvTypeForensicsConfigReply,
|
||||||
|
1030,config forensics,2110112,✔,TlvTypeSetForensicsConfigRequest,
|
||||||
|
1032,application config info forensics,2113680,✔,TlvTypeConfigForensicsApplicationInfoGeneric,
|
||||||
|
1032,application config info forensics,2113952,✔,TlvTypeConfigForensicsApplicationInfo,
|
||||||
|
1034,forensics,2117760,✔,TlvTypeConfigForensicsApplicationName,
|
||||||
|
1034,forensics,2117952,✔,TlvTypeConfigForensicsApplicationSize,
|
||||||
|
1034,forensics,2118208,✔,TlvTypeConfigForensicsApplicationID,
|
||||||
|
1034,forensics,2118528,✔,TlvTypeConfigForensicsApplicationCmdline,
|
||||||
|
1034,forensics,2118784,✔,TlvTypeConfigForensicsApplicationOutput,
|
||||||
|
1034,forensics,2118976,✔,TlvTypeConfigForensicsApplicationTimeout,
|
||||||
|
1034,forensics,2119232,✔,TlvTypeConfigForensicsApplicationVersion,
|
||||||
|
1034,forensics,2119552,✔,TlvTypeForensicsFriendlyName,
|
||||||
|
1035,output application config forensics,2119808,✔,TlvTypeConfigForensicsApplicationOutputPrepend,
|
||||||
|
1035,output application config forensics,2120064,✔,TlvTypeConfigForensicsApplicationOutputContentType,
|
||||||
|
1056,vo meta info ip,2163104,✔,TlvTypeVoIPMetaInfo,
|
||||||
|
1058,vo ip,2166912,✔,TlvTypeVoIPEncodingType,
|
||||||
|
1058,vo ip,2167168,✔,TlvTypeVoIPSessionType,
|
||||||
|
1058,vo ip,2167424,✔,TlvTypeVoIPApplicationName,Lorg/xmlpush/v3/o/n
|
||||||
|
1058,vo ip,2167696,✔,TlvTypeVoIPAppScreenshot,
|
||||||
|
1058,vo ip,2167952,✔,TlvTypeVoIPAudioRecording,
|
||||||
|
1058,vo ip,2168112,✔,TlvTypeConfigVoIPScreenshotEnabled,
|
||||||
|
1062,vo config ip,2175136,✔,TlvTypeGetVoIPConfigRequest,
|
||||||
|
1062,vo config ip,2175392,✔,TlvTypeVoIPConfigReply,
|
||||||
|
1062,vo config ip,2175648,✔,TlvTypeSetVoIPConfigRequest,
|
||||||
|
1088,clicks mouse,2228640,✔,TlvTypeMouseClicksMetaInfo,
|
||||||
|
1088,clicks mouse,2228896,✔,TlvTypeMouseClicksFrame,
|
||||||
|
1090,clicks mouse,2232448,✔,TlvTypeMouseClicksEncodingType,
|
||||||
|
1090,clicks mouse,2232896,✔,TlvTypeConfigMouseClicksRectangle,
|
||||||
|
1090,clicks mouse,2233152,✔,TlvTypeConfigMouseClicksSensitivity,
|
||||||
|
1090,clicks mouse,2233408,✔,TlvTypeConfigMouseClicksType,
|
||||||
|
1094,clicks config mouse,2240672,✔,TlvTypeGetMouseClicksConfigRequest,
|
||||||
|
1094,clicks config mouse,2240928,✔,TlvTypeMouseClicksConfigReply,
|
||||||
|
1094,clicks config mouse,2241184,✔,TlvTypeSetMouseClicksConfigRequest,
|
||||||
|
2112,sms,4325792,✔,TlvTypeMobileSMSMetaInfo,Lorg/xmlpush/v3/f/b
|
||||||
|
2112,sms,4326016,✔,TlvTypeMobileSMSData,Lorg/xmlpush/v3/f/b
|
||||||
|
2112,sms,4326256,✔,TlvTypeSMSSenderNumber,Lorg/xmlpush/v3/f/b
|
||||||
|
2112,sms,4326512,✔,TlvTypeSMSRecipientNumber,Lorg/xmlpush/v3/f/b
|
||||||
|
2112,sms,4326528,✔,TlvTypeSMSInformation,
|
||||||
|
2112,sms,4326768,✔,TlvTypeSMSDirection,Lorg/xmlpush/v3/f/b
|
||||||
|
2112,sms,4327040,×,unknown,Lorg/xmlpush/v3/f/b
|
||||||
|
2144,address book mobile,4391328,✔,TlvTypeMobileAddressBookMetaInfo,Lorg/xmlpush/v3/i/a
|
||||||
|
2144,address book mobile,4391552,✔,TlvTypeMobileAddressBookData,Lorg/xmlpush/v3/i/a
|
||||||
|
2152,address book checksum mobile,4407360,✔,TlvTypeMobileAddressBookChecksum,
|
||||||
|
2176,mobile blackberry,4456864,✔,TlvTypeMobileBlackberryMessengerMetaInfo,
|
||||||
|
2176,mobile blackberry,4457088,✔,TlvTypeMobileBlackberryMessengerData,
|
||||||
|
2176,mobile blackberry,4457328,✔,TlvTypeMobileBlackberryMsChatID,
|
||||||
|
2176,mobile blackberry,4457600,✔,TlvTypeMobileBlackberryMsConversationPartners,
|
||||||
|
2208,mobile tracking,4522400,✔,TlvTypeMobileTrackingStartRequest,
|
||||||
|
2208,mobile tracking,4522656,✔,TlvTypeMobileTrackingStopRequest,
|
||||||
|
2208,mobile tracking,4523376,✔,TlvTypeMobileTrackingDataV10,"Lorg/xmlpush/v3/t/e, Lorg/xmlpush/v3/t/e, Lorg/xmlpush/v3/t/e, Lorg/xmlpush/v3/t/e"
|
||||||
|
2214,mobile config tracking,4535200,✔,TlvTypeMobileTrackingConfig,Lorg/xmlpush/v3/h/c
|
||||||
|
2214,mobile config tracking,4535440,✔,TlvTypeMobileTrackingConfigRaw,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
2216,mobile tracking,4538432,✔,TlvTypeMobileTrackingTimeInterval,L/org/xmlpush/v3/h/c
|
||||||
|
2216,mobile tracking,4538688,✔,TlvTypeMobileTrackingDistance,L/org/xmlpush/v3/h/c
|
||||||
|
2216,mobile tracking,4538928,✔,TlvTypeMobileTrackingSendOnAnyChannel,L/org/xmlpush/v3/h/c
|
||||||
|
2240,mobile call phone,4587936,✔,TlvTypeMobilePhoneCallLogsMetaInfo,Lorg/xmlpush/v3/f/a
|
||||||
|
2240,mobile call phone,4588192,✔,TlvTypeMobilePhoneCallLogsData,Lorg/xmlpush/v3/f/b
|
||||||
|
2240,mobile call phone,4588400,✔,TlvTypeMobilePhoneCallLogsType,Lorg/xmlpush/v3/f/b
|
||||||
|
2240,mobile call phone,4588672,✔,TlvTypeMobilePhoneCallAdditionalInformation,Lorg/xmlpush/v3/f/b
|
||||||
|
2240,mobile call phone,4588912,✔,TlvTypeMobilePhoneCallLogsCallerNumber,Lorg/xmlpush/v3/f/b
|
||||||
|
2240,mobile call phone,4589168,✔,TlvTypeMobilePhoneCallLogsCalleeNumber,Lorg/xmlpush/v3/f/b
|
||||||
|
2240,mobile call phone,4589440,✔,TlvTypeMobilePhoneCallLogsCallerName,Lorg/xmlpush/v3/f/b
|
||||||
|
2241,name call phone logs mobile callee,4589696,✔,TlvTypeMobilePhoneCallLogsCalleeName,Lorg/xmlpush/v3/f/b
|
||||||
|
2242,last call phone entry mobile endtime log,4591680,✔,TlvTypeMobilePhoneCallLogLastEntryEndtime,
|
||||||
|
3072,mobile logging,6291872,✔,TlvTypeMobileLoggingMetaInfo,
|
||||||
|
3072,mobile logging,6292096,✔,TlvTypeMobileLoggingData,
|
||||||
|
3616,master agent,7405984,✔,TlvTypeMasterAgentLogin,
|
||||||
|
3616,master agent,7406240,✔,TlvTypeMasterAgentLoginAnswer,
|
||||||
|
3616,master agent,7406752,✔,TlvTypeMasterAgentTargetList,
|
||||||
|
3616,master agent,7407008,✔,TlvTypeMasterAgentTargetOnlineList,
|
||||||
|
3616,master agent,7407264,✔,TlvTypeMasterAgentTargetInfoReply,
|
||||||
|
3616,master agent,7407520,✔,TlvTypeMasterAgentUserList,
|
||||||
|
3617,master agent list,7407776,✔,TlvTypeMasterAgentUserListReply,
|
||||||
|
3617,master agent list,7408032,✔,TlvTypeMasterAgentTargetArchivedList,
|
||||||
|
3617,master agent list,7408288,✔,TlvTypeMasterAgentTargetListEx,
|
||||||
|
3617,master agent list,7408544,✔,TlvTypeMasterAgentTargetOnlineListEx,
|
||||||
|
3617,master agent list,7408800,✔,TlvTypeMasterAgentMobileTargetArchivedList,
|
||||||
|
3617,master agent list,7409056,✔,TlvTypeMasterAgentMobileTargetList,
|
||||||
|
3617,master agent list,7409312,✔,TlvTypeMasterAgentMobileTargetOnlineList,
|
||||||
|
3618,,7409824,✔,TlvTypeMasterAgentQueryFirst,
|
||||||
|
3618,,7410080,✔,TlvTypeMasterAgentQueryNext,
|
||||||
|
3618,,7410336,✔,TlvTypeMasterAgentQueryLast,
|
||||||
|
3618,,7410592,✔,TlvTypeMasterAgentQueryAnswer,
|
||||||
|
3618,,7410848,✔,TlvTypeMasterAgentRemoveRecord,
|
||||||
|
3618,,7411104,✔,TlvTypeMasterAgentTargetInfoExReply,
|
||||||
|
3618,,7411344,✔,TlvTypeTargetInfoExProperty,
|
||||||
|
3618,,7411616,✔,TlvTypeTargetInfoExPropertyValue,
|
||||||
|
3619,,7411840,✔,TlvTypeTargetInfoExPropertyValueName,
|
||||||
|
3619,,7411968,✔,TlvTypeTargetInfoExPropertyValueData,
|
||||||
|
3619,,7412384,✔,TlvTypeMasterAgentAlarm,
|
||||||
|
3620,master agent,7413920,✔,TlvTypeMasterAgentRetrieveData,
|
||||||
|
3620,master agent,7414176,✔,TlvTypeMasterAgentRetrieveDataAnswer,
|
||||||
|
3620,master agent,7414432,✔,TlvTypeMasterAgentRemoveUser,
|
||||||
|
3620,master agent,7414688,✔,TlvTypeMasterAgentRemoveTarget,
|
||||||
|
3620,master agent,7414944,✔,TlvTypeMasterAgentRetrieveDataComments,
|
||||||
|
3620,master agent,7415200,✔,TlvTypeMasterAgentUpdateDataComments,
|
||||||
|
3620,master agent,7415712,✔,TlvTypeMasterAgentRetrieveActivityLogging,
|
||||||
|
3621,master agent,7415968,✔,TlvTypeMasterAgentRetrieveMasterLogging,
|
||||||
|
3621,master agent,7416224,✔,TlvTypeMasterAgentRetrieveAgentActivityLogging,
|
||||||
|
3621,master agent,7417248,✔,TlvTypeMasterAgentSendUserGUIConfig,
|
||||||
|
3621,master agent,7417504,✔,TlvTypeMasterAgentGetUserGUIConfigRequest,
|
||||||
|
3621,master agent,7417760,✔,TlvTypeMasterAgentGetUserGUIConfigReply,
|
||||||
|
3622,master agent,7418016,✔,TlvTypeMasterAgentProxyList,
|
||||||
|
3622,master agent,7418272,✔,TlvTypeMasterAgentProxyInfoReply,
|
||||||
|
3622,master agent,7419040,✔,TlvTypeMasterAgentNameValuePacket,
|
||||||
|
3622,master agent,7419248,✔,TlvTypeMasterAgentValueName,
|
||||||
|
3622,master agent,7419392,✔,TlvTypeMasterAgentValueData,
|
||||||
|
3622,master agent,7419808,✔,TlvTypeMasterAgentRetrieveTargetHistory,
|
||||||
|
3623,install master agent,7421088,✔,TlvTypeMasterAgentInstallMasterLicense,
|
||||||
|
3623,install master agent,7421344,✔,TlvTypeMasterAgentInstallSoftwareUpdate,
|
||||||
|
3623,install master agent,7421600,✔,TlvTypeMasterAgentInstallSoftwareUpdateChunk,
|
||||||
|
3623,install master agent,7421856,✔,TlvTypeMasterAgentInstallSoftwareUpdateDone,
|
||||||
|
3624,master agent,7422112,✔,TlvTypeMasterAgentSoftwareUpdateInfo,
|
||||||
|
3624,master agent,7422368,✔,TlvTypeMasterAgentSoftwareUpdateInfoReply,
|
||||||
|
3624,master agent,7422624,✔,TlvTypeMasterAgentSoftwareUpdate,
|
||||||
|
3624,master agent,7422880,✔,TlvTypeMasterAgentSoftwareUpdateReply,
|
||||||
|
3624,master agent,7423136,✔,TlvTypeMasterAgentSoftwareUpdateNext,
|
||||||
|
3624,master agent,7423392,✔,TlvTypeMasterAgentAddTimeSchedule,
|
||||||
|
3624,master agent,7423648,✔,TlvTypeMasterAgentAddScreenSchedule,
|
||||||
|
3624,master agent,7423904,✔,TlvTypeMasterAgentAddLockedSchedule,
|
||||||
|
3625,master agent,7424160,✔,TlvTypeMasterAgentRemoveSchedule,
|
||||||
|
3625,master agent,7424416,✔,TlvTypeMasterAgentGetSchedulerList,
|
||||||
|
3625,master agent,7424672,✔,TlvTypeMasterAgentSchedulerTimeAction,
|
||||||
|
3625,master agent,7424928,✔,TlvTypeMasterAgentSchedulerScreenAction,
|
||||||
|
3625,master agent,7425184,✔,TlvTypeMasterAgentSchedulerLockedAction,
|
||||||
|
3625,master agent,7425440,✔,TlvTypeMasterAgentProjectSoftwareUpdateInfo,
|
||||||
|
3625,master agent,7425696,✔,TlvTypeMasterAgentProjectSoftwareUpdateInfoReply,
|
||||||
|
3625,master agent,7425952,✔,TlvTypeMasterAgentProjectSoftwareUpdate,
|
||||||
|
3626,master agent,7426112,✔,TlvTypeMasterAgentSchedulerID,
|
||||||
|
3626,master agent,7426368,✔,TlvTypeMasterAgentSchedulerStartTime,L/org/xmlpush/v3/h/c
|
||||||
|
3626,master agent,7426624,✔,TlvTypeMasterAgentSchedulerStopTime,L/org/xmlpush/v3/h/c
|
||||||
|
3626,master agent,7427488,✔,TlvTypeMasterAgentAddRecordedDataAvailableSchedule,
|
||||||
|
3626,master agent,7427744,✔,TlvTypeMasterAgentSchedulerRecordedDataAvailableAction,
|
||||||
|
3627,master agent data,7428256,✔,TlvTypeMasterAgentRetrieveRemoteMasterData,
|
||||||
|
3627,master agent data,7428512,✔,TlvTypeMasterAgentRetrieveRemoteMasterDataReply,
|
||||||
|
3627,master agent data,7428768,✔,TlvTypeMasterAgentDeleteRemoteMasterData,
|
||||||
|
3627,master agent data,7429024,✔,TlvTypeMasterAgentRetrieveOfflineMasterData,
|
||||||
|
3627,master agent data,7429280,✔,TlvTypeMasterAgentRetrieveOfflineMasterDataReply,
|
||||||
|
3627,master agent data,7429536,✔,TlvTypeMasterAgentDeleteOfflineMasterData,
|
||||||
|
3628,master agent,7430304,✔,TlvTypeMasterAgentQueryFirstEx,
|
||||||
|
3628,master agent,7430560,✔,TlvTypeMasterAgentQueryNextEx,
|
||||||
|
3628,master agent,7430816,✔,TlvTypeMasterAgentQueryLastEx,
|
||||||
|
3628,master agent,7431072,✔,TlvTypeMasterAgentQueryAnswerEx,
|
||||||
|
3628,master agent,7431328,✔,TlvTypeMasterAgentSendUserPreferences,
|
||||||
|
3628,master agent,7431584,✔,TlvTypeMasterAgentGetUserPreferencesRequest,
|
||||||
|
3628,master agent,7431840,✔,TlvTypeMasterAgentGetUserPreferencesReply,
|
||||||
|
3628,master agent,7432096,✔,TlvTypeMasterAgentListMCFilesRequest,
|
||||||
|
3629,master agent mc,7432608,✔,TlvTypeMasterAgentDeleteMCFiles,
|
||||||
|
3629,master agent mc,7432864,✔,TlvTypeMasterAgentSendMCFiles,
|
||||||
|
3629,master agent mc,7433120,✔,TlvTypeMasterAgentMCStatisticsRequest,
|
||||||
|
3629,master agent mc,7433376,✔,TlvTypeMasterAgentMCStatisticsReply,
|
||||||
|
3629,master agent mc,7433616,✔,TlvTypeMasterAgentMCStatisticsValues,
|
||||||
|
3630,master agent,7434400,✔,TlvTypeMasterAgentTrojanKeyRequest,
|
||||||
|
3630,master agent,7434656,✔,TlvTypeMasterAgentTrojanKeyReply,
|
||||||
|
3630,master agent,7434912,✔,TlvTypeMasterAgentEvProtectionX509Request,
|
||||||
|
3630,master agent,7435168,✔,TlvTypeMasterAgentEvProtectionX509Reply,
|
||||||
|
3630,master agent,7435424,✔,TlvTypeMasterAgentEvProtectionImportCert,
|
||||||
|
3630,master agent,7435680,✔,TlvTypeMasterAgentEvProtectionImportCertCompleted,
|
||||||
|
3630,master agent,7435936,✔,TlvTypeMasterAgentConfigurationRequest,
|
||||||
|
3630,master agent,7436192,✔,TlvTypeMasterAgentConfigurationReply,
|
||||||
|
3631,master agent configuration,7436448,✔,TlvTypeMasterAgentConfigurationUpdateRequest,
|
||||||
|
3631,master agent configuration,7436704,✔,TlvTypeMasterAgentConfigurationUpdateRequestCompleted,
|
||||||
|
3631,master agent configuration,7436944,✔,TlvTypeMasterAgentConfiguration,
|
||||||
|
3631,master agent configuration,7437216,✔,TlvTypeMasterAgentConfigurationValue,
|
||||||
|
3631,master agent configuration,7437424,✔,TlvTypeMasterAgentConfigurationValueName,
|
||||||
|
3631,master agent configuration,7437568,✔,TlvTypeMasterAgentConfigurationValueData,
|
||||||
|
3631,master agent configuration,7437984,✔,TlvTypeMasterAgentConfigurationTransferDone,
|
||||||
|
3632,master agent,7438496,✔,TlvTypeMasterAgentRetrieveTargetFile,
|
||||||
|
3632,master agent,7438752,✔,TlvTypeMasterAgentRetrieveTargetFileAnswer,
|
||||||
|
3632,master agent,7438912,✔,TlvTypeMasterAgentAlarmEntryID,
|
||||||
|
3632,master agent,7439168,✔,TlvTypeMasterAgentAlarmEntryVersion,
|
||||||
|
3632,master agent,7439424,✔,TlvTypeMasterAgentAlarmTriggerFlags,
|
||||||
|
3632,master agent,7439776,✔,TlvTypeMasterAgentGetAlarmList,
|
||||||
|
3632,master agent,7440032,✔,TlvTypeMasterAgentAddAlarmEntry,
|
||||||
|
3632,master agent,7440288,✔,TlvTypeMasterAgentRemoveAlarmEntry,
|
||||||
|
3633,master agent,7440544,✔,TlvTypeMasterAgentAlarmEntry,
|
||||||
|
3633,master agent,7440800,✔,TlvTypeMasterAgentSystemStatus,
|
||||||
|
3633,master agent,7441056,✔,TlvTypeMasterAgentSystemStatusRequest,
|
||||||
|
3633,master agent,7441312,✔,TlvTypeMasterAgentSystemStatusReply,
|
||||||
|
3633,master agent,7441552,✔,TlvTypeMasterAgentLicenseValues,
|
||||||
|
3633,master agent,7441824,✔,TlvTypeMasterAgentLicenseValuesRequest,
|
||||||
|
3633,master agent,7442080,✔,TlvTypeMasterAgentLicenseValuesReply,
|
||||||
|
3634,master agent,7442592,✔,TlvTypeMasterAgentGetNetworkConfigurationRequest,
|
||||||
|
3634,master agent,7442848,✔,TlvTypeMasterAgentSetNetworkConfigurationRequest,
|
||||||
|
3634,master agent,7443104,✔,TlvTypeMasterAgentSetNetworkConfigurationReply,
|
||||||
|
3634,master agent,7443360,✔,TlvTypeMasterAgentRetrieveAllowedModulesList,
|
||||||
|
3634,master agent,7443616,✔,TlvTypeMasterAgentRetrieveAllowedModulesListAnswer,
|
||||||
|
3636,master agent,7446688,✔,TlvTypeMasterAgentRemoveAllTargetData,
|
||||||
|
3636,master agent,7446944,✔,TlvTypeMasterAgentForceDownloadRecordedData,
|
||||||
|
3636,master agent,7447200,✔,TlvTypeMasterAgentTargetCreateNotification,
|
||||||
|
3636,master agent,7447456,✔,TlvTypeMasterAgentMobileTargetInfoReply,
|
||||||
|
3636,master agent,7447696,✔,TlvTypeMasterAgentMobileTargetInfoValues,
|
||||||
|
3638,master agent alert,7450784,✔,TlvTypeMasterAgentAlert,
|
||||||
|
3640,master agent,7454880,✔,TlvTypeMasterAgentAddUser,
|
||||||
|
3640,master agent,7455392,✔,TlvTypeMasterAgentAddUserReply,
|
||||||
|
3640,master agent,7455648,✔,TlvTypeMasterAgentModifyUser,
|
||||||
|
3640,master agent,7455904,✔,TlvTypeMasterAgentSetUserPermission,
|
||||||
|
3640,master agent,7456160,✔,TlvTypeMasterAgentSetTargetPermission,
|
||||||
|
3640,master agent,7456400,✔,TlvTypeMasterAgentUserPermission,
|
||||||
|
3640,master agent,7456656,✔,TlvTypeMasterAgentTargetPermission,
|
||||||
|
3641,master agent,7456928,✔,TlvTypeMasterAgentUserPermissionValuePacket,
|
||||||
|
3641,master agent,7457184,✔,TlvTypeMasterAgentTargetPermissionValuePacket,
|
||||||
|
3641,master agent,7457344,✔,TlvTypeMasterAgentUserPermissionValueName,
|
||||||
|
3641,master agent,7457600,✔,TlvTypeMasterAgentTargetPermissionValueName,
|
||||||
|
3641,master agent,7457856,✔,TlvTypeMasterAgentUserPermissionValueData,
|
||||||
|
3641,master agent,7458112,✔,TlvTypeMasterAgentTargetPermissionValueData,
|
||||||
|
3641,master agent,7458464,✔,TlvTypeMasterAgentModifyPassword,
|
||||||
|
3641,master agent,7458656,✔,TlvTypeMasterAgentMobileTargetPermissionValueName,
|
||||||
|
3642,master agent,7458976,✔,TlvTypeMasterAgentUploadFile,
|
||||||
|
3642,master agent,7459232,✔,TlvTypeMasterAgentUploadFileChunk,
|
||||||
|
3642,master agent,7459488,✔,TlvTypeMasterAgentUploadFileDone,
|
||||||
|
3642,master agent,7459744,✔,TlvTypeMasterAgentUploadFilesTransferDone,
|
||||||
|
3642,master agent,7460000,✔,TlvTypeMasterAgentGetTargetModuleConfigRequest,
|
||||||
|
3642,master agent,7460256,✔,TlvTypeMasterAgentRemoveFile,
|
||||||
|
3642,master agent,7460512,✔,TlvTypeMasterAgentMobileProxyList,
|
||||||
|
3642,master agent,7460768,✔,TlvTypeMasterAgentSMSProxyList,
|
||||||
|
3643,master agent,7461024,✔,TlvTypeMasterAgentSMSProxyInfoReply,
|
||||||
|
3643,master agent,7461280,✔,TlvTypeMasterAgentCallPhoneNumberList,
|
||||||
|
3643,master agent,7461536,✔,TlvTypeMasterAgentCallPhoneNumberInfoReply,
|
||||||
|
3643,master agent,7461792,✔,TlvTypeMasterAgentGetMobileTargetModuleConfigRequest,
|
||||||
|
3643,master agent,7462048,✔,TlvTypeMasterAgentSendSMS,
|
||||||
|
3647,master agent,7469984,✔,TlvTypeMasterAgentEncryptionRequired,
|
||||||
|
3647,master agent,7470240,✔,TlvTypeMasterAgentFileCompleted,
|
||||||
|
3647,master agent,7470496,✔,TlvTypeMasterAgentRequestCompleted,
|
||||||
|
3647,master agent,7470752,✔,TlvTypeAgentMasterComm,
|
||||||
|
3647,master agent,7471008,✔,TlvTypeMasterAgentRequestStatus,
|
||||||
|
3648,master,7471424,✔,TlvTypeProxyMasterCommSig,
|
||||||
|
3648,master,7471520,✔,TlvTypeMasterTargetConn,
|
||||||
|
3648,master,7471776,✔,TlvTypeProxyMasterComm,
|
||||||
|
3648,master,7472032,✔,TlvTypeMasterProxyComm,
|
||||||
|
3648,master,7472288,✔,TlvTypeProxyMasterHeartBeatAnswer,
|
||||||
|
3648,master,7472544,✔,TlvTypeProxyMasterDisconnect,
|
||||||
|
3648,master,7472704,✔,TlvTypeProxyMasterNotification,
|
||||||
|
3648,master,7473056,✔,TlvTypeProxyMasterRequest,
|
||||||
|
3649,master,7473312,✔,TlvTypeMasterProxyCommNotification,
|
||||||
|
3649,master,7473568,✔,TlvTypeMasterCheckTargetDisconnect,
|
||||||
|
3680,target proxy,7536960,✔,TlvTypeProxyTargetCommSig,
|
||||||
|
3680,target proxy,7537312,✔,TlvTypeProxyTargetComm,
|
||||||
|
3680,target proxy,7537568,✔,TlvTypeProxyMasterTargetComm,
|
||||||
|
3680,target proxy,7537728,✔,TlvTypeProxyTargetRequestCrypto,
|
||||||
|
3680,target proxy,7538064,✔,TlvTypeProxyTargetAnswerCrypto,
|
||||||
|
3744,target,7668128,✔,TlvTypeMasterTargetComm,
|
||||||
|
3744,target,7668384,✔,TlvTypeTargetCloseAllLiveStreaming,
|
||||||
|
3776,relay,7733664,✔,TlvTypeRelayProxyComm,
|
||||||
|
3776,relay,7734176,✔,TlvTypeRelayDummyHeartbeat,
|
||||||
|
4032,test type meta,8257792,✔,TlvTypeTestMetaTypeInvalid,
|
||||||
|
4032,test type meta,8258608,✔,TlvTypeTestMetaTypeBool,
|
||||||
|
4032,test type meta,8258880,✔,TlvTypeTestMetaTypeUInt,
|
||||||
|
4032,test type meta,8259152,✔,TlvTypeTestMetaTypeInt,
|
||||||
|
4032,test type meta,8259440,✔,TlvTypeTestMetaTypeString,
|
||||||
|
4033,test,8259712,✔,TlvTypeTestMetaTypeUnicode,
|
||||||
|
4033,test,8259984,✔,TlvTypeTestMetaTypeRaw,
|
||||||
|
4033,test,8260256,✔,TlvTypeTestMetaTypeGroup,
|
||||||
|
4033,test,8260416,✔,TlvTypeTestMemberIdentifier,
|
||||||
|
4033,test,8260736,✔,TlvTypeTestMemberName,
|
||||||
|
4096,target,8389008,✔,TlvTypeTargetData,
|
||||||
|
4096,target,8389280,✔,TlvTypeTargetHeartBeat,
|
||||||
|
4096,target,8389680,✔,TlvTypeTargetKeepSessionAlive,
|
||||||
|
4096,target,8390000,✔,TlvTypeTargetLocalIP,
|
||||||
|
4096,target,8390256,✔,TlvTypeTargetGlobalIP,
|
||||||
|
4096,target,8390448,✔,TlvTypeTargetState,
|
||||||
|
4097,agent master,8390784,✔,TlvTypeTargetID,
|
||||||
|
4097,agent master,8391072,✔,TlvTypeGetInstalledModulesRequest,
|
||||||
|
4097,agent master,8391328,✔,TlvTypeInstalledModulesReply,
|
||||||
|
4097,agent master,8391488,✔,TlvTypeTrojanUID,
|
||||||
|
4097,agent master,8391808,✔,TlvTypeTrojanID,
|
||||||
|
4097,agent master,8392000,✔,TlvTypeTrojanMaxInfections,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4097,agent master,8392240,✔,TlvTypeScreenSaverOn,
|
||||||
|
4097,agent master,8392496,✔,TlvTypeScreenLocked,
|
||||||
|
4098,agent master,8392752,✔,TlvTypeRecordedDataAvailable,
|
||||||
|
4098,agent master,8393024,✔,TlvTypeDownloadedRecordedDataTimeStamp,
|
||||||
|
4098,agent master,8393280,✔,TlvTypeInstallationMode,
|
||||||
|
4098,agent master,8393552,✔,TlvTypeTargetRemoveNotification,
|
||||||
|
4098,agent master,8393792,✔,TlvTypeTargetPlatformBits,
|
||||||
|
4098,agent master,8394032,✔,TlvTypeRemoveItselfMaxInfectionReached,
|
||||||
|
4098,agent master,8394288,✔,TlvTypeRemoveItselfAtMasterRequest,
|
||||||
|
4098,agent master,8394544,✔,TlvTypeRemoveItselfAtAgentRequest,
|
||||||
|
4099,agent master,8394912,✔,TlvTypeRemoveItselfAtAgentReqRequest,
|
||||||
|
4099,agent master,8395072,✔,TlvTypeRecordedFilesDownloadTotal,
|
||||||
|
4099,agent master,8395328,✔,TlvTypeRecordedFilesDownloadProgress,
|
||||||
|
4099,agent master,8395632,✔,TlvTypeTargetLicenseInfo,
|
||||||
|
4099,agent master,8395840,✔,TlvTypeRemoveTargetLicenseInfo,
|
||||||
|
4099,agent master,8396176,✔,TlvTypeTargetAllConfigurations,
|
||||||
|
4100,target error,8396960,✔,TlvTypeTargetError,
|
||||||
|
4102,target config,8401056,✔,TlvTypeGetTargetConfigRequest,
|
||||||
|
4102,target config,8401312,✔,TlvTypeTargetConfigReply,
|
||||||
|
4102,target config,8401568,✔,TlvTypeSetTargetConfigRequest,
|
||||||
|
4102,target config,8402304,✔,TlvTypeConfigTargetID,
|
||||||
|
4102,target config,8402496,✔,TlvTypeConfigTargetHeartbeatInterval,
|
||||||
|
4102,target config,8402800,✔,TlvTypeConfigTargetProxy,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4103,agent master,8403008,✔,TlvTypeConfigTargetPort,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4103,agent master,8403584,✔,TlvTypeConfigAutoRemovalDateTime,
|
||||||
|
4103,agent master,8403776,✔,TlvTypeConfigAutoRemovalIfNoProxy,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4103,agent master,8404032,✔,TlvTypeInternalAutoRemovalElapsedTime,
|
||||||
|
4104,active hiding config,8405040,✔,TlvTypeConfigActiveHiding,
|
||||||
|
4106,target module,8409248,✔,TlvTypeTargetLoadModuleRequest,
|
||||||
|
4106,target module,8409504,✔,TlvTypeTargetLoadModuleReply,
|
||||||
|
4106,target module,8409760,✔,TlvTypeTargetUnLoadModuleRequest,
|
||||||
|
4106,target module,8410016,✔,TlvTypeTargetUnLoadModuleReply,
|
||||||
|
4106,target module,8410272,✔,TlvTypeTargetUploadModuleRequest,
|
||||||
|
4106,target module,8410528,✔,TlvTypeTargetUploadModuleReply,
|
||||||
|
4106,target module,8410784,✔,TlvTypeTargetUploadModuleChunk,
|
||||||
|
4106,target module,8411040,✔,TlvTypeTargetUploadModuleDoneRequest,
|
||||||
|
4107,target module,8411296,✔,TlvTypeTargetUploadModuleDoneReply,
|
||||||
|
4107,target module,8411552,✔,TlvTypeTargetRemoveModuleRequest,
|
||||||
|
4107,target module,8411808,✔,TlvTypeTargetRemoveModuleReply,
|
||||||
|
4107,target module,8412064,✔,TlvTypeTargetOfflineUploadModuleRequest,
|
||||||
|
4107,target module,8412320,✔,TlvTypeTargetOfflineUploadModuleReply,
|
||||||
|
4107,target module,8412576,✔,TlvTypeTargetOfflineUploadModuleChunk,
|
||||||
|
4107,target module,8412832,✔,TlvTypeTargetOfflineUploadModuleDoneRequest,
|
||||||
|
4107,target module,8413088,✔,TlvTypeTargetOfflineUploadModuleDoneReply,
|
||||||
|
4108,target error,8413344,✔,TlvTypeTargetOfflineError,
|
||||||
|
4108,target error,8413600,✔,TlvTypeTargetUploadError,
|
||||||
|
4109,files reply master list agent mc,8415392,✔,TlvTypeMasterAgentListMCFilesReply,
|
||||||
|
4110,target recorded,8417440,✔,TlvTypeTargetGetRecordedFilesRequest,
|
||||||
|
4110,target recorded,8417696,✔,TlvTypeTargetRecordedFilesReply,
|
||||||
|
4110,target recorded,8417952,✔,TlvTypeTargetRecordedFileDownloadRequest,
|
||||||
|
4110,target recorded,8418208,✔,TlvTypeTargetRecordedFileDownloadReply,
|
||||||
|
4110,target recorded,8418464,✔,TlvTypeTargetRecordedFileDownloadChunk,
|
||||||
|
4110,target recorded,8418720,✔,TlvTypeTargetRecordedFileDownloadCompleted,
|
||||||
|
4110,target recorded,8418976,✔,TlvTypeTargetRecordedFileDeleteRequest,
|
||||||
|
4110,target recorded,8419232,✔,TlvTypeTargetRecordedFileDeleteReply,
|
||||||
|
4111,target recorded ex,8419488,✔,TlvTypeTargetGetRecordedFilesRequestEx,
|
||||||
|
4111,target recorded ex,8419744,✔,TlvTypeTargetRecordedFilesReplyEx,
|
||||||
|
4111,target recorded ex,8420000,✔,TlvTypeTargetRecordedFileDeleteRequestEx,
|
||||||
|
4111,target recorded ex,8420256,✔,TlvTypeTargetRecordedFilesDownloadRequestEx,
|
||||||
|
4128,data,8454544,✔,TlvTypeProxyData,
|
||||||
|
4128,data,8454800,✔,TlvTypeRelayData,
|
||||||
|
4130,proxy,8458400,✔,TlvTypeProxyTargetDisconnect,
|
||||||
|
4130,proxy,8458656,✔,TlvTypeProxyMobileTargetDisconnect,
|
||||||
|
4130,proxy,8458912,✔,TlvTypeProxyDummyHeartbeat,
|
||||||
|
4130,proxy,8459168,✔,TlvTypeProxyMobileDummyHeartbeat,
|
||||||
|
4160,master,8520080,✔,TlvTypeMasterData,
|
||||||
|
4160,master,8520768,✔,TlvTypeMasterMode,
|
||||||
|
4160,master,8521024,✔,TlvTypeMasterToken,
|
||||||
|
4160,master,8521344,✔,TlvTypeMasterQueryResult,
|
||||||
|
4161,string master alarm,8522368,✔,TlvTypeMasterAlarmString,
|
||||||
|
4192,agent,8585616,✔,TlvTypeAgentData,
|
||||||
|
4192,agent,8585808,✔,TlvTypeAgentQueryID,
|
||||||
|
4192,agent,8586048,✔,TlvTypeAgentQueryModSubmodID,
|
||||||
|
4192,agent,8586304,✔,TlvTypeAgentQueryFromDate,
|
||||||
|
4192,agent,8586560,✔,TlvTypeAgentQueryToDate,
|
||||||
|
4192,agent,8586816,✔,TlvTypeAgentQuerySortOrder,
|
||||||
|
4192,agent,8587136,✔,TlvTypeAgentQueryValueFilter,
|
||||||
|
4193,uid agent,8587328,✔,TlvTypeAgentUID,
|
||||||
|
4224,mobile,8651152,✔,TlvTypeMobileTargetData,
|
||||||
|
4224,mobile,8651376,✔,TlvTypeMobileTargetHeartBeatV10,"Lorg/xmlpush/v3/o/g, Lorg/xmlpush/v3/o/g"
|
||||||
|
4224,mobile,8651632,✔,TlvTypeMobileTargetExtendedHeartBeatV10,"Lorg/xmlpush/v3/o/g, Lorg/xmlpush/v3/q/b"
|
||||||
|
4224,mobile,8651888,✔,TlvTypeMobileHeartBeatReplyV10,"Lorg/xmlpush/v3/o/h$b, Lorg/xmlpush/v3/o/l$2, L/org/xmlpush/v3/q/a, L/org/xmlpush/v3/q/c"
|
||||||
|
4225,installed reply modules mobile,8653472,✔,TlvTypeMobileInstalledModulesReply,
|
||||||
|
4225,installed reply modules mobile,8652912,×,unknown,Lorg/xmlpush/v3/o/l$2
|
||||||
|
4226,module upload mobile target,8655008,✔,TlvTypeMobileTargetOfflineUploadModuleRequest,L/org/xmlpush/v3/o/h
|
||||||
|
4226,module upload mobile target,8656032,✔,TlvTypeMobileTargetUploadModuleRequest,
|
||||||
|
4226,module upload mobile target,8656288,✔,TlvTypeMobileTargetUploadModuleReply,
|
||||||
|
4226,module upload mobile target,8656544,✔,TlvTypeMobileTargetUploadModuleChunk,
|
||||||
|
4226,module upload mobile target,8656800,✔,TlvTypeMobileTargetUploadModuleDoneRequest,
|
||||||
|
4227,target mobile,8657056,✔,TlvTypeMobileTargetUploadModuleDoneReply,
|
||||||
|
4227,target mobile,8657312,✔,TlvTypeMobileTargetRemoveModuleRequest,
|
||||||
|
4227,target mobile,8657568,✔,TlvTypeMobileTargetRemoveModuleReply,
|
||||||
|
4227,target mobile,8657824,✔,TlvTypeMobileTargetOfflineUploadModuleReply,Lorg/xmlpush/v3/o/j
|
||||||
|
4227,target mobile,8658080,✔,TlvTypeMobileTargetOfflineUploadModuleChunk,L/org/xmlpush/v3/o/h
|
||||||
|
4227,target mobile,8658336,✔,TlvTypeMobileTargetOfflineUploadModuleDoneRequest,L/org/xmlpush/v3/o/h
|
||||||
|
4227,target mobile,8658592,✔,TlvTypeMobileTargetOfflineUploadModuleDoneReply,Lorg/xmlpush/v3/o/j
|
||||||
|
4227,target mobile,8658848,✔,TlvTypeMobileTargetOfflineError,
|
||||||
|
4228,mobile target,8659104,✔,TlvTypeMobileTargetError,
|
||||||
|
4228,mobile target,8659360,✔,TlvTypeMobileTargetGetRecordedFilesRequest,L/org/xmlpush/v3/o/h
|
||||||
|
4228,mobile target,8659616,✔,TlvTypeMobileTargetRecordedFilesReply,Lorg/xmlpush/v3/o/d
|
||||||
|
4228,mobile target,8659872,✔,TlvTypeMobileTargetRecordedFileDownloadRequest,L/org/xmlpush/v3/o/h
|
||||||
|
4228,mobile target,8660128,✔,TlvTypeMobileTargetRecordedFileDownloadReply,Lorg/xmlpush/v3/o/d
|
||||||
|
4228,mobile target,8660384,✔,TlvTypeMobileTargetRecordedFileDownloadChunk,Lorg/xmlpush/v3/o/d
|
||||||
|
4228,mobile target,8660640,✔,TlvTypeMobileTargetRecordedFileDownloadCompleted,Lorg/xmlpush/v3/o/d
|
||||||
|
4228,mobile target,8660896,✔,TlvTypeMobileTargetRecordedFileDeleteRequest,L/org/xmlpush/v3/o/h
|
||||||
|
4229,target reply delete mobile recorded file,8661152,✔,TlvTypeMobileTargetRecordedFileDeleteReply,
|
||||||
|
4230,mobile config target,8663968,✔,TlvTypeMobileTargetOfflineConfig,Lorg/xmlpush/v3/q/c
|
||||||
|
4230,mobile config target,8664224,✔,TlvTypeMobileTargetEmergencyConfigAsTLV,
|
||||||
|
4230,mobile config target,8664432,✔,TlvTypeMobileTargetEmergencyConfig,"L/org/xmlpush/v3/q/a, L/org/xmlpush/v3/q/c"
|
||||||
|
4234,load module mobile target,8671392,✔,TlvTypeMobileTargetLoadModuleRequest,
|
||||||
|
4234,load module mobile target,8671648,✔,TlvTypeMobileTargetLoadModuleReply,
|
||||||
|
4234,load module mobile target,8671904,✔,TlvTypeMobileTargetUnLoadModuleRequest,
|
||||||
|
4234,load module mobile target,8672160,✔,TlvTypeMobileTargetUnLoadModuleReply,
|
||||||
|
4236,target error,8675472,✔,TlvTypeMobileTargetHeartbeatEvents,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4236,agent master files mc reply list,8675648,✔,TlvTypeMobileTargetHeartbeatInterval,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4236,recorded target,8675984,✔,TlvTypeMobileTargetHeartbeatRestrictions,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4236,recorded target,8676208,✔,TlvTypeConfigSMSPhoneNumber,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4236,recorded target,8676496,✔,TlvTypeMobileTargetPositioning,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4236,recorded target,8676672,✔,TlvTypeMobileTrojanUID,"Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/t/d, Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/i, Lorg/xmlpush/v3/o/i, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/n, Lorg/xmlpush/v3/a/a, Lorg/xmlpush/v3/q/c, Lorg/xmlpush/v3/f/a, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/d/a, Lorg/xmlpush/v3/h/c, Lorg/xmlpush/v3/i/a, L/org/xmlpush/v3/h/c"
|
||||||
|
4236,recorded target,8676976,✔,TlvTypeMobileTrojanID,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4236,recorded target,8677296,✔,TlvTypeMobileTargetLocationChangedRange,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4237,config,8677440,✔,TlvTypeConfigMobileAutoRemovalDateTime,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4237,config,8677808,✔,TlvTypeConfigOverwriteProxyAndPhones,
|
||||||
|
4237,config,8678000,✔,TlvTypeConfigCallPhoneNumber,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4238,ex recorded target,8679488,✔,TlvTypeLocationAreaCode,"Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/f/a, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/d/a, Lorg/xmlpush/v3/i/a"
|
||||||
|
4238,ex recorded target,8679744,✔,TlvTypeCellID,"Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/f/a, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/d/a, Lorg/xmlpush/v3/i/a"
|
||||||
|
4238,ex recorded target,8680048,✔,TlvTypeMobileCountryCode,"Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/f/a, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/d/a, Lorg/xmlpush/v3/i/a"
|
||||||
|
4238,data,8680304,✔,TlvTypeMobileNetworkCode,"Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/f/a, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/d/a, Lorg/xmlpush/v3/i/a"
|
||||||
|
4238,data,8680560,✔,TlvTypeIMSI,
|
||||||
|
4238,proxy,8680816,✔,TlvTypeIMEI,
|
||||||
|
4238,proxy,8681072,✔,TlvTypeGPSLatitude,
|
||||||
|
4238,proxy,8681328,✔,TlvTypeGPSLongitude,
|
||||||
|
4239,proxy,8681520,✔,TlvTypeFirstHeartbeat,
|
||||||
|
4239,master,8681872,✔,TlvTypeInstalledModules,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4240,gps valid values,8683568,✔,TlvTypeValidGPSValues,
|
||||||
|
4288,mobile proxy comm target,8782176,✔,TlvTypeProxyMobileTargetCommSig,
|
||||||
|
4288,mobile proxy comm target,8782496,✔,TlvTypeProxyMobileTargetComm,
|
||||||
|
4288,mobile proxy comm target,8782752,✔,TlvTypeProxyMasterMobileTargetComm,
|
||||||
|
4384,master mobile,8978752,✔,TlvTypeMobileProxyMasterCommSig,
|
||||||
|
4384,master mobile,8978848,✔,TlvTypeMasterMobileTargetConn,
|
||||||
|
4384,master mobile,8979104,✔,TlvTypeMobileProxyMasterComm,
|
||||||
|
4384,master mobile,8979360,✔,TlvTypeMobileMasterProxyComm,
|
||||||
|
4384,master mobile,8979616,✔,TlvTypeProxyMasterMobileHeartBeatAnswer,"Lorg/xmlpush/v3/o/l$2, L/org/xmlpush/v3/o/h"
|
||||||
|
4384,master mobile,8979872,✔,TlvTypeMobileMasterProxyCommNotification,
|
||||||
|
8128,agent,16646544,✔,TlvTypePlaintext,
|
||||||
|
8128,agent uid,16646800,✔,TlvTypeCompression,
|
||||||
|
8128,mobile,16647056,✔,TlvTypeEncryption,"Lorg/xmlpush/v3/h/c, L/org/xmlpush/v3/h/c"
|
||||||
|
8128,mobile,16647232,✔,TlvTypeTargetUID,
|
||||||
|
8128,mobile,16647536,✔,TlvTypeIPAddress,"Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/i, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/n"
|
||||||
|
8128,mobile,16647808,✔,TlvTypeUserName,
|
||||||
|
8128,installed reply modules mobile,16648064,✔,TlvTypeComputerName,
|
||||||
|
8129,installed reply modules mobile,16648304,✔,TlvTypeLoginName,
|
||||||
|
8129,module upload mobile target,16648560,✔,TlvTypePassphrase,
|
||||||
|
8129,module upload mobile target,16648832,✔,TlvTypeRecordID,
|
||||||
|
8129,module upload mobile target,16649088,✔,TlvTypeOwner,
|
||||||
|
8129,module upload mobile target,16649344,✔,TlvTypeMetaData,
|
||||||
|
8129,module upload mobile target,16649536,✔,TlvTypeModuleID,"Lorg/xmlpush/v3/o/d, L/org/xmlpush/v3/o/h, L/org/xmlpush/v3/h/c, L/org/xmlpush/v3/h/c"
|
||||||
|
8129,mobile target,16649856,✔,TlvTypeOSName,
|
||||||
|
8129,mobile target,16650048,✔,TlvTypeModuleSubID,"Lorg/xmlpush/v3/o/d, L/org/xmlpush/v3/h/c, L/org/xmlpush/v3/h/c"
|
||||||
|
8130,mobile target,16650320,✔,TlvTypeErrorCode,
|
||||||
|
8130,mobile target,16650560,✔,TlvTypeOffset,
|
||||||
|
8130,mobile target,16650816,✔,TlvTypeLength,
|
||||||
|
8130,mobile target,16651088,✔,TlvTypeRequestID,"Lorg/xmlpush/v3/w, Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/j, Lorg/xmlpush/v3/o/j, Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/i, Lorg/xmlpush/v3/o/b, Lorg/xmlpush/v3/o/b, Lorg/xmlpush/v3/o/b, Lorg/xmlpush/v3/o/b, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/n, Lorg/xmlpush/v3/o/d, Lorg/xmlpush/v3/o/d, Lorg/xmlpush/v3/o/d, Lorg/xmlpush/v3/o/d, Lorg/xmlpush/v3/q/c, Lorg/xmlpush/v3/f/b, L/org/xmlpush/v3/o/h, L/org/xmlpush/v3/h/c, L/org/xmlpush/v3/h/c"
|
||||||
|
8130,mobile target,16651328,✔,TlvTypeRequestType,
|
||||||
|
8130,mobile target,16651584,✔,TlvTypeVersion,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c, L/org/xmlpush/v3/h/c"
|
||||||
|
8130,mobile target,16651840,✔,TlvTypeMachineID,
|
||||||
|
8130,mobile target,16652096,✔,TlvTypeMajorNumber,
|
||||||
|
8131,mobile target,16652352,✔,TlvTypeMinorNumber,
|
||||||
|
8131,mobile target,16652656,✔,TlvTypeGlobalIPAddress,
|
||||||
|
8131,mobile target,16652912,✔,TlvTypeASCII_Filename,
|
||||||
|
8131,mobile target,16653120,✔,TlvTypeFilesize,
|
||||||
|
8131,mobile target,16653392,✔,TlvTypeFilecount,
|
||||||
|
8131,mobile target,16653712,✔,TlvTypeFiledata,
|
||||||
|
8131,target reply recorded delete file mobile,16653968,✔,TlvTypeMD5Sum,
|
||||||
|
8131,mobile target config,16654144,✔,TlvTypeProxyPort,
|
||||||
|
8132,mobile target config,16654400,✔,TlvTypeStatus,
|
||||||
|
8132,mobile target config,16654656,✔,TlvTypeUserID,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
8132,module load mobile target,16654912,✔,TlvTypeGroupID,
|
||||||
|
8132,module load mobile target,16655168,✔,TlvTypePermissions,
|
||||||
|
8132,module load mobile target,16655424,✔,TlvTypeRequestCode,
|
||||||
|
8132,module load mobile target,16655680,✔,TlvTypeDataSize,
|
||||||
|
8132,,16655936,✔,TlvTypeKeyType,
|
||||||
|
8132,,16656240,✔,TlvTypeEmail,
|
||||||
|
8133,,16656432,✔,TlvTypeEnabled,
|
||||||
|
8133,,16656688,✔,TlvTypeLicensed,
|
||||||
|
8133,,16656960,✔,TlvTypeAudioFrequency,"Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/n"
|
||||||
|
8133,,16657216,✔,TlvTypeAudioBitsPerSample,"Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/n"
|
||||||
|
8133,,16657472,✔,TlvTypeAudioChannels,"Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/n"
|
||||||
|
8133,,16657728,✔,TlvTypeStartTime,
|
||||||
|
8133,config,16657984,✔,TlvTypeStopTime,
|
||||||
|
8133,config,16658240,✔,TlvTypeBitMask,
|
||||||
|
8134,config,16658560,✔,TlvTypeTimeZone,"Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/t/d, Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/i, Lorg/xmlpush/v3/o/b, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/o/n, Lorg/xmlpush/v3/a/a, Lorg/xmlpush/v3/f/a, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/d/a, Lorg/xmlpush/v3/i/a"
|
||||||
|
8134,,16658816,✔,TlvTypeDateTime,"Lorg/xmlpush/v3/t/d, Lorg/xmlpush/v3/o/e, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b"
|
||||||
|
8134,,16659072,✔,TlvTypeStartSessionDateTime,"Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/i, Lorg/xmlpush/v3/o/n, Lorg/xmlpush/v3/a/a, Lorg/xmlpush/v3/f/a, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/d/a, Lorg/xmlpush/v3/i/a"
|
||||||
|
8134,,16659328,✔,TlvTypeStopSessionDateTime,"Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/b, Lorg/xmlpush/v3/o/n"
|
||||||
|
8134,,16659520,✔,TlvTypeDateTimeRef,"L/org/xmlpush/v3/h/c, L/org/xmlpush/v3/h/c"
|
||||||
|
8134,,16659776,✔,TlvTypeScheduleRepeat,"L/org/xmlpush/v3/h/c, L/org/xmlpush/v3/h/c"
|
||||||
|
8134,,16660032,✔,TlvTypeUnixMasterDateTime,
|
||||||
|
8134,,16660288,✔,TlvTypeUnixUTCDateTime,
|
||||||
|
8135,,16660544,✔,TlvTypeDurationInSeconds,Lorg/xmlpush/v3/f/b
|
||||||
|
8135,,16660864,✔,TlvTypeMasterRefTime,
|
||||||
|
8135,,16661120,✔,TlvTypeMasterRefTimeStart,
|
||||||
|
8135,values gps valid,16661376,✔,TlvTypeMasterRefTimeEnd,
|
||||||
|
8135,,16661568,✔,TlvTypeCounter,"Lorg/xmlpush/v3/q/c, Lorg/xmlpush/v3/h/c, L/org/xmlpush/v3/h/c"
|
||||||
|
8135,,16661888,✔,TlvTypeWhiteListEntry,type: byte array
|
||||||
|
8135,,16662144,✔,TlvTypeBlackListEntry,type: array
|
||||||
|
8135,,16662336,✔,TlvTypeBlackWhiteListingMode,
|
||||||
|
8136,config,16662576,✔,TlvTypeConfigEnabled,
|
||||||
|
8136,config,16662848,✔,TlvTypeConfigMaxRecordingSize,
|
||||||
|
8136,config,16663104,✔,TlvTypeConfigAudioQuality,"Lorg/xmlpush/v3/o/a, Lorg/xmlpush/v3/o/n, L/org/xmlpush/v3/h/c"
|
||||||
|
8136,config,16663344,✔,TlvTypeConfigVideoBlackAndWhite,"Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/b, Lorg/xmlpush/v3/o/b, L/org/xmlpush/v3/h/c"
|
||||||
|
8136,config,16663616,✔,TlvTypeConfigVideoResolution,L/org/xmlpush/v3/h/c
|
||||||
|
8136,config,16663872,✔,TlvTypeConfigCaptureFrequency,"Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/b, Lorg/xmlpush/v3/o/b, L/org/xmlpush/v3/h/c"
|
||||||
|
8136,config,16664128,✔,TlvTypeConfigVideoQuality,"Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/k, Lorg/xmlpush/v3/o/b, Lorg/xmlpush/v3/o/b, L/org/xmlpush/v3/h/c"
|
||||||
|
8136,config,16664384,✔,TlvTypeConfigFilesStandardFilter,
|
||||||
|
8137,config,16664704,✔,TlvTypeConfigFilesCustomFilter,
|
||||||
|
8137,config,16664896,✔,TlvTypeConfigStandardLocation,
|
||||||
|
8137,config,16665216,✔,TlvTypeConfigCustomLocation,
|
||||||
|
8137,config,16665408,✔,TlvTypeConfigFileChunkSize,
|
||||||
|
8137,config,16665664,✔,TlvTypeConfigFileTransferSpeed,
|
||||||
|
8137,config,16665904,✔,TlvTypeConfigUploadFileOverwrite,
|
||||||
|
8137,config,16666160,✔,TlvTypeConfigDeleteOverReboot,
|
||||||
|
8137,config,16666496,✔,TlvTypeConfigCustomLocationException,
|
||||||
|
8138,master mobile,16666752,✔,TlvTypeExtraData,
|
||||||
|
8138,master mobile,16667008,✔,TlvTypeSignature,
|
||||||
|
8138,,16667264,✔,TlvTypeComments,
|
||||||
|
8138,,16667520,✔,TlvTypeDescription,
|
||||||
|
8138,,16667776,✔,TlvTypeFilenameExtension,"Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/f/b"
|
||||||
|
8138,,16668032,✔,TlvTypeSessionType,
|
||||||
|
8138,,16668224,✔,TlvTypePeriod,
|
||||||
|
8138,,16668512,✔,TlvTypeMobileTargetUID,"Lorg/xmlpush/v3/w, Lorg/xmlpush/v3/o/g, Lorg/xmlpush/v3/o/c, Lorg/xmlpush/v3/a/a, Lorg/xmlpush/v3/q/c, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/h/c, Lorg/xmlpush/v3/h/c, L/org/xmlpush/v3/o/h, L/org/xmlpush/v3/h/c, L/org/xmlpush/v3/h/c"
|
||||||
|
8139,,16668784,✔,TlvTypeMobileTargetID,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
8139,,16669072,✔,TlvTypeMobilePlaintext,
|
||||||
|
8139,,16669328,✔,TlvTypeMobileCompression,Lorg/xmlpush/v3/k
|
||||||
|
8139,,16669584,✔,TlvTypeMobileEncryption,"Lorg/xmlpush/v3/o/m, Lorg/xmlpush/v3/h/c"
|
||||||
|
8139,,16669824,✔,TlvTypeEncodingType,
|
||||||
|
8139,,16670576,✔,TlvTypePhoneNumber,"Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/n/m, Lorg/xmlpush/v3/t/d, Lorg/xmlpush/v3/a/a, Lorg/xmlpush/v3/f/a, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/f/b, Lorg/xmlpush/v3/d/a, Lorg/xmlpush/v3/i/a"
|
||||||
|
8140,custom config location mode,16670784,✔,TlvTypeConfigCustomLocationMode,
|
||||||
|
8140,custom config location mode,16672080,×,unknown,Lorg/xmlpush/v3/n/k
|
||||||
|
8140,custom config location mode,16671792,×,unknown,Lorg/xmlpush/v3/n/m
|
||||||
|
8142,network interface,16674928,✔,TlvTypeNetworkInterface,
|
||||||
|
8142,network interface,16675136,✔,TlvTypeNetworkInterfaceMode,
|
||||||
|
8142,network interface,16675440,✔,TlvTypeNetworkInterfaceAddress,
|
||||||
|
8142,network interface,16675696,✔,TlvTypeNetworkInterfaceNetmask,
|
||||||
|
8142,network interface,16675952,✔,TlvTypeNetworkInterfaceGateway,
|
||||||
|
8142,network interface,16676208,✔,TlvTypeNetworkInterfaceDNS_1,
|
||||||
|
8142,network interface,16676464,✔,TlvTypeNetworkInterfaceDNS_2,
|
||||||
|
8143,,16677440,✔,TlvTypeLoginTime,
|
||||||
|
8143,,16677696,✔,TlvTypeLogoffTime,
|
||||||
|
8143,,16678720,✔,TlvTypeGeneric_Type,
|
||||||
|
8144,,16678976,✔,TlvTypeChecksum,
|
||||||
|
8144,,16679280,✔,TlvTypeCity,
|
||||||
|
8144,,16679536,✔,TlvTypeCountry,
|
||||||
|
8144,,16679792,✔,TlvTypeCountryCode,
|
||||||
|
8146,,16683072,✔,TlvTypeTargetType,
|
||||||
|
8146,,16683392,✔,TlvTypeDurationString,Lorg/xmlpush/v3/o/a
|
||||||
|
8146,,16683904,×,unknown,Lorg/xmlpush/v3/n/m
|
||||||
|
8146,,16684848,×,unknown,"Lorg/xmlpush/v3/o/k, L/org/xmlpush/v3/h/c"
|
||||||
|
8160,,16712000,✔,TlvTypeTargetConnectionBroken,
|
||||||
|
8160,,16712256,✔,TlvTypeAgentConnectionBroken,
|
||||||
|
8160,,16712512,✔,TlvTypeTargetOffline,
|
||||||
|
8176,,16744768,✔,TlvTypeProxyConnectionBroken,
|
||||||
|
4242,,8688960,×,unknown,Lorg/xmlpush/v3/w
|
||||||
|
4242,,8689296,×,unknown,Lorg/xmlpush/v3/w
|
||||||
|
4242,,8689568,×,unknown,Lorg/xmlpush/v3/w
|
||||||
|
2752,,5636992,×,unknown,Lorg/xmlpush/v3/n/k
|
||||||
|
2752,,5637504,×,unknown,Lorg/xmlpush/v3/n/k
|
||||||
|
2752,,5637760,×,unknown,Lorg/xmlpush/v3/n/k
|
||||||
|
2752,,5636464,×,unknown,Lorg/xmlpush/v3/n/m
|
||||||
|
2752,,5636736,×,unknown,Lorg/xmlpush/v3/n/m
|
||||||
|
2752,,5637248,×,unknown,Lorg/xmlpush/v3/n/m
|
||||||
|
2753,,5638256,×,unknown,Lorg/xmlpush/v3/n/m
|
||||||
|
2753,,5638768,×,unknown,Lorg/xmlpush/v3/n/m
|
||||||
|
2754,,5641600,×,unknown,Lorg/xmlpush/v3/n/m
|
||||||
|
2754,,5640608,×,unknown,Lorg/xmlpush/v3/n/m
|
||||||
|
2754,,5641120,×,unknown,Lorg/xmlpush/v3/n/m
|
||||||
|
2754,,5640864,×,unknown,Lorg/xmlpush/v3/n/m
|
||||||
|
2754,,5640352,×,unknown,Lorg/xmlpush/v3/n/m
|
||||||
|
2218,,4542832,×,unknown,Lorg/xmlpush/v3/t/d
|
||||||
|
2218,,4542624,×,unknown,Lorg/xmlpush/v3/t/d
|
||||||
|
8147,,16685104,×,unknown,"Lorg/xmlpush/v3/o/k, L/org/xmlpush/v3/h/c"
|
||||||
|
8147,,16685392,×,unknown,"Lorg/xmlpush/v3/o/k, L/org/xmlpush/v3/h/c"
|
||||||
|
2658,,5444000,×,unknown,Lorg/xmlpush/v3/o/k
|
||||||
|
2658,,5444512,×,unknown,Lorg/xmlpush/v3/o/k
|
||||||
|
2656,,5440320,×,unknown,Lorg/xmlpush/v3/o/k
|
||||||
|
2656,,5439904,×,unknown,Lorg/xmlpush/v3/o/k
|
||||||
|
2660,,5447840,×,unknown,Lorg/xmlpush/v3/o/k
|
||||||
|
2722,,5575072,×,unknown,Lorg/xmlpush/v3/o/a
|
||||||
|
2722,,5575328,×,unknown,Lorg/xmlpush/v3/o/a
|
||||||
|
2722,config,5575840,×,unknown,Lorg/xmlpush/v3/o/a
|
||||||
|
2560,config,5243552,×,unknown,Lorg/xmlpush/v3/o/i
|
||||||
|
2560,config,5243296,×,unknown,Lorg/xmlpush/v3/o/i
|
||||||
|
4244,config,8693104,×,unknown,Lorg/xmlpush/v3/o/g
|
||||||
|
4244,config,8692080,×,unknown,Lorg/xmlpush/v3/o/g
|
||||||
|
4244,config,8692336,×,unknown,Lorg/xmlpush/v3/o/g
|
||||||
|
4244,config,8692592,×,unknown,Lorg/xmlpush/v3/o/g
|
||||||
|
4244,config,8692848,×,unknown,Lorg/xmlpush/v3/o/g
|
||||||
|
4244,config,8693360,×,unknown,Lorg/xmlpush/v3/o/g
|
||||||
|
4244,config,8691872,×,unknown,Lorg/xmlpush/v3/o/g
|
||||||
|
2690,config,5509536,×,unknown,Lorg/xmlpush/v3/o/b
|
||||||
|
2690,config,5510048,×,unknown,Lorg/xmlpush/v3/o/b
|
||||||
|
2692,config,5513376,×,unknown,Lorg/xmlpush/v3/o/b
|
||||||
|
2688,config,5505856,×,unknown,Lorg/xmlpush/v3/o/b
|
||||||
|
2688,config,5505440,×,unknown,Lorg/xmlpush/v3/o/b
|
||||||
|
2592,config,5309088,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2602,,5329824,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2602,,5330592,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2602,,5329568,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2602,,5330080,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2596,,5317536,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2596,,5317792,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2596,,5318048,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2596,,5317280,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2594,,5313440,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2594,,5312928,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2594,,5313184,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2600,,5325216,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2598,,5321376,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2598,,5322144,×,unknown,Lorg/xmlpush/v3/o/e
|
||||||
|
2784,mode location custom config,5703584,×,unknown,Lorg/xmlpush/v3/o/n
|
||||||
|
2784,mode location custom config,5703328,×,unknown,Lorg/xmlpush/v3/o/n
|
||||||
|
2784,mode location custom config,5702816,×,unknown,Lorg/xmlpush/v3/o/n
|
||||||
|
2784,interface network,5702032,×,unknown,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
2784,interface network,5702304,×,unknown,Lorg/xmlpush/v3/h/c
|
||||||
|
2785,interface network,5703808,×,unknown,Lorg/xmlpush/v3/o/n
|
||||||
|
2785,interface network,5704064,×,unknown,Lorg/xmlpush/v3/o/n
|
||||||
|
1757,interface network,3600000,×,unknown,Lorg/xmlpush/v3/b/f
|
||||||
|
2696,interface network,5521552,×,unknown,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
2696,interface network,5521568,×,unknown,Lorg/xmlpush/v3/h/c
|
||||||
|
2720,,5570960,×,unknown,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
2720,,5571232,×,unknown,Lorg/xmlpush/v3/h/c
|
||||||
|
2756,,5644432,×,unknown,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
2756,,5644704,×,unknown,Lorg/xmlpush/v3/h/c
|
||||||
|
2848,,5833104,×,unknown,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
2848,,5833376,×,unknown,Lorg/xmlpush/v3/h/c
|
||||||
|
3104,,6357392,×,unknown,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
3104,,6357664,×,unknown,Lorg/xmlpush/v3/h/c
|
||||||
|
2664,,5456016,×,unknown,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
2664,,5456288,×,unknown,Lorg/xmlpush/v3/h/c
|
||||||
|
4243,,8690064,×,unknown,"Lorg/xmlpush/v3/q/c, L/org/xmlpush/v3/h/c"
|
||||||
|
4243,,8690336,×,unknown,Lorg/xmlpush/v3/h/c
|
||||||
|
4243,,8689712,×,unknown,"Lorg/xmlpush/v3/h/c, L/org/xmlpush/v3/h/c"
|
||||||
|
2304,,4719008,×,unknown,Lorg/xmlpush/v3/d/a
|
||||||
|
2304,,4719232,×,unknown,Lorg/xmlpush/v3/d/a
|
||||||
|
3106,,6361200,×,unknown,Lorg/xmlpush/v3/k/c
|
||||||
|
16425,,33639248,×,unknown,Lorg/xmlpush/v3/h/a
|
||||||
|
48781,,99903492,×,unknown,"Lorg/b/b/e$gs, L/org/b/b/e$r"
|
||||||
|
41609,,85215461,×,unknown,"Lorg/b/b/e$df, L/org/b/b/e$j"
|
||||||
|
4494,,9203775,×,unknown,"Lorg/b/b/e$ol, L/org/b/b/e$pi"
|
||||||
|
25586,,52401552,×,unknown,"Lorg/b/b/e$js, L/org/b/b/e$x"
|
||||||
|
21214,,43446532,×,unknown,"Lorg/b/b/e$ec, L/org/b/b/e$m"
|
||||||
|
27793,,56920439,×,unknown,"Lorg/b/b/e$az, L/org/b/b/e$d"
|
||||||
|
26992,,55281185,×,unknown,"Lorg/b/b/e$nj, L/org/b/b/e$ag"
|
||||||
|
44308,,90744648,×,unknown,"Lorg/b/b/e$ew, L/org/b/b/e$ev"
|
||||||
|
@@ -0,0 +1,4 @@
|
|||||||
|
flash.browserupdate.download
|
||||||
|
current.browserupdate.download
|
||||||
|
files.browserupdate.download
|
||||||
|
browserupdate.download
|
||||||
6
data/ioc/spyware/amnesty/2020-09-25_finfisher/ips.txt
Normal file
6
data/ioc/spyware/amnesty/2020-09-25_finfisher/ips.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
172.241.27.171
|
||||||
|
5.135.174.213
|
||||||
|
158.69.105.207
|
||||||
|
207.244.95.223
|
||||||
|
45.11.19.235
|
||||||
|
185.125.230.203
|
||||||
174
data/ioc/spyware/amnesty/2020-09-25_finfisher/rules.yar
Normal file
174
data/ioc/spyware/amnesty/2020-09-25_finfisher/rules.yar
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
rule finspy_linux_installer1 {
|
||||||
|
meta:
|
||||||
|
description = "Rule for FinSpy Linux installer x86 or x64"
|
||||||
|
author = "Etienne Maynier, Amnesty Tech"
|
||||||
|
sample = "8aaf886a2a2cd459e65277343bc951a2d23555980eddd73218a5c608e6d2a29c"
|
||||||
|
strings:
|
||||||
|
$a = "%s/.kde/Autostart" ascii wide nocase
|
||||||
|
$b = "%s/.kde4/Autostart" ascii wide nocase
|
||||||
|
$c = "dmesg --notime 2>/dev/null | grep -i \"hypervisor detected\" | cut -d ':' -f2" ascii wide nocase
|
||||||
|
$d = "g_plauncher" ascii wide nocase
|
||||||
|
$e = "g_pinstall_host_location" ascii wide nocase
|
||||||
|
$f = "g_pinstall_folder" ascii wide nocase
|
||||||
|
$g = "%s/.bash_profile" ascii wide nocase
|
||||||
|
$h = "lspci 2>/dev/null | grep -i \"system peripheral\" | grep -i \"virtual\"" ascii wide nocase
|
||||||
|
$i = "lspci | grep -i \"system peripheral\" | grep -i \"virtual\"" ascii nocase
|
||||||
|
|
||||||
|
condition:
|
||||||
|
7 of them
|
||||||
|
}
|
||||||
|
|
||||||
|
rule finppy_linux_coremodule {
|
||||||
|
meta:
|
||||||
|
description = "Rule for FinSpy Linux core module x86 or x64"
|
||||||
|
author = "Etienne Maynier, Amnesty Tech"
|
||||||
|
strings:
|
||||||
|
$s1 = "ps auxww | grep -iEe 'bt-scan' | grep -v -e grep" ascii
|
||||||
|
$s2 = "ls /sys/class/net/ 2>/dev/null | awk '{printf (\"%s\n\", $1)}' 2>/dev/null" ascii
|
||||||
|
$s3 = "cat /sys/class/net/eth?/address 2>/dev/null" ascii
|
||||||
|
$s4 = "dmesg --notime 2>/dev/null | grep -i \"cpu\" | grep -i \"virtual\"" ascii
|
||||||
|
$s5 = "/etc/hostname-merlin" ascii
|
||||||
|
$s6 = "@%02X%X%c%08X.dat" ascii
|
||||||
|
$s7 = "%s/.bash_profile1" ascii
|
||||||
|
$s8 = "%s/.kde4/share/config" ascii
|
||||||
|
$s9 = "ls /dev/disk/by-id/ 2>/dev/null" ascii
|
||||||
|
$s10 = "/index.php HTTP/1.1" ascii
|
||||||
|
|
||||||
|
condition:
|
||||||
|
uint16(0) == 0x457F and 8 of them
|
||||||
|
}
|
||||||
|
|
||||||
|
rule finspy_linux_installer2 {
|
||||||
|
meta:
|
||||||
|
description = "Rule for FinSpy Linux installer"
|
||||||
|
author = "Etienne Maynier, Amnesty Tech"
|
||||||
|
|
||||||
|
strings:
|
||||||
|
$encrypted_conf = { 5? a5 aa ca a6 54 5a ?? a? 5a a5 0a } /* header of configuration files */
|
||||||
|
$encrypted_bin_32 = { 7f 0d 45 4c 46 01 02 c2 14 68 03 05 0e } /* header of encrypted bin */
|
||||||
|
$encrypted_bin_64 = { 7f 07 45 4c 46 02 01 1e 15 01 8e 03 0e } /* header of encrypted bin */
|
||||||
|
|
||||||
|
condition:
|
||||||
|
(uint16(0) == 0x457F or uint16(0) == 0x2123) and (#encrypted_conf > 5 or #encrypted_bin_32 > 5 or #encrypted_bin_64 > 5)
|
||||||
|
}
|
||||||
|
|
||||||
|
rule finspy_macos_installer {
|
||||||
|
meta:
|
||||||
|
description = "Rule for FinSpy OSX installer"
|
||||||
|
author = "Etienne Maynier, Amnesty Tech"
|
||||||
|
|
||||||
|
strings:
|
||||||
|
$s1 = "80.bundle.zip" ascii
|
||||||
|
$s2 = "AAC.dat" ascii
|
||||||
|
$s3 = "arch.zip" ascii
|
||||||
|
$s4 = "/Library/LaunchAgents" ascii
|
||||||
|
$s5 = "7FC.dat" ascii
|
||||||
|
$s6 = "logind.plist" ascii
|
||||||
|
$s7 = "org.logind.ctp.archive" ascii
|
||||||
|
$s8 = "helper" ascii
|
||||||
|
$s9 = "Contents/Resources/7f.bundle/Contents/Resources" ascii
|
||||||
|
|
||||||
|
condition:
|
||||||
|
uint16(0) == 0xFACF and 8 of them
|
||||||
|
}
|
||||||
|
|
||||||
|
rule finspy_macos_datapkg {
|
||||||
|
meta:
|
||||||
|
description = "Rule for FinSpy OSX core module"
|
||||||
|
author = "Etienne Maynier, Amnesty Tech"
|
||||||
|
|
||||||
|
strings:
|
||||||
|
$s1 = "vlacwjwcefforoxisdryuvbqlxvxt" ascii
|
||||||
|
$s2 = "vquyqefxqpwytfuherfvzwaqqyanaddmvquyqefxqpwytfu" ascii
|
||||||
|
$s3 = "vsczabsutfuhajffslhlkulomhivwligvscza:" ascii
|
||||||
|
$s4 = "ijfrkptshbsurggfqxshpiolwupesxewijfrkptxnj" ascii
|
||||||
|
$s5 = "wwsodegezqrtafprejkrytzablizbddgwwsodegezqrtafprejxnj" ascii
|
||||||
|
$s6 = "clfggqtyflyspjewoxpodxesnpavcpofclfggqtyflyspjewoxpodxesnpavcpofclfggqtyflyspjewoxpodx" ascii
|
||||||
|
$s7 = "mhqxzxdbxsfblsxmidzcribjewzkezujmhqxzxdbxsfblsxmidzcribjewzkezujmh" ascii
|
||||||
|
$s8 = "sqpviurrqssxwzrzdwldcanprnsuadyhsqpvixnj" ascii
|
||||||
|
$s9 = "zfocytolmylaejykmwphsbchfkfzyadbzfocytolmylaejykmwphsbchfkfzyadbz" ascii
|
||||||
|
$s10 = "fehbsdjwmqrdndkskegllpixxabegjrdfehbsdjwmqrdndkske" ascii
|
||||||
|
$s11 = "exmycityouezjfdczebdfhqdgt:" ascii
|
||||||
|
$s12 = "denueozlbzhqzzdjhxjnjhoadjdsmashdenueozlbzhqzzd" ascii
|
||||||
|
|
||||||
|
|
||||||
|
condition:
|
||||||
|
uint16(0) == 0xFACF and 8 of them
|
||||||
|
}
|
||||||
|
|
||||||
|
rule finspy_android_configinapk : android apkhideconfig finspy {
|
||||||
|
meta:
|
||||||
|
description = "Detect FinFisher FinSpy configuration in APK file. Probably the original FinSpy version."
|
||||||
|
date = "2020/08/05"
|
||||||
|
reference = "https://github.com/devio/FinSpy-Tools"
|
||||||
|
author = "Esther Onfroy a.k.a U+039b - *@0x39b.fr (https://twitter.com/u039b)"
|
||||||
|
warning = "May have some False Positive"
|
||||||
|
|
||||||
|
strings:
|
||||||
|
$re = /\x50\x4B\x01\x02[\x00-\xff]{32}[A-Za-z0-9+\/]{6}/
|
||||||
|
|
||||||
|
condition:
|
||||||
|
uint32(0) == 0x04034b50 and $re and (#re > 50)
|
||||||
|
}
|
||||||
|
|
||||||
|
rule finspy_android_dexden : android dexhideconfig finspy
|
||||||
|
{
|
||||||
|
meta:
|
||||||
|
description = "Detect FinFisher FinSpy configuration in DEX file. Probably a newer FinSpy variant."
|
||||||
|
date = "2020/08/05"
|
||||||
|
author = "Esther Onfroy a.k.a U+039b - *@0x39b.fr (https://twitter.com/u039b)"
|
||||||
|
|
||||||
|
strings:
|
||||||
|
$config_1 = { 90 5b fe 00 }
|
||||||
|
$config_2 = { 70 37 80 00 }
|
||||||
|
$config_3 = { 40 38 80 00 }
|
||||||
|
$config_4 = { a0 33 84 }
|
||||||
|
$config_5 = { 90 79 84 00 }
|
||||||
|
|
||||||
|
condition:
|
||||||
|
uint16(0) == 0x6564 and
|
||||||
|
#config_1 >= 2 and
|
||||||
|
#config_2 >= 2 and
|
||||||
|
#config_3 >= 2 and
|
||||||
|
#config_4 >= 2 and
|
||||||
|
#config_5 >= 2
|
||||||
|
}
|
||||||
|
|
||||||
|
rule FinSpy_TippyTime: finspyTT {
|
||||||
|
meta:
|
||||||
|
description = "Detect FinFisher FinSpy 'TippyTime' variant."
|
||||||
|
date = "2020/08/05"
|
||||||
|
author = "Esther Onfroy a.k.a U+039b - *@0x39b.fr (https://twitter.com/u039b)"
|
||||||
|
strings:
|
||||||
|
$config_1 = { 90 5b fe 00 }
|
||||||
|
$config_2 = { 70 37 80 00 }
|
||||||
|
$config_3 = { 40 38 80 00 }
|
||||||
|
$config_4 = { a0 33 84 }
|
||||||
|
$config_5 = { 90 79 84 00 }
|
||||||
|
$timestamp = { 95 E9 D1 5B }
|
||||||
|
|
||||||
|
condition:
|
||||||
|
uint16(0) == 0x6564 and
|
||||||
|
$timestamp and
|
||||||
|
$config_1 and
|
||||||
|
$config_2 and
|
||||||
|
$config_3 and
|
||||||
|
$config_4 and
|
||||||
|
$config_5
|
||||||
|
}
|
||||||
|
|
||||||
|
rule FinSpy_TippyPad: finspyTP
|
||||||
|
{
|
||||||
|
meta:
|
||||||
|
description = "Detect FinFisher FinSpy 'TippyPad' variant."
|
||||||
|
date = "2020/08/05"
|
||||||
|
author = "Esther Onfroy a.k.a U+039b - *@0x39b.fr (https://twitter.com/u039b)"
|
||||||
|
strings:
|
||||||
|
$pad_1 = "0123456789abcdef"
|
||||||
|
$pad_2 = "fedcba9876543210"
|
||||||
|
|
||||||
|
condition:
|
||||||
|
uint16(0) == 0x6564 and
|
||||||
|
#pad_1 > 50 and
|
||||||
|
#pad_2 > 50
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
import argparse
|
||||||
|
import struct
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
|
||||||
|
"""
|
||||||
|
Extract configuration from a Cobalt Strike decrypted beacon
|
||||||
|
|
||||||
|
Author : Etienne Maynier, Amnesty Tech
|
||||||
|
Date : March 2020
|
||||||
|
"""
|
||||||
|
|
||||||
|
CONFIG_STRUCT = {
|
||||||
|
1: "dns_ssl",
|
||||||
|
2: "port",
|
||||||
|
3: ".sleeptime",
|
||||||
|
4: ".http-get.server.output",
|
||||||
|
5: ".jitter",
|
||||||
|
6: ".maxdns",
|
||||||
|
7: "publickey",
|
||||||
|
8: ".http-get.uri",
|
||||||
|
9: ".user-agent",
|
||||||
|
10: ".http-post.uri",
|
||||||
|
11: ".http-get.server.output",
|
||||||
|
12: ".http-get.client",
|
||||||
|
13: ".http-post.client",
|
||||||
|
14: ".spawnto",
|
||||||
|
15: "unknown",
|
||||||
|
19: ".dns_idle",
|
||||||
|
20: ".dns_sleep ",
|
||||||
|
26: ".http-get.verb",
|
||||||
|
27: ".http-post.verb",
|
||||||
|
28: "shouldChunkPosts",
|
||||||
|
29: ".post-ex.spawnto_x86",
|
||||||
|
30: ".post-ex.spawnto_x64",
|
||||||
|
31: "cryptoscheme",
|
||||||
|
37: "watermark",
|
||||||
|
38: ".stage.cleanup",
|
||||||
|
39: "CFGCaution",
|
||||||
|
50: "cookieBeacon"
|
||||||
|
}
|
||||||
|
CONFIG_SIZE = 1978
|
||||||
|
|
||||||
|
class JsonEncoder(json.JSONEncoder):
|
||||||
|
def default(self, obj):
|
||||||
|
if isinstance(obj, bytearray):
|
||||||
|
return obj.hex()
|
||||||
|
return json.JSONEncoder.default(self, obj)
|
||||||
|
|
||||||
|
|
||||||
|
def search_config(data):
|
||||||
|
r = re.search(b"ihihik.{2}ikihik", data)
|
||||||
|
if r:
|
||||||
|
return r.span()[0]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def decode_config(data):
|
||||||
|
config = {}
|
||||||
|
i = 0
|
||||||
|
while i < len(data) - 8:
|
||||||
|
dec = struct.unpack(">HHH", data[i:i+6])
|
||||||
|
if dec[0] == 1:
|
||||||
|
v = struct.unpack(">H", data[i+6:i+8])[0]
|
||||||
|
config["dns"] = ((v & 1) == 1)
|
||||||
|
config["ssl"] = ((v & 8) == 8)
|
||||||
|
elif dec[0] in CONFIG_STRUCT.keys():
|
||||||
|
if dec[1] == 1 and dec[2] == 2:
|
||||||
|
# Short
|
||||||
|
config[CONFIG_STRUCT[dec[0]]] = struct.unpack(">H", data[i+6:i+8])[0]
|
||||||
|
elif dec[1] == 2 and dec[2] == 4:
|
||||||
|
# Int
|
||||||
|
config[CONFIG_STRUCT[dec[0]]] = struct.unpack(">I", data[i+6:i+10])[0]
|
||||||
|
elif dec[1] == 3:
|
||||||
|
# Byte or string
|
||||||
|
v = data[i+6:i+6+dec[2]]
|
||||||
|
try:
|
||||||
|
config[CONFIG_STRUCT[dec[0]]] = v.decode('utf-8').strip('\x00')
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
config[CONFIG_STRUCT[dec[0]]] = v
|
||||||
|
else:
|
||||||
|
print("Unknown config command {}".format(dec[0]))
|
||||||
|
# Add size +
|
||||||
|
i += dec[2] + 6
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(description='Extract Cobalt Strike configuration')
|
||||||
|
parser.add_argument('PAYLOAD', help='A Cobalt Strike beacon')
|
||||||
|
parser.add_argument('--json', '-j', action="store_true", help='Print json')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
with open(args.PAYLOAD, "rb") as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
START = search_config(data)
|
||||||
|
if not START:
|
||||||
|
print("Start position of the config struct not found")
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
# Configuration is xored with 105
|
||||||
|
conf = bytearray([c ^ 105 for c in data[START:START+CONFIG_SIZE]])
|
||||||
|
|
||||||
|
config = decode_config(conf)
|
||||||
|
if args.json:
|
||||||
|
print(json.dumps(config, indent=4, sort_keys=True, cls=JsonEncoder))
|
||||||
|
else:
|
||||||
|
for d in config:
|
||||||
|
if isinstance(config[d], bytearray):
|
||||||
|
print("{} : {}".format(d, config[d].hex()))
|
||||||
|
else:
|
||||||
|
print("{} : {}".format(d, config[d]))
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import argparse
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
|
||||||
|
"""
|
||||||
|
Decrypt a Cobalt Strike encrypted beacon
|
||||||
|
|
||||||
|
Author: Etienne Maynier, Amnesty Tech
|
||||||
|
Date: March 2020
|
||||||
|
"""
|
||||||
|
|
||||||
|
def xor(a, b):
|
||||||
|
return bytearray([a[0]^b[0], a[1]^b[1], a[2]^b[2], a[3]^b[3]])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(description='Decode an encoded Cobalt Strike beacon')
|
||||||
|
parser.add_argument('PAYLOAD', help='an integer for the accumulator')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
with open(args.PAYLOAD, "rb") as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
# The base address of the sample change depending on the code
|
||||||
|
ba = data.find(b"\xe8\xd4\xff\xff\xff")
|
||||||
|
if ba == -1:
|
||||||
|
ba = data.find(b"\xe8\xd0\xff\xff\xff")
|
||||||
|
if ba == -1:
|
||||||
|
print("Base Address not found")
|
||||||
|
sys.exit(1)
|
||||||
|
ba += 5
|
||||||
|
|
||||||
|
key = data[ba:ba+4]
|
||||||
|
print("Key : {}".format(key))
|
||||||
|
size = struct.unpack("I", xor(key, data[ba+4:ba+8]))[0]
|
||||||
|
print("Size : {}".format(size))
|
||||||
|
|
||||||
|
res = bytearray()
|
||||||
|
i = ba+8
|
||||||
|
while i < (len(data) - ba - 8):
|
||||||
|
d = data[i:i+4]
|
||||||
|
res += xor(d, key)
|
||||||
|
key = d
|
||||||
|
i += 4
|
||||||
|
|
||||||
|
if not res.startswith(b"MZ"):
|
||||||
|
print("Invalid decoding, no PE header")
|
||||||
|
|
||||||
|
with open("a.out", "wb+") as f:
|
||||||
|
f.write(res)
|
||||||
|
print("PE file extracted in a.out")
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
import hashlib
|
||||||
|
import ctypes
|
||||||
|
import binascii
|
||||||
|
import argparse
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
"""
|
||||||
|
Decode FinSpy modules for Linux and MacOS
|
||||||
|
|
||||||
|
Author : Maciek mak@malwarelab.pl
|
||||||
|
Date: August 2020
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def unpack(data, s=0):
|
||||||
|
"""
|
||||||
|
Decode the binary with aplib
|
||||||
|
"""
|
||||||
|
cin = ctypes.c_buffer(data)
|
||||||
|
cout = ctypes.c_buffer(s if s else len(data) * 20)
|
||||||
|
aplib_path = os.path.join(
|
||||||
|
os.path.dirname(os.path.realpath(__file__)),
|
||||||
|
"_aplib.so")
|
||||||
|
aPLIB = ctypes.cdll.LoadLibrary(aplib_path)
|
||||||
|
n = aPLIB.aP_depack(cin, cout)
|
||||||
|
return cout.raw[:n]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description='Unpack FinSpy modules')
|
||||||
|
parser.add_argument('MODULE', help='Finspy module')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
with open(args.MODULE,'rb') as f:
|
||||||
|
hmd5 = f.read(0x10)
|
||||||
|
IV = f.read(0x10)
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
hash_iv_data = hashlib.md5(IV + data)
|
||||||
|
if hmd5 == hash_iv_data.digest():
|
||||||
|
data = IV + data
|
||||||
|
IV = b'\xd9!V\xee\xbe\x0c\xf9\x18*\xfaR;%&\xb7\x08'
|
||||||
|
|
||||||
|
if hmd5 == hashlib.md5(data).digest():
|
||||||
|
print('[+] DATA HASH match {}'.format(binascii.hexlify(hmd5)))
|
||||||
|
|
||||||
|
key = b'YO\xf4\xa6\xd6\x1d\xd7!\xdc\x01A\xbfg\x83"m'
|
||||||
|
xdata = AES.new(key,mode=AES.MODE_CBC,IV=bytes(IV)).decrypt(data)
|
||||||
|
size = struct.unpack('I',xdata[:4])[0]
|
||||||
|
print('[+] Unpacked size: {:x}'.format(size))
|
||||||
|
depack = unpack(xdata[4:], size)
|
||||||
|
with open(args.MODULE + '.unpacked.bin','wb') as f:
|
||||||
|
f.write(depack)
|
||||||
|
print('[*] saved to {}.unpacked.bin'.format(sys.argv[1]))
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
import struct
|
||||||
|
|
||||||
|
"""
|
||||||
|
Extract configuration of Linux FinSpy from an installer
|
||||||
|
author: Etienne Maynier, Amnesty Tech
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description='Extract configuration Linux Finspy sample')
|
||||||
|
parser.add_argument('FILE', help='FinSpy sample for Linux')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
regex_cfg = re.compile(b'.[\x50-\x5f]\xa5\xaa\xca\xa6\x54\x5a.[\xa0-\xaf]\x5a\xa5\x0a')
|
||||||
|
|
||||||
|
with open(args.FILE, 'rb') as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
if len(regex_cfg.findall(data)) < 5:
|
||||||
|
print("This does not look like a FinSpy sample")
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
if not os.path.isdir('extracted'):
|
||||||
|
os.mkdir('extracted')
|
||||||
|
|
||||||
|
i = 1
|
||||||
|
for cfg in regex_cfg.finditer(data):
|
||||||
|
pos = cfg.span()[0]
|
||||||
|
# Decrypt the first 4 bytes to get the length
|
||||||
|
length = struct.unpack('I', bytearray([data[pos]^0xaa, data[pos+1]^0x5a, data[pos+2]^0xa5, data[pos+3]^0xaa]))[0]
|
||||||
|
with open('extracted/{0:02d}.dat'.format(i), 'wb+') as f:
|
||||||
|
f.write(data[pos:pos+length])
|
||||||
|
print("Configuration file extracted {0:02d}.dat ({} bytes)".format(i, length))
|
||||||
|
i += 1
|
||||||
@@ -0,0 +1,872 @@
|
|||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import struct
|
||||||
|
#import simplejson as json
|
||||||
|
from json import JSONEncoder
|
||||||
|
import json
|
||||||
|
from io import BytesIO
|
||||||
|
"""
|
||||||
|
Decode configuration from FinSpy Linux, MacOS and Android samples
|
||||||
|
Python3 only
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "Maciek mak@malwarelab.pl"
|
||||||
|
|
||||||
|
|
||||||
|
# From https://github.com/devio/FinSpy-Tools/blob/master/Android/finspyCfgParse.py
|
||||||
|
tlv_types = {
|
||||||
|
4522400: "TlvTypeMobileTrackingStartRequest",
|
||||||
|
4522656: "TlvTypeMobileTrackingStopRequest",
|
||||||
|
4523376: "TlvTypeMobileTrackingDataV10",
|
||||||
|
4535200: "TlvTypeMobileTrackingConfig",
|
||||||
|
4535440: "TlvTypeMobileTrackingConfigRaw",
|
||||||
|
4538432: "TlvTypeMobileTrackingTimeInterval",
|
||||||
|
4538688: "TlvTypeMobileTrackingDistance",
|
||||||
|
4538928: "TlvTypeMobileTrackingSendOnAnyChannel",
|
||||||
|
6291872: "TlvTypeMobileLoggingMetaInfo",
|
||||||
|
6292096: "TlvTypeMobileLoggingData",
|
||||||
|
4456864: "TlvTypeMobileBlackberryMessengerMetaInfo",
|
||||||
|
4457088: "TlvTypeMobileBlackberryMessengerData",
|
||||||
|
4457328: "TlvTypeMobileBlackberryMsChatID",
|
||||||
|
4457600: "TlvTypeMobileBlackberryMsConversationPartners",
|
||||||
|
4587936: "TlvTypeMobilePhoneCallLogsMetaInfo",
|
||||||
|
4588192: "TlvTypeMobilePhoneCallLogsData",
|
||||||
|
4588400: "TlvTypeMobilePhoneCallLogsType",
|
||||||
|
4588672: "TlvTypeMobilePhoneCallAdditionalInformation",
|
||||||
|
4588912: "TlvTypeMobilePhoneCallLogsCallerNumber",
|
||||||
|
4589168: "TlvTypeMobilePhoneCallLogsCalleeNumber",
|
||||||
|
4589440: "TlvTypeMobilePhoneCallLogsCallerName",
|
||||||
|
4589696: "TlvTypeMobilePhoneCallLogsCalleeName",
|
||||||
|
4591680: "TlvTypeMobilePhoneCallLogLastEntryEndtime",
|
||||||
|
4325792: "TlvTypeMobileSMSMetaInfo",
|
||||||
|
4326016: "TlvTypeMobileSMSData",
|
||||||
|
4326256: "TlvTypeSMSSenderNumber",
|
||||||
|
4326512: "TlvTypeSMSRecipientNumber",
|
||||||
|
4326768: "TlvTypeSMSDirection",
|
||||||
|
4326528: "TlvTypeSMSInformation",
|
||||||
|
4391328: "TlvTypeMobileAddressBookMetaInfo",
|
||||||
|
4391552: "TlvTypeMobileAddressBookData",
|
||||||
|
4407360: "TlvTypeMobileAddressBookChecksum",
|
||||||
|
8978752: "TlvTypeMobileProxyMasterCommSig",
|
||||||
|
8979104: "TlvTypeMobileProxyMasterComm",
|
||||||
|
8979360: "TlvTypeMobileMasterProxyComm",
|
||||||
|
8979616: "TlvTypeProxyMasterMobileHeartBeatAnswer",
|
||||||
|
8979872: "TlvTypeMobileMasterProxyCommNotification",
|
||||||
|
8782176: "TlvTypeProxyMobileTargetCommSig",
|
||||||
|
8782496: "TlvTypeProxyMobileTargetComm",
|
||||||
|
8782752: "TlvTypeProxyMasterMobileTargetComm",
|
||||||
|
1507744: "TlvTypeAccessedFileMetaInfo",
|
||||||
|
1507968: "TlvTypeAccessedFileAccessTime",
|
||||||
|
1508224: "TlvTypeAccessedFileAccessEvent",
|
||||||
|
1508496: "TlvTypeAccessedFileRecording",
|
||||||
|
1508736: "TlvTypeAccessedApplicationName",
|
||||||
|
1508912: "TlvTypeConfigRecordImagesFromExplorer",
|
||||||
|
1519776: "TlvTypeGetAccessedConfigRequest",
|
||||||
|
1520032: "TlvTypeAccessedConfigReply",
|
||||||
|
1520288: "TlvTypeSetAccessedConfigRequest",
|
||||||
|
1520448: "TlvTypeConfigAccessedEvents",
|
||||||
|
2240672: "TlvTypeGetMouseClicksConfigRequest",
|
||||||
|
2240928: "TlvTypeMouseClicksConfigReply",
|
||||||
|
2241184: "TlvTypeSetMouseClicksConfigRequest",
|
||||||
|
2228640: "TlvTypeMouseClicksMetaInfo",
|
||||||
|
2228896: "TlvTypeMouseClicksFrame",
|
||||||
|
2232448: "TlvTypeMouseClicksEncodingType",
|
||||||
|
2232896: "TlvTypeConfigMouseClicksRectangle",
|
||||||
|
2233152: "TlvTypeConfigMouseClicksSensitivity",
|
||||||
|
2233408: "TlvTypeConfigMouseClicksType",
|
||||||
|
2175136: "TlvTypeGetVoIPConfigRequest",
|
||||||
|
2175392: "TlvTypeVoIPConfigReply",
|
||||||
|
2175648: "TlvTypeSetVoIPConfigRequest",
|
||||||
|
2163104: "TlvTypeVoIPMetaInfo",
|
||||||
|
2166912: "TlvTypeVoIPEncodingType",
|
||||||
|
2167168: "TlvTypeVoIPSessionType",
|
||||||
|
2167424: "TlvTypeVoIPApplicationName",
|
||||||
|
2167696: "TlvTypeVoIPAppScreenshot",
|
||||||
|
2167952: "TlvTypeVoIPAudioRecording",
|
||||||
|
2168112: "TlvTypeConfigVoIPScreenshotEnabled",
|
||||||
|
2109600: "TlvTypeGetForensicsConfigRequest",
|
||||||
|
2109856: "TlvTypeForensicsConfigReply",
|
||||||
|
2110112: "TlvTypeSetForensicsConfigRequest",
|
||||||
|
2097568: "TlvTypeUploadForensicsApplicationRequest",
|
||||||
|
2097824: "TlvTypeUploadForensicsApplicationReply",
|
||||||
|
2098080: "TlvTypeUploadForensicsApplicationChunk",
|
||||||
|
2098336: "TlvTypeUploadForensicsApplicationDoneRequest",
|
||||||
|
2098592: "TlvTypeUploadForensicsApplicationDoneReply",
|
||||||
|
2101664: "TlvTypeRemoveForensicsApplicationRequest",
|
||||||
|
2101920: "TlvTypeRemoveForensicsApplicationReply",
|
||||||
|
2105760: "TlvTypeForensicsAppExecuteRequest",
|
||||||
|
2106016: "TlvTypeForensicsAppExecuteReply",
|
||||||
|
2106272: "TlvTypeForensicsAppExecuteResult",
|
||||||
|
2106528: "TlvTypeForensicsAppExecuteResultChunk",
|
||||||
|
2106784: "TlvTypeForensicsAppExecuteResultDone",
|
||||||
|
2107040: "TlvTypeForensicsCancelAppExecuteRequest",
|
||||||
|
2107296: "TlvTypeForensicsCancelAppExecuteReply",
|
||||||
|
2113680: "TlvTypeConfigForensicsApplicationInfoGeneric",
|
||||||
|
2113952: "TlvTypeConfigForensicsApplicationInfo",
|
||||||
|
2117760: "TlvTypeConfigForensicsApplicationName",
|
||||||
|
2117952: "TlvTypeConfigForensicsApplicationSize",
|
||||||
|
2118208: "TlvTypeConfigForensicsApplicationID",
|
||||||
|
2118528: "TlvTypeConfigForensicsApplicationCmdline",
|
||||||
|
2118784: "TlvTypeConfigForensicsApplicationOutput",
|
||||||
|
2118976: "TlvTypeConfigForensicsApplicationTimeout",
|
||||||
|
2119232: "TlvTypeConfigForensicsApplicationVersion",
|
||||||
|
2119552: "TlvTypeForensicsFriendlyName",
|
||||||
|
2119808: "TlvTypeConfigForensicsApplicationOutputPrepend",
|
||||||
|
2120064: "TlvTypeConfigForensicsApplicationOutputContentType",
|
||||||
|
1638816: "TlvTypeDeletedFileMetaInfo",
|
||||||
|
1639296: "TlvTypeDeletedFileDeletionTime",
|
||||||
|
1639552: "TlvTypeDeletedFileRecycleBin",
|
||||||
|
1639808: "TlvTypeDeletedMethod",
|
||||||
|
1640064: "TlvTypeDeletedApplicationName",
|
||||||
|
1640336: "TlvTypeDeletedFileRecording",
|
||||||
|
1650848: "TlvTypeGetDeletedConfigRequest",
|
||||||
|
1651104: "TlvTypeDeletedConfigReply",
|
||||||
|
1651360: "TlvTypeSetDeletedConfigRequest",
|
||||||
|
1573280: "TlvTypePrintFileMetaInfo",
|
||||||
|
1573520: "TlvTypePrintFrame",
|
||||||
|
1581184: "TlvTypePrintApplicationName",
|
||||||
|
1581440: "TlvTypePrintFilename",
|
||||||
|
1581696: "TlvTypePrintEncodingType",
|
||||||
|
1585312: "TlvTypeGetPrintConfigRequest",
|
||||||
|
1585568: "TlvTypePrintConfigReply",
|
||||||
|
1585824: "TlvTypeSetPrintConfigRequest",
|
||||||
|
1442208: "TlvTypeChangedFileMetaInfo",
|
||||||
|
1442432: "TlvTypeChangedFileChangeTime",
|
||||||
|
1442688: "TlvTypeChangedFileChangeEvent",
|
||||||
|
1442960: "TlvTypeChangedFileRecording",
|
||||||
|
1454240: "TlvTypeGetChangedConfigRequest",
|
||||||
|
1454496: "TlvTypeChangedConfigReply",
|
||||||
|
1454752: "TlvTypeSetChangedConfigRequest",
|
||||||
|
1454912: "TlvTypeConfigChangedEvents",
|
||||||
|
1311136: "TlvTypeSkypeAudioMetaInfo",
|
||||||
|
1311376: "TlvTypeSkypeAudioRecording",
|
||||||
|
1311648: "TlvTypeSkypeTextRecording",
|
||||||
|
1311904: "TlvTypeSkypeFileMetaInfo",
|
||||||
|
1312144: "TlvTypeSkypeFileRecording",
|
||||||
|
1312416: "TlvTypeSkypeContactsRecording",
|
||||||
|
1312640: "TlvTypeSkypeContactsUserData",
|
||||||
|
1323168: "TlvTypeGetSkypeConfigRequest",
|
||||||
|
1323424: "TlvTypeSkypeConfigReply",
|
||||||
|
1323680: "TlvTypeSetSkypeConfigRequest",
|
||||||
|
1324336: "TlvTypeConfigSkypeAudioEnable",
|
||||||
|
1324592: "TlvTypeConfigSkypeTextEnable",
|
||||||
|
1324848: "TlvTypeConfigSkypeFileEnable",
|
||||||
|
1325104: "TlvTypeConfigSkypeContactsListEnable",
|
||||||
|
1327232: "TlvTypeSkypeAudioEncodingType",
|
||||||
|
1327488: "TlvTypeSkypeLoggedInUserAccountName",
|
||||||
|
1327744: "TlvTypeSkypeConversationPartnerAccountName",
|
||||||
|
1328000: "TlvTypeSkypeConversationPartnerDisplayName",
|
||||||
|
1328256: "TlvTypeSkypeChatMembers",
|
||||||
|
1328512: "TlvTypeSkypeTextMessage",
|
||||||
|
1328768: "TlvTypeSkypeChatID",
|
||||||
|
1329024: "TlvTypeSkypeSenderAccountName",
|
||||||
|
1329280: "TlvTypeSkypeSenderDisplayName",
|
||||||
|
1329536: "TlvTypeSkypeIncoming",
|
||||||
|
1329792: "TlvTypeSkypeSessionType",
|
||||||
|
1192096: "TlvTypeGetKeyloggerConfigRequest",
|
||||||
|
1192352: "TlvTypeKeyloggerConfigReply",
|
||||||
|
1192608: "TlvTypeSetKeyloggerConfigRequest",
|
||||||
|
1180064: "TlvTypeStartKeyLoggingRequest",
|
||||||
|
1180320: "TlvTypeStartKeyLoggingReply",
|
||||||
|
1180576: "TlvTypeKeyLoggingFrame",
|
||||||
|
1180832: "TlvTypeStopKeyLoggingRequest",
|
||||||
|
1181088: "TlvTypeKeyLoggingStoppedReply",
|
||||||
|
1196416: "TlvTypeKLFrameData",
|
||||||
|
1126560: "TlvTypeGetVideoConfigRequest",
|
||||||
|
1126816: "TlvTypeVideoConfigReply",
|
||||||
|
1127072: "TlvTypeSetVideoConfigRequest",
|
||||||
|
1114528: "TlvTypeStartScreenRequest",
|
||||||
|
1114784: "TlvTypeStartScreenReply",
|
||||||
|
1115040: "TlvTypeScreenFrame",
|
||||||
|
1115296: "TlvTypeStopScreenRequest",
|
||||||
|
1115552: "TlvTypeScreenStoppedReply",
|
||||||
|
1115808: "TlvTypeStartScreenRecording",
|
||||||
|
1122720: "TlvTypeStartWebCamRequest",
|
||||||
|
1122976: "TlvTypeStartWebCamReply",
|
||||||
|
1123232: "TlvTypeWebCamFrame",
|
||||||
|
1123488: "TlvTypeStopWebCamRequest",
|
||||||
|
1123744: "TlvTypeWebCamStoppedReply",
|
||||||
|
1124000: "TlvTypeStartWebCamRecording",
|
||||||
|
1130560: "TlvTypeVDFrameID",
|
||||||
|
1130896: "TlvTypeVDFrameData",
|
||||||
|
1131136: "TlvTypeOriginalVideoResolution",
|
||||||
|
1131392: "TlvTypeVideoResolution",
|
||||||
|
1066112: "TlvTypeVideoSessionType",
|
||||||
|
1066368: "TlvTypeVideoEncodingType",
|
||||||
|
1132160: "TlvTypeAutomaticRecordingUID",
|
||||||
|
1061024: "TlvTypeGetAudioConfigRequest",
|
||||||
|
1061280: "TlvTypeAudioConfigReply",
|
||||||
|
1061536: "TlvTypeSetAudioConfigRequest",
|
||||||
|
1048992: "TlvTypeStartMicrophoneRequest",
|
||||||
|
1049248: "TlvTypeStartMicrophoneReply",
|
||||||
|
1049504: "TlvTypeMicrophoneFrame",
|
||||||
|
1049760: "TlvTypeStopMicrophoneRequest",
|
||||||
|
1050016: "TlvTypeMicrophoneStoppedReply",
|
||||||
|
1050272: "TlvTypeStartMicrophoneRecording",
|
||||||
|
1052736: "TlvTypeMICFrameID",
|
||||||
|
1053072: "TlvTypeMICFrameData",
|
||||||
|
1053312: "TlvTypeAudioSessionType",
|
||||||
|
1053568: "TlvTypeAudioEncodingType",
|
||||||
|
328096: "TlvTypeGetSchedulerConfigRequest",
|
||||||
|
328352: "TlvTypeSchedulerConfigReply",
|
||||||
|
328608: "TlvTypeSetSchedulerConfigRequest",
|
||||||
|
331920: "TlvTypeSchedulerTask",
|
||||||
|
332192: "TlvTypeSchedulerTaskRecordByTime",
|
||||||
|
332448: "TlvTypeSchedulerTaskRecordScreenWhenAppRuns",
|
||||||
|
332704: "TlvTypeSchedulerTaskRecordMicWhenAppUsesIt",
|
||||||
|
332960: "TlvTypeSchedulerTaskRecordWebCamWhenAppUsesIt",
|
||||||
|
360592: "TlvTypeSCHTaskConfiguration",
|
||||||
|
360752: "TlvTypeSCHTaskEnabled",
|
||||||
|
361344: "TlvTypeSCHTaskStartDateTime",
|
||||||
|
361600: "TlvTypeSCHTaskStopDateTime",
|
||||||
|
362112: "TlvTypeSCHApplicationName",
|
||||||
|
362288: "TlvTypeSCHApplicationWindowOnly",
|
||||||
|
299168: "TlvTypeGetCmdLineConfigRequest",
|
||||||
|
299424: "TlvTypeCmdLineConfigReply",
|
||||||
|
299680: "TlvTypeSetCmdLineConfigRequest",
|
||||||
|
262560: "TlvTypeStartCmdLineSessionRequest",
|
||||||
|
262816: "TlvTypeStartCmdLineSessionReply",
|
||||||
|
263072: "TlvTypeStopCmdLineSessionRequest",
|
||||||
|
263328: "TlvTypeCmdLineSessionStoppedReply",
|
||||||
|
263584: "TlvTypeCmdLineExecute",
|
||||||
|
263840: "TlvTypeCmdLineExecutionResult",
|
||||||
|
266352: "TlvTypeCmdLineExecuteCommand",
|
||||||
|
266560: "TlvTypeCmdLineExecuteAnswerID",
|
||||||
|
266864: "TlvTypeCmdLineExecuteAnswerData",
|
||||||
|
168096: "TlvTypeGetFileSystemConfigRequest",
|
||||||
|
168352: "TlvTypeFileSystemConfigReply",
|
||||||
|
168608: "TlvTypeSetFileSystemConfigRequest",
|
||||||
|
131488: "TlvTypeGetAllDrivesRequest",
|
||||||
|
131744: "TlvTypeGetAllDrivesReply",
|
||||||
|
135328: "TlvTypeGetFolderContentsRequest",
|
||||||
|
135584: "TlvTypeGetFolderContentsReply",
|
||||||
|
135840: "TlvTypeGetFolderContentsNext",
|
||||||
|
136096: "TlvTypeGetFolderContentsEnd",
|
||||||
|
139424: "TlvTypeDownloadFileRequest",
|
||||||
|
139680: "TlvTypeCancelDownloadFileRequest",
|
||||||
|
139936: "TlvTypeDownloadFileReply",
|
||||||
|
140192: "TlvTypeDownloadFileNext",
|
||||||
|
140448: "TlvTypeDownloadFileEnd",
|
||||||
|
140704: "TlvTypeCancelDownloadFileReply",
|
||||||
|
143520: "TlvTypeUploadFileRequest",
|
||||||
|
143776: "TlvTypeCancelUploadFileRequest",
|
||||||
|
144032: "TlvTypeUploadFileReply",
|
||||||
|
144288: "TlvTypeUploadFileNext",
|
||||||
|
144544: "TlvTypeUploadFileEnd",
|
||||||
|
144800: "TlvTypeUploadFileCompleted",
|
||||||
|
145056: "TlvTypeCancelUploadFileReply",
|
||||||
|
147616: "TlvTypeDeleteFileRequest",
|
||||||
|
147872: "TlvTypeDeleteFileReply",
|
||||||
|
151968: "TlvTypeSearchFileRequest",
|
||||||
|
152224: "TlvTypeSearchFileReply",
|
||||||
|
152480: "TlvTypeSearchFileNext",
|
||||||
|
152736: "TlvTypeSearchFileEnd",
|
||||||
|
152992: "TlvTypeCancelSearchFileRequest",
|
||||||
|
153248: "TlvTypeCancelSearchFileReply",
|
||||||
|
159888: "TlvTypeFSFileDataChunk",
|
||||||
|
160128: "TlvTypeFSDiskDrive",
|
||||||
|
160384: "TlvTypeFSFullPath",
|
||||||
|
160640: "TlvTypeFSFilename",
|
||||||
|
160896: "TlvTypeFSFileExtension",
|
||||||
|
161088: "TlvTypeFSDiskDriveType",
|
||||||
|
161408: "TlvTypeFSFileSize",
|
||||||
|
161584: "TlvTypeFSIsFolder",
|
||||||
|
161840: "TlvTypeFSReadOnly",
|
||||||
|
162096: "TlvTypeFSHidden",
|
||||||
|
162352: "TlvTypeFSSystem",
|
||||||
|
162688: "TlvTypeFSFileCreationTime",
|
||||||
|
162944: "TlvTypeFSFileLastAccessTime",
|
||||||
|
163200: "TlvTypeFSFileLastWriteTime",
|
||||||
|
163472: "TlvTypeFSFullPathM",
|
||||||
|
8978848: "TlvTypeMasterMobileTargetConn",
|
||||||
|
7471520: "TlvTypeMasterTargetConn",
|
||||||
|
7405984: "TlvTypeMasterAgentLogin",
|
||||||
|
7406240: "TlvTypeMasterAgentLoginAnswer",
|
||||||
|
7406752: "TlvTypeMasterAgentTargetList",
|
||||||
|
7407008: "TlvTypeMasterAgentTargetOnlineList",
|
||||||
|
7407264: "TlvTypeMasterAgentTargetInfoReply",
|
||||||
|
7407520: "TlvTypeMasterAgentUserList",
|
||||||
|
7407776: "TlvTypeMasterAgentUserListReply",
|
||||||
|
7408032: "TlvTypeMasterAgentTargetArchivedList",
|
||||||
|
7408288: "TlvTypeMasterAgentTargetListEx",
|
||||||
|
7408544: "TlvTypeMasterAgentTargetOnlineListEx",
|
||||||
|
7408800: "TlvTypeMasterAgentMobileTargetArchivedList",
|
||||||
|
7409056: "TlvTypeMasterAgentMobileTargetList",
|
||||||
|
7409312: "TlvTypeMasterAgentMobileTargetOnlineList",
|
||||||
|
7409824: "TlvTypeMasterAgentQueryFirst",
|
||||||
|
7410080: "TlvTypeMasterAgentQueryNext",
|
||||||
|
7410336: "TlvTypeMasterAgentQueryLast",
|
||||||
|
7410592: "TlvTypeMasterAgentQueryAnswer",
|
||||||
|
7410848: "TlvTypeMasterAgentRemoveRecord",
|
||||||
|
7411104: "TlvTypeMasterAgentTargetInfoExReply",
|
||||||
|
7411344: "TlvTypeTargetInfoExProperty",
|
||||||
|
7411616: "TlvTypeTargetInfoExPropertyValue",
|
||||||
|
7411840: "TlvTypeTargetInfoExPropertyValueName",
|
||||||
|
7411968: "TlvTypeTargetInfoExPropertyValueData",
|
||||||
|
7412384: "TlvTypeMasterAgentAlarm",
|
||||||
|
7413920: "TlvTypeMasterAgentRetrieveData",
|
||||||
|
7414176: "TlvTypeMasterAgentRetrieveDataAnswer",
|
||||||
|
7414432: "TlvTypeMasterAgentRemoveUser",
|
||||||
|
7414688: "TlvTypeMasterAgentRemoveTarget",
|
||||||
|
7414944: "TlvTypeMasterAgentRetrieveDataComments",
|
||||||
|
7415200: "TlvTypeMasterAgentUpdateDataComments",
|
||||||
|
7415712: "TlvTypeMasterAgentRetrieveActivityLogging",
|
||||||
|
7415968: "TlvTypeMasterAgentRetrieveMasterLogging",
|
||||||
|
7416224: "TlvTypeMasterAgentRetrieveAgentActivityLogging",
|
||||||
|
7417248: "TlvTypeMasterAgentSendUserGUIConfig",
|
||||||
|
7417504: "TlvTypeMasterAgentGetUserGUIConfigRequest",
|
||||||
|
7417760: "TlvTypeMasterAgentGetUserGUIConfigReply",
|
||||||
|
7418016: "TlvTypeMasterAgentProxyList",
|
||||||
|
7418272: "TlvTypeMasterAgentProxyInfoReply",
|
||||||
|
7419040: "TlvTypeMasterAgentNameValuePacket",
|
||||||
|
7419248: "TlvTypeMasterAgentValueName",
|
||||||
|
7419392: "TlvTypeMasterAgentValueData",
|
||||||
|
7419808: "TlvTypeMasterAgentRetrieveTargetHistory",
|
||||||
|
7421088: "TlvTypeMasterAgentInstallMasterLicense",
|
||||||
|
7421344: "TlvTypeMasterAgentInstallSoftwareUpdate",
|
||||||
|
7421600: "TlvTypeMasterAgentInstallSoftwareUpdateChunk",
|
||||||
|
7421856: "TlvTypeMasterAgentInstallSoftwareUpdateDone",
|
||||||
|
7422112: "TlvTypeMasterAgentSoftwareUpdateInfo",
|
||||||
|
7422368: "TlvTypeMasterAgentSoftwareUpdateInfoReply",
|
||||||
|
7422624: "TlvTypeMasterAgentSoftwareUpdate",
|
||||||
|
7422880: "TlvTypeMasterAgentSoftwareUpdateReply",
|
||||||
|
7423136: "TlvTypeMasterAgentSoftwareUpdateNext",
|
||||||
|
7423392: "TlvTypeMasterAgentAddTimeSchedule",
|
||||||
|
7423648: "TlvTypeMasterAgentAddScreenSchedule",
|
||||||
|
7423904: "TlvTypeMasterAgentAddLockedSchedule",
|
||||||
|
7424160: "TlvTypeMasterAgentRemoveSchedule",
|
||||||
|
7424416: "TlvTypeMasterAgentGetSchedulerList",
|
||||||
|
7424672: "TlvTypeMasterAgentSchedulerTimeAction",
|
||||||
|
7424928: "TlvTypeMasterAgentSchedulerScreenAction",
|
||||||
|
7425184: "TlvTypeMasterAgentSchedulerLockedAction",
|
||||||
|
7425440: "TlvTypeMasterAgentProjectSoftwareUpdateInfo",
|
||||||
|
7425696: "TlvTypeMasterAgentProjectSoftwareUpdateInfoReply",
|
||||||
|
7425952: "TlvTypeMasterAgentProjectSoftwareUpdate",
|
||||||
|
7426112: "TlvTypeMasterAgentSchedulerID",
|
||||||
|
7426368: "TlvTypeMasterAgentSchedulerStartTime",
|
||||||
|
7426624: "TlvTypeMasterAgentSchedulerStopTime",
|
||||||
|
7427488: "TlvTypeMasterAgentAddRecordedDataAvailableSchedule",
|
||||||
|
7427744: "TlvTypeMasterAgentSchedulerRecordedDataAvailableAction",
|
||||||
|
7428256: "TlvTypeMasterAgentRetrieveRemoteMasterData",
|
||||||
|
7428512: "TlvTypeMasterAgentRetrieveRemoteMasterDataReply",
|
||||||
|
7428768: "TlvTypeMasterAgentDeleteRemoteMasterData",
|
||||||
|
7429024: "TlvTypeMasterAgentRetrieveOfflineMasterData",
|
||||||
|
7429280: "TlvTypeMasterAgentRetrieveOfflineMasterDataReply",
|
||||||
|
7429536: "TlvTypeMasterAgentDeleteOfflineMasterData",
|
||||||
|
7430304: "TlvTypeMasterAgentQueryFirstEx",
|
||||||
|
7430560: "TlvTypeMasterAgentQueryNextEx",
|
||||||
|
7430816: "TlvTypeMasterAgentQueryLastEx",
|
||||||
|
7431072: "TlvTypeMasterAgentQueryAnswerEx",
|
||||||
|
7431328: "TlvTypeMasterAgentSendUserPreferences",
|
||||||
|
7431584: "TlvTypeMasterAgentGetUserPreferencesRequest",
|
||||||
|
7431840: "TlvTypeMasterAgentGetUserPreferencesReply",
|
||||||
|
7432096: "TlvTypeMasterAgentListMCFilesRequest",
|
||||||
|
8415392: "TlvTypeMasterAgentListMCFilesReply",
|
||||||
|
7432608: "TlvTypeMasterAgentDeleteMCFiles",
|
||||||
|
7432864: "TlvTypeMasterAgentSendMCFiles",
|
||||||
|
7433120: "TlvTypeMasterAgentMCStatisticsRequest",
|
||||||
|
7433376: "TlvTypeMasterAgentMCStatisticsReply",
|
||||||
|
7433616: "TlvTypeMasterAgentMCStatisticsValues",
|
||||||
|
7434400: "TlvTypeMasterAgentTrojanKeyRequest",
|
||||||
|
7434656: "TlvTypeMasterAgentTrojanKeyReply",
|
||||||
|
7434912: "TlvTypeMasterAgentEvProtectionX509Request",
|
||||||
|
7435168: "TlvTypeMasterAgentEvProtectionX509Reply",
|
||||||
|
7435424: "TlvTypeMasterAgentEvProtectionImportCert",
|
||||||
|
7435680: "TlvTypeMasterAgentEvProtectionImportCertCompleted",
|
||||||
|
7435936: "TlvTypeMasterAgentConfigurationRequest",
|
||||||
|
7436192: "TlvTypeMasterAgentConfigurationReply",
|
||||||
|
7436448: "TlvTypeMasterAgentConfigurationUpdateRequest",
|
||||||
|
7436704: "TlvTypeMasterAgentConfigurationUpdateRequestCompleted",
|
||||||
|
7436944: "TlvTypeMasterAgentConfiguration",
|
||||||
|
7437216: "TlvTypeMasterAgentConfigurationValue",
|
||||||
|
7437424: "TlvTypeMasterAgentConfigurationValueName",
|
||||||
|
7437568: "TlvTypeMasterAgentConfigurationValueData",
|
||||||
|
7437984: "TlvTypeMasterAgentConfigurationTransferDone",
|
||||||
|
7438496: "TlvTypeMasterAgentRetrieveTargetFile",
|
||||||
|
7438752: "TlvTypeMasterAgentRetrieveTargetFileAnswer",
|
||||||
|
7438912: "TlvTypeMasterAgentAlarmEntryID",
|
||||||
|
7439168: "TlvTypeMasterAgentAlarmEntryVersion",
|
||||||
|
7439424: "TlvTypeMasterAgentAlarmTriggerFlags",
|
||||||
|
7439776: "TlvTypeMasterAgentGetAlarmList",
|
||||||
|
7440032: "TlvTypeMasterAgentAddAlarmEntry",
|
||||||
|
7440288: "TlvTypeMasterAgentRemoveAlarmEntry",
|
||||||
|
7440544: "TlvTypeMasterAgentAlarmEntry",
|
||||||
|
7440800: "TlvTypeMasterAgentSystemStatus",
|
||||||
|
7441056: "TlvTypeMasterAgentSystemStatusRequest",
|
||||||
|
7441312: "TlvTypeMasterAgentSystemStatusReply",
|
||||||
|
7441552: "TlvTypeMasterAgentLicenseValues",
|
||||||
|
7441824: "TlvTypeMasterAgentLicenseValuesRequest",
|
||||||
|
7442080: "TlvTypeMasterAgentLicenseValuesReply",
|
||||||
|
7442592: "TlvTypeMasterAgentGetNetworkConfigurationRequest",
|
||||||
|
7442848: "TlvTypeMasterAgentSetNetworkConfigurationRequest",
|
||||||
|
7443104: "TlvTypeMasterAgentSetNetworkConfigurationReply",
|
||||||
|
7443360: "TlvTypeMasterAgentRetrieveAllowedModulesList",
|
||||||
|
7443616: "TlvTypeMasterAgentRetrieveAllowedModulesListAnswer",
|
||||||
|
7446688: "TlvTypeMasterAgentRemoveAllTargetData",
|
||||||
|
7446944: "TlvTypeMasterAgentForceDownloadRecordedData",
|
||||||
|
7447200: "TlvTypeMasterAgentTargetCreateNotification",
|
||||||
|
7447456: "TlvTypeMasterAgentMobileTargetInfoReply",
|
||||||
|
7447696: "TlvTypeMasterAgentMobileTargetInfoValues",
|
||||||
|
7450784: "TlvTypeMasterAgentAlert",
|
||||||
|
7454880: "TlvTypeMasterAgentAddUser",
|
||||||
|
7455392: "TlvTypeMasterAgentAddUserReply",
|
||||||
|
7455648: "TlvTypeMasterAgentModifyUser",
|
||||||
|
7455904: "TlvTypeMasterAgentSetUserPermission",
|
||||||
|
7456160: "TlvTypeMasterAgentSetTargetPermission",
|
||||||
|
7456400: "TlvTypeMasterAgentUserPermission",
|
||||||
|
7456656: "TlvTypeMasterAgentTargetPermission",
|
||||||
|
7456928: "TlvTypeMasterAgentUserPermissionValuePacket",
|
||||||
|
7457184: "TlvTypeMasterAgentTargetPermissionValuePacket",
|
||||||
|
7457344: "TlvTypeMasterAgentUserPermissionValueName",
|
||||||
|
7457600: "TlvTypeMasterAgentTargetPermissionValueName",
|
||||||
|
7457856: "TlvTypeMasterAgentUserPermissionValueData",
|
||||||
|
7458112: "TlvTypeMasterAgentTargetPermissionValueData",
|
||||||
|
7458464: "TlvTypeMasterAgentModifyPassword",
|
||||||
|
7458656: "TlvTypeMasterAgentMobileTargetPermissionValueName",
|
||||||
|
7458976: "TlvTypeMasterAgentUploadFile",
|
||||||
|
7459232: "TlvTypeMasterAgentUploadFileChunk",
|
||||||
|
7459488: "TlvTypeMasterAgentUploadFileDone",
|
||||||
|
7459744: "TlvTypeMasterAgentUploadFilesTransferDone",
|
||||||
|
7460000: "TlvTypeMasterAgentGetTargetModuleConfigRequest",
|
||||||
|
7460256: "TlvTypeMasterAgentRemoveFile",
|
||||||
|
7460512: "TlvTypeMasterAgentMobileProxyList",
|
||||||
|
7460768: "TlvTypeMasterAgentSMSProxyList",
|
||||||
|
7461024: "TlvTypeMasterAgentSMSProxyInfoReply",
|
||||||
|
7461280: "TlvTypeMasterAgentCallPhoneNumberList",
|
||||||
|
7461536: "TlvTypeMasterAgentCallPhoneNumberInfoReply",
|
||||||
|
7461792: "TlvTypeMasterAgentGetMobileTargetModuleConfigRequest",
|
||||||
|
7462048: "TlvTypeMasterAgentSendSMS",
|
||||||
|
7469984: "TlvTypeMasterAgentEncryptionRequired",
|
||||||
|
7470752: "TlvTypeAgentMasterComm",
|
||||||
|
7470240: "TlvTypeMasterAgentFileCompleted",
|
||||||
|
7470496: "TlvTypeMasterAgentRequestCompleted",
|
||||||
|
7471008: "TlvTypeMasterAgentRequestStatus",
|
||||||
|
7733664: "TlvTypeRelayProxyComm",
|
||||||
|
8454800: "TlvTypeRelayData",
|
||||||
|
7734176: "TlvTypeRelayDummyHeartbeat",
|
||||||
|
7668128: "TlvTypeMasterTargetComm",
|
||||||
|
7668384: "TlvTypeTargetCloseAllLiveStreaming",
|
||||||
|
7471424: "TlvTypeProxyMasterCommSig",
|
||||||
|
7471776: "TlvTypeProxyMasterComm",
|
||||||
|
7472032: "TlvTypeMasterProxyComm",
|
||||||
|
7472288: "TlvTypeProxyMasterHeartBeatAnswer",
|
||||||
|
7472544: "TlvTypeProxyMasterDisconnect",
|
||||||
|
7472704: "TlvTypeProxyMasterNotification",
|
||||||
|
7473056: "TlvTypeProxyMasterRequest",
|
||||||
|
7473312: "TlvTypeMasterProxyCommNotification",
|
||||||
|
7473568: "TlvTypeMasterCheckTargetDisconnect",
|
||||||
|
7536960: "TlvTypeProxyTargetCommSig",
|
||||||
|
7537312: "TlvTypeProxyTargetComm",
|
||||||
|
7537568: "TlvTypeProxyMasterTargetComm",
|
||||||
|
7537728: "TlvTypeProxyTargetRequestCrypto",
|
||||||
|
7538064: "TlvTypeProxyTargetAnswerCrypto",
|
||||||
|
8454544: "TlvTypeProxyData",
|
||||||
|
8458400: "TlvTypeProxyTargetDisconnect",
|
||||||
|
8458656: "TlvTypeProxyMobileTargetDisconnect",
|
||||||
|
8458912: "TlvTypeProxyDummyHeartbeat",
|
||||||
|
8459168: "TlvTypeProxyMobileDummyHeartbeat",
|
||||||
|
8585616: "TlvTypeAgentData",
|
||||||
|
8585808: "TlvTypeAgentQueryID",
|
||||||
|
8586048: "TlvTypeAgentQueryModSubmodID",
|
||||||
|
8586304: "TlvTypeAgentQueryFromDate",
|
||||||
|
8586560: "TlvTypeAgentQueryToDate",
|
||||||
|
8586816: "TlvTypeAgentQuerySortOrder",
|
||||||
|
8587136: "TlvTypeAgentQueryValueFilter",
|
||||||
|
8587328: "TlvTypeAgentUID",
|
||||||
|
8520080: "TlvTypeMasterData",
|
||||||
|
8520768: "TlvTypeMasterMode",
|
||||||
|
8521024: "TlvTypeMasterToken",
|
||||||
|
8521344: "TlvTypeMasterQueryResult",
|
||||||
|
8522368: "TlvTypeMasterAlarmString",
|
||||||
|
8651152: "TlvTypeMobileTargetData",
|
||||||
|
8651376: "TlvTypeMobileTargetHeartBeatV10",
|
||||||
|
8651632: "TlvTypeMobileTargetExtendedHeartBeatV10",
|
||||||
|
8651888: "TlvTypeMobileHeartBeatReplyV10",
|
||||||
|
8653472: "TlvTypeMobileInstalledModulesReply",
|
||||||
|
8656032: "TlvTypeMobileTargetUploadModuleRequest",
|
||||||
|
8656288: "TlvTypeMobileTargetUploadModuleReply",
|
||||||
|
8656544: "TlvTypeMobileTargetUploadModuleChunk",
|
||||||
|
8656800: "TlvTypeMobileTargetUploadModuleDoneRequest",
|
||||||
|
8657056: "TlvTypeMobileTargetUploadModuleDoneReply",
|
||||||
|
8657312: "TlvTypeMobileTargetRemoveModuleRequest",
|
||||||
|
8657568: "TlvTypeMobileTargetRemoveModuleReply",
|
||||||
|
8655008: "TlvTypeMobileTargetOfflineUploadModuleRequest",
|
||||||
|
8657824: "TlvTypeMobileTargetOfflineUploadModuleReply",
|
||||||
|
8658080: "TlvTypeMobileTargetOfflineUploadModuleChunk",
|
||||||
|
8658336: "TlvTypeMobileTargetOfflineUploadModuleDoneRequest",
|
||||||
|
8658592: "TlvTypeMobileTargetOfflineUploadModuleDoneReply",
|
||||||
|
8658848: "TlvTypeMobileTargetOfflineError",
|
||||||
|
8659104: "TlvTypeMobileTargetError",
|
||||||
|
8659360: "TlvTypeMobileTargetGetRecordedFilesRequest",
|
||||||
|
8659616: "TlvTypeMobileTargetRecordedFilesReply",
|
||||||
|
8659872: "TlvTypeMobileTargetRecordedFileDownloadRequest",
|
||||||
|
8660128: "TlvTypeMobileTargetRecordedFileDownloadReply",
|
||||||
|
8660384: "TlvTypeMobileTargetRecordedFileDownloadChunk",
|
||||||
|
8660640: "TlvTypeMobileTargetRecordedFileDownloadCompleted",
|
||||||
|
8660896: "TlvTypeMobileTargetRecordedFileDeleteRequest",
|
||||||
|
8661152: "TlvTypeMobileTargetRecordedFileDeleteReply",
|
||||||
|
8663968: "TlvTypeMobileTargetOfflineConfig",
|
||||||
|
8664224: "TlvTypeMobileTargetEmergencyConfigAsTLV",
|
||||||
|
8664432: "TlvTypeMobileTargetEmergencyConfig",
|
||||||
|
8671392: "TlvTypeMobileTargetLoadModuleRequest",
|
||||||
|
8671648: "TlvTypeMobileTargetLoadModuleReply",
|
||||||
|
8671904: "TlvTypeMobileTargetUnLoadModuleRequest",
|
||||||
|
8672160: "TlvTypeMobileTargetUnLoadModuleReply",
|
||||||
|
8675472: "TlvTypeMobileTargetHeartbeatEvents",
|
||||||
|
8675648: "TlvTypeMobileTargetHeartbeatInterval",
|
||||||
|
8675984: "TlvTypeMobileTargetHeartbeatRestrictions",
|
||||||
|
8676208: "TlvTypeConfigSMSPhoneNumber",
|
||||||
|
8676496: "TlvTypeMobileTargetPositioning",
|
||||||
|
8676672: "TlvTypeMobileTrojanUID",
|
||||||
|
8676976: "TlvTypeMobileTrojanID",
|
||||||
|
8677296: "TlvTypeMobileTargetLocationChangedRange",
|
||||||
|
8677440: "TlvTypeConfigMobileAutoRemovalDateTime",
|
||||||
|
8677808: "TlvTypeConfigOverwriteProxyAndPhones",
|
||||||
|
8678000: "TlvTypeConfigCallPhoneNumber",
|
||||||
|
8679488: "TlvTypeLocationAreaCode",
|
||||||
|
8679744: "TlvTypeCellID",
|
||||||
|
8680048: "TlvTypeMobileCountryCode",
|
||||||
|
8680304: "TlvTypeMobileNetworkCode",
|
||||||
|
8680560: "TlvTypeIMSI",
|
||||||
|
8680816: "TlvTypeIMEI",
|
||||||
|
8681072: "TlvTypeGPSLatitude",
|
||||||
|
8681328: "TlvTypeGPSLongitude",
|
||||||
|
8681520: "TlvTypeFirstHeartbeat",
|
||||||
|
8681872: "TlvTypeInstalledModules",
|
||||||
|
8683568: "TlvTypeValidGPSValues",
|
||||||
|
8389008: "TlvTypeTargetData",
|
||||||
|
8389280: "TlvTypeTargetHeartBeat",
|
||||||
|
8389680: "TlvTypeTargetKeepSessionAlive",
|
||||||
|
8390000: "TlvTypeTargetLocalIP",
|
||||||
|
8390256: "TlvTypeTargetGlobalIP",
|
||||||
|
8390448: "TlvTypeTargetState",
|
||||||
|
8390784: "TlvTypeTargetID",
|
||||||
|
8391072: "TlvTypeGetInstalledModulesRequest",
|
||||||
|
8391328: "TlvTypeInstalledModulesReply",
|
||||||
|
8391488: "TlvTypeTrojanUID",
|
||||||
|
8391808: "TlvTypeTrojanID",
|
||||||
|
8392000: "TlvTypeTrojanMaxInfections",
|
||||||
|
8392240: "TlvTypeScreenSaverOn",
|
||||||
|
8392496: "TlvTypeScreenLocked",
|
||||||
|
8392752: "TlvTypeRecordedDataAvailable",
|
||||||
|
8393024: "TlvTypeDownloadedRecordedDataTimeStamp",
|
||||||
|
8393280: "TlvTypeInstallationMode",
|
||||||
|
8393552: "TlvTypeTargetRemoveNotification",
|
||||||
|
8393792: "TlvTypeTargetPlatformBits",
|
||||||
|
8394032: "TlvTypeRemoveItselfMaxInfectionReached",
|
||||||
|
8394288: "TlvTypeRemoveItselfAtMasterRequest",
|
||||||
|
8394544: "TlvTypeRemoveItselfAtAgentRequest",
|
||||||
|
8394912: "TlvTypeRemoveItselfAtAgentReqRequest",
|
||||||
|
8395072: "TlvTypeRecordedFilesDownloadTotal",
|
||||||
|
8395328: "TlvTypeRecordedFilesDownloadProgress",
|
||||||
|
8395632: "TlvTypeTargetLicenseInfo",
|
||||||
|
8395840: "TlvTypeRemoveTargetLicenseInfo",
|
||||||
|
8396176: "TlvTypeTargetAllConfigurations",
|
||||||
|
8396960: "TlvTypeTargetError",
|
||||||
|
8401056: "TlvTypeGetTargetConfigRequest",
|
||||||
|
8401312: "TlvTypeTargetConfigReply",
|
||||||
|
8401568: "TlvTypeSetTargetConfigRequest",
|
||||||
|
8402304: "TlvTypeConfigTargetID",
|
||||||
|
8402496: "TlvTypeConfigTargetHeartbeatInterval",
|
||||||
|
8402800: "TlvTypeConfigTargetProxy",
|
||||||
|
8403008: "TlvTypeConfigTargetPort",
|
||||||
|
8403584: "TlvTypeConfigAutoRemovalDateTime",
|
||||||
|
8403776: "TlvTypeConfigAutoRemovalIfNoProxy",
|
||||||
|
8404032: "TlvTypeInternalAutoRemovalElapsedTime",
|
||||||
|
8405040: "TlvTypeConfigActiveHiding",
|
||||||
|
8409248: "TlvTypeTargetLoadModuleRequest",
|
||||||
|
8409504: "TlvTypeTargetLoadModuleReply",
|
||||||
|
8409760: "TlvTypeTargetUnLoadModuleRequest",
|
||||||
|
8410016: "TlvTypeTargetUnLoadModuleReply",
|
||||||
|
8410272: "TlvTypeTargetUploadModuleRequest",
|
||||||
|
8410528: "TlvTypeTargetUploadModuleReply",
|
||||||
|
8410784: "TlvTypeTargetUploadModuleChunk",
|
||||||
|
8411040: "TlvTypeTargetUploadModuleDoneRequest",
|
||||||
|
8411296: "TlvTypeTargetUploadModuleDoneReply",
|
||||||
|
8411552: "TlvTypeTargetRemoveModuleRequest",
|
||||||
|
8411808: "TlvTypeTargetRemoveModuleReply",
|
||||||
|
8412064: "TlvTypeTargetOfflineUploadModuleRequest",
|
||||||
|
8412320: "TlvTypeTargetOfflineUploadModuleReply",
|
||||||
|
8412576: "TlvTypeTargetOfflineUploadModuleChunk",
|
||||||
|
8412832: "TlvTypeTargetOfflineUploadModuleDoneRequest",
|
||||||
|
8413088: "TlvTypeTargetOfflineUploadModuleDoneReply",
|
||||||
|
8413344: "TlvTypeTargetOfflineError",
|
||||||
|
8413600: "TlvTypeTargetUploadError",
|
||||||
|
8417440: "TlvTypeTargetGetRecordedFilesRequest",
|
||||||
|
8417696: "TlvTypeTargetRecordedFilesReply",
|
||||||
|
8417952: "TlvTypeTargetRecordedFileDownloadRequest",
|
||||||
|
8418208: "TlvTypeTargetRecordedFileDownloadReply",
|
||||||
|
8418464: "TlvTypeTargetRecordedFileDownloadChunk",
|
||||||
|
8418720: "TlvTypeTargetRecordedFileDownloadCompleted",
|
||||||
|
8418976: "TlvTypeTargetRecordedFileDeleteRequest",
|
||||||
|
8419232: "TlvTypeTargetRecordedFileDeleteReply",
|
||||||
|
8419488: "TlvTypeTargetGetRecordedFilesRequestEx",
|
||||||
|
8419744: "TlvTypeTargetRecordedFilesReplyEx",
|
||||||
|
8420000: "TlvTypeTargetRecordedFileDeleteRequestEx",
|
||||||
|
8420256: "TlvTypeTargetRecordedFilesDownloadRequestEx",
|
||||||
|
16744768: "TlvTypeProxyConnectionBroken",
|
||||||
|
16712000: "TlvTypeTargetConnectionBroken",
|
||||||
|
16712256: "TlvTypeAgentConnectionBroken",
|
||||||
|
16712512: "TlvTypeTargetOffline",
|
||||||
|
16646544: "TlvTypePlaintext",
|
||||||
|
16646800: "TlvTypeCompression",
|
||||||
|
16647056: "TlvTypeEncryption",
|
||||||
|
16647232: "TlvTypeTargetUID",
|
||||||
|
16647536: "TlvTypeIPAddress",
|
||||||
|
16647808: "TlvTypeUserName",
|
||||||
|
16648064: "TlvTypeComputerName",
|
||||||
|
16648304: "TlvTypeLoginName",
|
||||||
|
16648560: "TlvTypePassphrase",
|
||||||
|
16648832: "TlvTypeRecordID",
|
||||||
|
16649088: "TlvTypeOwner",
|
||||||
|
16649344: "TlvTypeMetaData",
|
||||||
|
16649536: "TlvTypeModuleID",
|
||||||
|
16649856: "TlvTypeOSName",
|
||||||
|
16650048: "TlvTypeModuleSubID",
|
||||||
|
16650320: "TlvTypeErrorCode",
|
||||||
|
16650560: "TlvTypeOffset",
|
||||||
|
16650816: "TlvTypeLength",
|
||||||
|
16651088: "TlvTypeRequestID",
|
||||||
|
16651328: "TlvTypeRequestType",
|
||||||
|
16651584: "TlvTypeVersion",
|
||||||
|
16651840: "TlvTypeMachineID",
|
||||||
|
16652096: "TlvTypeMajorNumber",
|
||||||
|
16652352: "TlvTypeMinorNumber",
|
||||||
|
16652656: "TlvTypeGlobalIPAddress",
|
||||||
|
16652912: "TlvTypeASCII_Filename",
|
||||||
|
16653120: "TlvTypeFilesize",
|
||||||
|
16653392: "TlvTypeFilecount",
|
||||||
|
16653712: "TlvTypeFiledata",
|
||||||
|
16653968: "TlvTypeMD5Sum",
|
||||||
|
16654144: "TlvTypeProxyPort",
|
||||||
|
16654400: "TlvTypeStatus",
|
||||||
|
16654656: "TlvTypeUserID",
|
||||||
|
16654912: "TlvTypeGroupID",
|
||||||
|
16655168: "TlvTypePermissions",
|
||||||
|
16655424: "TlvTypeRequestCode",
|
||||||
|
16655680: "TlvTypeDataSize",
|
||||||
|
16655936: "TlvTypeKeyType",
|
||||||
|
16656240: "TlvTypeEmail",
|
||||||
|
16656432: "TlvTypeEnabled",
|
||||||
|
16656688: "TlvTypeLicensed",
|
||||||
|
16656960: "TlvTypeAudioFrequency",
|
||||||
|
16657216: "TlvTypeAudioBitsPerSample",
|
||||||
|
16657472: "TlvTypeAudioChannels",
|
||||||
|
16657728: "TlvTypeStartTime",
|
||||||
|
16657984: "TlvTypeStopTime",
|
||||||
|
16658240: "TlvTypeBitMask",
|
||||||
|
16658560: "TlvTypeTimeZone",
|
||||||
|
16658816: "TlvTypeDateTime",
|
||||||
|
16659072: "TlvTypeStartSessionDateTime",
|
||||||
|
16659328: "TlvTypeStopSessionDateTime",
|
||||||
|
16659520: "TlvTypeDateTimeRef",
|
||||||
|
16659776: "TlvTypeScheduleRepeat",
|
||||||
|
16660032: "TlvTypeUnixMasterDateTime",
|
||||||
|
16660288: "TlvTypeUnixUTCDateTime",
|
||||||
|
16660544: "TlvTypeDurationInSeconds",
|
||||||
|
16660864: "TlvTypeMasterRefTime",
|
||||||
|
16661120: "TlvTypeMasterRefTimeStart",
|
||||||
|
16661376: "TlvTypeMasterRefTimeEnd",
|
||||||
|
16661568: "TlvTypeCounter",
|
||||||
|
16661888: "TlvTypeWhiteListEntry",
|
||||||
|
16662144: "TlvTypeBlackListEntry",
|
||||||
|
16662336: "TlvTypeBlackWhiteListingMode",
|
||||||
|
16662576: "TlvTypeConfigEnabled",
|
||||||
|
16662848: "TlvTypeConfigMaxRecordingSize",
|
||||||
|
16663104: "TlvTypeConfigAudioQuality",
|
||||||
|
16663344: "TlvTypeConfigVideoBlackAndWhite",
|
||||||
|
16663616: "TlvTypeConfigVideoResolution",
|
||||||
|
16663872: "TlvTypeConfigCaptureFrequency",
|
||||||
|
16664128: "TlvTypeConfigVideoQuality",
|
||||||
|
16664384: "TlvTypeConfigFilesStandardFilter",
|
||||||
|
16664704: "TlvTypeConfigFilesCustomFilter",
|
||||||
|
16664896: "TlvTypeConfigStandardLocation",
|
||||||
|
16665216: "TlvTypeConfigCustomLocation",
|
||||||
|
16665408: "TlvTypeConfigFileChunkSize",
|
||||||
|
16665664: "TlvTypeConfigFileTransferSpeed",
|
||||||
|
16665904: "TlvTypeConfigUploadFileOverwrite",
|
||||||
|
16666160: "TlvTypeConfigDeleteOverReboot",
|
||||||
|
16666496: "TlvTypeConfigCustomLocationException",
|
||||||
|
16666752: "TlvTypeExtraData",
|
||||||
|
16667008: "TlvTypeSignature",
|
||||||
|
16667264: "TlvTypeComments",
|
||||||
|
16667520: "TlvTypeDescription",
|
||||||
|
16667776: "TlvTypeFilenameExtension",
|
||||||
|
16668032: "TlvTypeSessionType",
|
||||||
|
16668224: "TlvTypePeriod",
|
||||||
|
16668512: "TlvTypeMobileTargetUID",
|
||||||
|
16668784: "TlvTypeMobileTargetID",
|
||||||
|
16669072: "TlvTypeMobilePlaintext",
|
||||||
|
16669328: "TlvTypeMobileCompression",
|
||||||
|
16669584: "TlvTypeMobileEncryption",
|
||||||
|
16669824: "TlvTypeEncodingType",
|
||||||
|
16670576: "TlvTypePhoneNumber",
|
||||||
|
16670784: "TlvTypeConfigCustomLocationMode",
|
||||||
|
16674928: "TlvTypeNetworkInterface",
|
||||||
|
16675136: "TlvTypeNetworkInterfaceMode",
|
||||||
|
16675440: "TlvTypeNetworkInterfaceAddress",
|
||||||
|
16675696: "TlvTypeNetworkInterfaceNetmask",
|
||||||
|
16675952: "TlvTypeNetworkInterfaceGateway",
|
||||||
|
16676208: "TlvTypeNetworkInterfaceDNS_1",
|
||||||
|
16676464: "TlvTypeNetworkInterfaceDNS_2",
|
||||||
|
16677440: "TlvTypeLoginTime",
|
||||||
|
16677696: "TlvTypeLogoffTime",
|
||||||
|
16678720: "TlvTypeGeneric_Type",
|
||||||
|
16678976: "TlvTypeChecksum",
|
||||||
|
16679280: "TlvTypeCity",
|
||||||
|
16679536: "TlvTypeCountry",
|
||||||
|
16679792: "TlvTypeCountryCode",
|
||||||
|
16683072: "TlvTypeTargetType",
|
||||||
|
16683392: "TlvTypeDurationString",
|
||||||
|
8257792: "TlvTypeTestMetaTypeInvalid",
|
||||||
|
8258608: "TlvTypeTestMetaTypeBool",
|
||||||
|
8258880: "TlvTypeTestMetaTypeUInt",
|
||||||
|
8259152: "TlvTypeTestMetaTypeInt",
|
||||||
|
8259440: "TlvTypeTestMetaTypeString",
|
||||||
|
8259712: "TlvTypeTestMetaTypeUnicode",
|
||||||
|
8259984: "TlvTypeTestMetaTypeRaw",
|
||||||
|
8260256: "TlvTypeTestMetaTypeGroup",
|
||||||
|
8260416: "TlvTypeTestMemberIdentifier",
|
||||||
|
8260736: "TlvTypeTestMemberName",
|
||||||
|
0x2331a0: "TlvTypeVideoConfigReply", # Guess based on module
|
||||||
|
0x2431a0: "TlvTypeScreenRecordingConfigReply", # Guess
|
||||||
|
0x2731a0: "TlvTypeEmailConfigReply", # Guess
|
||||||
|
0x2831a0: "TlvTypeWifiConfigReply", # Guess
|
||||||
|
0x2931a0: "TlvTypeRemoteConfigReply", #Guess
|
||||||
|
}
|
||||||
|
|
||||||
|
NEED_RECURSION = ["TlvTypeChangedConfigReply", "TlvTypeTargetConfigReply",
|
||||||
|
"TlvTypeFileSystemConfigReply", "TlvTypeCmdLineConfigReply",
|
||||||
|
"TlvTypeSchedulerConfigReply", "TlvTypeMobileTargetOfflineConfig",
|
||||||
|
"TlvTypeMobileTrackingConfigRaw", "TlvTypeMobileTrackingConfig",
|
||||||
|
"0x544090", "0x5440a0", "0x534090", "0x5341a0"]
|
||||||
|
|
||||||
|
|
||||||
|
def decode(m):
|
||||||
|
cfg = {}
|
||||||
|
while m.b.tell() < m._len:
|
||||||
|
size = m.dword()
|
||||||
|
tag = m.dword()
|
||||||
|
tag_type = (tag & 0xf0) >> 4
|
||||||
|
name = tlv_types.get(tag)
|
||||||
|
if tag_type < 4:
|
||||||
|
data = m.byte()
|
||||||
|
elif tag_type >= 6:
|
||||||
|
data = m.read(size - 8)
|
||||||
|
if tag_type == 8:
|
||||||
|
data = data.decode('utf-16')
|
||||||
|
if u"\u0380" in data:
|
||||||
|
category, rest = data.split(u"\u0380")
|
||||||
|
data = {'category': category, 'list': rest.split(u"\u0381")}
|
||||||
|
else:
|
||||||
|
data = m.dword()
|
||||||
|
if not name:
|
||||||
|
name = hex(tag)
|
||||||
|
|
||||||
|
if name in NEED_RECURSION or "ConfigReply" in name:
|
||||||
|
nm = M(data)
|
||||||
|
cfg[name] = decode(nm)
|
||||||
|
elif name in cfg and type(cfg[name]) != list:
|
||||||
|
olv = cfg[name]
|
||||||
|
cfg[name] = [olv, data]
|
||||||
|
elif name in cfg and type(cfg[name]) == list:
|
||||||
|
cfg[name].append(data)
|
||||||
|
elif name == "TlvTypeInstalledModules":
|
||||||
|
# Specific decoding for Android modules
|
||||||
|
olv = {"data": data}
|
||||||
|
olv["logging"] = (data[68] == 1)
|
||||||
|
olv["spycall"] = (data[64] == 1)
|
||||||
|
olv["call_interception"] = (data[65] == 1)
|
||||||
|
olv["sms"] = (data[66] == 1)
|
||||||
|
olv["addressbook"] = (data[67] == 1)
|
||||||
|
olv["tracking"] = (data[69] == 1)
|
||||||
|
olv["phonelogs"] = (data[70] == 1)
|
||||||
|
cfg[name] = olv
|
||||||
|
else:
|
||||||
|
cfg[name] = data
|
||||||
|
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
class MyEncoder(JSONEncoder):
|
||||||
|
"""
|
||||||
|
JSON encoder to encode bytes
|
||||||
|
"""
|
||||||
|
def default(self, o):
|
||||||
|
if isinstance(o, bytes):
|
||||||
|
try:
|
||||||
|
return o.decode('utf-8')
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return repr(o)
|
||||||
|
return o
|
||||||
|
|
||||||
|
|
||||||
|
# From https://github.com/mak/mlib
|
||||||
|
class M(object):
|
||||||
|
TRANSL = {'byte': ('B', 1), 'word': ('H', 2),
|
||||||
|
'dword': ('I', 4), 'qword': ('Q', 8)}
|
||||||
|
|
||||||
|
def __init__(self, d, end_fmt=''):
|
||||||
|
self._len = len(d)
|
||||||
|
self.b = BytesIO(d)
|
||||||
|
|
||||||
|
def _get_bytes(self, fmt, s, off):
|
||||||
|
return struct.unpack(fmt, self.read(off, s) if off else self.read(s))[0]
|
||||||
|
|
||||||
|
def skip(self, n):
|
||||||
|
self.b.seek(n, os.SEEK_CUR)
|
||||||
|
|
||||||
|
def unskip(self, n):
|
||||||
|
self.b.seek(-n, os.SEEK_CUR)
|
||||||
|
|
||||||
|
def read(self, a0, a1= None):
|
||||||
|
r = None
|
||||||
|
if a1 is None:
|
||||||
|
r = self.b.read(a0)
|
||||||
|
else:
|
||||||
|
r = self.read_at(a0,a1)
|
||||||
|
return r
|
||||||
|
|
||||||
|
def read_at(self, off, n):
|
||||||
|
old_l = self.b.tell()
|
||||||
|
self.b.seek(off, os.SEEK_SET)
|
||||||
|
r = self.b.read(n)
|
||||||
|
self.b.seek(old_l, os.SEEK_SET)
|
||||||
|
return r
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return self._len
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
at = False
|
||||||
|
if name.endswith('_at'):
|
||||||
|
name = name[:-3]
|
||||||
|
|
||||||
|
if name in M.TRANSL:
|
||||||
|
f, s = M.TRANSL[name]
|
||||||
|
return lambda off = None: self._get_bytes(f, s, off)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description='Decode FinSpy configuration files')
|
||||||
|
parser.add_argument('CONFFILE', help='Configuration file')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
with open(args.CONFFILE, 'rb') as f:
|
||||||
|
d = f.read()
|
||||||
|
|
||||||
|
m = M(d)
|
||||||
|
total_size = m.dword()
|
||||||
|
if total_size != len(d):
|
||||||
|
print("Encrypted configuration, decrypting...")
|
||||||
|
k = (0xaa, 0x5a, 0xa5)
|
||||||
|
r = bytearray()
|
||||||
|
for i, c in enumerate(bytearray(d)):
|
||||||
|
r.append(c ^ k[i % 3])
|
||||||
|
data = bytes(r)
|
||||||
|
m = M(data)
|
||||||
|
total_size = m.dword()
|
||||||
|
|
||||||
|
_ = m.dword() ## doesn't matter but config is wrapped into TlvTypeEncryption
|
||||||
|
cfg = decode(m)
|
||||||
|
print(json.dumps(cfg, cls=MyEncoder, indent=4))
|
||||||
13
data/ioc/spyware/amnesty/2020-09-25_finfisher/sha256.csv
Normal file
13
data/ioc/spyware/amnesty/2020-09-25_finfisher/sha256.csv
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
sha256,Description
|
||||||
|
1e9162cd0941557304a6a097dfaadf59f90bc8bbaa9879afe67b5ce0d1514be8,Linux FinSpy sample
|
||||||
|
854774a198db490a1ae9f06d5da5fe6a1f683bf3d7186e56776516f982d41ad3,Android FinSpy sample
|
||||||
|
bb8c0e477512adab1db26eb77fe10dadbc5dcbf8e94569061c7199ca4626a420,Backdoored rar installer
|
||||||
|
80d6e71c54fb3d4a904637e4d56e108a8255036cbb4760493b142889e47b951f,MacOS Installer
|
||||||
|
f960144126748b971386731d35e41288336ad72a9da0c6b942287f397d57c600,Backdoored flash installer
|
||||||
|
fab6b3bbc14c80049f95b040680fba6d1b47f07746729d04c887a55272084648,Encoded cobalt strike beacon
|
||||||
|
8f216d2f0be2c4a5c07abf45cf138453f72f00ec598327756c6fc9d5f4dabe0d,Decoded Cobalt Strike beacon
|
||||||
|
4f3003dd2ed8dcb68133f95c14e28b168bd0f52e5ae9842f528d3f7866495cea,Older Mac OS sample
|
||||||
|
bd1b8bc046dbf19f8c9bbf9398fdbc47c777e1d9e6d9ff1787ada05ed75c1b12,Older Linux sample
|
||||||
|
9f04439bc94f2eef76b72ac2e0aeece0d4f46b6c42ef179fc860f6b5876f5f50,Android FinSpy sample
|
||||||
|
928aefbcac9386c953b3491230a719ff65b21612eb6bd9b32501de149cacbc92,Android FinSpy sample
|
||||||
|
14658327efaa15275fb8718956ee97ebcad5bc80312a4f3182a3b10cd3dcf257,NilePhish downloader
|
||||||
|
157
data/ioc/spyware/amnesty/2021-02-24_vietnam/README.md
Normal file
157
data/ioc/spyware/amnesty/2021-02-24_vietnam/README.md
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
# Overview of Ocean Lotus Samples used to target Vietnamese Human Rights Defenders
|
||||||
|
|
||||||
|
From May to November 2020, we have identified malware attacks targeting Human Rights Defenders and organizations from Viet Nam. This technical blog post provides an overview of the different Ocean Lotus samples identified, technical indicators, and details on the link with earlier Ocean Lotus activities. For more information on the context of these attacks and the targets we identified, please read the report entitled [“Click and Bait: Vietnamese Human Rights Defenders Targeted with Spyware Attacks”](https://www.amnesty.org/en/latest/research/2021/02/click-and-bait-vietnamese-human-rights-defenders-targeted-with-spyware-attacks/) on the Amnesty website (also available in Vietnamese).
|
||||||
|
|
||||||
|
We found 9 different malware samples in this investigation: 4 for Mac OS, and 5 for Microsoft Windows.
|
||||||
|
|
||||||
|
## Mac OS Malware
|
||||||
|
|
||||||
|
### First appearance in 2018
|
||||||
|
|
||||||
|
The first Mac OS sample we identified targeted Bui Thanh Hieu in February 2018. Attackers delivered a malicious Mac OS application named _“PHIẾU GHI DANH THAM DỰ TĨNH HỘI HMDC 2018”_ attached to an email. This sample belongs to the same family as the Ocean Lotus samples analysed by [Trend Micro in 2018](https://www.trendmicro.com/en_us/research/18/d/new-macos-backdoor-linked-to-oceanlotus-found.html), and they even share the same string encryption algorithm and key.
|
||||||
|
|
||||||
|
The malicious application uses a first stage dropper to bypass Apple GateKeeper, then it installs the final payload either in `/Library/CoreMediaIO/Plug-Ins/FCP-DAL/iOSScreenCapture.plugin/Contents/Resources/screenassistantd`, if it is launched with root access, otherwise in `~/Library/Spelling/spellagentd`. The malware gains persistence with a Property List file placed in `~/Library/LaunchAgents/`.
|
||||||
|
|
||||||
|
The final payload communicates with the same domains mentioned in the Trend Micro report: `ssl.arkouthrie.com`, `s3.hiahornber.com` and `widget.shoreoa.com`.
|
||||||
|
|
||||||
|
### New variants from 2019
|
||||||
|
|
||||||
|
In 2019 Bui Thanh Hieu received three more malicious emails with links to or attached malicious Mac OS applications, which are more recent variants of the same malware we described above. However, these variants seem less developed than the samples analysed by [Trend Micro in November 2020](https://www.trendmicro.com/en_us/research/20/k/new-macos-backdoor-connected-to-oceanlotus-surfaces.html), making them likely intermediate versions between those discovered by Trend Micro in 2018 and in 2020.
|
||||||
|
|
||||||
|
When executed, these applications launch an installer either embedded in the package or decrypted by a dedicated Python script. The installer disables security protections by removing the _com.apple.quarantine_ bit, launches the final payload and configures persistence by creating a property list in the LaunchAgent user folder, or in the _/Library/LaunchDaemons/_ folder if launched as root.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The installer drops two files in the destination folder: one Mach-O binary payload and an encrypted shared Mach-O library named `[INTEGER].3gp` (such as 33.3gp or 152.3gp). To avoid their discovery during forensic analysis, these files’ creation date and time are faked with the command `touch –t`.
|
||||||
|
|
||||||
|
The payload first gathers information on the system, including the MacOS version, the kernel version and details on the hardware and CPU. Then it tries to decrypt all the files in the folder until it finds a shared library exporting the functions `ArchaeologistCodeine` and `PlayerAberadurtheIncomprehensible`. This shared library implements the communication with one of three configured Command & Control (C&C) domains, using libcurl to send POST HTTP requests with an encrypted body.
|
||||||
|
|
||||||
|
This malware uses custom base64 and AES algorithms to obfuscate all the strings, making it harder to analyse or build signatures as the encryption keys are changing regularly. In comparison, the 2018 variant used a custom base64 but standard AES, while more recent samples analysed by Trend Micro in 2020 abandoned AES in favour of a custom byte manipulation algorithm.
|
||||||
|
|
||||||
|
This backdoor has limited purpose. It allows to manipulate files and execute commands in a terminal. For the full list of supported commands, check [Trend Micro’s report](https://www.trendmicro.com/en_us/research/18/d/new-macos-backdoor-linked-to-oceanlotus-found.html).
|
||||||
|
|
||||||
|
## Windows Backdoors
|
||||||
|
|
||||||
|
We identified five emails in 2019 and 2020 each containing two files compressed in RAR or ISO archives. The first file is a legitimate copy of Microsoft Word 2007’s executable used for DLL side-loading, while the second is a DLL named wwlib.dll loaded at launch by the Word executable it accompanies.
|
||||||
|
|
||||||
|
DLL side-loading is a technique observed [several times](https://unit42.paloaltonetworks.com/tracking-oceanlotus-new-downloader-kerrdown/) used by Ocean Lotus, typically with a Microsoft Word executable. The final payload is always a variant of a downloader used exclusively by Ocean Lotus and [named Kerrdown](https://unit42.paloaltonetworks.com/tracking-oceanlotus-new-downloader-kerrdown/) by the cybersecurity company Palo Alto. All the Kerrdown samples we analysed delivered a Cobalt Strike payload.
|
||||||
|
|
||||||
|
### Kerrdown analysis
|
||||||
|
|
||||||
|
Kerrdown is a dropper that uses several layers of shellcode to obfuscate the final payload. Each one of them decrypting and redirecting to the next layer, until the final payload is reached.
|
||||||
|
|
||||||
|
For instance, the first Kerrdown sample we found in May 2019 used 4 distinct stages before executing the final shellcode that downloads a payload from `api.ciscofreak.com/HjRX` (the domain was down during our investigation, but [this Cobalt Strike beacon](https://www.virustotal.com/gui/file/1cc3f2296f5cd9207f6c84fa9de26dcdbff0b16e49accb0f8dd670ee8d32dd50/detection) uploaded on Virus Total in 2019 communicates with this domain)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
These layers of shellcode are different for each Kerrdown sample we discovered, making it challenging to build signatures for this malware family.
|
||||||
|
|
||||||
|
One of the samples which targeted the Vietnamese blogger in July 2020 introduced an additional step in the execution. The _wwwlib.dll_ payload installs a binary in `C:\ProgramData\Java\UK.exe`, a self-extractable RAR archive containing a legitimate executable copy of the Opera browser, then used to sideload a malicious DLL called _opera.dll_.
|
||||||
|
|
||||||
|
This opera.dll is another variant of the Kerrdown family, but the file itself is exceptionally large (42MB). Expanding payloads with junk data is [a technique](https://attack.mitre.org/techniques/T1027/001/), called “binary padding”, often used by malware to avoid detection by security solutions as some do not analyse large files in depth to avoid performance issues. Binary padding is known to have been used by Ocean Lotus [in the past](https://www.welivesecurity.com/2019/03/20/fake-or-fake-keeping-up-with-oceanlotus-decoys/). This Kerrdown sample includes an obfuscated Cobalt Strike beacon communicating with the domain `delicalo.dnsalias.net`.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Cobalt Strike
|
||||||
|
|
||||||
|
Cobalt Strike is an intrusion toolkit sold by the US company [Strategic Cyber LLC](Strategic Cyber LLC) for penetration testing or adversary simulation. Over the past years, cracked versions of Cobalt Strike have been regularly used by attack groups in their operations. [Cobalt Strike allows](https://www.cobaltstrike.com/features) to remotely monitor a compromised system, including accessing files but also logging keystrokes or taking screenshots.
|
||||||
|
|
||||||
|
Ocean Lotus has been known for using Cobalt Strike since [at least 2017](https://www.cybereason.com/blog/operation-cobalt-kitty-apt). The 4 Kerrdown samples we identified all either embedded or downloaded a Cobalt Strike beacon. They all used a Cobalt Strike profile impersonating Google Safe Browsing services URLs, similar to [this public profile](https://github.com/rsmudge/Malleable-C2-Profiles/blob/master/normal/safebrowsing.profile).
|
||||||
|
|
||||||
|
The configuration can be easily extracted with the [scripts we released in September 2020](https://github.com/AmnestyTech/investigations/tree/master/2020-09-25_finfisher/scripts/cobaltstrike). Here is an example of configuration for a beacon hosted on `delicalo.dnsalias.net`:
|
||||||
|
|
||||||
|
```
|
||||||
|
dns False
|
||||||
|
ssl True
|
||||||
|
port 443
|
||||||
|
.sleeptime 4100
|
||||||
|
.http-get.server.output
|
||||||
|
.jitter 12
|
||||||
|
.maxdns 245
|
||||||
|
publickey 30819f300d06092a864886f70d010101050003818d0030818902818100ac50b035fd1b294778b8cbd4ee33323f9b04af158cca225d099052d7987441cbb365ab0f81c4c1190cd8758324e1cb7085dac65ce264dc510c57cfa1d1c7711f26c767d574f04ac16d20a0acf91d4e5dc1cc62c764676b0c38ba50d43953df5184468efdd6b4098c12b5c94be562de22881484accf8e69473621efa95e290f19020301000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
.http-get.uri delicalo.dnsalias[.]net,/safebrowsing/rd/e3Iz4FnySnhy3IuXKqrWM40JnseSLDHcH-OzVVfWmVgwx
|
||||||
|
.user-agent Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
|
||||||
|
.http-post.uri /safebrowsing/rd/3KHLhJGZRq4iyImdpSZ5RM90vLo3Yt2hB
|
||||||
|
.http-get.client
|
||||||
|
GAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|
||||||
|
Accept-Language: en-US,en;q=0.5
|
||||||
|
Accept-Encoding: gzip, deflaPREF=ID=Cookie
|
||||||
|
.http-post.client
|
||||||
|
GAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|
||||||
|
Accept-Language: en-US,en;q=0.5
|
||||||
|
Accept-Encoding: gzip, deflatU=NoncmvrScxBxlwoPREF=ID=Cookie
|
||||||
|
.post-ex.spawnto_x86 %windir%\syswow64\rundll32.exe
|
||||||
|
.post-ex.spawnto_x64 %windir%\sysnative\rundll32.exe
|
||||||
|
.pipename
|
||||||
|
.cryptoscheme 1
|
||||||
|
.dns_idle 0
|
||||||
|
.dns_sleep 0
|
||||||
|
.http-get.verb GET
|
||||||
|
.http-post.verb POST
|
||||||
|
shouldChunkPosts 0
|
||||||
|
.watermark 0
|
||||||
|
.stage.cleanup 0
|
||||||
|
CFGCaution 0
|
||||||
|
.proxy_type 2
|
||||||
|
killdate 0
|
||||||
|
text_section 0
|
||||||
|
process-inject-start-rwx 64
|
||||||
|
process-inject-use-rwx 64
|
||||||
|
process-inject-min_alloc 0
|
||||||
|
process-inject-transform-x86
|
||||||
|
process-inject-transform-x64
|
||||||
|
```
|
||||||
|
|
||||||
|
## Indicators of Compromise
|
||||||
|
|
||||||
|
### Mac OS samples
|
||||||
|
|
||||||
|
| Feb 2018 | |
|
||||||
|
| ------------- |-------------|
|
||||||
|
| Package name | PHIẾU GHI DANH THAM DỰ TĨNH HỘI HMDC 2018 |
|
||||||
|
| Dropper | 952c16674bde3c16aa3935b3e01f3f0fb4cbac7ffa130143cbf6ccaa72733068 |
|
||||||
|
| Payload | d3a198e18f8c5e9ed54ed4959b471a0f15fbda7d4abf92b7726bc07723e46dd5 |
|
||||||
|
| C&C | `ssl.arkouthrie.com` `widget.shoreoa.com` `s3.hiahornber.com` |
|
||||||
|
| **June 2019** | |
|
||||||
|
| Package name | TaiLieu |
|
||||||
|
| Dropper | ecb6186a5e722fa360ece37191589305858a0e176321c9339831f2884dcb0405 |
|
||||||
|
| Payload | 1599fe6cc77764c17802cfde1ca77f091bb3ec2a49f6cab1c80ee667ea7c752b |
|
||||||
|
| Network library | b8567ce4d0595e6466414999798bcb1dfe01cc5ca1dd058bfc55f92033f0f3d8 |
|
||||||
|
| C&C | `tips.jasperpfeiffer.com` `land.rellecharlessper.com` and `art.guillermoespana.com` |
|
||||||
|
| **October 2019** | |
|
||||||
|
| Package Name | Danh sach nhan su |
|
||||||
|
| Dropper | b252a8d2ec5c7080286fe3f0ad193062f506b5c34c4c797f97717e396c0a22d5 |
|
||||||
|
| Payload | 9c14cffd79f863fec0a6c0ed337ea82a9044db09afda53b8ac2aef1d49f74f4f |
|
||||||
|
| Network Library | 5ed6b7b450ead2d0e69faa3069d1e0bd3a6852909092235f75087da0ca05462f |
|
||||||
|
| C&C | `tips.jasperpfeiffer.com` `land.rellecharlessper.com` and `art.guillermoespana.com` |
|
||||||
|
| **December 2019** | |
|
||||||
|
| Package Name | Don keu cuu cua gia dinh Le Nam Tra |
|
||||||
|
| Dropper | a890c88b6c64371242b4047830b9189b4546536c6b11576d0738f0ba1840ade |
|
||||||
|
| Payload | 0c41358adeea24d80b35bac4b4f60d93711e32e287343cb604e1fa79b5e5e465 |
|
||||||
|
| Network Library | 5ed6b7b450ead2d0e69faa3069d1e0bd3a6852909092235f75087da0ca05462f |
|
||||||
|
| C&C | `tips.jasperpfeiffer.com` `land.rellecharlessper.com` and `art.guillermoespana.com` |
|
||||||
|
|
||||||
|
### Windows Samples
|
||||||
|
|
||||||
|
| June 2019 | |
|
||||||
|
|-----------|--|
|
||||||
|
| Winword.exe (legitimate) | 6c959cfb001fbb900958441dfd8b262fb33e052342948bab338775d3e83ef7f7 |
|
||||||
|
| wwlib.dll | 148e647885712b69258967c5f8798966fb9b8ae24847dda8aeb880cb6f56b6da |
|
||||||
|
| C&C | `api.ciscofreak.com` |
|
||||||
|
| **April 2020** | |
|
||||||
|
| Winword.exe (legitimate) | 6c959cfb001fbb900958441dfd8b262fb33e052342948bab338775d3e83ef7f7 |
|
||||||
|
| wwlib.dll | acb33adf7429424170f63fa5490ed580cf502de4a7ef00e4b8c962425cd85052 |
|
||||||
|
| C&C | `node.podzone.org` |
|
||||||
|
| **July 2020** | |
|
||||||
|
| Winword.exe (legitimate) | 6c959cfb001fbb900958441dfd8b262fb33e052342948bab338775d3e83ef7f7 |
|
||||||
|
| wwlib.dll | 5cc8d52fcabfd35042336e095f1f78c2b2884e7826358f5385729cf45ce4d860 |
|
||||||
|
| Opera.exe (legitimate) | 71c3b9538a0f14a8ab67e579ecc4ce2b01e25507d8c07eaf46555e8f44181e37 |
|
||||||
|
| Opera.dll | a51fb048e5a2730bffd0fd43e3bdda4e931c9358254aff960ddf43526c768120 |
|
||||||
|
| C&C | `delicalo.dnsalias.net` |
|
||||||
|
| **November 2020 (2 emails)** | |
|
||||||
|
| Winword.exe (legitimate) | 6c959cfb001fbb900958441dfd8b262fb33e052342948bab338775d3e83ef7f7 |
|
||||||
|
| wwlib.dll | a574720e7b4f420098a0ac0055089000435439eb61ec6de2077ac0f782a506e9 |
|
||||||
|
| C&C | `coco.cechire.com` |
|
||||||
|
|
||||||
|
|
||||||
|
You can find the full list of indicators of compromise [here](https://github.com/AmnestyTech/investigations/tree/master/2021-02-24_vietnam/indicators).
|
||||||
BIN
data/ioc/spyware/amnesty/2021-02-24_vietnam/img/1.png
Normal file
BIN
data/ioc/spyware/amnesty/2021-02-24_vietnam/img/1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
data/ioc/spyware/amnesty/2021-02-24_vietnam/img/2.png
Normal file
BIN
data/ioc/spyware/amnesty/2021-02-24_vietnam/img/2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
BIN
data/ioc/spyware/amnesty/2021-02-24_vietnam/img/3.png
Normal file
BIN
data/ioc/spyware/amnesty/2021-02-24_vietnam/img/3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
@@ -0,0 +1,9 @@
|
|||||||
|
# Indicators of Compromise
|
||||||
|
|
||||||
|
Indicators of compromise of the report [Click and Bait: Vietnamese Human Rights Defenders Targeted with Spyware Attacks ](https://www.amnesty.org/en/latest/research/2021/02/click-and-bait-vietnamese-human-rights-defenders-targeted-with-spyware-attacks/)
|
||||||
|
|
||||||
|
Files:
|
||||||
|
* `domains.txt`: list of domains
|
||||||
|
* `ips.txt`: list of IP addresses
|
||||||
|
* `rules.yar`: YARA rules
|
||||||
|
* `sha256.txt`: SHA256 of samples
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
ssl.arkouthrie.com
|
||||||
|
widget.shoreoa.com
|
||||||
|
s3.hiahornber.com
|
||||||
|
tips.jasperpfeiffer.com
|
||||||
|
land.rellecharlessper.com
|
||||||
|
art.guillermoespana.com
|
||||||
|
api.ciscofreak.com
|
||||||
|
node.podzone.org
|
||||||
|
delicalo.dnsalias.net
|
||||||
|
coco.cechire.com
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
185.174.101.13
|
||||||
|
185.157.79.134
|
||||||
|
95.168.191.35
|
||||||
|
45.76.106.146
|
||||||
|
5.149.254.19
|
||||||
|
103.114.161.122
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
rule apt32_macos_dropper {
|
||||||
|
meta:
|
||||||
|
author = "Amnesty Tech"
|
||||||
|
|
||||||
|
strings:
|
||||||
|
$s1 = "setStartup" ascii
|
||||||
|
$s2 = "getSizeDataLoader" ascii
|
||||||
|
$s3 = "GET_LAUNCHNAME" ascii
|
||||||
|
$s4 = "GET_PROCESSNAME" ascii
|
||||||
|
$s5 = "getProcessnameRoot" ascii
|
||||||
|
$s6 = "getProcessnameUser" ascii
|
||||||
|
$s7 = "getProcessPathRoot" ascii
|
||||||
|
$s8 = "getLabelnameRoot" ascii
|
||||||
|
$s9 = "getLabelnameUser" ascii
|
||||||
|
$s10 = "stringFromHex" ascii
|
||||||
|
$s11 = "_b64_decode_ex" ascii
|
||||||
|
|
||||||
|
condition:
|
||||||
|
(uint16(0) == 0xfacf or uint16(0) == 0xface) and 9 of them
|
||||||
|
}
|
||||||
|
|
||||||
|
rule apt32_macos_backdoor_2018_encryption_key {
|
||||||
|
strings:
|
||||||
|
$key = { 63 49 2f 6e 22 00 10 fe 33 4f 2f c5 05 b2 11 03 ba 5b dd 02 }
|
||||||
|
$ccc = "CCCrypt" ascii
|
||||||
|
condition:
|
||||||
|
(uint16(0) == 0xfacf or uint16(0) == 0xface) and all of them
|
||||||
|
}
|
||||||
|
|
||||||
|
rule apt32_macos_backdoor_2019_encryption_key {
|
||||||
|
meta:
|
||||||
|
report = "https://www.welivesecurity.com/2019/04/09/oceanlotus-macos-malware-update/"
|
||||||
|
strings:
|
||||||
|
$key1 = { 9D 72 74 AD 7B CE F0 DE D2 9B DB B4 28 C2 51 DF 8B 35 0B 92 }
|
||||||
|
$key2 = {2c e4 25 29 5e 2a 20 40 9c a5 13 1e 61 1e 51 6f 2c b7 a7 7f }
|
||||||
|
$key3 = { 8b b2 c4 67 56 5c 63 42 8e f0 cf c5 f4 8d 87 ae 58 0c 5b a4 }
|
||||||
|
$ccc = "CCCrypt" ascii
|
||||||
|
condition:
|
||||||
|
(uint16(0) == 0xfacf or uint16(0) == 0xface) and $ccc and any of ($key*)
|
||||||
|
}
|
||||||
|
|
||||||
|
rule apt32_macos_backdoor_2018 {
|
||||||
|
meta:
|
||||||
|
author = "Amnesty Tech"
|
||||||
|
|
||||||
|
strings:
|
||||||
|
$s1 = "respondDownloadThreadP" ascii
|
||||||
|
$s2 = "checkProcessExist" ascii
|
||||||
|
$s3 = "setFristRandom" ascii
|
||||||
|
$s4 = "getInstalledTime" ascii
|
||||||
|
$s5 = "getSerialNumber" ascii
|
||||||
|
$s6 = "appendPathComponent" ascii
|
||||||
|
$s7 = "initFirstRandom" ascii
|
||||||
|
$s8 = "CFURLToString" ascii
|
||||||
|
$s9 = "GET_DOMAIN_CLIENT_INFO" ascii
|
||||||
|
$s10 = "getFirstRandom_Header" ascii
|
||||||
|
$s11 = "respondLoadLunaThread" ascii
|
||||||
|
|
||||||
|
condition:
|
||||||
|
(uint16(0) == 0xfacf or uint16(0) == 0xface) and 9 of them
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
952c16674bde3c16aa3935b3e01f3f0fb4cbac7ffa130143cbf6ccaa72733068
|
||||||
|
d3a198e18f8c5e9ed54ed4959b471a0f15fbda7d4abf92b7726bc07723e46dd5
|
||||||
|
ecb6186a5e722fa360ece37191589305858a0e176321c9339831f2884dcb0405
|
||||||
|
1599fe6cc77764c17802cfde1ca77f091bb3ec2a49f6cab1c80ee667ea7c752b
|
||||||
|
b8567ce4d0595e6466414999798bcb1dfe01cc5ca1dd058bfc55f92033f0f3d8
|
||||||
|
b252a8d2ec5c7080286fe3f0ad193062f506b5c34c4c797f97717e396c0a22d5
|
||||||
|
9c14cffd79f863fec0a6c0ed337ea82a9044db09afda53b8ac2aef1d49f74f4f
|
||||||
|
5ed6b7b450ead2d0e69faa3069d1e0bd3a6852909092235f75087da0ca05462f
|
||||||
|
a890c88b6c64371242b4047830b9189b4546536c6b11576d0738f0ba1840aded
|
||||||
|
0c41358adeea24d80b35bac4b4f60d93711e32e287343cb604e1fa79b5e5e465
|
||||||
|
5ed6b7b450ead2d0e69faa3069d1e0bd3a6852909092235f75087da0ca05462f
|
||||||
|
148e647885712b69258967c5f8798966fb9b8ae24847dda8aeb880cb6f56b6da
|
||||||
|
acb33adf7429424170f63fa5490ed580cf502de4a7ef00e4b8c962425cd85052
|
||||||
|
5cc8d52fcabfd35042336e095f1f78c2b2884e7826358f5385729cf45ce4d860
|
||||||
|
a574720e7b4f420098a0ac0055089000435439eb61ec6de2077ac0f782a506e9
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user