首页
社区
课程
招聘
[原创]梆梆官网加固免费版逆向脱壳及原理分析-2017-03-08
发表于: 2017-3-9 12:58 22575

[原创]梆梆官网加固免费版逆向脱壳及原理分析-2017-03-08

2017-3-9 12:58
22575

分析使用的手机系统android4.4.4 dalvik,其它4.1-4.3,2.2,2.3的流程肯定是不一样的

本人菜鸟一枚,刚刚接触android逆向不久,对逆向不是很了解,但对加固稍微有一点点了解,研究了下梆梆的加固包,发现其加固包目录下存在个加密的secData0.jar,现在市场上,加固厂商采用的加固方式一般是启动代理dex,然后通过DexClassLoader动态加载jardex的方式,将要保护的类加载到内存中去,但这种方式只能传参文件的路径,无法传参内存地址,不知道梆梆是怎么做到的,猜想是hook方式。本人也用过hook,但是兼容性和稳定性不太理想。接下来开始逆向分析,第一次发帖,写的有点乱,有些的不对的地方望大神指正。

1、  先将代理dex拖到jeb中看看其大致流程,代理dex是各大厂商普遍采用的,手动new要保护的Application类,调用native方法attach,将new出来的Application设置到应用程序上下文context中,系统调用代理类的onCreate时,再在其中调用手动newApplicationonCreate方法,至此,代理dex完成了启动目标dex

SecAppWrapper中,有一静态变量 realApplication,attachBaseContext函数中通过,根据,Helper.APPNAME,手动加载并实例化一个对象,Helper.APPNAMEnull,应该是在so中通过反射赋值的,在调用attachBaseContext函数的时候,this.getClassLoader中已经关联到了要保护的dex,所以在此之前,一定做了解密dex,加载dex,并设置loader的操作。比Application更早提前执行的就是类的静态块代码,再看看静态块代码,只是加载了libSecShell.so,加载so的流程大致说下,java层通过System.loadLibrary函数,调用到c层的dvmLoadNativeCode->dlopen,dlopenso加载到内存中后,会调用so中的initinit_array,接下来dvmLoadNativeCode会通过dlsym查找到so中的JNI_OnLoad函数,如果存在去执行。所以基本上可以确定梆梆对dex的解密、加载操作就是在so的这三个地方。

2、  将梆梆加固用到的libSecShell.so,拖到ida里,先静态,大致能不能看出点什么东西来,还好ida能打开,看看initfinitJNI_OnLoad,没找的initfinit也为空,判断所以操作在JNI_OnLoad中进行。

 

 

 

 

 

 

3JNI_Onload分析

看看流程图,这流程服了,一般程序不会这么写的,肯定是llvm混淆过的,刚开始看确实头疼,不过慢慢看还是可以分析的,以下是我的分析过程

 

 

r3=15

if(r3==52){

         Jni_Onload退出

}else if(r3>52){

         无效分支

}else{ //r3<52

         进入switch{

          case 15: GetEnv

          case 28:

sub_CF10dlsym 查找符号(mmprotectmmap unmmap)放到全局变量中,com/secshell/shellwrapper/Helper

                   解密字符串“Ljava/lang/String; PKGNAME

                   env-> env->GetStaticFieldID(clazz, "PKGNAME", "Ljava/lang/String;"));

                   获取PKGNAME = "com.example.test8"

          case 29:

                  动态解密解密用到的字符串

 

          case 7 :

                   新建.cache目录,sub_D570:data/data/com.example.test8/.cache/classes.dve 24个字节,不知道有什么用。

找到/data/dalvik-cache/data@app@com.example.test8-1.apk@classes.dex = dexPtr,字符串

                            open(dexPtr)

                           

case 32:主要的逻辑包括加载jar,解密jar,从jar中释放dex,反射调用installhook函数,反调试函数等等。          

{

         jclass jc = findClass("com/secshell/shellwrapper/Helper");

env->RegisterNatives(jc,{"attach"," (Landroid/app/Application;Landroid/content/Context;)V }”);

                  

p6325BD8519FF3EAD9668F36987CD0110()//4.4.4dalvik手机上没用到

{   dlopen(libdvm.so,0)

dlsym(_Z22dvmRawDexFileOpenArray),sym1=dlsym(dvmRawDexFileOpen),         

p4B2441F65675A731D2FEFF5CC2166CE2(findClass(dalvik/system/DexFile);env->getMethodId("<init>","(Ljava/lang/String;)V")

}       

pB35C255E59C8408F082D5490EB26F32C()

{

         dlopen(libc.so)

    p845C09B79D87F284CE0F33FBC24DD952()

{

进行inline hook函数,hook了好多libc.so中的函数

包括readwrite close munmap msync

 __openat pread64 __mmap2

}

}

pC0E901BB7A6D1B669B72D78E6861439F(/data/com.example.test8/.cache/classes.dex)

{

判断file指向内存前三个字节是否为“dexordey

         }       

 

pFBF8EA28AB5406DC5CFADBC7CE32467F()//读取so最后几个字节,存储起来

{

         fopen( /data/data/com.example.test8/lib/libSecShell.so);

fseek(fd,-8,SEEK_END);

fread(buf,1,8,fd);

fseek(fd,-10,SEEK_END);

fclose(fd)

}

 

 

 

 

pD87C3778018C8497DE25DC3140A39FA6()

//打开/data/app/com.example.test8-1.app/从中取出secData0.jar

{

         p64068FFF75D5FF726D395AD2CF88C6F7()

{

                   fd = open("/data/app/com.example.test8-1.app",0x0,0x0);

}

p5A0228D84B11FF138D5616E546386E2A()

{

         strlen("assets/secData0.jar")

         return 0x00002722

}

p8D083BC566F0CE8A42363E0F1CBA1CD9()

         pDB44B5F00E6156543E0CAE1D01C88736()

{

                   apk中抽取加密的secData0.jar到内存中

}

p34D946B85C4E13BE6E95110517F61C41(addr,len) //在这个函数中下断可以dump jar

{

解密SecData0.jar

                  sub_195FC(0,addr,len)//解密算法所在的函数***************************

{

p3CBBD6F30D91F38FCD0A378BE7E54877()

{

         malloc分配内存地址存放到p5E7BF0B62C098453447B32884992D488

p5E7BF0B62C098453447B32884992D488è存放明文dex地址

         pDB44B5F00E6156543E0CAE1D01C88736()//在这个函数中下断可以dump dex

{从解密的jar中释放dex文件到p5E7BF0B62C098453447B32884992D488

                           inflateInit2_();

                           inflate();

                           write(fd,buf,size);//writehook,写到.cache上的为加密dex

                           inflateEnd();}   

}

         unk_D268()

         {        jni

                   NewStringUTF(/data/data/com.example.test8/.cache/classes.jar);

                   NewStringUTF(/data/data/com.example.test8/.cache/classes.dex);

                  FindClass(com/secshell/shellwrapper/DexInstall);

                   FindClass(java/lang/Class);

                   GetMethodID(0x1D400071,"getClassLoader","()Ljava/lang/ClassLoader;");

                   CallObjectMethod(DexInstall, getClassLoad_ID);

                   GetStaticMethodID(DexInstall,"install",

                            "(Ljava/lang/ClassLoader;Ljava/lang/String;)V");

                   CallStaticVoidMethod(DexInstall, install_ID, loader, dexPath);

                   Java层:

makeDexElements-> openDexFileNative->dvmRawDexFileOpen(dex,dex)

梆梆hookdvmRawDexFileOpen函数,会调用到

                   pB7F20650D654BF17487B377A15C6F5FF

                   pB7F20650D654BF17487B377A15C6F5FF()构建RawDexFile->cookie返回java

{

         case 7

                   0xBEEAE44C = “/sclass.dex”

                   strcmp(/sclass.dex,/data/data/com.example.test8/.cache/classes.dex);

         case 10:

                    strstr(/data/data/com.example.test8/.cache/classes.dex,

./cache/classes.dex)

         case 9:

         case 4:

                   dvmRawDexFileOpenArray(明文dexlen

RawDexFile** ppRawDexFile/*0xBEEAE48C*/)

         case 1:

         case 8:

}

}                

 

至此完成了加密jar的解密,释放dex,加载dex,设置loader,然后在代理壳的onCreate调用realApplication.onCreate,应用程序就运行起来了。

        

                            ///////////////////////////////////////////////////////////////////

p071ADBC73D8008F1BE158FD0441DC741(//创建线程(kill -9))

{

         case 8:

                   access("/data/app/com.example.test8-1.app");

         case 9:

                   malloc 存储字符串"/data/app/com.example.test8-1.app"

         case 0:

         case 10:

         0x0003148C pthread_thread_create p2CDCBA17913F0B54DE1DBA053AFBD7EB(kill -9));

}                

p7E7056598F77DFCC42AE68DF7F0151CA*************** 反调试

{

         case 5

                   prtcl(PR_SET_DUMPABLE,1,0,0,0);

                   getpid()

         case 3:

         case 6:

         case 11:

                   pipe(sp+0x58);

         case 8:

                   pid = fork();

                   if(pid >0)

                            r3=9;

                   else

                            r3=4;

         case 9://父进程

                   设置管道为写端

         case 9->case 10:

                   write(fd,1,);

         case 4

                   p845C09B79D87F284CE0F33FBC24DD952(libc.so,ptrace){

                   }

                   调用反调试函数,附加父进程,调用扫描函数

                   anti_thread_of_process_debug

p78D3797A85ACABF62A884C5574655B5A//启动线程 pEB4046F8D020AD7E1F60BA0D1D8F989B

                   r3=1;

         case 1:

                   read(fd,buf,1) = '';

                   r3=5;

         case 5:

                   栈检查

         case 38

}

                   p794BC17E009571800343687071A57359 //不清楚功能

                            ///////////////////////////////////////////////////////////////////         

          case 38:

          case 43:打开/data/app/com.example.test8-1.apk

                     fgets读取 /proc/pid/status

                     打开/data/data/com.example.test8/lib/libSecShell.so

                     打开/data/app/com.example.test8-1.apk

         }

}

 

总结,梆梆官网免费版加固大致的流程就是这样的,还是使用的内存加载的方式,语言组织能力太差,写的太粗糙,哪里有分析错误的地方,还请大神来指正,共同进步,不过还有两点没有搞明白

1)  为什么反调试线程会在,jar全部解密加载完成后再启动????????奇了怪

2)  上面完成之后,梆梆还调用了好多函数,比如forkfork,两次fork之后然后在

子进程中调用:

fork_execute_dex2opt –>execute_dex2opt-> dvmPrepForDexOpt-> getenv->

->dvmContinueOptimization不知道这个流程有什么用???



[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 1
支持
分享
最新回复 (7)
雪    币: 2748
活跃值: (3734)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
没有搞明白的两点,希望有大牛能补上.
2017-3-9 13:09
0
雪    币: 1037
活跃值: (1775)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
楼主图片是不是挂了,上传的图是白框
2017-3-9 14:08
0
雪    币: 93
活跃值: (136)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
图片挂了,看不见
2017-3-9 14:18
0
雪    币: 9479
活跃值: (757)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
看不到图片,铁通的宽带
2017-3-9 14:30
0
雪    币: 43
活跃值: (170)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
gugubupt 图片挂了,看不见
附件中有个word可以,尽做参考,写的太矬
2017-3-9 16:08
0
雪    币: 18
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
可以啊
2017-3-9 18:35
0
雪    币: 208
活跃值: (258)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
赞一个。写的不错
2017-3-10 09:11
0
游客
登录 | 注册 方可回帖
返回
//