吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 17548|回复: 14
收起左侧

[Android 原创] 一种安卓逆向方法--"存档注入"

  [复制链接]
spguangz 发表于 2015-8-13 19:47
本帖最后由 spguangz 于 2015-8-13 19:50 编辑

"存档注入"就是把修改好的存档放到原存档位置,当应用读取新存档时,即可达到跳过内购支付过程、免激活、无限金币等目的。"存档注入"按照注入的方式可分为手动式和自动式。
手动就是指拿到存档后,自己动手把其放到存档位置,取代原存档。
自动即应用运行过程中,应用自行把存档放到存档位置,全由代码实现。
存档注入
手动注入
代码注入
优点
不需要修改应用
快捷,简便,不需要root
缺点
繁琐,需要root
要修改应用,可能还会涉及应用自校验等
所以后者是一种相对"一劳永逸"的方法!下文主要阐述用代码进行存档注入的方法。

"存档注入"按照存档文件的数量可分为复制式和解压式。
复制式用于存档文件只有1个。假如不止1个的话,可以进行多次复制,或用解压式。

1 复制式存档注入

游戏:涂鸦双轮车  (1个存档文件)
来源:联通沃游戏搜索下载
目标:去除游戏激活过程

1-1 存档的准备

a.内购破解
游戏玩到第4关,需要进行解锁。
20150813_174906.png     20150813_174920.png

点击退出,提示未支付,游戏并未解锁。
20150813_175229.png

看到联通支付框里的文字,可以搜索"游戏激活",定位到Lcom/cloud/dw/DoodleWheels;
查看源码,发现某方法
[Java] 纯文本查看 复制代码
protected void onActivityResult(int paramInt1, int paramInt2, Intent paramIntent)
  {
    int i = 1;
    switch (paramInt1)
    {
    default: 
      super.onActivityResult(paramInt1, paramInt2, paramIntent);
      return;
    }
    if (paramIntent.getIntExtra("result", i) == 0) {}
    while (i != 0)
    {
      setActivated();
      Toast.makeText(this, 2130903080, 0).show();
      return;
      i = 0;
    }
    Toast.makeText(this, paramIntent.getStringExtra("errorstr"), 0).show();
  }

其中setActivated();为完成激活游戏,所以把代码跳转到此处即可,
或者直接setActivated();将挪到switch分支前,那么退出支付时,实际上也是完成了游戏的激活。

b.存档导出
把手机上的存档导出到电脑上备用。我的方法是使用Android killer的文件管理功能。(。・・)ノ

游戏激活后的存档大致内容:
[HTML] 纯文本查看 复制代码
<int name="lv0state" value="1" />
<int name="lv1state" value="1" />
<int name="lv2state" value="1" />
<int name="lv3state" value="1" />
[color=#ff0000]<boolean name="activated" value="true" />[/color]
<float name="lv1time" value="8.622523" />
<int name="topScore" value="1126" />
<boolean name="init" value="true" />
<boolean name="sound" value="true" />


为了装作我没玩过的样子,我把打开了的关卡关上。
[HTML] 纯文本查看 复制代码
<int name="lv0state" value="1" />
<int name="lv1state" value="0" />
<int name="lv2state" value="0" />
<int name="lv3state" value="0" />
[color=#ff0000]<boolean name="activated" value="true" />[/color]
<float name="lv1time" value="0.0" />
<int name="topScore" value="0" />
<boolean name="init" value="true" />
<boolean name="sound" value="true" />


因为"activated"为true,所以游戏一打开即为已激活版。
存档准备部分完成。

1-2 "复制式"代码的添加

在主Activity里添加以下方法:
[Java] 纯文本查看 复制代码
.method public static doCopyAssets(Landroid/content/Context;)V
    .locals 9
    .param p0, "context"    # Landroid/content/Context;

    .prologue
    .line 15
    
    new-instance v2, Ljava/io/File;

    const-string v7, "/data/data/包名/shared_prefs/存档文件名"

    invoke-direct {v2, v7}, Ljava/io/File;-><init>(Ljava/lang/String;)V

    .line 18
    .local v2, "file":Ljava/io/File;
    invoke-virtual {v2}, Ljava/io/File;->exists()Z

    move-result v7

    if-nez v7, :cond_1

    .line 26
    :cond_0
    :try_start_0
    new-instance v6, Ljava/io/FileOutputStream;

    const-string v7, "/data/data/包名/shared_prefs/存档文件名"
                                                       
    invoke-direct {v6, v7}, Ljava/io/FileOutputStream;-><init>(Ljava/lang/String;)V

    .line 27
    .local v6, "myOutput":Ljava/io/OutputStream;
    invoke-virtual {p0}, Landroid/content/Context;->getAssets()Landroid/content/res/AssetManager;

    move-result-object v7

    const-string v8, "存档文件名"

    invoke-virtual {v7, v8}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream;

    move-result-object v5

    .line 28
    .local v5, "myInput":Ljava/io/InputStream;
    const/16 v7, 0x400

    new-array v0, v7, [B

    .line 29
    .local v0, "buffer":[B
    invoke-virtual {v5, v0}, Ljava/io/InputStream;->read([B)I

    move-result v4

    .line 30
    .local v4, "length":I
    :goto_0
    if-gtz v4, :cond_2

    .line 34
    invoke-virtual {v6}, Ljava/io/OutputStream;->flush()V

    .line 35
    invoke-virtual {v5}, Ljava/io/InputStream;->close()V

    .line 36
    invoke-virtual {v6}, Ljava/io/OutputStream;->close()V

    .line 45
    .end local v0    # "buffer":[B
    .end local v2    # "file":Ljava/io/File;
    .end local v3    # "file1":Ljava/io/File;
    .end local v4    # "length":I
    .end local v5    # "myInput":Ljava/io/InputStream;
    .end local v6    # "myOutput":Ljava/io/OutputStream;
    :cond_1
    :goto_1
    return-void

    .line 31
    .restart local v0    # "buffer":[B
    .restart local v2    # "file":Ljava/io/File;
    .restart local v3    # "file1":Ljava/io/File;
    .restart local v4    # "length":I
    .restart local v5    # "myInput":Ljava/io/InputStream;
    .restart local v6    # "myOutput":Ljava/io/OutputStream;
    :cond_2
    const/4 v7, 0x0

    invoke-virtual {v6, v0, v7, v4}, Ljava/io/OutputStream;->write([BII)V

    .line 32
    invoke-virtual {v5, v0}, Ljava/io/InputStream;->read([B)I
    :try_end_0
    .catch Ljava/io/FileNotFoundException; {:try_start_0 .. :try_end_0} :catch_0
    .catch Ljava/io/IOException; {:try_start_0 .. :try_end_0} :catch_1

    move-result v4

    goto :goto_0

    .line 37
    .end local v0    # "buffer":[B
    .end local v4    # "length":I
    .end local v5    # "myInput":Ljava/io/InputStream;
    .end local v6    # "myOutput":Ljava/io/OutputStream;
    :catch_0
    move-exception v1

    .line 38
    .local v1, "e":Ljava/io/FileNotFoundException;
    invoke-virtual {v1}, Ljava/io/FileNotFoundException;->printStackTrace()V

    goto :goto_1

    .line 39
    .end local v1    # "e":Ljava/io/FileNotFoundException;
    :catch_1
    move-exception v1

    .line 41
    .local v1, "e":Ljava/io/IOException;
    invoke-virtual {v1}, Ljava/io/IOException;->printStackTrace()V

    goto :goto_1
.end method

其大概作用为将assets里的指定文件复制到指定的存档位置。
当然需有个存档文件是否存在的判断,不然每次打开游戏都要重玩了。

把准备好的存档文件置于assets文件夹下,并于主Activity中(一般在onCreate)添加调用以上方法的代码。
回编译。试玩,目标达成。


2 解压式存档注入

应用:计算管家 v3.4  (多个存档文件)
来源:繁华最近的一篇“求破”贴
目标:软件一打开即为已付费版

2-1 存档的准备

按照繁华入门教程(五)的方法,
吾爱破解安卓逆向入门教程(五)---Smali实战分析
进行授权破解和去掉软件重启验证后,进行授权,成功后获得存档,并导出到电脑备用。

2-2 "解压式"代码的添加

在主Activity里添加以下方法:
[Java] 纯文本查看 复制代码
.method private doUnZipAssets(Ljava/lang/String;Ljava/lang/String;)V                                                                
    .locals 3                                                                
    .param p1, "path"    # Ljava/lang/String;                                                                
    .param p2, "zipfileInAssets"    # Ljava/lang/String;                                                                
                                                                
    .prologue                                                                
    .line 201                                                                
                                                                
    const/4 v1, 0x0                                                                
                                                                
    .line 203                                                                
    .local v1, "is":Ljava/io/InputStream;                                                                
    :try_start_0                                                                
    invoke-virtual {p0}, Lx/y/z;->getResources()Landroid/content/res/Resources; 
                                                                
    move-result-object v2                                                                
                                                                
    invoke-virtual {v2}, Landroid/content/res/Resources;->getAssets()Landroid/content/res/AssetManager;                                                                
                                                                
    move-result-object v2                                                                
                                                                
    invoke-virtual {v2, p2}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream;                                                                
    :try_end_0                                                                
    .catch Ljava/io/IOException; {:try_start_0 .. :try_end_0} :catch_0                                                                
                                                                
    move-result-object v1                                                                
                                                                
    .line 208                                                                
    :goto_0                                                                 
    :try_start_1                                                                
    invoke-static {v1, p1}, Lx/y/z;->extnativeZipFileList(Ljava/io/InputStream;Ljava/lang/String;)V 
    :try_end_1                                                                
    .catch Ljava/lang/Exception; {:try_start_1 .. :try_end_1} :catch_1                                                                
                                                                
    .line 212                                                                
    :goto_1                                                                
    return-void                                                                
                                                                
    .line 204                                                                
    :catch_0                                                                
    move-exception v0                                                                
                                                                
    .line 205                                                                
    .local v0, "e":Ljava/io/IOException;                                                                
    invoke-virtual {v0}, Ljava/io/IOException;->printStackTrace()V                                                                
                                                                
    goto :goto_0                                                                
                                                                
    .line 209                                                                
    .end local v0    # "e":Ljava/io/IOException;                                                                
    :catch_1                                                                
    move-exception v0                                                                
                                                                
    .line 210                                                                
    .local v0, "e":Ljava/lang/Exception;                                                                
    invoke-virtual {v0}, Ljava/lang/Exception;->printStackTrace()V                                                                
                                                                
    goto :goto_1                                                                
.end method                                                                

再于主Activity的onCreate中添加以下代码:
[Java] 纯文本查看 复制代码
 
new-instance v0, Ljava/io/File;

    const-string v1, "/data/data/包名/shared_prefs/存档文件名字"

    invoke-direct {v0, v1}, Ljava/io/File;-><init>(Ljava/lang/String;)V

    .line 46
    .local v0, "file":Ljava/io/File;
    invoke-virtual {v0}, Ljava/io/File;->exists()Z

    move-result v1 
    
    if-nez v1, :cond_0
     
    const-string v1, "存档位置"
 
    const-string v2, "xxx.zip"

    invoke-direct {p0, v1, v2}, Lx/y/z;->doUnZipAssets(Ljava/lang/String;Ljava/lang/String;)V

    .line 47
    :cond_0
    return-void

其大概作用为判断存档里是否有某个存档文件,没有的话执行:将assets里的xxx.zip解压到指定的存档位置。

这样软件首次运行会将修改好的存档解压到存档目录,以后就不会了。

将授权成功后的存档压缩成xxx.zip,并置于assets文件夹下。
进行回编译。试玩,目标达成。

3 小结
"存档注入"适用于某些代码难分析修改,但存档易于攻破的应用。
或者某游戏自己打出极品装备,想共享存档给好友,他丫手机却没有root?不妨试试此方法。



点评

良心工程绝对点赞!相见太晚啊!好人平安啊!  发表于 2018-2-9 22:56

免费评分

参与人数 10威望 +3 热心值 +10 收起 理由
独行风云 + 1 感谢楼主分享
XhyEax + 1 赞一个!
Ericky + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
流云 + 1 我很赞同!
爱自由 + 1 谢谢@Thanks!
yeelnn + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
tredawn + 1 我很赞同!
cz5420 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
hehesd + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
qtfreet00 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

晓源 发表于 2015-12-15 13:11
回编译失败了
>I: 编译 smali 到 classes.dex...
>..\..\projects\com\Project\smali\com\nflystudio\InfiniteStaircase\UnityPlayerNativeActivity.smali[3339,4] There is already a label with that name.
>Exception in thread "main" b.a.D: Could not smali file: com/nflystudio/InfiniteStaircase/UnityPlayerNativeActivity.smali
>        at b.a.e.e.a(Unknown Source)
>        at b.a.e.e.a(Unknown Source)
>        at b.a.e.e.a(Unknown Source)
>        at b.a.a.a(Unknown Source)
>        at b.a.a.a(Unknown Source)
>        at b.a.a.e(Unknown Source)
>        at b.a.a.a(Unknown Source)
>        at b.b.a.b(Unknown Source)
>        at b.b.a.a(Unknown Source)
>        at com.rover12421.shaka.cli.Main.main(Unknown Source)
糯米与绿茶 发表于 2015-8-13 19:53
yeelnn 发表于 2015-8-14 07:53
情侣的书包 发表于 2015-8-14 08:04
存档注入其实很简单!不过我复习一下!
心存侥幸 发表于 2015-8-14 14:23
好厉害的样子 支持下~
叶小凡01 发表于 2015-8-28 12:17
还是要学会查看smali源码。。。。
 楼主| spguangz 发表于 2015-8-28 12:18
叶小凡01 发表于 2015-8-28 12:17
还是要学会查看smali源码。。。。

源码会看自然好
不会看的话也行
tigor65 发表于 2015-8-28 21:51
我来看评论
xiaomi1991 发表于 2016-4-8 12:31
支持楼主 学习一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-29 02:22

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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