DebugConfig gains fake_line_numbers (deterministic upward walk replacing LineNumberTable rows when stripping is off; strip wins) and strip_source_file (drops SourceFile entirely, beating spoof). Debug tests moved to passes/tests/debug_info.rs with new cases for both flags and their precedence.
202 lines
6.4 KiB
Rust
202 lines
6.4 KiB
Rust
//! Config sections: name styles and per-pass settings.
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// Name generation style.
|
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "kebab-case")]
|
|
pub enum NameStyle {
|
|
/// `a`, `b`, ... `aa` - short Latin.
|
|
ShortLatin,
|
|
/// `I`, `l`, `O`, `0` - visually identical.
|
|
IlO0,
|
|
/// Random Unicode names (surrogates are valid in modified UTF-8).
|
|
Unicode,
|
|
/// Medium-length mixed-case Latin.
|
|
#[default]
|
|
MixedLatin,
|
|
/// Pseudo-meaningful words from another project (misdirection).
|
|
DecoyWords,
|
|
/// Plausible names: `TextureCache`, `resolveToken` - blends in as
|
|
/// ordinary application code instead of obvious noise.
|
|
Plausible,
|
|
}
|
|
|
|
/// Rename pass settings.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(default, deny_unknown_fields)]
|
|
pub struct RenameConfig {
|
|
/// Scatter packages into random paths.
|
|
pub spread_packages: bool,
|
|
/// Size of the random package pool.
|
|
pub package_pool: usize,
|
|
/// Name style for classes.
|
|
pub class_style: NameStyle,
|
|
/// Name style for fields and methods.
|
|
pub member_style: NameStyle,
|
|
/// Name style for local variables and parameters.
|
|
pub local_style: NameStyle,
|
|
/// Widen members to `public` (so moving to a new package doesn't break
|
|
/// inheritance).
|
|
pub widen_access: bool,
|
|
/// Rename enum constants.
|
|
pub rename_enum_constants: bool,
|
|
/// Rename local variables and parameters.
|
|
pub rename_locals: bool,
|
|
/// Also rename non-private members (aggressive: safe for applications,
|
|
/// dangerous for libraries and reflection-heavy code).
|
|
pub rename_public_members: bool,
|
|
}
|
|
|
|
impl Default for RenameConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
spread_packages: true,
|
|
package_pool: 12,
|
|
class_style: NameStyle::ShortLatin,
|
|
member_style: NameStyle::MixedLatin,
|
|
local_style: NameStyle::IlO0,
|
|
widen_access: true,
|
|
rename_enum_constants: true,
|
|
rename_locals: true,
|
|
rename_public_members: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// String encryption settings.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(default, deny_unknown_fields)]
|
|
pub struct StringsConfig {
|
|
/// Cipher schemes strings are rotated across.
|
|
pub schemes: Vec<String>,
|
|
/// Strings shorter than this are not encrypted.
|
|
pub min_len: usize,
|
|
/// Split long strings into chunks (looks less like a string pool).
|
|
pub split_above: usize,
|
|
/// Don't encrypt strings matching these patterns.
|
|
pub skip: Vec<String>,
|
|
/// Derive the key from KDF(class, method, index) instead of placing it
|
|
/// next to the ciphertext.
|
|
pub derive_key: bool,
|
|
}
|
|
|
|
impl Default for StringsConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
schemes: vec!["xor-splitmix".to_string(), "xtea-ctr".to_string()],
|
|
min_len: 2,
|
|
split_above: 64,
|
|
skip: Vec::new(),
|
|
derive_key: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Control-flow obfuscation settings.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(default, deny_unknown_fields)]
|
|
pub struct FlowConfig {
|
|
/// Schemes picked randomly per method.
|
|
pub schemes: Vec<String>,
|
|
/// Don't touch methods larger than this many instructions (size budget).
|
|
pub max_insns: usize,
|
|
/// Weave opaque predicates into block bodies.
|
|
pub encrypt_block_bodies: bool,
|
|
}
|
|
|
|
impl Default for FlowConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
schemes: vec![
|
|
"state-spread".to_string(),
|
|
"computed-switch".to_string(),
|
|
"butterfly".to_string(),
|
|
"exception-goto".to_string(),
|
|
],
|
|
max_insns: 4000,
|
|
encrypt_block_bodies: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Constant encryption settings.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(default, deny_unknown_fields)]
|
|
pub struct ConstantsConfig {
|
|
/// Splitting schemes (`xor`, `add`, `shift`), picked by RNG per constant.
|
|
pub schemes: Vec<String>,
|
|
/// Insert opaque predicates (at most this many per method).
|
|
pub max_predicates: usize,
|
|
/// Don't touch constants in these classes (internal-name prefixes).
|
|
pub skip: Vec<String>,
|
|
}
|
|
|
|
impl Default for ConstantsConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
schemes: vec!["xor".to_string(), "add".to_string(), "shift".to_string()],
|
|
max_predicates: 1,
|
|
skip: Vec::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Noise pass settings.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(default, deny_unknown_fields)]
|
|
pub struct NoiseConfig {
|
|
/// How many junk classes per real one (0 = disabled).
|
|
pub junk_ratio: usize,
|
|
/// Branching helper methods per junk class (their results feed a
|
|
/// static field so the bodies read as live code, not dead weight).
|
|
pub junk_methods_per_class: usize,
|
|
/// Number of junk annotations per class.
|
|
pub junk_annotations: usize,
|
|
/// Weave junk classes into the reachability graph (required for them to
|
|
/// make sense).
|
|
pub weave_reachable: bool,
|
|
}
|
|
|
|
impl Default for NoiseConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
junk_ratio: 0,
|
|
junk_methods_per_class: 3,
|
|
junk_annotations: 0,
|
|
weave_reachable: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Debug info pass settings.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(default, deny_unknown_fields)]
|
|
pub struct DebugConfig {
|
|
/// Strip `LineNumberTable`.
|
|
pub strip_line_numbers: bool,
|
|
/// Replace line numbers with plausible-but-wrong ones. Applies only
|
|
/// when `strip_line_numbers` is off (stripping wins).
|
|
pub fake_line_numbers: bool,
|
|
/// Strip `LocalVariableTable`.
|
|
pub strip_local_variables: bool,
|
|
/// Replace `SourceFile` with a fake name.
|
|
pub spoof_source_file: bool,
|
|
/// Remove `SourceFile` entirely instead of spoofing it.
|
|
pub strip_source_file: bool,
|
|
/// Strip `Signature`/`InnerClasses`/`EnclosingMethod`.
|
|
pub strip_signatures: bool,
|
|
}
|
|
|
|
impl Default for DebugConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
strip_line_numbers: true,
|
|
fake_line_numbers: false,
|
|
strip_local_variables: true,
|
|
spoof_source_file: true,
|
|
strip_source_file: false,
|
|
strip_signatures: false,
|
|
}
|
|
}
|
|
}
|