Java字节码文件保护方法之字节码加密实现(方法及伪码)

1.使用程序对.class文件进行加密,之后使用jvm hook对加载的.class文件进行解密然后完成类加载的工作
2.注意事项
由于java解密代码调用非常的频繁 所以一定要注意申请的资源要及时释放 否则会导致内存泄漏以至程序崩溃
目前该程序只适用于java 1.6 java1.5实现未作测试 java1.7不能使用 由于底层实现有变java1.7的兼容性开发还未做
3.程序解释

1)加密程序
    可采用对称加密如需要可以再修改成其它加密算法 并对加密的文件做上加密标记

2)
    1>.Java agent程序 java虚拟机在运行是使用-agentpath或-agentlib参数加载该dll 如
       java -agentpath:C:\temp\xxxagent.dll=C:\temp\key.dat HelloWorld
       其中的HelloWorld.class为已经加密过的类 当然如果这个类未加密也可以正常运行 xxxagent.dll会识别哪些类加密了
       
    2>.该dll向jvm注册了一些本地的方法最重要的一个是defineClass1
    
    3>.注册之后在做了解密处理之后还要调用jvm本身的函数defineClass1(这个函数位于java.dll中)
    
    4>.此程序设计时一定要注意性能
    
    5>.与还可以利用类似的方法对jvm的性能做一个统计及优化等工作
    
3)xxxagent.dll开发的关键外在于取得相关的函数定义及签名等信息
取得函数名方法如下:
    1>. 可以通过ClassLoader.java ClassLoader.c取得相关的方法

    2>. 可以使用dumpbin.exe取得方法在java.dll中的导出名
        dumpbin.exe /EXPORTS java.dll
    
    3>. 通过javap -s -private ClassLoader取得相关类的签名信息

    4>. 由于java语言及其实现是开源的所以可以取得相关的源代码 这样更易开发
    
    

伪代码如下:

1.注册虚拟机初始化结束事件 JVM_EVENT_VM_INIT
JNIEXPORT jint JNICALL Agent_OnLoad( JavaVM *jvm, char *options, void *reserved )
{

    printf( "starting agent ......\n" );

    error = gb_jvmti->SetEventNotificationMode(JVMTI_ENABLE,JVMTI_EVENT_VM_INIT, (jthread)NULL);

    return JNI_OK;

}

typedef jclass(JNICALL  *lpDefineClass1_32)
(
    JNIEnv *env,
    jobject loader,
    jstring name,
    jbyteArray b,
    jint off,
    jint len,
    jobject pd,
    jstring source,
    jboolean bVerify
 );
//用于指向java.dll中的 _Java_java_lang_ClassLoader_defineClass1@36
//32位的函数指针
//64位的和这个不同
//可通过ClassLoader.java ClassLoader.c 及使用dumpbin.exe /EXPORTS java.dll查看即可得知参数及函数名
2. 响应虚拟机初始化结束事件 并注册要hook的函数 及取得要调用的函数指针
static void JNICALL jvmInitFinish( jvmtiEnv *jvmti_env, JNIEnv* env, jthread thr )
{
    printf( "jvm Init finish ......\n" );

    int iLen = env->RegisterNatives( jcls, jni_methes1_6, iLen );

    HMOUDLE hJavaDll = LoadLibrary( "java.dll" );

    funcDefineClass1_32 = (lpDefineClass1_32)(GetProcAddress(hJavaDll, "_Java_java_lang_ClassLoader_defineClass1@36" ));

    funcDefineClass2_32 = (lpDefineClass2_32)(GetProcAddress(hJavaDll, "_Java_java_lang_ClassLoader_defineClass2@36" ));

}

注意其中的函数指针要定义正确 可以ClassLoader中得到正常的定义

3. 要hook的函数
   
JNIEXPORT jclass JNICALL
comdev_defineClass1_6(
                      JNIEnv *env,
                      jobject loader,
                      jstring name,
                      jbyteArray data,
                      jint offset,
                      jint length,
                      jobject pd,
                      jstring source,
                      jboolean verify
                      )
{
    
    if( !strncmp( (const char*)LABEL, (const char*)originByte, strlen((const char*)LABEL)) )
    {    //如果是已加密的类则执行解密操作
        lPlainText = DES_DecryptByteArray( pCipher, pCharKey, LABEL, pPlainText, iCipherLen );
    }

    if( pPlainText )
    {
        cls = funcDefineClass1_32( env, loader, name, pByteArr, offset, lPlainText, pd, source, verify );
    }
    else
    {    //如果是非加密类则直接执行java.dll中的原函数
        cls = funcDefineClass1_32( env, loader, name, data, offset, length, pd, source, verify );
    }
    return cls;
}

fzq整理所得 欢迎转载
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值