http://bbs.pediy.com/showthread.php?p=1365122

看雪安全论坛

 

 

 

 


返回   看雪安全论坛 移动平台 『Android 安全』
忘记密码?

发表新主题 回复
关注  
主题工具  显示模式 

杨剑超 的头像

普通会员
普通会员

资 料:
注册日期: Jan 2015
帖子:  111  杨剑超 品行端正
精华:  1
现金: 14 Kx
致谢数: 0
获感谢文章数:2
获会员感谢数:10
1  旧 2015-04-14, 14:21:18  默认  已解答: 【原创】逆向Android SO,以《遇见》App为例
杨剑超 当前离线

工具:IDA6.6,不会发图,只能用文字描述了。
研究过《遇见》登录的同学可能都知道,只要修改过APK,在登录时都会提示软件盗版。
经研究登录时safecode字段有问题,可能是验证了签名。在libiaroundnet.so中Java_net_iaround_utils_NativeLibUtil_aaa实现。

步骤1:下载   http://gdown.baidu.com/data/wisegame...yujian_570.apk
将yujian_570.apk改名为yujian_570.zip,将lib目录下的lib\armeabi\libiaroundnet.so提取出来拖入IDA中。

步骤2:
    拖进来后发现SHA1Input,SHA1Output这样带有SHA1的函数,断定SO中用到了SHA1加密算法。

步骤3:
    查看Java_net_iaround_utils_NativeLibUtil_aaa函数按F5出来C的伪代码,此时代码还不易读懂,不如像“v9 = (*(int (**)(void))(v8 + 124))()”,这样的代码。但是看到这个我们是不是应该想到C++里面的内存的寻址?,成员变量的首地址=对象的首地址+成员变量在类中的偏移.
假如
Struct node
{
      int,x,y;
};
node a;如果A的首地址是0x00000000,那么a.x的地址是0x00000000,a.y的地址是0x00000004;
由C伪代码我们不难得出:v8是JNIEnv *类型,查看jni.h并计算我们不难发现v8 + 124是GetObjectClass函数指针,同理我们可以计算出其他类似的调用。

步骤4:
     有了步骤三的基础,我们可以想到一个简便的方法就是导入jni.h,从而确定JNIEnv类的结构,借助IDA直接识别函数。下载jni.h(虫大大书上修改JNI.H的方法貌似不好使,我自己改了个):http://pan.baidu.com/s/1sj3EaTn,然后File->Load File->parse C header file... 选择下载好的jni.h确定。然后在structures页面里按下insert键
->add standard structure->滑到最下方选择"JNIEnv_",然后确定。

步骤5:
    返回伪代码界面,鼠标点击Java_net_iaround_utils_NativeLibUtil_aaa的第一个参数,右键->convert to struct*->选择jnienv_*,这时,伪代码中不明函数的调用已经出来。
刚刚的(*(int (**)(void))(v8 + 124))()已经变成 ((int (*)(void))v8->GetObjectClass)();
这时只要仔细阅读伪代码就知道该函数做了啥,逆向的C代码为:
代码:
JNIEXPORT jstring JNICALL Java_net_iaround_utils_NativeLibUtil_aaa
(JNIEnv *env, jobject ob, jobject paramContext, jobject paramPackageInfo, jstring paramString1, jstring paramString2)
{
  SHA1Context context;
  jstring ret=0;
  JNIEnv* p_env=env;
  char cifferbuf[128]={0};
  char buf[64]={0};
  jclass obClass=env->GetObjectClass(ob);
  char *pString="()Ljava/lang/String;";
  jmethodID  reusltID=p_env->GetMethodID(obClass,"getPackageName","()Ljava/lang/String;");
  jobject retObject=p_env->CallObjectMethod(paramContext,reusltID);
  jboolean boolean=0;
  const char *str=p_env->GetStringUTFChars((jstring)retObject,&boolean);
  bool cmpResult=strcmp("net.iaround",str);
  if(cmpResult==0)
  {
    ret=p_env->NewStringUTF("123456");
  }
  else
  {
    char destBuffer[128]={0};
    const char* s1=p_env->GetStringUTFChars(paramString1,&boolean);
    const char *s2=p_env->GetStringUTFChars(paramString2,&boolean);
    __android_log_print(4, "logfromc", "%s",s1);
    __android_log_print(4, "logfromc", "%s",s2);
    int len1=strlen(s1);
    int len2=strlen(s2);
    memcpy(destBuffer,s1,len1);
    memcpy(destBuffer+len1,s2,len2);
    jclass packageInfo= p_env->GetObjectClass(paramPackageInfo);
    ret=(jstring)packageInfo;
    if(packageInfo)
    {
      jfieldID signatures=p_env->GetFieldID(packageInfo,"signatures","[Landroid/content/pm/Signature;");
      ret=(jstring)signatures;
      if(signatures)
      {

        jobjectArray sigarray=(jobjectArray)p_env->GetObjectField(paramPackageInfo,signatures);
        if(sigarray)
        {

          jsize sigLength=p_env->GetArrayLength(sigarray);
          if(sigLength>0)
          {

            jobject ob=p_env->GetObjectArrayElement(sigarray,0);
            if(ob)
            {

              jclass jc=p_env->GetObjectClass(ob);
              if(jc)
              {

                jmethodID id=p_env->GetMethodID(jc,"toCharsString","()Ljava/lang/String;");
                if(id)
                {

                  jstring sigString =(jstring)p_env->CallObjectMethod(ob,id);
                  const char* sigStr=p_env->GetStringUTFChars(sigString,&boolean);
                  int passLen=strlen(destBuffer);
                  memcpy(cifferbuf,sigStr+16,32);
                  //__android_log_print(4, "logfromc", "%s",sigStr+16);
                  //memcpy(cifferbuf,"a00302010202044e549d3a300d06092a",32);
                  memcpy(cifferbuf+32,destBuffer,passLen);

                  __android_log_print(4, "logfromc", "cifferString:%s",cifferbuf);

                  SHA1Reset(&context);
                  int cifferlen=strlen(cifferbuf);

                  SHA1Input(&context,cifferbuf,cifferlen);
                  //memset(&v51, 48, 0x29u);
                  memset(buf,0,sizeof(buf));
                  if(SHA1Result(&context))
                  {
                    sprintf(buf, "%08X%08X%08X%08X%08X", context.Message_Digest[0],context.Message_Digest[1],
                        context.Message_Digest[2],context.Message_Digest[3],context.Message_Digest[4]);
                  }
                  else
                  {
                    __android_log_print(4, "logfromc", "ERROR-- could not compute message digest\n");
                  }
                  ret=p_env->NewStringUTF(buf);
                }
              }
            }
          }
        }
      }
    }
  }
  return ret;
}
这时代码的意图就明显了
一句话概括就是:将签名中取出32位+paramString1+paramString2后用SHA1加密
                        如果中途出错,直接返回“123456”。。。

这时可以得出该APK包是利用了签名加密后到服务器验证的。服务器计算出safecode和收到的safecode不一样时,反馈软件盗版。。


此贴只供学习,如做其它用途,后果自负。 
 
回复时引用此帖 返回顶端
共 7 位会员
感谢 杨剑超 发表的文章:
bengou (2015-04-17), leeven超人 (2015-11-23), Lnju (2015-04-18), sunwood (2015-06-11), weishi (2016-01-13), zhczf (2015-04-18), 雪衫 (2015-04-18)
最佳答案 - 作者: 杨剑超
在哪删帖,我要删帖!!!!!!!!!!!!!!!!!!!!!

杨剑超 的头像

普通会员
普通会员

资 料:
注册日期: Jan 2015
帖子:  111  杨剑超 品行端正
精华:  1
现金: 14 Kx
致谢数: 0
获感谢文章数:2
获会员感谢数:10
2  旧 2015-04-14, 19:59:42  默认
杨剑超 当前离线

在哪删帖,我要删帖!!!!!!!!!!!!!!!!!!!!! 
 
回复时引用此帖 返回顶端

exile 的头像

普通会员
普通会员

资 料:
注册日期: Jun 2007
帖子:  1,203  exile 品行端正
精华:  1
现金: 2074 Kx
致谢数: 24
获感谢文章数:36
获会员感谢数:36
3  旧 2015-04-14, 20:41:05  默认
exile 当前离线

点一下编辑就行了 哈哈 被警告了吧 
 
回复时引用此帖 返回顶端

杨剑超 的头像

普通会员
普通会员

资 料:
注册日期: Jan 2015
帖子:  111  杨剑超 品行端正
精华:  1
现金: 14 Kx
致谢数: 0
获感谢文章数:2
获会员感谢数:10
4  旧 2015-04-15, 11:56:29  默认
杨剑超 当前离线

引用:
最初由 exile发布  查看帖子
点一下编辑就行了 哈哈 被警告了吧
那倒是没有,感觉这个我技术太水了。。想技术好点以后再出来发贴 
 
回复时引用此帖 返回顶端

exile 的头像

普通会员
普通会员

资 料:
注册日期: Jun 2007
帖子:  1,203  exile 品行端正
精华:  1
现金: 2074 Kx
致谢数: 24
获感谢文章数:36
获会员感谢数:36
5  旧 2015-04-15, 13:02:32  默认
exile 当前离线

引用:
最初由 杨剑超发布  查看帖子
那倒是没有,感觉这个我技术太水了。。想技术好点以后再出来发贴
我觉得你写的挺好的  
 
回复时引用此帖 返回顶端

初级会员
初级会员

资 料:
注册日期: Nov 2005
帖子:  75  cnywco 品行端正
精华: 0
现金: 179 Kx
致谢数: 0
获感谢文章数:0
获会员感谢数:0
6  旧 2015-04-18, 09:21:49  默认
cnywco 当前离线

写的很不错啊。、 
 
回复时引用此帖 返回顶端

杨剑超 的头像

普通会员
普通会员

资 料:
注册日期: Jan 2015
帖子:  111  杨剑超 品行端正
精华:  1
现金: 14 Kx
致谢数: 0
获感谢文章数:2
获会员感谢数:10
7  旧 2015-04-18, 09:47:30  默认
杨剑超 当前离线

引用:
最初由 cnywco发布  查看帖子
写的很不错啊。、
你要导入JNI.h,识别JNIENV的数据结构,然后自己阅读代码,才能理解,上面是我根据我的理解重新写的。

PS:我KX不够,不能和你悄悄话 
 
回复时引用此帖 返回顶端

普通会员
普通会员

资 料:
注册日期: Sep 2008
帖子:  611  elianmeng 品行端正
精华:  1
现金: 994 Kx
致谢数: 0
获感谢文章数:4
获会员感谢数:5
8  旧 2015-04-18, 10:10:25  默认
elianmeng 当前离线

MARK 
 
回复时引用此帖 返回顶端

初级会员
初级会员

资 料:
注册日期: Feb 2007
帖子:  274  zhczf 品行端正
精华: 0
现金: 199 Kx
致谢数: 388
获感谢文章数:0
获会员感谢数:0
9  旧 2015-04-18, 10:49:08  默认
zhczf 当前离线

这么好的技术文章,就不要删除了 
 
回复时引用此帖 返回顶端

Lnju 的头像

普通会员
普通会员

资 料:
注册日期: Dec 2014
帖子:  32  Lnju 品行端正
精华:  1
现金: 49 Kx
致谢数: 16
获感谢文章数:1
获会员感谢数:1
10  旧 2015-04-18, 17:19:22  默认
Lnju 当前离线

学习了  感谢分享!! 
 
回复时引用此帖 返回顶端

初级会员
初级会员

资 料:
注册日期: Dec 2010
帖子:  100  cqzhou 品行端正
精华: 0
现金: 10 Kx
致谢数: 3
获感谢文章数:1
获会员感谢数:1
11  旧 2015-04-18, 22:02:32  默认
cqzhou 当前离线

不错哦 继续加油 
 
回复时引用此帖 返回顶端

vVv一 的头像

初级会员
初级会员

资 料:
注册日期: Aug 2014
帖子:  25  vVv一 品行端正
精华: 0
现金: 75 Kx
致谢数: 0
获感谢文章数:0
获会员感谢数:0
12  旧 2015-04-18, 22:10:42  默认
vVv一 当前离线

赞一个    长知识了~ 
 
回复时引用此帖 返回顶端

初级会员
初级会员

资 料:
注册日期: Jun 2008
帖子:  16  fanweiriu 品行端正
精华: 0
现金: 147 Kx
致谢数: 0
获感谢文章数:0
获会员感谢数:0
13  旧 2015-04-30, 09:28:19  默认
fanweiriu 当前离线

这个也就是通过c++部分再回调java的 
 
回复时引用此帖 返回顶端

初级会员
初级会员

资 料:
注册日期: May 2009
帖子:  24  chmlqw 品行端正
精华: 0
现金: 55 Kx
致谢数: 21
获感谢文章数:0
获会员感谢数:0
14  旧 2015-05-13, 16:51:15  默认
chmlqw 当前离线

貌似IDA6.6 自动导入了jni.h这个文件了 
 
回复时引用此帖 返回顶端

杨剑超 的头像

普通会员
普通会员

资 料:
注册日期: Jan 2015
帖子:  111  杨剑超 品行端正
精华:  1
现金: 14 Kx
致谢数: 0
获感谢文章数:2
获会员感谢数:10
15  旧 2015-05-14, 17:18:45  默认
杨剑超 当前离线

引用:
最初由 chmlqw发布  查看帖子
貌似IDA6.6 自动导入了jni.h这个文件了
这个我不知道,反正我的IDA没有看不到相关的数据结构 
 
回复时引用此帖 返回顶端
发表新主题 回复

添加到书签

«  上一主题 |  下一主题  »

发帖规则
不可以发表主题
不可以回复帖子
不可以上传附件
不可以编辑自己的帖子
论坛论坛 启用  vB 代码
论坛 启用  表情图标
论坛 启用  [IMG] 代码
  •    
  •  
  •  
  •  
  •  
  •  
  •  
  •    
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

    相似的主题
    主题 主题作者 论坛 回复 最后发表
    如果没有遇见“你” lijingli 7)看雪十周年专版 26 2014-06-06 03:35:10
    调试逆向 【求助】【求助】调试中 遇见一个函数zwqueryobject fwoi 『软件调试逆向』 19 2008-11-07 09:27:13
    【求助】脱壳中遇见的问题 xinghong 『求助问答』 1 2008-09-08 11:16:58
    【原创破解驱动PC/SC遇见麻烦!! www 『求助问答』 0 2008-07-27 11:52:58
    【求助】脱ASPack 2.12 -> Alexey Solodovnikov遇见的问题 糖醋鱼 『求助问答』 3 2008-01-31 12:14:44


    所有时间均为 北京时间, 现在的时间是  16:30:10.

  •    
  •  
  •  
  •  
  •  
  •    
  •  
  •  
  •  
  •  

      ©2000-2016 看雪学院(PEdiy.com) |关于我们 |  京ICP备10040895号-17 |  知道创宇提供带宽资源 | 微信公众帐号: ikanxue   手机客户端: 
    • 0
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值