吾爱破解 - LCG - LSG |安卓破解|病毒分析|破解软件|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5868|回复: 52

[Android 原创] 某Xposed微信群发工具dex解密分析

  [复制链接]
发表于 2017-6-16 17:34 | 显示全部楼层
本帖最后由 qtfreet00 于 2017-6-16 17:49 编辑
jadx载入

寻找xposed_init文件中定义的xposed程序的入口,发现主体只有如下三个函数,那猜想真正的hook函数被加密存储了,执行时通过dexClassloader动态加载执行

    public class XposedEntry implements IXposedHookLoadPackage {
        private static final String enDexName = "appcompat_v4.dex";
        private static final String gsonDexName = "gson.dex";
    public static String pkgName = "wechat.simpleforwarder";
    private static final String soName = "libJpush.so";        

        public void copyFileFromAssets(InputStream inputStream, String str) {
          ...
        }

        String getCurProcessName(Context context) {
          ...
        }

        public void handleLoadPackage(LoadPackageParam loadPackageParam) {
          ...
        }
}

Markdown

在程序的assets下发现了如下几个后缀为dex的文件,直接尝试了使用jadx去反编译,发现反编译不成功,拖入010Editor

Markdown

dex被作者进行了加密,那就得去代码中寻找解密执行代码

直接看ui的入口并没有发现任何的解密地方,猜想既然是xposed插件,那一定会有findAndHookMethod的地方,以及beforeHook和afterHook,直接去查找,找到如下代码

protected void afterHookedMethod(MethodHookParam methodHookParam) {
    super.afterHookedMethod(methodHookParam);
    Context context = (Context) methodHookParam.thisObject;
    String curProcessName = this.ʼ.getCurProcessName(context);
    XposedBridge.log("processName = " + curProcessName);
    if (context.getPackageName().equalsIgnoreCase(curProcessName)) {
        File dir = context.getDir("forward_so", 0);
        File dir2 = context.getDir("forward_dex", 0);
        String absolutePath = new File(dir, "libJpush.so").getAbsolutePath();
        Context createPackageContext = context.createPackageContext(XposedEntry.pkgName, 2);
        this.ʼ.copyFileFromAssets(createPackageContext.getAssets().open("libJpush.so"), absolutePath);
        this.ʼ.copyFileFromAssets(createPackageContext.getAssets().open("appcompat_v4.dex"), new File(dir2, "appcompat_v4.dex").getAbsolutePath());
        this.ʼ.copyFileFromAssets(createPackageContext.getAssets().open("gson.dex"), new File(dir2, "gson.dex").getAbsolutePath());
        System.load(absolutePath);
        Class cls = (Class) JniUtil.getXClass(context, dir.getAbsolutePath(), dir2.getAbsolutePath());
        cls.getMethod(JniUtil.getXMethodName(), new Class[]{LoadPackageParam.class, Context.class}).invoke(cls.newInstance(), new Object[]{this.ʻ, context});
    }
}

程序读取assets中的文件,并加载了assets下的so文件,调用了一个名为JniUtil的getXClass函数,传入了三个参数,分别是context和两个路径,此处没有看到DexClassLoader,猜想这里的context是用作后面classloader使用的,IDA载入libJpush.so(居然用极光推送的名称)

  if ( ((int (__fastcall *)(JavaVM *, JNIEnv **, signed int))(*v2)->GetEnv)(v2, &env, 0x10004)
    || (v3 = env, (v4 = (*env)->FindClass(env, "wechat/simpleforwarder/util/JniUtil")) == 0)
    || ((int (__fastcall *)(JNIEnv *, jclass, JNINativeMethod *, signed int))(*v3)->RegisterNatives)(
         v3,
         v4,
         gMethods,
         2) < 0 )
  {
    result = 0xFFFFFFFF;
  }

在jni_Onload处看到动态动态了函数,直接双击gMethods跳过去

int __fastcall getXClass(JNIEnv *env, jclass jls, jobject context, jstring soDir, jstring dexDir)
{
  jobject v5; // ST08_4@1
  jclass v6; // r7@1
  JNIEnv *v7; // r4@1
  jstring v8; // r6@1
  unsigned __int8 *v9; // r5@3
  unsigned __int8 *v10; // r0@3
  int v11; // r5@3
  unsigned __int8 *v12; // r6@3
  unsigned __int8 *v13; // r0@3
  jstring dexPath; // [sp+0h] [bp-28h]@1
  jstring gsonDexPath; // [sp+4h] [bp-24h]@1
  jstring soDira; // [sp+Ch] [bp-1Ch]@1

  v5 = context;
  v6 = jls;
  soDira = soDir;
  v7 = env;
  dexPath = appendCharStr(env, dexDir, string27);
  v8 = appendCharStr(v7, dexDir, string28);
  gsonDexPath = appendCharStr(v7, dexDir, string29);
  if ( getSignatureHashCode(v7, v6, v5) != 0x962F5B7 )
    killSelf(v7);
  v9 = (unsigned __int8 *)((int (__fastcall *)(JNIEnv *, jstring, _DWORD))(*v7)->GetStringUTFChars)(v7, v8, 0);
  v10 = (unsigned __int8 *)((int (__fastcall *)(JNIEnv *, jstring, _DWORD))(*v7)->GetStringUTFChars)(v7, dexPath, 0);
  decryptFun(v9, v10);
  v11 = DexClassLoader(v7, dexPath, gsonDexPath, soDira);
  v12 = (unsigned __int8 *)((int (__fastcall *)(JNIEnv *, jstring, _DWORD))(*v7)->GetStringUTFChars)(v7, v8, 0);
  v13 = (unsigned __int8 *)((int (__fastcall *)(JNIEnv *, jstring, _DWORD))(*v7)->GetStringUTFChars)(v7, dexPath, 0);
  copyFun(v12, v13);
  return v11;
}

这里就来到了getXClass处,这里函数并没有做混淆,所以很好分析,看到一个DecryptFun函数,跟进去

void __fastcall decryptFun(unsigned __int8 *path, unsigned __int8 *dePath)
{
  unsigned __int8 *v2; // r4@1
  FILE *v3; // r0@1
  FILE *v4; // r5@1
  unsigned int v5; // r6@2
  FILE *v6; // r7@2
  unsigned int i; // r6@2
  int v8; // r4@3

  v2 = dePath;
  v3 = j_j_fopen((const char *)path, "r");
  v4 = v3;
  if ( v3 )
  {
    v5 = j_j_fgetc(v3) << 0x18;
    v6 = j_j_fopen((const char *)v2, "w");
    for ( i = v5 >> 0x18; ; j_j_fputc(v8 ^ i, v6) )
    {
      v8 = (unsigned __int8)j_j_fgetc(v4);
      if ( j_j_feof(v4) )
        break;
    }
    j_j_fclose(v4);
    j_j_fclose(v6);
  }
}

这里就可以看到两个传入的路径,分别是文件所在路径和保存的解密文件的路径,而且包括下面一个DexClassLoader函数都没有做remove文件操作,所以也可以在程序执行后使用re把真实的dex拖出来

上面的DecryptFun函数,可以看到打开了加密dex文件,并进行异或后保存在v6中,fgetc会每次读取一个字符,这里v5即是该文件的第一个字符,0x2D-->45 ,所以可以推导出该文件的每个字符会和45进行异或,

 public static void main(String[] args) throws Exception {
     FileInputStream fis = new FileInputStream(new File("appcompat_v4.dex"));
     byte[] b = new byte[fis.available()];
     fis.read(b);
     int len = b.length;
     for(int i=0;i<len;i++){
         b  = (byte) (b^45);

     }
     FileOutputStream fos = new FileOutputStream("appcompat_v43333.dex");
     fos.write(b);

 } 

异或完成后使用010打开

Markdown

去除掉第一个00字符,然后重新使用jadx打开

Markdown



免费评分

参与人数 30威望 +1 吾爱币 +43 热心值 +29 收起 理由
东孙离 + 1 + 1 用心讨论,共获提升!
slljspy + 1 + 1 用心讨论,共获提升!
gaoranaa + 1 + 1 我很赞同!
独行风云 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Hmily + 1 + 10 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
oxxo119 + 1 我很赞同!
rufeng313 + 1 + 1 用心讨论,共获提升!
ripples + 1 + 1 我很赞同!
iamcjsyr + 1 + 1 用心讨论,共获提升!
Nboos + 1 热心回复!
skfxzxc + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
绿软奔跑者 + 1 谢谢@Thanks!
hlink1021 + 1 + 1 热心回复!
zxl1993 + 1 + 1 我是来膜拜的!
aken + 3 + 1 一篇帖子,不知道要分析多久,佩服解密大神
xia8520 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Jxdm + 1 + 1 膜拜大神
SomnusXZY + 1 + 1 已答复!
oxygen + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
jiachengzi + 1 + 1 热心回复!
wmsuper + 2 + 1 我很赞同!
我的宝宝 + 1 + 1 我很赞同!
xuanle6 + 1 + 1 谢谢@Thanks!
ahuiaini + 1 + 1 热心回复!
Enigma_G + 2 + 1 用心讨论,共获提升!
wi5101 + 1 + 1 用心讨论,共获提升!
小范 + 3 + 1 我很赞同!
panwanpeng + 1 用心讨论,共获提升!
YYYYY + 1 + 1 我很赞同!
Only丶爱你 + 1 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【CB】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复

使用道具 举报

发表于 2017-6-16 19:17 | 显示全部楼层
武林高手就是不一样,像大学教授的论文一样,耐人寻味

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【CB】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 2 反对 0

使用道具 举报

发表于 2017-7-11 14:49 | 显示全部楼层

DEX的16进制有明显的结构性,很容易猜到就是异或加密,而DEX中00出现的较多,你这个图中加密后的dex出现的较多的就是2D这个值,所以加密方式就是单字节的与0x2D异或运算。只看图就能看出来了,不需要分析代码啊

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【CB】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

发表于 2017-6-16 17:52 | 显示全部楼层

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【CB】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

发表于 2017-6-16 18:04 | 显示全部楼层
板凳看看

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【CB】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

发表于 2017-6-16 18:26 来自手机 | 显示全部楼层
楼主,想找你逆向app,私聊你呦

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【CB】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

发表于 2017-6-16 18:47 | 显示全部楼层
前排围观下 学习学习

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【CB】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

发表于 2017-6-16 20:17 | 显示全部楼层
不明觉厉, 我是码盲

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【CB】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

发表于 2017-6-16 20:38 | 显示全部楼层
谢谢分享

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【CB】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

发表于 2017-6-16 20:43 | 显示全部楼层
   学习系啊   = =

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【CB】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

发表于 2017-6-16 21:32 | 显示全部楼层
围观下 学习学习

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】【CB】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则


免责声明:
吾爱破解所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。

Mail To:Service@52PoJie.Cn

快速回复 收藏帖子 返回列表 搜索

RSS订阅|手机版|小黑屋|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2017-8-21 19:50

Powered by Discuz!

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表