记大神的一次反汇编/更新

首先解压,在assets文件夹下在找到了要汇编的文件:appmgr.jar,这个文件在安装后在/data/data/<package name>/files/文件夹下会生成一个appmgr.apk,

「其实只是一个存放代码的资源文件,安装的时候重命名了,以apk结尾罢了。」

-------------2014.10.9修正---------------

上面打中文引号的这句话有待考究,如果直接解压得到classes.dex,那个dex只有6kB,而安装后提取的classes.dex有278.23KB,这篇文章用到的是后者。

 

解压这个apk文件,得到classes.dex,拖到IDA Pro 6.1以上版本里面去,可以识别成Android的dex文件。

鉴于要找signature_md5的算法,用alt+t查找「signature_md5」字符串,找到:

CODE:0001ACCE                 const-string/jumbo              v1, aSignature_md5 # "signature_md5"//定义一个aSignature_md5字符串,放到v1寄存器 
//Dalvik指令集看这里

接下来对v1做了这些事情:

从JSON里拿到一个键值对放到v2,v1里;

move-result-object,把数据放回v1里;

check-cast,转换成String格式;

定义逗号,放到v8里;//为什么会有逗号出现?

用v8里的逗号,调用String的split方法 split v1,注意split返回的是分割后的数组

把split之后的数组放到v11里;

下面就不太重要了因为定义了Edition_brief这个变量,下面追踪v11:

array-length开始,把v11的数组长度放到v9里去;

下面if-ge, greater or equal,v2>=v9就跳转到loc_1AD72,注意v2上面定义了是0;就是如果长度等于零则跳转,注意这个v9是JSON里拿到的字符串分割成数组的长度;

if-nez,not equal zero,v8!=0就跳转到loc_1AD72,注意上面刚定义v8等于0,这里有些迷糊;

下一句从packageInfo_signatures得到签名放到v13,v10;

 

注意Arrays.toString(ref);和xx.toString();是不同的。

xx.toString();输出的东西是[@XXXXX一串,而且好像每次都不一样,大神猜测是地址,网上有人说是HASH。

数值数组是不能够整体输出的,

你可以使用循环输出
for(i=0;i<10;i++)
System.out.println(a[i]+" ");

而借助Arrays.toString(a)就节省了上面的循环步骤,而一步输出(当然,调用函数的内部进行了处理)。

然后注意v13中存储了v13,v13又给了v23,v23经过一系列转换格式,最后用一个ad.a(ref)得到了signature_md5;

然后倒数第三行,v11和v2给了v24;

v23和v24比较,亦即PackageInfo_signatures经过ad.a(ref)后,与JSON中的MD5比较。

到此可以看到要找的函数就是ad.a(byte [] x );

此时用dex2jar把dex反编译成jar,放到jd-gui里,找到ad.a():

TIP:昨天才发现函数名冒号后面的代表返回类型。a这个函数里是这样的:

可是循着w.f()找过去发现没有getMD5()。

大神提议用Notepad++的搜索文件中的字符串功能搜索360 apk整个文件反编译出的smali,不知道他怎么想到的。

找到了。下面就是追踪混淆代码了,需要极大的耐心。

evt.c(),然后找到evg.b(),

找到eua.d();本来在eua里找这个a(paramArrayOfByte)怎么也找不到,转念一想才想起来应该在b所在的函数evg里找!

最后找到了。

 

这个真需要很大耐心。我的话恐怕某一步早就放弃了,因为难以接受弄了半天弄不出的结果。大神牛B。

2014年8月7日。

--------------------------2014年10月30日---------------------------

昨天花时间跟了一下另一个混淆了的应用的某个算法,最后跟到了,记录一下。

首先是用jd-gui从混淆的类中跟到的相关的一系列程序片段(只是思路,并没有遵循语法):

//chasing the signmd5 algorithm

u localu = (u)localIterator.next();
localJSONObject2.put("signmd5", localu.a(this.a));//start from here,find localu.a(this.a)!

this.c = paramJSONObject.getString("PackageName");
private long d = -1L;
//localu.a(this.a)
  public long a(Context paramContext)
  {
    if (this.d == -1L)
    {
      PackageInfo localPackageInfo = j.a(paramContext, this.c);
      if (localPackageInfo != null)
        this.d = j.a(j.a(localPackageInfo.signatures[0].toCharsString().getBytes()));
    }
    return this.d;
  }
//the first j.a(byte[] paramArrayOfByte) returns us a String
//the second j.a(String paramArrayOfByte) returns us a long int,which is presented to this.d


//j.a(byte[] paramArrayOfByte)
  public static String a(byte[] paramArrayOfByte)
  {
    try
    {
      MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
      localMessageDigest.update(paramArrayOfByte);
      String str = b(localMessageDigest.digest());
      return str;
    }
    catch (NoSuchAlgorithmException localNoSuchAlgorithmException)
    {
      return "";
    }
    catch (Exception localException)
    {
    }
    return "";
  }    
  
//j.a(String paramArrayOfByte)
  public static long a(String paramString)
  {
    long l1 = 0L;
    int i = 8;
    if ((TextUtils.isEmpty(paramString)) || (paramString.length() < 32))
      return -1L;
    String str = paramString.substring(i, 24);
    int j = 0;
    long l2 = l1;
    while (j < i)
    {
      l2 = l2 * 16L + Integer.parseInt(str.substring(j, j + 1), 16);
      j++;
    }
    while (i < str.length())
    {
      l1 = l1 * 16L + Integer.parseInt(str.substring(i, i + 1), 16);
      i++;
    }
    return 0xFFFFFFFF & l1 + l2;
  }
//j.a(Context paramContext, String paramString)
  public static PackageInfo a(Context paramContext, String paramString)
  {
    try
    {
      PackageInfo localPackageInfo = paramContext.getPackageManager().getPackageInfo(paramString, 64);
      return localPackageInfo;
    }
    catch (Exception localException)
    {
    }
    return null;
  }
//b(localMessageDigest.digest());
    public static String b(byte[] paramArrayOfByte)
  {
    if (paramArrayOfByte == null)
      return "";
    StringBuilder localStringBuilder = new StringBuilder(2 * paramArrayOfByte.length);
    for (int i = 0; i < paramArrayOfByte.length; i++)
    {
      localStringBuilder.append(b[((0xF0 & paramArrayOfByte[i]) >>> 4)]);
      localStringBuilder.append(b[(0xF & paramArrayOfByte[i])]);
    }
    return localStringBuilder.toString();
  }

可以看出只是要找到“localu.a(this.a)”,localu是u这个类的对象,所以到u里面找a的各种方法。

好了最后找到之后写成Android代码:

package com.larry.baidusignmd5;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;

public class MainActivity extends Activity {
//    Context context = getApplicationContext();// is it right?
    Context context = MainActivity.this;
    private long signmd5 = -1L;
    String two = null;
    private static final char[] b = { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
            97, 98, 99, 100, 101, 102 };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String pkgName = "com.phantomz.lightball";
        PackageInfo localPackageInfo = one(context, pkgName);
        byte[] sig = localPackageInfo.signatures[0].toCharsString().getBytes();
        two = two(sig);
        signmd5 = three(two);
        String stringmd5 = Long.toString(signmd5);
        Log.d("signmd5",stringmd5);
    }

    // j.a(Context paramContext, String paramString)
    public static PackageInfo one(Context paramContext, String paramString) {
        try {
            PackageInfo localPackageInfo = paramContext.getPackageManager()
                    .getPackageInfo(paramString, 64);
            return localPackageInfo;
        } catch (Exception localException) {
        }
        return null;
    }

    // j.a(byte[] paramArrayOfByte)
    public static String two(byte[] paramArrayOfByte) {
        try {
            MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
            localMessageDigest.update(paramArrayOfByte);
            String str = b(localMessageDigest.digest());
            return str;
        } catch (NoSuchAlgorithmException localNoSuchAlgorithmException) {
            return "";
        } catch (Exception localException) {
        }
        return "";
    }

    // b(localMessageDigest.digest());
    public static String b(byte[] paramArrayOfByte) {
        if (paramArrayOfByte == null)
            return "";
        StringBuilder localStringBuilder = new StringBuilder(
                2 * paramArrayOfByte.length);
        for (int i = 0; i < paramArrayOfByte.length; i++) {
            localStringBuilder.append(b[((0xF0 & paramArrayOfByte[i]) >>> 4)]);
            localStringBuilder.append(b[(0xF & paramArrayOfByte[i])]);
        }
        return localStringBuilder.toString();
    }

    // j.a(String paramArrayOfByte)
    public static long three(String paramString) {
        long l1 = 0L;
        int i = 8;
        if ((TextUtils.isEmpty(paramString)) || (paramString.length() < 32))
            return -1L;
        String str = paramString.substring(i, 24);
        int j = 0;
        long l2 = l1;
        while (j < i) {
            l2 = l2 * 16L + Integer.parseInt(str.substring(j, j + 1), 16);
            j++;
        }
        while (i < str.length()) {
            l1 = l1 * 16L + Integer.parseInt(str.substring(i, i + 1), 16);
            i++;
        }
        return 0xFFFFFFFF & l1 + l2;
    }
}

好了。可以看出同样是读signature,但是也是要读本地安装的signature;而原来的应用中似乎是可以读下载应用的signature的。

 

posted @ 2014-07-08 21:39  LarryLawrence  阅读(865)  评论(0编辑  收藏  举报