欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]百度加固逆向分析

[原创]百度加固逆向分析

    最近一直在研究百度壳,发现网上这方面的资料非常少。所以我把自己做的发出来跟大家分享,共同学习进步。

下面开始:

一、init_array 

我们发现init_array中存在多个函数地址,JNI_Onload为加密状态

动态调试在init_array上下断跟着进入一个大循环。发现他在此处对so进行了抹头操作。

之后遇到反调试崩溃退出。后来发现反调试检测了以下字段:

android_server

gdbserver

gdb

TracePid:

/proc/self/task/%s/status

isDebuggerConnected等。。

二、bypass

编写了一个loader程序调用该so中的JNI_Onload函数bypass壳代码和反调试。

#include <stdio.h>

#include <string.h>

#include <dlfcn.h>

#include <jni.h>

int main()

{

	JavaVM* vm;

	JNIEnv* env;

	jint res;

	JavaVMInitArgs vm_args;

	JavaVMOption options[1];

	options[0].optionString = "-Djava.class.path=.";

	vm_args.version=0x00010002;

	vm_args.options=options;

	vm_args.nOptions =1;

	vm_args.ignoreUnrecognized=JNI_TRUE;

	printf("[+] dlopen libdvm.so\n");

	void *handle = dlopen("/system/lib/libdvm.so", RTLD_LAZY);//RTLD_LAZY RTLD_NOW

	if(!handle){

	printf("[-] dlopen libdvm.so failed!!\n");

	return 0;

	}

	//这里我先创建一个java虚拟机。因为JNI_ONload函数参数第一个参数为JavaVM。

	typedef int (*JNI_CreateJavaVM_Type)(JavaVM**, JNIEnv**, void*);

	JNI_CreateJavaVM_Type JNI_CreateJavaVM_Func = (JNI_CreateJavaVM_Type)dlsym(handle, "JNI_CreateJavaVM");

	if(!JNI_CreateJavaVM_Func){

	printf("[-] dlsym failed\n");

	return 0;

	}

	res=JNI_CreateJavaVM_Func(&vm,&env,&vm_args)

	void* si=dlopen("/data/local/tmp/libbaiduprotect.so",RTLD_LAZY);

	if(si == NULL){

	printf("[-] dlopen err!\n");

	return 0;

	}

	typedef jint (*FUN)(JavaVM* vm,void* res);

	FUN func_onload=(FUN)dlsym(si,"JNI_OnLoad");

	if(func_onload==NULL)//我将断点下在了这里可以正好获取到JNI_Onload的函数地址。

		return 0;

	func_onload(vm,NULL);

	return 0;

}

此时R0为dlsym返回的JNI_Onload地址.我们跳转过去,按C将字节码转成代码,发现此时JNI_Onload已经解密。

这时候我们将so从内存中dump出来。将原来的so头部和section修复回去。代码的解密已经完成。

3、字符串解密

这时候我们发现so的字符串还是加密状态,每个字符串对应一个解密函数。

经过分析发现。解密算法是一样的,只是异或的偏移地址不一样。

_BYTE *__fastcall sub_17A28(_BYTE *a1)

{

  _BYTE *v1; // r4@1

  int v2; // r0@1

  int v3; // r1@2

  unsigned int v4; // r5@3

  int v5; // r3@3

  int v6; // r7@3

  _BYTE *v7; // r4@4

  int v8; // r6@4

  _BYTE *v9; // r5@4

  unsigned int v10; // r2@5

  signed int v11; // r0@5

  unsigned int v12; // r1@7

  int v13; // r3@7

  int v14; // r7@7

  int v15; // r0@9

  int v16; // r2@9

  _BYTE *v18; // [sp+4h] [bp-1Ch]@3

  v1 = a1;

  v2 = (int)(a1 - 1);

  do

    v3 = *(_BYTE *)(v2++ + 1);

  while ( v3 );

  v4 = (unsigned int)(v2 - (_DWORD)v1) >> 1;

  v18 = j_j_malloc(v4 + 1);

  v5 = 0;

  v18[v4] = 0;

  v6 = *v1;

  if ( *v1 )

  {

    v7 = v1 + 2;

    v8 = 0;

    v9 = v18;

    do

    {

      v10 = v7[~v5];

      v11 = 208;

      if ( v10 >= 0x3A )

        v11 = 201;

      v12 = (unsigned __int8)v6;

      v13 = 16 * v6;

      v14 = 16 * v6 + 144;

      if ( v12 >= 0x3A )

        v13 = v14;

      v15 = v13 + v11 + v10;

      v5 = 0;

      v16 = 0;

      if ( v8 != 8 )

        v16 = v8;

      *v9 = byte_5FB25[v16] ^ v15;//此处byte数组值不同。

      v8 = v16 + 1;

      ++v9;

      v6 = *v7;

      v7 += 2;

    }

    while ( v6 );

  }

  return v18;

}

分析完解密算法后,写了个ida py解密脚本。由于初次写ida脚本。借鉴了一些网上的代码。写的很糟糕。

import re

def getDispatchAddress(ea):

    ea =  FindText(ea, SEARCH_DOWN |SEARCH_NEXT | SEARCH_REGEX,0, 0,"BL      sub")

   

    #Message("Find in %x\n" % ea)

    if ea == BADADDR:

        #Message("Cann't find the Dispatch address")

        address = BADADDR

    else:

        address = GetOperandValue(ea,0)

        #Message("Dispatch address is %x\n" % address)

    return address

def getFunctionInstructions(addr):

    Instructions = []

    DispatchBeginAddress = getDispatchAddress(addr)

    if DispatchBeginAddress == BADADDR:

       Message("Cann't find the Function Instructions List")

       return None

    DispatchEndAddress = GetFunctionAttr(DispatchBeginAddress,FUNCATTR_END)

    i =  DispatchBeginAddress

    while True:

      #Instructions.append(GetDisasm(i))

      Instructions.append(i)

      tmp = i + ItemSize(i)

      if tmp < DispatchEndAddress:

         i = i + ItemSize(i)

      else:

         break

    address = i

    return Instructions

def getaddr(addr):

    for x in XrefsTo(addr,flags = 0):

        #print hex(x.frm)

        num=0

        got=0

        for i in getFunctionInstructions(x.frm):

            mnem = GetMnem(i)

            if "LDR" in mnem :

                if num == 5:

                    #print hex(i)

                    op  =  GetOperandValue(i,1)

                    b3=Byte(op+3)<<24

                    b2=Byte(op+2)<<16

                    b1=Byte(op+1)<<8

                    b0=Byte(op+0)

                    got=b0+b1+b2+b3+(i+6)

                if num == 6:

                    #print hex(i)

                    op  =  GetOperandValue(i,1)

                    b3=Byte(op+3)<<24

                    b2=Byte(op+2)<<16

                    b1=Byte(op+1)<<8

                    b0=Byte(op+0)

                    tmp=b0+b1+b2+b3

                    off=got+tmp

                    #print hex(off&0xffffffff)

                    return off&0xffffffff

                    break

                num=num+1

        break      

def decrypt1(addr,str):

    len1=len(str)>>1

    out=''

    for i in range(0,len1):

        v1=208

        v2=16*ord(str[2*i])

        if ord(str[2*i+1])>=0x3a:

            v1=201

        if ord(str[2*i])>=0x3a:

            v2=16*ord(str[2*i])+144

        v3=(v1+v2+ord(str[2*i+1]))&0xff

        out=out+chr(Byte(addr+i%8)^v3)

    print out

def decrypt(addr1,str):#这里就是主要的解密

    addr=getaddr(addr1)

    if addr == None:

        return ''

    len1=len(str)>>1

    out=''

    for i in range(0,len1):

        v1=208

        v2=16*ord(str[2*i])

        if ord(str[2*i+1])>=0x3a:

            v1=201

        if ord(str[2*i])>=0x3a:

            v2=16*ord(str[2*i])+144

        v3=(v1+v2+ord(str[2*i+1]))&0xff

        out=out+chr(Byte(addr+i%8)^v3)

    print out

    #print hex(addr1)

    MakeComm(addr1,out)

    for x in XrefsTo(addr1,flags = 0):

        MakeComm(x.frm,out)

def GetAllString(addr):

    str_1=GetString(addr,-1,ASCSTR_C)

    len_1=len(str_1)

    if str_1 != '' and addr<0x5f6c8:

        if re.search("^[0-9A-Z]+$",str_1):

            #print addr,str_1

            decrypt(addr,str_1)

        return GetAllString(addr+len_1+1)

    else:

        decrypt(addr,str_1)

addr=0x5d8e8

GetAllString(addr)

运行之后可以看到字符串已解密成功。

之后就可以继续分析so对dex的保护过程,我目前还未分析完成。大家有兴趣的可以一起分析。分析好后我会再发一篇文章。

libbaiduprotect.so我放到附件了

上传的附件 libbaiduprotect.so

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功