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.6";
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 CompilerSettings {
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 ModuleSettings {
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    /// Should the output file be packed/compressed? This option only works for usermode modules.
112    #[serde(default)]
113    pub pack_output_file: bool,
114    /// Obscure the entry point of the module with anti tamper and anti debug tactics
115    #[serde(default)]
116    pub obscure_entry_point: bool,
117    /// Clear unwind information. makes it harder for attackers to locate functions, however
118    /// structured exception handling will not work.
119    #[serde(default)]
120    pub clear_unwind_info: bool,
121    /// Fake PDB string settings.
122    #[serde(default)]
123    pub fake_pdb_string: FakePdbString,
124    /// Custom PE section name settings.
125    #[serde(default)]
126    pub custom_section_name: CustomSectionName,
127}
128
129/// Instruction-level semantics used in transformations.
130#[derive(Debug, Serialize, Deserialize, Clone)]
131pub struct Semantics {
132    #[serde(default)]
133    pub add: bool,
134    #[serde(default)]
135    pub sub: bool,
136    #[serde(default)]
137    pub and: bool,
138    #[serde(default)]
139    pub xor: bool,
140    #[serde(default)]
141    pub or: bool,
142    #[serde(default)]
143    pub not: bool,
144    #[serde(default)]
145    pub neg: bool,
146}
147
148/// Bit widths to apply transformations to.
149#[derive(Debug, Serialize, Deserialize, Clone)]
150pub struct BitWidths {
151    #[serde(default)]
152    pub bit8: bool,
153    #[serde(default)]
154    pub bit16: bool,
155    #[serde(default)]
156    pub bit32: bool,
157    #[serde(default)]
158    pub bit64: bool,
159}
160
161/// The origin of SSA value from within the instruction.
162/// Please refer to this documentation for more info:
163/// https://docs.codedefender.io/features/ethnicity
164#[derive(Debug, Serialize, Deserialize, Clone)]
165pub struct SsaOrigins {
166    pub normal: bool,
167    pub memop: bool,
168    pub fp_based_memop: bool,
169    pub sp_based_memop: bool,
170}
171
172/// Configuration for the Loop Encode Semantics pass.
173#[derive(Debug, Serialize, Deserialize, Clone)]
174pub struct LoopEncodeSemantics {
175    /// Number of times to attempt transformation.
176    pub iterations: u32,
177    /// Percent chance to apply transformation (0–100).
178    pub probability: u32,
179    /// Instruction semantics to consider.
180    pub semantics: Semantics,
181    /// Bit widths to target.
182    pub bitwidths: BitWidths,
183    pub ethnicities: SsaOrigins,
184}
185
186/// Configuration for Mixed Boolean Arithmetic pass.
187#[derive(Debug, Serialize, Deserialize, Clone)]
188pub struct MixedBooleanArithmetic {
189    pub iterations: u32,
190    pub probability: u32,
191    pub semantics: Semantics,
192    pub bitwidths: BitWidths,
193    pub ethnicities: SsaOrigins,
194}
195
196/// Configuration for Mutation Engine pass.
197#[derive(Debug, Serialize, Deserialize, Clone)]
198pub struct MutationEngine {
199    pub iterations: u32,
200    pub probability: u32,
201    pub extension: MutationEngineExtension,
202    pub semantics: Semantics,
203    pub bitwidths: BitWidths,
204    pub ethnicities: SsaOrigins,
205}
206
207/// Pass that crashes IDA’s decompiler.
208#[derive(Debug, Serialize, Deserialize, Clone)]
209pub struct IDADecompilerCrasher;
210
211/// Suppress constants and prevent them from rematerializing at runtime.
212#[derive(Debug, Serialize, Deserialize, Clone)]
213pub struct SuppressConstants {
214    pub mba_enhance: bool,
215    pub ethnicities: SsaOrigins,
216}
217
218/// Statically obscure constants, this does not prevent rematerialization at runtime.
219/// Use the SuppressConstants pass in tandem with this!
220#[derive(Debug, Serialize, Deserialize, Clone)]
221pub struct ObscureConstants {
222    pub mba_enhance: bool,
223    pub probability: u32,
224    pub iterations: u32,
225    pub bitwidths: BitWidths,
226    pub ethnicities: SsaOrigins,
227}
228
229/// Memory reference obfuscation pass.
230#[derive(Debug, Serialize, Deserialize, Clone)]
231pub struct ObscureReferences {
232    pub mba_enhance: bool,
233}
234
235/// Control-flow obfuscation pass.
236#[derive(Debug, Serialize, Deserialize, Clone)]
237pub struct ObscureControlFlow {
238    pub mba_enhance: bool,
239    pub probability: u32,
240}
241
242/// Tether extraction pass.
243#[derive(Debug, Serialize, Deserialize, Clone)]
244pub struct TetherExtraction {
245    /// Min length of a sequence of instructions that should be extracted.
246    /// Its a bad idea for this to be 1 usually because its easy to synthesize
247    pub min_extract_len: usize,
248    /// Tether server endpoint
249    pub endpoint: String,
250    /// Tether server port
251    pub port: u16,
252    /// Hex string of the servers public key. This is used for public key pinning.
253    /// This needs to be length 64...
254    pub server_public_key: String,
255}
256
257/// Opaque block duplication pass.
258#[derive(Debug, Serialize, Deserialize, Clone)]
259pub struct OpaqueBlockDuplication {
260    /// Number of iterations to attempt transformation.
261    pub iterations: u32,
262    /// Percent chance to apply transformation (0–100).
263    pub probability: u32,
264}
265
266/// Split block pass, used to create more control flow points for other passes to transform.
267#[derive(Debug, Serialize, Deserialize, Clone)]
268pub struct SplitBlockPass {
269    /// The number of SSA values required to be within a block for it to be split into two seperate blocks.
270    pub threshold: u32,
271}
272
273/// Encode immediate ssa values into lea's
274#[derive(Debug, Serialize, Deserialize, Clone)]
275pub struct LeaEncodeImm {
276    pub mba_enhance: bool,
277    /// Number of iterations to attempt transformation.
278    pub iterations: u32,
279    /// Percent chance to apply transformation (0–100).
280    pub probability: u32,
281    pub ethnicities: SsaOrigins,
282}
283
284#[derive(Debug, Serialize, Deserialize, Clone)]
285pub struct SigBreaker {
286    pub shuffle_insts: bool,
287    pub random_segment_selector: bool,
288    /// Calling convention used for lifting, only `WindowsAbi`, and `Conservative` are supported.
289    pub calling_convention: String,
290    pub shuffle_opcodes: bool,
291    pub instruction_substitution: bool,
292}
293
294/// All possible obfuscation passes.
295#[derive(Debug, Serialize, Deserialize, Clone)]
296#[serde(tag = "type")]
297pub enum ObfuscationPass {
298    LoopEncodeSemantics(LoopEncodeSemantics),
299    MixedBooleanArithmetic(MixedBooleanArithmetic),
300    MutationEngine(MutationEngine),
301    TetherExtraction(TetherExtraction),
302    SplitBlockPass(SplitBlockPass),
303    OpaqueBlockDuplication(OpaqueBlockDuplication),
304    ObscureControlFlow(ObscureControlFlow),
305    LeaEncodeImm(LeaEncodeImm),
306    ObscureConstants(ObscureConstants),
307    SuppressConstants(SuppressConstants),
308    ObscureReferences(ObscureReferences),
309    SigBreaker(SigBreaker),
310    IDADecompilerCrasher,
311    AntiEmulator,
312}
313
314/// Profile definition used to apply passes to symbols.
315#[derive(Debug, Serialize, Deserialize)]
316pub struct Profile {
317    /// Name of the profile.
318    pub name: String,
319    /// Obfuscation passes for this profile.
320    pub passes: Vec<ObfuscationPass>,
321    /// Compiler settings for this profile.
322    pub compiler_settings: CompilerSettings,
323    /// List of symbol RVAs this profile targets.
324    pub symbols: Vec<u64>,
325}
326
327/// Top-level config file structure.
328#[derive(Debug, Serialize, Deserialize)]
329pub struct Config {
330    /// Module-wide settings.
331    pub module_settings: ModuleSettings,
332    /// All profiles to apply during obfuscation.
333    pub profiles: Vec<Profile>,
334}
335
336/// Information about a single function found during analysis.
337#[derive(Deserialize, Serialize, Clone, Debug)]
338pub struct AnalysisFunction {
339    /// RVA of the function.
340    pub rva: u64,
341    /// Function name.
342    pub symbol: String,
343    /// Number of references to this function.
344    pub ref_count: usize,
345}
346
347/// Reason why a function was rejected from analysis.
348#[derive(Deserialize, Serialize, Clone, Debug)]
349pub struct AnalysisReject {
350    /// RVA of the rejected function.
351    pub rva: u64,
352    /// Symbol name.
353    pub symbol: String,
354    /// Mnemonic reason string (e.g., internal enum).
355    pub ty: String,
356    /// Stringified reason (human-readable).
357    pub reason: String,
358}
359
360/// Grouping of functions under a named macro profile.
361#[derive(Deserialize, Serialize, Clone, Debug)]
362pub struct AnalysisMacroProfile {
363    /// Name of the macro profile.
364    pub name: String,
365    /// List of function RVAs in this macro.
366    pub rvas: Vec<u64>,
367}
368
369/// Results from binary analysis, returned to the frontend.
370#[derive(Deserialize, Serialize, Clone, Debug)]
371pub struct AnalysisResult {
372    /// Environment type (UserMode, KernelMode, UEFI).
373    pub environment: PeEnvironment,
374    /// Functions found during analysis.
375    pub functions: Vec<AnalysisFunction>,
376    /// Rejected functions and reasons.
377    pub rejects: Vec<AnalysisReject>,
378    /// Macro profiles generated from analysis.
379    pub macros: Vec<AnalysisMacroProfile>,
380}
381
382#[derive(Deserialize, Serialize, Clone, Debug)]
383pub struct DisassemblySettings {
384    pub allow_code_reads_and_writes: bool,
385    pub allow_unknown_indirect_jumps: bool,
386    pub allow_mismatched_branch_counts: bool,
387    pub thunk_mismatched_branch_counts: bool,
388    pub thunk_branch_target_identifiers: bool,
389    pub thunk_no_prev_block: bool,
390    pub thunk_data_references: bool,
391    pub always_thunk_entry: bool,
392    pub follow_faulting_instructions: bool,
393    pub pass_interrupts: bool,
394    pub pass_exceptions: bool,
395    pub aggressive_pointer_analysis: bool,
396    pub perform_relocation_analysis: bool,
397    pub explore_catch_funclet_continuations: bool,
398}
399
400/// Symbol representation used in YAML: either name or RVA.
401#[derive(Debug, Serialize, Deserialize)]
402pub enum YamlSymbol {
403    /// Symbol name
404    Name(String),
405    /// Symbol RVA.
406    Rva(u64),
407    /// All Symbols
408    All,
409}
410
411/// Obfuscation profile for YAML configuration.
412#[derive(Debug, Serialize, Deserialize)]
413pub struct YamlProfile {
414    /// Profile name (referenced by source macros).
415    pub name: String,
416    /// Passes to apply to this profile.
417    pub passes: Vec<ObfuscationPass>,
418    /// Compiler configuration for this profile.
419    pub compiler_settings: CompilerSettings,
420    /// Symbols targeted by this profile.
421    pub symbols: Vec<YamlSymbol>,
422}
423
424/// Root YAML config structure.
425#[derive(Debug, Serialize, Deserialize)]
426pub struct YamlConfig {
427    /// Version of the config file format.
428    pub version: String,
429    /// The global disassembly settings.
430    pub disassembly_settings: DisassemblySettings,
431    /// Global module-wide obfuscation settings.
432    pub module_settings: ModuleSettings,
433    /// Obfuscation profiles to apply.
434    pub profiles: Vec<YamlProfile>,
435}