|
JAVALINE
|
Control flow flattening | Control flow flattening is the obfuscation technique that "... splits all the source code's basic blocks - such as the function body, loops, and conditional branches - and puts them all inside a single infinite loop with a switch statement..." with hidden dispatcher of switching values. This makes the reverse engineering of a programs considerably harder because the original natural control flow is now broken and the switching procedure is obscured. The following image demonstrates the control flow graphs before and after this transformation ( see Control-Flow Flattening) |
HOW IT WORKS |
1. FLATCODE JOB uses several obfuscation techniques including control flow flattening and byte code modification with further code reconstruction using java instrumentation.
2. During obfuscation FLATCODE
JOB
flattens the control flow of the application's
methods, rearranges
their basic blocks, creates
the values of switching variables according to the
original code, and encrypts them. 3. After flattening, byte codes of java classes are further modified 4. It attaches a Dll file to the obfuscated program for decryption of the switching variables at run time. |
RUNNING APPLICATION | 1. At run time, the Dll file attached to the application reconstructs the modifications made in byte codes of java classes and decrypts the switching variables |
Example of obfuscation by FlatcodeJOB Original method |
synchronized public void insertTrain() { if(totalTrains <ctsp.NUM_OF_TRAINS) { int rndDir=ctsp.DIRECTION; int sYpos=0; switch(rndDir) { case 0: sYpos=137; break; case 1: sYpos=427; break; } if(countTrains == 4){ CTSTrain train = new CTSTrain("images/expTr.gif",'x',rndDir, trains.size(), this,stations,50, sYpos); trains.add(train); map[0][0][0] = train; countTrains = 0; } else { CTSTrain train = new CTSTrain("images/T"+(rnd.nextInt(6)+1)+".gif",'n',rndDir, trains.size(), this,stations,50, sYpos); trains.add(train); map[0][0][0] = train; countTrains++; } trIns=false; totalTrains++; } } |
Decompiler Prycon Decompiler cavaj |
public synchronized void cYd() { int n = 1; int n2 = 1; long n3 = 0; int vnV_ = HHU.VnV_; while (true) { switch (vnV_ = array[vnV_ + n3]) { case 0: { this.usv = false; ++this.PHO; } case 9: { n3 = lcmp((long)n, (long)1); ++n3; continue; } case 1: { n2 = 137; n3 = 1; continue; } case 3: { n2 = 427; n3 = 1; continue; } case 5: { n3 = lcmp((long)this.Bxl,(long)4); ++n3; continue; } case 13: { n3 = lcmp((long)this.Bxl, (long)4); ++n3; continue; } case 2: { final rjt e = new rjt(CB.due("1=EQ5ZUbTgAIniwHK0FyTpMeHsZbWMwAtT"),'x', n,this.ANX.size(), this, this.EJW, 50, n2); this.ANX.add(e); this.Gze[0][0][0]=e; this.Bxl = 0; } case 16: { this.usv = false; ++this.PHO; n3 = 1; continue; } case 11: { n2 = 137; n3 = 1; continue; } case 4: { final rjt e2 = new rjt(CB.due("1=onc31x3vp73*ROC8ChLvJg==") + (this.Igf.nextInt(6) +1) + CB.due("1=appyDOXfu*0="), 'n', n, this.ANX.size(), this, this.EJW, 50, n2); this.ANX.add(e2); this.Gze[0][0][0]= e2; ++this.Bxl; } case 12: { n2 = 427; n3 = 1; continue; } case 14: { final rjt e3 = new rjt(CB.due("1=EQ5ZUbTgAIniwHK0FyTpMeHsZbWMwAtT"), 'x', n, this.ANX.size(), this, this.EJW, 50, n2); this.ANX.add(e3); this.Gze[0][0][0]=e3; this.Bxl = 0; n3 = 1; continue; } case 6: { long n4 = lcmp((long)n, (long)1); ++n4; } case 15: { final rjt e4 = new rjt(CB.due("1=onc31x3vp73*ROC8ChLvJg==") + (this.Igf.nextInt(6) + 1) + CB.due("1=appyDOXfu*0="), 'n', n, this.ANX.size(), this, this.EJW, 50, n2); this.ANX.add(e4); this.Gze[0][0][0]=e4; ++this.Bxl; n3 = 1; continue; } default: { } case 10: { n3 = 1; continue; } case 8: { final ANX ryA = this.ryA; final int fIr = ANX.fIr; n2 = 0; n = fIr; n3 = lcmp((long)n, (long)0); ++n3; continue; } case 7: { final int pho = this.PHO; final ANX ryA2 = this.ryA; n3 = lcmp((long)pho, (long)ANX.Jmb); ++n3; continue; } } }
public synchronized void cYd() { int i; char c; int j; int k; int ai[]; false; i = 1; c = '\001'; Object obj = null; boolean flag = false; j = 0; k = VnV_; long l = 0L; ai = _VnV_.array(); _L20: k = ai[k +j]; JVM INSTR tableswitch 0 17: default 614 // 0 368 // 1 146 // 2 156 // 3 218 // 4 228 // 5 330 // 6 350 // 7 652 // 8 621 // 9 128 // 10 615 // 11 430 // 12 440 // 13 389 // 14 450 // 15 512 // 16 409 // 17 614; goto _L1 _L2 _L3 _L4 _L5 _L6 _L7 _L8 _L9 _L10 _L11 _L12 _L13 _L14 _L15 _L16 _L17 _L18 _L1 _L11: long l1 = 1; j =(long)i != l1; j++; continue; /* Loop/switch isn't completed */ _L3: c = '\211'; j = 1; continue; /* Loop/switch isn't completed*/ _L4: rjt rjt1 = new rjt(CB.due("1=EQ5ZUbTgAIniwHK0FyTpMeHsZbWMwAtT"), 'x', i, ANX.size(), this, EJW, 50, c); ANX.add(rjt1); Gze[0][0][0] = rjt1; Bxl =0; j = 1; goto _L18 _L5: c = '\u01AB'; j = 1; continue; /*Loop/switch isn't completed */ _L6: rjt rjt2 = new rjt((new StringBuilder()) .append(CB.due("1=onc31x3vp73*ROC8ChLvJg==")) .append(Igf.nextInt(6)+ 1) .append(CB.due("1=appyDOXfu*0=")).toString(), 'n', i, ANX.size(), this, EJW, 50, c); ANX.add(rjt2); Gze[0][0][0] = rjt2; Bxl++; goto _L14 _L7: long l2 = 4; j = (long)Bxl != l2; j++; continue; /* Loop/switch isn't completed */ _L8: long l3 = 1; j = (long)i != l3; j++; goto _L17 _L2: usv = false; PHO++; j = 1; goto _L11 _L15: long l4 = 4; j = (long)Bxl != l4; j++; continue;/* Loop/switch isn't completed */ _L18: usv = false; PHO++; j = 1; continue; /* Loop/switch isn't completed */ _L13: c = '\211'; j =1; continue; /* Loop/switch isn't completed */ _L14: c = '\u01AB'; j = 1; continue; /* Loop/switch isn't completed */ _L16: rjt rjt3 = new rjt(CB.due("1=EQ5ZUbTgAIniwHK0FyTpMeHsZbWMwAtT"), 'x', i,ANX.size(), this, EJW, 50, c); ANX.add(rjt3); Gze[0][0][0] = rjt3; Bxl = 0; j = 1; continue; /* Loop/switch isn't completed */ _L17: rjt rjt4 = new rjt((new StringBuilder()) .append(CB.due("1=onc31x3vp73*ROC8ChLvJg==")) .append(Igf.nextInt(6) + 1) .append(CB.due("1=appyDOXfu*0=")).toString(), 'n', i, ANX.size(), this, EJW, 50, c); ANX.add(rjt4); Gze[0][0][0] = rjt4; Bxl++; j = 1; continue; /* Loop/switch isn't completed */ _L1: return; _L12: j = 1; continue; /* Loop/switch isn't completed */ _L10: ryA; i = ANX.fIr; c = '\0'; i = i; long l5 = 0; j = (long)i != l5; j++; continue; /* Loop/switch isn't completed */ _L9: ryA; long l6 = ANX.Jmb; j = (long)PHO != l6; j++; if(true) goto _L20; else goto _L19 _L19: }