cornercorner
FeaturesPluginsDocs & SupportCommunityPartners

DevFaqModuleObfuscation

Can I obfuscate a module?

If you want to protect a NetBeans module from disassembly, you can obfuscate it. For example you can use ProGuard, an open-source obfuscator.

  1. Copy proguard.jar somewhere on disk, referenced by proguard.jar.path.
  2. Edit the build.xml of your module and override some targets as in the following excerpt:
<!-- Replace the non-obfuscated jar with the obfuscated one when compiling -->
<target name="netbeans-extra" depends="obfuscate">
    <copy file="${suite.dir}/build/obfuscated/${module.jar}" tofile="${cluster}/${module.jar}"/>
</target>

<!-- Overridden debug target that depends on netbeans-debug -->
<target name="debug" depends="netbeans-debug,-jdk-presetdef-nbjpdastart">
    <ant antfile="${harness.dir}/run.xml" target="debug"/>
</target>

<!-- netbeans-debug DOES NOT depends on netbeans-extra (then DOES NOT depends on obfuscate) -->
<target name="netbeans-debug"
        depends="init,jar,module-xml-regular,module-xml-autoload,module-xml-eager,javahelp,module-auto-deps,release,verify-class-linkage">
    <genlist outputfiledir="${cluster}" module="${module.jar}">
        <fileset dir="${cluster}">
            <patternset refid="module.files"/>
        </fileset>
    </genlist>
</target>

<!-- Overridden to delete also the obfuscated jar -->
<target name="clean" depends="files-init,testuserdir-delete">
    <delete failonerror="false" includeemptydirs="true">
        <fileset dir="build">
            <exclude name="testuserdir/"/>
        </fileset>
    </delete>
    <delete dir="${netbeans.javadoc.dir}/${code.name.base.dashes}"/>
    <delete file="${netbeans.javadoc.dir}/${code.name.base.dashes}.zip"/>
    <delete failonerror="false"> <!-- #59457: OK if cluster does not exist currently -->
        <fileset dir="${cluster}">
            <patternset refid="module.files"/>
        </fileset>
    </delete>
    <delete file="${cluster}/update_tracking/${code.name.base.dashes}.xml"/>
    <delete file="${suite.dir}/build/obfuscated/${module.jar}"/>
</target>

<!--  Just a cut and paste of how the proguard obfuscator works.
      This is not supposed to work below.  In fact, this seems to work
      on jars, not .class files, so it will have to be placed in a
      post jar target, which I haven't identified yet -->
<target name="obfuscate" depends="init">
    <taskdef resource="proguard/ant/task.properties"
             classpath="${proguard.jar.path}" />

    <echo message="Obfuscating ${cluster}/${module.jar}..."/>
    <mkdir dir="${suite.dir}/build/obfuscated"/>
    <proguard printmapping="${suite.dir}/build/obfuscated/${code.name.base.dashes}.map"
              renamesourcefileattribute="SourceFile" ignorewarnings="true">

        <!-- Specify the input jars, output jars, and library jars. -->
        <injar  file="${cluster}/${module.jar}" />
        <outjar file="${suite.dir}/build/obfuscated/${module.jar}" />

        <libraryjar path="${module.run.classpath}" />
        <libraryjar file="${nbjdk.home}/jre/lib/rt.jar" />

        <!-- Keep some useful attributes. -->

        <keepattribute name="InnerClasses" />
        <keepattribute name="SourceFile" />
        <keepattribute name="LineNumberTable" />
        <keepattribute name="Deprecated" />
        <keepattribute name="*Annotation*" />
        <keepattribute name="Signature" />

        <!-- Preserve all public classes, and their public and protected fields and methods. -->

        <keep access="public">
            <field  access="public protected" />
            <method access="public protected" />
        </keep>


        <!-- Preserve all .class method names. -->

        <keepclassmembernames access="public">
            <method type      ="java.lang.Class"
                    name      ="class$"
                    parameters="java.lang.String" />
            <method type      ="java.lang.Class"
                    name      ="class$"
                    parameters="java.lang.String,boolean" />
        </keepclassmembernames>

        <!-- Preserve all native method names and the names of their classes. -->

        <keepclasseswithmembernames>
            <method access="native" />
        </keepclasseswithmembernames>

        <!-- Preserve the methods that are required in all enumeration classes. -->

        <keepclassmembers extends="java.lang.Enum">
            <method access="public static"
                    type="**[]"
                    name="values"
                    parameters="" />
            <method access="public static"
                    type="**"
                    name="valueOf"
                    parameters="java.lang.String" />
        </keepclassmembers>

        <!-- Explicitly preserve all serialization members. The Serializable
             interface is only a marker interface, so it wouldn't save them.
             You can comment this out if your library doesn't use serialization.
             With this code serializable classes will be backward compatible -->

        <keepnames implements="java.io.Serializable"/>
        <keepclassmembers implements="java.io.Serializable">
            <field  access    ="final"
                    type      ="long"
                    name      ="serialVersionUID" />
            <field  access    ="!static !transient"
                    name      ="**"/>
            <field  access    ="!private"
                    name      ="**"/>
            <method access    ="!private"
                    name      ="**"/>
            <method access    ="private"
                    type      ="void"
                    name      ="writeObject"
                    parameters="java.io.ObjectOutputStream" />
            <method access    ="private"
                    type      ="void"
                    name      ="readObject"
                    parameters="java.io.ObjectOutputStream" />
            <method type      ="java.lang.Object"
                    name      ="writeReplace"
                    parameters="" />
            <method type      ="java.lang.Object"
                    name      ="readResolve"
                    parameters="" />
        </keepclassmembers>

        <!-- Your application may contain more items that need to be preserved;
             typically classes that are dynamically created using Class.forName -->

    </proguard>
</target>

In this way when running and when creating the NBM (as well from a suite) the module will be obfuscated. When debugging your module you use the non-obfuscated JAR, so you can step through source as well.


Applies to: ??? (unverified)