PageRenderTime 136ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/sandmark-3.4/src/sandmark/obfuscate/scalarmerger/ScalarMerger.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 459 lines | 225 code | 81 blank | 153 comment | 39 complexity | 21cbb49fd190ca5a5b94d177225cc209 MD5 | raw file
  1. package sandmark.obfuscate.scalarmerger;
  2. /**
  3. * Provides a method obfuscator that combines two int variables
  4. * into a single long, making access to either more confusing.
  5. *
  6. * @author Gregg Townsend
  7. * (<a href="mailto:gmt@cs.arizona.edu">gmt@cs.arizona.edu</a>)
  8. * @version 1.0, August 29, 2003
  9. */
  10. public class ScalarMerger extends sandmark.obfuscate.MethodObfuscator {
  11. private static boolean DEBUG = false;
  12. /**
  13. * Applies this obfuscation to a single method.
  14. */
  15. public void apply(sandmark.program.Method meth) throws Exception {
  16. if (meth.isInterface() || meth.isAbstract() || meth.isNative()) {
  17. return; // nothing to do
  18. }
  19. // Choose two local int variables (ix1 and ix2) for merging.
  20. int[] vscores = tally(meth); // tally integer accesses
  21. skipArgs(meth, vscores); // invalidate entries of incoming args
  22. int ix1 = best(vscores); // get best integer candidate
  23. int ix2 = best(vscores); // get next-best candidate
  24. if (ix1 < 0 || ix2 < 0) { // if couldn't find two candidates
  25. return;
  26. }
  27. // Allocate a new long variable and initilize it to 1,
  28. // effectively initializing the two ints to 0 and 1.
  29. // The actual value doesn't matter because the translation
  30. // of the old code will reinitialize each half separately.
  31. int lx = vscores.length; // index of new long variable
  32. org.apache.bcel.generic.InstructionList il = meth.getInstructionList();
  33. org.apache.bcel.generic.InstructionHandle ih =
  34. il.insert(new org.apache.bcel.generic.LCONST(1));
  35. il.append(ih, new org.apache.bcel.generic.LSTORE(lx));
  36. // trace actions, if enabled
  37. if (DEBUG) {
  38. System.err.println("ScalarMerger: (" + ix1 + "," + ix2 + ")->" + lx +
  39. " in " + meth.getClassName() + "." + meth.getName());
  40. }
  41. // Replace instructions that operate on the ints
  42. fixup(il, ix1, ix2, lx);
  43. // Clean up and exit.
  44. meth.setInstructionList(il);
  45. meth.setMaxLocals();
  46. meth.setMaxStack();
  47. }
  48. /**
  49. * Checks all local variable instructions in an instruction list and
  50. * tallies variable usage.
  51. * Returns an array of scores corresponding to local variables.
  52. * A positive score counts the number of integer accesses.
  53. * A negative score indicates a variable that is used for a
  54. * non-integer value.
  55. */
  56. private int[] tally(sandmark.program.Method meth) {
  57. int n = meth.getMaxLocals();
  58. int[] vscores = new int[n];
  59. org.apache.bcel.generic.Instruction[] ilist =
  60. meth.getInstructionList().getInstructions();
  61. for (int i = 0; i < ilist.length; i++) {
  62. org.apache.bcel.generic.Instruction ins = ilist[i];
  63. if (ins instanceof org.apache.bcel.generic.LocalVariableInstruction) {
  64. int v = ((org.apache.bcel.generic.LocalVariableInstruction)(ins))
  65. .getIndex();
  66. if (ins instanceof org.apache.bcel.generic.ILOAD
  67. || ins instanceof org.apache.bcel.generic.IINC
  68. || ins instanceof org.apache.bcel.generic.ISTORE) {
  69. if (vscores[v] >= 0) {
  70. vscores[v]++;
  71. }
  72. } else {
  73. vscores[v] = -1;
  74. }
  75. }
  76. }
  77. return vscores;
  78. }
  79. /**
  80. * Invalidates tally entries that correspond to method arguments.
  81. */
  82. private void skipArgs(sandmark.program.Method meth, int[] vscores) {
  83. org.apache.bcel.generic.Type[] types = meth.getArgumentTypes();
  84. int n = meth.isStatic() ? 0 : 1;
  85. for (int i = 0; i < types.length; i++) {
  86. n += types[i].getSize();
  87. }
  88. for (int i = 0; i < n; i++) {
  89. vscores[i] = -1;
  90. }
  91. }
  92. /**
  93. * Scans an array of tallies and returns the index of the most active
  94. * integer local variable after resetting that variable's score to zero.
  95. * Ties are broken in favor of lower numbered variables.
  96. * Returns -1 if there is no local variable with a positive score.
  97. */
  98. private int best(int[] vscores) {
  99. int leader = -1;
  100. int peak = 0;
  101. for (int i = 0; i < vscores.length; i++) {
  102. if (vscores[i] > peak) {
  103. leader = i;
  104. peak = vscores[i];
  105. }
  106. }
  107. if (leader >= 0) {
  108. vscores[leader] = 0;
  109. }
  110. return leader;
  111. }
  112. /**
  113. * Scans the instruction list and replaces instructions
  114. * that operate on the chosen integer locals.
  115. */
  116. private void fixup(
  117. org.apache.bcel.generic.InstructionList il, int ix1, int ix2, int lx) {
  118. org.apache.bcel.generic.InstructionHandle[] hlist =
  119. il.getInstructionHandles();
  120. for (int i = 0; i < hlist.length; i++) {
  121. org.apache.bcel.generic.InstructionHandle ih = hlist[i];
  122. org.apache.bcel.generic.Instruction ins = ih.getInstruction();
  123. if (ins instanceof org.apache.bcel.generic.LocalVariableInstruction) {
  124. int ivx =
  125. ((org.apache.bcel.generic.LocalVariableInstruction)ins)
  126. .getIndex();
  127. boolean lefthalf = (ivx == ix1);
  128. boolean righthalf = (ivx == ix2);
  129. if (lefthalf || righthalf) {
  130. if (ins instanceof org.apache.bcel.generic.ILOAD) {
  131. fixLoad(il, ih, lx, lefthalf);
  132. } else if (ins instanceof org.apache.bcel.generic.ISTORE) {
  133. fixStore(il, ih, lx, lefthalf);
  134. } else if (ins instanceof org.apache.bcel.generic.IINC) {
  135. fixIncr(il, ih, lx, lefthalf);
  136. } else {
  137. throw new java.lang.Error("non-int access to local " + ivx);
  138. }
  139. }
  140. }
  141. }
  142. }
  143. /**
  144. * Replaces an ILOAD with a load from one half of lx.
  145. * The generated sequence is as follows:
  146. * <PRE>
  147. *
  148. * left half right half comments
  149. * --------- ---------- ---------------------------------------------
  150. * LLOAD lx LLOAD lx load combined value
  151. * BIPUSH 32 push shift count
  152. * LSHR position to low 32 bits
  153. * L2I L2I convert low 32 bits to int
  154. *
  155. * </PRE>
  156. */
  157. private void fixLoad(
  158. org.apache.bcel.generic.InstructionList il,
  159. org.apache.bcel.generic.InstructionHandle ih,
  160. int lx, boolean lefthalf) {
  161. ih.setInstruction(new org.apache.bcel.generic.LLOAD(lx));
  162. if (lefthalf) {
  163. ih = il.append(ih, new org.apache.bcel.generic.BIPUSH((byte) 32));
  164. ih = il.append(ih, new org.apache.bcel.generic.LSHR());
  165. }
  166. ih = il.append(ih, new org.apache.bcel.generic.L2I());
  167. }
  168. /**
  169. * Replace an ISTORE with a store into one half of lx.
  170. * The generated sequence is as follows:
  171. * <PRE>
  172. *
  173. * left half right half comments
  174. * --------- ---------- ---------------------------------------------
  175. * I2L I2L convert the new int to a long
  176. * BIPUSH 32 push shift count
  177. * LSHL shift into position
  178. * LLOAD lx LLOAD lx load the old combined value
  179. * DUP2_X2 DUP2_X2 hide a second copy below the new value
  180. * LXOR LXOR compute bitwise difference to new value
  181. * LCONST_1 LCONST_1 load long constant 1
  182. * LNEG LNEG convert to all-ones mask
  183. * BIPUSH 32 BIPUSH 32 push shift count
  184. * LSHL !=!= LUSHR shift to make half ones, half zeroes
  185. * LAND LAND select the change bits for the correct half
  186. * LXOR LXOR change the bits in the combined value
  187. * LSTORE lx LSTORE lx store new combined value
  188. *
  189. * </PRE>
  190. */
  191. private void fixStore(
  192. org.apache.bcel.generic.InstructionList il,
  193. org.apache.bcel.generic.InstructionHandle ih,
  194. int lx, boolean lefthalf) {
  195. ih.setInstruction(new org.apache.bcel.generic.I2L());
  196. if (lefthalf) {
  197. ih = il.append(ih, new org.apache.bcel.generic.BIPUSH((byte)32));
  198. ih = il.append(ih, new org.apache.bcel.generic.LSHL());
  199. }
  200. ih = il.append(ih, new org.apache.bcel.generic.LLOAD(lx));
  201. ih = il.append(ih, new org.apache.bcel.generic.DUP2_X2());
  202. ih = il.append(ih, new org.apache.bcel.generic.LXOR());
  203. ih = il.append(ih, new org.apache.bcel.generic.LCONST(1));
  204. ih = il.append(ih, new org.apache.bcel.generic.LNEG());
  205. ih = il.append(ih, new org.apache.bcel.generic.BIPUSH((byte)32));
  206. if (lefthalf) {
  207. ih = il.append(ih, new org.apache.bcel.generic.LSHL());
  208. } else {
  209. ih = il.append(ih, new org.apache.bcel.generic.LUSHR());
  210. }
  211. ih = il.append(ih, new org.apache.bcel.generic.LAND());
  212. ih = il.append(ih, new org.apache.bcel.generic.LXOR());
  213. ih = il.append(ih, new org.apache.bcel.generic.LSTORE(lx));
  214. }
  215. /*
  216. * This fixStore code was also tested, but it is longer and less confusing:
  217. * I2L I2L convert store value to long
  218. * BIPUSH 32 BIPUSH 32 push shift count
  219. * LSHL LSHL shift int to top of long
  220. * BIPUSH 32 push shift count again
  221. * LUSHR shift back down (clears I2D sign bit extension)
  222. * LCONST_1 LCONST_1 load long constant 1
  223. * LNEG LNEG convert to all-ones mask
  224. * BIPUSH 32 BIPUSH 32 push shift count
  225. * LUSHR !=!= LSHL shift to make half ones, half zeroes
  226. * LLOAD lx LLOAD lx load old combined value
  227. * LAND LAND preserve old value of other variable
  228. * LADD LADD combine with new value for this variable
  229. * LSTORE lx LSTORE lx store combined long value
  230. */
  231. /**
  232. * Replaces an IINC with an increment of half of lx.
  233. * The generated sequence is as follows:
  234. * <PRE>
  235. *
  236. * left half right half comments
  237. * --------- ---------- ---------------------------------------------
  238. * LLOAD lx LLOAD lx load combined value
  239. * DUP2 duplicate for later use
  240. * DUP2 duplicate for later use
  241. * BIPUSH n BIPUSH n push increment value
  242. * I2L I2L convert to long
  243. * BIPUSH 32 push shift count
  244. * LSHL position increment value
  245. * LADD LADD add increment to long value
  246. * LXOR compute bitwise difference vs. old value
  247. * LCONST_1 load long constant 1
  248. * LNEG convert to all-ones mask
  249. * BIPUSH 32 push shift count
  250. * LUSHR shift to fill top half with zeroes
  251. * LAND isolate changes to lower half
  252. * LXOR apply changes to original value
  253. * LSTORE lx LSTORE lx store combined long value
  254. *
  255. * </PRE>
  256. */
  257. private void fixIncr(
  258. org.apache.bcel.generic.InstructionList il,
  259. org.apache.bcel.generic.InstructionHandle ih,
  260. int lx, boolean lefthalf) {
  261. int k =
  262. ((org.apache.bcel.generic.IINC)(ih.getInstruction())).getIncrement();
  263. ih.setInstruction(new org.apache.bcel.generic.LLOAD(lx));
  264. if (!lefthalf) {
  265. ih = il.append(ih, new org.apache.bcel.generic.DUP2());
  266. ih = il.append(ih, new org.apache.bcel.generic.DUP2());
  267. }
  268. ih = il.append(ih, new org.apache.bcel.generic.BIPUSH((byte)k));
  269. ih = il.append(ih, new org.apache.bcel.generic.I2L());
  270. if (lefthalf) {
  271. ih = il.append(ih, new org.apache.bcel.generic.BIPUSH((byte)32));
  272. ih = il.append(ih, new org.apache.bcel.generic.LSHL());
  273. }
  274. ih = il.append(ih, new org.apache.bcel.generic.LADD());
  275. if (!lefthalf) {
  276. ih = il.append(ih, new org.apache.bcel.generic.LXOR());
  277. ih = il.append(ih, new org.apache.bcel.generic.LCONST(1));
  278. ih = il.append(ih, new org.apache.bcel.generic.LNEG());
  279. ih = il.append(ih, new org.apache.bcel.generic.BIPUSH((byte)32));
  280. ih = il.append(ih, new org.apache.bcel.generic.LUSHR());
  281. ih = il.append(ih, new org.apache.bcel.generic.LAND());
  282. ih = il.append(ih, new org.apache.bcel.generic.LXOR());
  283. }
  284. ih = il.append(ih, new org.apache.bcel.generic.LSTORE(lx));
  285. }
  286. /**
  287. * Returns "Scalar Merger", the short name of this algorithm.
  288. */
  289. public java.lang.String getShortName() {
  290. return "Merge Local Integers";
  291. }
  292. /**
  293. * Returns "Scalar Merger", the long name of this algorithm.
  294. */
  295. public java.lang.String getLongName() {
  296. return "Scalar Merger";
  297. }
  298. /**
  299. * Returns an HTML description of this obfuscator's function.
  300. */
  301. public java.lang.String getAlgHTML() {
  302. return
  303. "<HTML><BODY>" +
  304. "Scalar Merger combines two int variables into a single long" +
  305. "variable, making access to either more confusing.\n" +
  306. "<TABLE>" +
  307. "<TR><TD>" +
  308. "Author: <a href =\"mailto:gmt@cs.arizona.edu\">Gregg Townsend</a> " +
  309. "</TR></TD>" +
  310. "</TABLE>" +
  311. "</BODY></HTML>";
  312. }
  313. /**
  314. * Returns the URL within the source tree
  315. * of an HTML file describing this obfuscator.
  316. */
  317. public java.lang.String getAlgURL() {
  318. return "sandmark/obfuscate/scalarmerger/doc/help.html";
  319. }
  320. /**
  321. * Returns the name of the author of this obfuscator.
  322. */
  323. public java.lang.String getAuthor() {
  324. return "Gregg Townsend";
  325. }
  326. /**
  327. * Returns the e-mail address of the author of this obfuscator.
  328. */
  329. public java.lang.String getAuthorEmail() {
  330. return "gmt@cs.arizona.edu";
  331. }
  332. /**
  333. * Returns a brief description of this obfuscator.
  334. */
  335. public java.lang.String getDescription() {
  336. return
  337. "Scalar Merger combines two int variables into a single long " +
  338. "variable, making access to either more confusing.";
  339. }
  340. /**
  341. * Returns a list of modification properties characterizing
  342. * this obfuscator.
  343. */
  344. public sandmark.config.ModificationProperty[] getMutations() {
  345. return new sandmark.config.ModificationProperty[] {
  346. sandmark.config.ModificationProperty.I_ADD_LOCAL_VARIABLES,
  347. sandmark.config.ModificationProperty.I_CHANGE_LOCAL_VARIABLES,
  348. sandmark.config.ModificationProperty.I_CHANGE_METHOD_BODIES,
  349. sandmark.config.ModificationProperty.I_ADD_METHOD_CODE,
  350. sandmark.config.ModificationProperty.I_MODIFY_METHOD_CODE,
  351. sandmark.config.ModificationProperty.I_REMOVE_METHOD_CODE,
  352. sandmark.config.ModificationProperty.PERFORMANCE_DEGRADE_MED,
  353. };
  354. }
  355. /**
  356. * Applies the obfuscation to every method in the jar file
  357. * given as the command argument.
  358. *
  359. * <P> Usage: java sandmark.obfuscate.scalarmerger.ScalarMerger file.jar
  360. *
  361. * <P> Writes: CHANGED.jar
  362. */
  363. public static void main(String[] args) throws java.lang.Exception {
  364. sandmark.program.Application app =
  365. new sandmark.program.Application(args[0]);
  366. sandmark.obfuscate.scalarmerger.ScalarMerger obfuscator =
  367. new sandmark.obfuscate.scalarmerger.ScalarMerger();
  368. java.util.Iterator itr = app.classes();
  369. while (itr.hasNext()) {
  370. sandmark.program.Class cls = (sandmark.program.Class) itr.next();
  371. sandmark.program.Method[] methods = cls.getMethods();
  372. for (int i = 0; i < methods.length; i++) {
  373. obfuscator.apply(methods[i]);
  374. }
  375. }
  376. app.save("CHANGED.jar");
  377. }
  378. } // class ScalarMerger