转自:

<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. NodeJS下载文件实例

    var http = require('http');var express = require('express');var fs=require("fs"); var app ...

  2. .NET面试题解答

    抽象类和接口有什么区别?使用时候有什么需要注意的吗?答:相同点:都不能被直接实例化,都通过继承实现其抽象方法: 不同点: 1) 接口支持多继承:抽象类不能实现多继承: 2) 接口只能定义行为:抽象类既 ...

  3. 使用VC++通过远程进程注入来实现HOOK指定进程的某个API

    前阵子读到一篇关于<HOOK API入门之Hook自己程序的MessageBoxW>的博客,博客地址:http://blog.csdn.net/friendan/article/detai ...

  4. TCPL 行计数

    C programming language: P13 行计数 e.g. #include <stdio.h>int main(void){    int c, nb, nt, nl;   ...

  5. Telnet RFC

    http://tools.ietf.org/html/rfc857 http://www.faqs.org/rfcs/rfc854.html 不错: http://blog.csdn.net/chao ...

  6. Windows 7妙用 笔记本变无线AP轻松共享

    笔记本变AP的前提和应用原理 笔记本变AP的前提是你所处的房间或地点需要提供有线宽带的连接,而且你的笔记本要有无线网卡.如果这两个条件具备了,即使没有路由器/无线AP等辅助设备,多个笔记本电脑共享上网 ...

  7. 在非gui线程使用QMessageBox

    最近我写项目的时候遇到一个奇怪的需求,要在工作线程内,根据某个情况弹出一个MessageBox 但是Qt提供的MessageBox只可以在gui线程(主线程)使用,于是我就对QMessageBox封装 ...

  8. 强烈推荐visual c++ 2012入门经典适合初学者入门

    强烈推荐visual c++ 2012入门经典适合初学者入门 此书循序渐进,用其独特.易于理解的教程风格来介绍各个主题,无论是编程新手,还是经验丰富的编程人员,都很容易理解. 此书的目录基本覆盖了Wi ...

  9. GDOI2015酱油记

    GDOI2015酱油记 今年的GDOI在北江举行,比赛前一天坐了5小时的车才到,幸好忍住了,没有在车上吐. Day 1 刚到电教楼,看完考室后,第一时间找厕所,结果发现只有一楼有厕所,坑爹我的考室在三 ...

  10. [置顶] 北漂的大三IT男(暂完)

    今天是2013年8月9日,是我待在北京的最后一个晚上,今天我已经正式向公司提出辞职了,虽然公司已经答应从下个月起涨部分工资,但是我还是坚决的离开了,回想当时进公司的想法----------干了一个月后 ...