转自:

<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代码混淆还是需要的,虽然代码仍可以被一步步逆向跟踪,但语义上的隔离会加大追踪的时间成本。

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

  1. Android逆向破解表单注册程序

    Android逆向破解表单注册程序 Android开发 ADT: android studio(as) 程序界面如下,注册码为6位随机数字,注册成功时弹出通知注册成功,注册失败时弹出通知注册失败. 布 ...

  2. Android逆向破解表单登录程序

    Android逆向破解表单登录程序 Android开发 ADT: android studio(as) 程序界面如下,登录成功时弹出通知登录成功,登录失败时弹出通知登录失败. 布局代码 <?xm ...

  3. 2018-2019-2 20165316 《网络对抗技术》Exp1 PC平台逆向破解

    2018-2019-2 20165316 <网络对抗技术>Exp1 PC平台逆向破解 1 逆向及Bof基础实践说明 1.1 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件 ...

  4. 20165207 Exp1 PC平台逆向破解

    20165207 Exp1 PC平台逆向破解 0.写在最前面 在做三个实验的前两个的时候,我还没有到博客里去看作业的要求.当时我的主机名是kali5207也就是用我的学号命名的,要求的是姓名全拼命名k ...

  5. # 2018-2019-2 20165210《网络攻防技术》Exp1 PC平台逆向破解(BOF实验)

    2018-2019-2 20165210<网络攻防技术>Exp1 PC平台逆向破解(BOF实验) 实验分为三个部分: 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数. ...

  6. 2019-2020-2 20174318张致豪《网络对抗技术》Exp1 PC平台逆向破解

    Exp1_PC平台逆向破解 前期准备 一.逆向及Bof基础实践说明 1.1 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数 ...

  7. 【MyEclipse 2015】 逆向破解实录系列【2】(纯研究)

    声明 My Eclipse 2015 程序版权为Genuitec, L.L.C所有. My Eclipse 2015 的注册码.激活码等授权为Genuitec, L.L.C及其付费用户所有. 本文只从 ...

  8. Android引入高速缓存的异步加载全分辨率

    Android引进高速缓存的异步加载全分辨率 为什么要缓存 通过图像缩放,我们这样做是对的异步加载优化的大图,但现在的App这不仅是一款高清大图.图.动不动就是图文混排.以图代文,假设这些图片都载入到 ...

  9. 20165223《网络对抗技术》Exp1 PC平台逆向破解

    目录--PC平台逆向破解 1 逆向及BOF基础实践说明 1.1 实践内容 1.2 实践要求 1.3 基础知识 2 实验步骤 2.1 直接修改程序机器指令,改变程序执行流程 2.2 通过构造输入参数,造 ...

随机推荐

  1. JAVA读取propertise配置文件

    java中的properties文件是一种配置文件,主要用于表达配置信息,文件类型为*.properties,格式为文本文件,文件的内容是格式是"key=value"的格式,在pr ...

  2. Spring MVC JSON 实现JsonSerializer Date类型转换

    转载至:http://blog.csdn.net/lantianzhange/article/details/40920933 在Spring MVC中存在两大类的类型转换,一类是Json,一个是Sp ...

  3. 工作备份 build.gradle

    apply plugin: 'com.android.application' android { compileSdkVersion 22 buildToolsVersion '22.0.0' de ...

  4. avalon.js实践 svg地图配置工具

    MVVM模式,在很多复杂交互逻辑下面,有很大的优势.现在相关的框架也很多,现在项目中使用了avalon.js,选择它的原因,是兼容性的考虑,当然也要支持下国内开发大牛,至于性能方面的,没有实际测试过, ...

  5. C#学习日志 day7 --------------LINQ与Lamda语句的初步尝试以及XML的生成

    LINQ是一种集成在计算机语言里的信息查询语句,是c#3.0中最惹人瞩目的功能. 在C#中,LINQ语句有两种写法. 第一种写法与SQL语句类似: IEnumerable<Customer> ...

  6. 在Win7的IIS上搭建FTP服务及用户授权——转载!!

    原文地址:http://blog.sina.com.cn/s/blog_6cccb1630100q0qg.html FTP服务 FTP是文件传输协议(File Transfer Protocol)的简 ...

  7. OpenCV学习 2:播放AVI视频

    原创文章,欢迎转载,转载请注明出处 第二个程序,播放视频.用opencv做起来是如此的简单..哈哈.           学Opencv,只是为了在它的基础上实现工程应用,而它里面高深的理论我等屌丝只 ...

  8. 理解TCP为什么需要进行三次握手

        在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接. 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认: ...

  9. Httpwatch 工具介绍

    一 概述: HttpWatch强大的网页数据分析工具.集成在Internet Explorer工具栏.包括网页摘要.Cookies管理.缓存管理.消息头发送/接受.字符查询.POST 数据和目录管理功 ...

  10. Exec sql/c

    Exec sql/c 利用高级语言的过程性结构来弥补SQL语言实现复杂应用方面的不足. 嵌入SQL的高级语言称为主语言或宿主语言. 在混合编程中,SQL语句负责操作数据库,高级语言语句负责控制程序流程 ...