Android 一个抽奖应用的逆向破解全流程之加固自己应用

转自:

<a href="http://www.pedant.cn/2014/07/22/crack-a-draw-app/">http://www.pedant.cn/2014/07/22/crack-a-draw-app/</a>

  

东窗事发

偶然见到一个应用内有抽奖的活动(应用具体名称就不便告知),而且是每天都可以抽。同时抽奖之前也不需要用户登录什么的,但限定了用户一天(自然天)只能抽奖一次。那么应用的服务端在用户没有登录的情况下是依据什么来判定当前用户今天是否已抽过奖了呢?这当中判断的依据是否可靠,能否被伪造然后实现一天多次抽奖呢?带着这些问题,让我们来剥开应用的层层外纱。

初识庐山

首先在PC端打开LogCat,然后手机连接PC,最后手机上打开该应用的抽奖界面。这时我们在LogCat中发现了该应用输出的如下日志:

里面有onPageStart并且包含了被加载网页的url。由此可以得出结论,抽奖页是用WebView加载网页实现的。那加载这个WebView的Activity又是什么呢?

在PC端打开Android DDMS,在进程列表中找到该应用包对应的进程(如下图的进程ID为21641),然后查看Activity Manager State。

这时我们得到的Activity Stack就像这样。

由此我们就可以大概知道它Java内部的实现结构是怎样的了。首先创建的是ActivityToolsExplorer,然后在其中嵌入了一个名为FragmentToolsExplorer的Fragment,最后由FragmentToolsExplorer在onCreate里实现WebView加载网页的过程。

顺水推舟

由上面我们知道了抽奖页的Url。好了,我们首先在浏览器上打开这个Url,看看它的抽奖是怎样一步步实现的。

这个页面打开后,在页面正中间有一个用来作抽奖操作的按钮,嵌套样式名为.lucky-btn .lucky-cell-conn。当然在浏览器上这个程序是运行不起来的,我们关心的只是开始抽奖这个动作是怎样发起的。查看源码打开main.js。js文件竟然没有压缩,就更方便我们逆向跟踪了。我们找到对这个按钮绑定点击事件的位置:

main.js

 

function init(info) {
...
var deviceID=info.deviceId;
checkDrawEnable(drawingObject,deviceID);
$(".lucky-btn .lucky-cell-conn").on("click",function(e){
...
window.setTimeout(function(){
..
getJSONP(BASE_URL+"draw/"+deviceID,function(data){
drawResult(drawingObject,data);
});
},Math.random()*1000+1000);
});

}

  

ok,在这里我们就直接发现了,服务端用来判断用户当天已抽奖的依据是DeviceId(设备ID)。现在我们需要的是一步步逆向跟踪,找到是谁调用了init函数并带入的info参数是怎样构成的,这样似乎整个程序逻辑就会变得清晰起来。

这个网页中bridge对象为java层注入的对象,而脚本中一些初始化信息也是通过调用java方法获得的。那么我们要跟踪整个代码流程,就必须对java代码也进行逆向分析。首先拿到应用的apk包,unzip后使用baksmali将classes.dex解为smali代码包。结合脚本代码,对代码调用层次一步步追踪,这个过程需要你对smali代码也比较熟悉。最后得到如下图所示的调用流程图(具体追踪过程就不在这展开):

由此,我们就知道deviceId串是主要就由Lcom/xx/util/e;->a(Landroid/content/Context;)Ljava/lang/String;方法负责生成。这个方法中获取到AndroidID与DeviceId后用”_”符连接。

Lcom/xx/util/e;->j(Landroid/content/Context;)Ljava/lang/String;就是获取DeviceId的方法,具体的smali代码为:

Lcom/xx/util/e;->j(Landroid/content/Context;)Ljava/lang/String;

 

method public static j(Landroid/content/Context;)Ljava/lang/String;
.registers 2

const-string v0, "phone"

invoke-virtual {p0, v0}, Landroid/content/Context;->getSystemService(Ljava/lang/String;)Ljava/lang/Object;

move-result-object v0

check-cast v0, Landroid/telephony/TelephonyManager;

invoke-virtual {v0}, Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;

move-result-object v0

return-object v0
.end method

  


偷梁换柱
至此找到获取DeviceId真正的位置,我们就破案了。

上面我们知道了,服务端用来判断用户当天已抽奖的依据是DeviceId,同时我们也追踪到了代码中获取DeviceId具体位置。这样,程序每次获取DeviceId时我们就可以伪造返回值(每次伪造的结果都不能相同),就实现一天无限次抽奖了。那怎样伪造这样的返回值呢,下面的简单一句Java代码就可以实现了。


1

return String.valueOf(System.currentTimeMillis() ^ 537400335373457L);

把上面这句翻译成smali代码后,替换掉j(Landroid/content/Context;)Ljava/lang/String;方法内原来的全部smali代码,偷梁换柱。

registers 9

invoke-static {}, Ljava/lang/System;->currentTimeMillis()J

move-result-wide v0

const-wide v2, 0x1e8c344179491L

xor-long/2addr v0, v2

invoke-static {v0, v1}, Ljava/lang/String;->valueOf(J)Ljava/lang/String;

move-result-object v0

return-object v0

  


魔高一尺,道高一丈

最后用smali.jar打包回去,签名后安装。运行起来后应用在抽奖页面已经没有了次数限制。

学习破解的目的不是为了走更多的捷径。有个道理大家都知道,最好的防守就是进攻。我们只有了解怎样去破解一个应用,才知道应该如何去加固自己的应用。就比如这个应用中,有下面这些问题可以改进来加大各方面破解的难度:

  • Debug日志不应该存在于发布版本,Error日志也尽量少暴露敏感信息。
  • 线上网页的脚本代码及样式应该压缩,压缩后可以增加逆向时阅读及追踪上的难度。
  • 不能以客户端上任何固有参数作为服务端上的关键凭据,比如这里的抽奖凭据依赖了客户端的DeviceID。
  • Java代码混淆还是需要的,虽然代码仍可以被一步步逆向跟踪,但语义上的隔离会加大追踪的时间成本。
时间: 2024-10-18 20:20:08

Android 一个抽奖应用的逆向破解全流程之加固自己应用的相关文章

root技术背后android手机内核提取及逆向分析

root技术背后android手机内核提取及逆向分析       安卓ROOT技术背景:      Android手机获得Root权限,可以让/system和/data分区获得读写的权限.这两个分区的权限配置,一般在根分区的init.rc文件中,修改这个文件可永久获得root权限.众所周知,市面上绝大部分的Android手机文件系统有三个分区,分别是/,/system,/data.根分区(/)是打包为ramdisk.img后,再与kernel的zImage打包为boot.img. boot.im

uc浏览器-Android 在listview中实现视频播放和全屏

问题描述 Android 在listview中实现视频播放和全屏 比如 新的UC浏览器中的视频 网易新闻的视听 效果,这是我能拿出的最大的悬赏 请大神赐教 解决方案 http://download.csdn.net/detail/u012440207/7978157 你可以再做一个activity,传值,在新的activity播放http://jingyan.baidu.com/article/86fae346c8b0013c49121a2a.html 解决方案二: 一般listview展示的都

Android实现抽奖转盘实例代码_Android

本文详述了android抽奖程序的实现方法,程序为一个抽奖大转盘代码,里面定义了很多图形方法和动画. 实现主要功能的SlyderView.java源代码如下: import android.app.Activity; import android.content.Context; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; import android.graphics.Color; import

Android编程使WebView支持HTML5 Video全屏播放的解决方法_Android

本文实例讲述了Android编程使WebView支持HTML5 Video全屏播放的解决方法.分享给大家供大家参考,具体如下: 1)需要在AndroidManifest.xml文件中声明需要使用HardwareAccelerate, 可以细化到Activity级别,如果不需要的View可以声明不要用加速,但是需要在代码中做,具体如下: a. 如果要声明整个应用都要加速: 复制代码 代码如下: <application ... android:hardwareAccelerated ="tr

Android编程使WebView支持HTML5 Video全屏播放的解决方法

本文实例讲述了Android编程使WebView支持HTML5 Video全屏播放的解决方法.分享给大家供大家参考,具体如下: 1)需要在AndroidManifest.xml文件中声明需要使用HardwareAccelerate, 可以细化到Activity级别,如果不需要的View可以声明不要用加速,但是需要在代码中做,具体如下: a. 如果要声明整个应用都要加速: 复制代码 代码如下:<application ... android:hardwareAccelerated ="tru

Android实现抽奖转盘实例代码

本文详述了android抽奖程序的实现方法,程序为一个抽奖大转盘代码,里面定义了很多图形方法和动画. 实现主要功能的SlyderView.java源代码如下: import android.app.Activity; import android.content.Context; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; import android.graphics.Color; import

android一个普通app-Android一个普通app,后台常驻服务实现

问题描述 Android一个普通app,后台常驻服务实现 [重金求]Android一个普通app,后台常驻服务实现,例如QQ.微信等的后台消息推送服务,要求如下: 常驻后台运行,系统杀死后,可自行启动: 不能被360等手机助手杀死: 电量消耗要低 解决方案 haonanhhhhhhhhhhhh 解决方案二: haonanhhhhhhhhhhhh 解决方案三: 这个有点不现实吧 QQ 微信都是能被杀死的哟 解决方案四: Android 软件升级(后台服务 + 通知栏进度条)

图片-android一个简单动画的制作问题

问题描述 android一个简单动画的制作问题 我有一个Button,本来是这个样子,我想当按下的时候这三个样子轮流变化: 当再按下的时候变回原来的,也就是第一张的样子 怎么实现? 解决方案 制作一个简单的动画 解决方案二: j亲爱的发噶盛大而搁浅

新时代服务营销是一个全流程精益化过程

"服务营销"是一个关注客户--向客户提供服务--实现有利交换的三级跳过程,服务营销包含产品.定价.渠道.促销.人员.有形展示.服务过程等综合要素,也就是传说中的服务营销7Ps理论.而在人工智能.机器人.虚拟现实.物联网纵横的全新时代,是的,叫这个时代为互联网时代似乎已经过时了,时代变化之快让人瞠目结舌,未来已来,难以置信之间已经身处未来之中,产品.技术.商机.模式在这样的时代势必会被催生出不可思议的变化,新时代的服务营销是一个什么样子,仁者见仁,智者见智,我们尽管大胆发挥自己的想象力,