codedefender_config/
lib.rs

1//! `codedefender-config` provides the Rust data structures used for serializing and deserializing
2//! CodeDefender YAML configuration files and analysis results. These structures are used by both
3//! the CodeDefender CLI and its backend services.
4//!
5//! This crate is intended to be consumed by tools that integrate with or generate CodeDefender config files.
6
7use serde::{Deserialize, Serialize};
8
9/// Current supported YAML config version.
10pub const YAML_CONFIG_VERSION: &str = "1.0.4";
11
12/// Available SIMD extension types used by mutation engines.
13#[derive(Debug, Serialize, Deserialize, Clone)]
14pub enum MutationEngineExtension {
15    /// All base instructions
16    Generic,
17    /// All base instructions + Legacy SSE instructions up until SSE3
18    SSE3,
19    /// All base instructions + Legacy SSE instructions up until SSE4.2
20    SSE42
21}
22
23/// Supported PE environments.
24#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
25pub enum PeEnvironment {
26    /// User-mode PE (exe, dll)
27    UserMode,
28    /// Kernel-mode PE (sys)
29    KernelMode,
30    /// UEFI firmware image
31    UEFI,
32}
33
34/// Configuration settings for lifting x86 instructions into IR.
35#[derive(Debug, Serialize, Deserialize, Clone)]
36pub struct LifterSettings {
37    /// Whether to lift calls into IR.
38    pub lift_calls: bool,
39    /// Calling convention used for lifting, only `WindowsAbi`, and `Conservative` are supported.
40    pub calling_convention: String,
41    /// Max stack copy size in bytes when lifting.
42    pub max_stack_copy_size: u32,
43    /// Fallback: split on calls if lifting fails.
44    pub split_on_calls_fallback: bool,
45}
46
47/// IR optimization settings.
48#[derive(Debug, Serialize, Deserialize, Clone)]
49pub struct OptimizationSettings {
50    /// Enable constant propagation.
51    pub constant_propagation: bool,
52    /// Enable instruction combining.
53    pub instruction_combine: bool,
54    /// Enable dead code elimination.
55    pub dead_code_elim: bool,
56    /// Enable pruning of unused block parameters.
57    pub prune_useless_block_params: bool,
58    /// Number of optimization iterations to run.
59    pub iterations: u32,
60}
61
62/// Assembler-level codegen settings.
63#[derive(Debug, Serialize, Deserialize, Clone)]
64pub struct AssemblerSettings {
65    /// Whether to shuffle basic blocks.
66    pub shuffle_basic_blocks: bool,
67    /// Instruction prefix to prepend to emitted instructions.
68    pub instruction_prefix: String,
69    /// Chance of randomly applying the prefix.
70    pub random_prefix_chance: f64,
71}
72
73/// Compiler configuration (IR + codegen) for a profile.
74#[derive(Debug, Serialize, Deserialize, Clone)]
75pub struct CDCompilerSettings {
76    /// Assembler settings.
77    pub assembler_settings: AssemblerSettings,
78    /// Optimization settings.
79    pub optimization_settings: OptimizationSettings,
80    /// IR lifter settings.
81    pub lifter_settings: LifterSettings,
82}
83
84/// Fake PDB string settings to confuse debuggers.
85#[derive(Default, Debug, Serialize, Deserialize)]
86pub struct FakePdbString {
87    /// Whether the fake PDB string is enabled.
88    pub enabled: bool,
89    /// Value to emit as the fake PDB string.
90    pub value: String,
91}
92
93/// Custom `.text` section name override.
94#[derive(Default, Debug, Serialize, Deserialize)]
95pub struct CustomSectionName {
96    /// Whether this feature is enabled.
97    pub enabled: bool,
98    /// Custom section name value.
99    pub value: String,
100}
101
102/// Global obfuscation settings for the module.
103#[derive(Debug, Serialize, Deserialize)]
104pub struct CDModuleSettings {
105    /// Whether to crash the IDA decompiler intentionally.
106    #[serde(default)]
107    pub ida_crasher: bool,
108    /// Whether to enable IAT/Import protection.
109    #[serde(default)]
110    pub import_protection: bool,
111    /// Obscure the entry point of the module with anti tamper and anti debug tactics
112    #[serde(default)]
113    pub obscure_entry_point: bool,
114    /// Clear unwind information. makes it harder for attackers to locate functions, however
115    /// structured exception handling will not work.
116    #[serde(default)]
117    pub clear_unwind_info: bool,
118    /// Fake PDB string settings.
119    #[serde(default)]
120    pub fake_pdb_string: FakePdbString,
121    /// Custom PE section name settings.
122    #[serde(default)]
123    pub custom_section_name: CustomSectionName,
124}
125
126/// Instruction-level semantics used in transformations.
127#[derive(Debug, Serialize, Deserialize, Clone)]
128pub struct Semantics {
129    #[serde(default)]
130    pub add: bool,
131    #[serde(default)]
132    pub sub: bool,
133    #[serde(default)]
134    pub and: bool,
135    #[serde(default)]
136    pub xor: bool,
137    #[serde(default)]
138    pub or: bool,
139    #[serde(default)]
140    pub not: bool,
141    #[serde(default)]
142    pub neg: bool,
143}
144
145/// Bit widths to apply transformations to.
146#[derive(Debug, Serialize, Deserialize, Clone)]
147pub struct BitWidths {
148    #[serde(default)]
149    pub bit8: bool,
150    #[serde(default)]
151    pub bit16: bool,
152    #[serde(default)]
153    pub bit32: bool,
154    #[serde(default)]
155    pub bit64: bool,
156}
157
158/// The origin of SSA value from within the instruction.
159/// Please refer to this documentation for more info:
160/// https://docs.codedefender.io/features/ethnicity
161#[derive(Debug, Serialize, Deserialize, Clone)]
162pub struct SsaOrigins {
163    pub normal: bool,
164    pub memop: bool,
165    pub fp_based_memop: bool,
166    pub sp_based_memop: bool,
167}
168
169/// Configuration for the Loop Encode Semantics pass.
170#[derive(Debug, Serialize, Deserialize, Clone)]
171pub struct LoopEncodeSemantics {
172    /// Number of times to attempt transformation.
173    pub iterations: u32,
174    /// Percent chance to apply transformation (0–100).
175    pub probability: u32,
176    /// Instruction semantics to consider.
177    pub semantics: Semantics,
178    /// Bit widths to target.
179    pub bitwidths: BitWidths,
180    pub ethnicities: SsaOrigins,
181}
182
183/// Configuration for Mixed Boolean Arithmetic pass.
184#[derive(Debug, Serialize, Deserialize, Clone)]
185pub struct MixedBooleanArithmetic {
186    pub iterations: u32,
187    pub probability: u32,
188    pub semantics: Semantics,
189    pub bitwidths: BitWidths,
190    pub ethnicities: SsaOrigins,
191}
192
193/// Configuration for Mutation Engine pass.
194#[derive(Debug, Serialize, Deserialize, Clone)]
195pub struct MutationEngine {
196    pub iterations: u32,
197    pub probability: u32,
198    pub extension: MutationEngineExtension,
199    pub semantics: Semantics,
200    pub bitwidths: BitWidths,
201    pub ethnicities: SsaOrigins,
202}
203
204/// Pass that crashes IDA’s decompiler.
205#[derive(Debug, Serialize, Deserialize, Clone)]
206pub struct IDADecompilerCrasher;
207
208/// Suppress constants and prevent them from rematerializing at runtime.
209#[derive(Debug, Serialize, Deserialize, Clone)]
210pub struct SuppressConstants {
211    pub ethnicities: SsaOrigins,
212}
213
214/// Statically obscure constants, this does not prevent rematerialization at runtime.
215/// Use the SuppressConstants pass in tandem with this!
216#[derive(Debug, Serialize, Deserialize, Clone)]
217pub struct ObscureConstants {
218    pub probability: u32,
219    pub iterations: u32,
220    pub bitwidths: BitWidths,
221    pub ethnicities: SsaOrigins,
222}
223
224/// Memory reference obfuscation pass.
225#[derive(Debug, Serialize, Deserialize, Clone)]
226pub struct ObscureReferences;
227
228/// Control-flow obfuscation pass.
229#[derive(Debug, Serialize, Deserialize, Clone)]
230pub struct ObscureControlFlow {
231    pub probability: u32,
232}
233
234/// Tether extraction pass.
235#[derive(Debug, Serialize, Deserialize, Clone)]
236pub struct TetherExtraction {
237    /// Min length of a sequence of instructions that should be extracted.
238    /// Its a bad idea for this to be 1 usually because its easy to synthesize
239    pub min_extract_len: usize,
240    /// Tether server endpoint
241    pub endpoint: String,
242    /// Tether server port
243    pub port: u16,
244    /// Hex string of the servers public key. This is used for public key pinning.
245    /// This needs to be length 64...
246    pub server_public_key: String,
247}
248
249/// Opaque block duplication pass.
250#[derive(Debug, Serialize, Deserialize, Clone)]
251pub struct OpaqueBlockDuplication {
252    /// Number of iterations to attempt transformation.
253    pub iterations: u32,
254    /// Percent chance to apply transformation (0–100).
255    pub probability: u32,
256}
257
258/// Split block pass, used to create more control flow points for other passes to transform.
259#[derive(Debug, Serialize, Deserialize, Clone)]
260pub struct SplitBlockPass {
261    /// The number of SSA values required to be within a block for it to be split into two seperate blocks.
262    pub threshold: u32,
263}
264
265/// Encode immediate ssa values into lea's
266#[derive(Debug, Serialize, Deserialize, Clone)]
267pub struct LeaEncodeImm {
268    /// Percent chance to apply transformation (0–100).
269    pub probability: u32,
270    pub ethnicities: SsaOrigins,
271}
272
273/// All possible obfuscation passes.
274#[derive(Debug, Serialize, Deserialize, Clone)]
275#[serde(tag = "type")]
276pub enum ObfuscationPass {
277    LoopEncodeSemantics(LoopEncodeSemantics),
278    MixedBooleanArithmetic(MixedBooleanArithmetic),
279    MutationEngine(MutationEngine),
280    TetherExtraction(TetherExtraction),
281    SplitBlockPass(SplitBlockPass),
282    OpaqueBlockDuplication(OpaqueBlockDuplication),
283    ObscureControlFlow(ObscureControlFlow),
284    LeaEncodeImm(LeaEncodeImm),
285    ObscureConstants(ObscureConstants),
286    SuppressConstants(SuppressConstants),
287    IDADecompilerCrasher,
288    ObscureReferences,
289    AntiEmulator,
290}
291
292/// Profile definition used to apply passes to symbols.
293#[derive(Debug, Serialize, Deserialize)]
294pub struct CDProfile {
295    /// Name of the profile.
296    pub name: String,
297    /// Obfuscation passes for this profile.
298    pub passes: Vec<ObfuscationPass>,
299    /// Compiler settings for this profile.
300    pub compiler_settings: CDCompilerSettings,
301    /// List of symbol RVAs this profile targets.
302    pub symbols: Vec<u64>,
303}
304
305/// Top-level config file structure.
306#[derive(Debug, Serialize, Deserialize)]
307pub struct CDConfig {
308    /// Module-wide settings.
309    pub module_settings: CDModuleSettings,
310    /// All profiles to apply during obfuscation.
311    pub profiles: Vec<CDProfile>,
312}
313
314/// Information about a single function found during analysis.
315#[derive(Deserialize, Serialize, Clone, Debug)]
316pub struct AnalysisFunction {
317    /// RVA of the function.
318    pub rva: u64,
319    /// Function name.
320    pub symbol: String,
321    /// Number of references to this function.
322    pub ref_count: usize,
323}
324
325/// Reason why a function was rejected from analysis.
326#[derive(Deserialize, Serialize, Clone, Debug)]
327pub struct AnalysisReject {
328    /// RVA of the rejected function.
329    pub rva: u64,
330    /// Symbol name.
331    pub symbol: String,
332    /// Mnemonic reason string (e.g., internal enum).
333    pub ty: String,
334    /// Stringified reason (human-readable).
335    pub reason: String,
336}
337
338/// Grouping of functions under a named macro profile.
339#[derive(Deserialize, Serialize, Clone, Debug)]
340pub struct AnalysisMacroProfile {
341    /// Name of the macro profile.
342    pub name: String,
343    /// List of function RVAs in this macro.
344    pub rvas: Vec<u64>,
345}
346
347/// Results from binary analysis, returned to the frontend.
348#[derive(Deserialize, Serialize, Clone, Debug)]
349pub struct AnalysisResult {
350    /// Environment type (UserMode, KernelMode, UEFI).
351    pub environment: PeEnvironment,
352    /// Functions found during analysis.
353    pub functions: Vec<AnalysisFunction>,
354    /// Rejected functions and reasons.
355    pub rejects: Vec<AnalysisReject>,
356    /// Macro profiles generated from analysis.
357    pub macros: Vec<AnalysisMacroProfile>,
358}
359
360/// Symbol representation used in YAML: either name or RVA.
361#[derive(Debug, Serialize, Deserialize)]
362pub enum YamlSymbol {
363    /// Symbol name
364    Name(String),
365    /// Symbol RVA.
366    Rva(u64),
367}
368
369/// Obfuscation profile for YAML configuration.
370#[derive(Debug, Serialize, Deserialize)]
371pub struct YamlProfile {
372    /// Profile name (referenced by source macros).
373    pub name: String,
374    /// Passes to apply to this profile.
375    pub passes: Vec<ObfuscationPass>,
376    /// Compiler configuration for this profile.
377    pub compiler_settings: CDCompilerSettings,
378    /// Symbols targeted by this profile.
379    pub symbols: Vec<YamlSymbol>,
380    /// Only used by the SaaS UI. Not used by the CLI.
381    pub color: Option<String>,
382}
383
384/// Root YAML config structure.
385#[derive(Debug, Serialize, Deserialize)]
386pub struct YamlConfig {
387    /// Version of the config file format.
388    pub version: String,
389    /// Global module-wide obfuscation settings.
390    pub module_settings: CDModuleSettings,
391    /// Obfuscation profiles to apply.
392    pub profiles: Vec<YamlProfile>,
393}