Semantic Designs can construct custom obfuscators for virtually any source language as a part of the corresponding Source Formatter. This page contains Ada sample code, its obfuscated version, and the generated obfuscation map.
-- GENERAL OPERATIONS ON DIRECTED GRAPHS ------------------------------------- -- Creation : 8-JUN-1988 with Stacks, Queues; package body Directed_Graph_Operations is -------------------------------------- procedure Graph_Traversal (From : in Vertex; In_Graph : in Graph; Order : in Graph_Traversal_Order; Direction : in Graph_Traversal_Direction) is generic type Vertex_Storage is limited private; with procedure Store (Item : in Vertex; Into : in out Vertex_Storage); with procedure Retrieve (From : in out Vertex_Storage; Item : out Vertex); with function Empty (Storage : Vertex_Storage) return Boolean is <>; with procedure Destroy (Storage : in out Vertex_Storage) is <>; procedure Graph_Traversal; procedure Graph_Traversal is Waiting_Vertices : Vertex_Storage; Marked_Vertices : Vertex_Set; V : Vertex; function Adjacent (V : Vertex; In_Graph : Graph) return Vertex_List is begin case Direction is when Forward => return Succ(V, In_Graph); when Backward => return Pred(V, In_Graph); end case; end Adjacent; use Set_Of_Vertex; begin Add(From, To => Marked_Vertices); Store(From, Into => Waiting_Vertices); while not Empty(Waiting_Vertices) loop Retrieve(Item => V, From => Waiting_Vertices); begin Action(V); exception when others => Destroy(Waiting_Vertices); Empty(Marked_Vertices); raise; end; declare Adjacent_To_V : constant Vertex_List := Adjacent(V, In_Graph); begin for I in Adjacent_To_V'Range loop if not Member(Adjacent_To_V(I), Marked_Vertices) then Add(Adjacent_To_V(I), To => Marked_Vertices); Store(Adjacent_To_V(I), Into => Waiting_Vertices); end if; end loop; end; end loop; Empty(Marked_Vertices); end Graph_Traversal; begin case Order is when Depth_First => declare package Vertex_Stacks is new Stacks(Vertex, Count => Natural); procedure Traverse_Depth_First is new Graph_Traversal(Vertex_Storage => Vertex_Stacks.Stack, Store => Vertex_Stacks.Push, Retrieve => Vertex_Stacks.Pop, Empty => Vertex_Stacks.Empty, Destroy => Vertex_Stacks.Destroy); begin Traverse_Depth_First; end; when Breadth_First => declare package Vertex_Queues is new Queues(Vertex, Count => Natural); procedure Traverse_Breadth_First is new Graph_Traversal(Vertex_Storage => Vertex_Queues.Queue, Store => Vertex_Queues.Put, Retrieve => Vertex_Queues.Get, Empty => Vertex_Queues.Empty, Destroy => Vertex_Queues.Destroy); begin Traverse_Breadth_First; end; end case; end Graph_Traversal; end Directed_Graph_Operations;
(You may need to use your horizontal scroll bar to see it completely). Notice that comments are gone, names have been scrambled, and whitespace has been garbled. Larger constants (none in this example) have their radix twiddled. The obfuscator uses special lists provided by the user to define names that should be preserved, ensuring that public interfaces and accesses to standard packages and public libraries remain valid; we didn't take advantage of that here. If you obfuscate a set of Ada source files simultaneously, only the public symbols they collectively offer will be visible in the compiled source files. An SD-supplied list covers the Standard Ada packages.
with l0,O0; package body l1 is procedure O1(l2: in O2; l3: in O3; l4: in O4; l5: in O5) is generic type l6 is limited private; with procedure O6(l7: in O2; O7: in out l6); with procedure l8(l2: in out l6; l7: out O2); with function O8(l9: l6) return Boolean is <>; with procedure O9(l9: in out l6) is <>; procedure O1; procedure O1 is la: l6; Oa: lb; Ob: O2; function lc(Ob: O2; l3: O3) return Oc is begin case l5 is when ld => return Od(Ob,l3); when le => return Oe(Ob,l3); end case; end lc; use lf; begin Of(l2,lg => Oa); O6(l2,O7 => la); while not O8(la) loop l8(l7 => Ob,l2 => la); begin Og(Ob); exception when others => O9(la); O8(Oa); raise; end; declare lh: constant Oc := lc(Ob,l3); begin for Oh in lh'Range loop if not li(lh(Oh),Oa) then Of(lh(Oh),lg => Oa); O6(lh(Oh),O7 => la); end if; end loop; end; end loop; O8(Oa); end O1; begin case l4 is when Oi => declare package lj is new l0(O2,Oj => lk); procedure Ok is new O1(l6 => lj.ll,O6 => lj.Ol,l8 => lj.lm,O8 => lj.O8,O9 => lj.O9); begin Ok; end; when Om => declare package ln is new O0(O2,Oj => lk); procedure On is new O1(l6 => ln.lo,O6 => ln.Oo,l8 => ln.lp,O8 => ln.O8,O9 => ln.O9); begin On; end; end case; end O1; end l1;
The obfuscator produces a cross reference mapping obfuscated symbols to the orginal symbols, so that obfuscated code in the field can still be decoded if necessary. In fact, by reversing this map, the obfuscator can unobfuscate the code (of course, it cannot restore the comments).
### Obfuscated Identifiers ### Action -> Og Add -> Of Adjacent -> lc Adjacent_To_V -> lh Backward -> le Breadth_First -> Om Count -> Oj Depth_First -> Oi Destroy -> O9 Directed_Graph_Operations -> l1 Direction -> l5 Empty -> O8 Forward -> ld From -> l2 Get -> lp Graph -> O3 Graph_Traversal -> O1 Graph_Traversal_Direction -> O5 Graph_Traversal_Order -> O4 I -> Oh In_Graph -> l3 Into -> O7 Item -> l7 Marked_Vertices -> Oa Member -> li Natural -> lk Order -> l4 Pop -> lm Pred -> Oe Push -> Ol Put -> Oo Queue -> lo Queues -> O0 Retrieve -> l8 Set_Of_Vertex -> lf Stack -> ll Stacks -> l0 Storage -> l9 Store -> O6 Succ -> Od To -> lg Traverse_Breadth_First -> On Traverse_Depth_First -> Ok V -> Ob Vertex -> O2 Vertex_List -> Oc Vertex_Queues -> ln Vertex_Set -> lb Vertex_Stacks -> lj Vertex_Storage -> l6 Waiting_Vertices -> la