好友
阅读权限 40
听众
最后登录 1970-1-1
本帖最后由 spguangz 于 2015-8-13 19:50 编辑
"存档注入"就是把修改好的存档放到原存档位置,当应用读取新存档时,即可达到跳过内购支付过程、免激活、无限金币等目的。"存档注入"按照注入的方式可分为手动式和自动式。
手动就是指拿到存档后,自己动手把其放到存档位置,取代原存档。
自动即应用运行过程中,应用自行把存档放到存档位置,全由代码实现。
存档注入
手动注入
代码注入
优点
不需要修改应用
快捷,简便,不需要root
缺点
繁琐,需要root
要修改应用,可能还会涉及应用自校验等
所以后者是一种相对"一劳永逸"的方法!下文主要阐述用代码进行存档注入的方法。
"存档注入"按照存档文件的数量可分为复制式和解压式。
复制式用于存档文件只有1个。假如不止1个的话,可以进行多次复制,或用解压式。
1 复制式存档注入
游戏:涂鸦双轮车 (1个存档文件)
来源:联通沃游戏搜索下载
目标:去除游戏激活过程
1-1 存档的准备
a.内购破解
游戏玩到第4关,需要进行解锁。
点击退出,提示未支付,游戏并未解锁。
看到联通支付框里的文字,可以搜索"游戏激活",定位到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?不妨试试此方法。
免费评分
查看全部评分