吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 30079|回复: 46
上一主题 下一主题
收起左侧

[Android 原创] 安卓逆向之给激活码添加一个「口令」

  [复制链接]
跳转到指定楼层
楼主
spguangz 发表于 2016-1-10 19:32 回帖奖励
这次要破解的软件叫Stellio Music Player,是一款手机音乐播放器。
它的破解点是激活码。

用到的工具:
用Androidkiller反编译和修改代码,由于激活码是网络验证,所以用Charles抓包分析。


一、激活码破解篇
本篇的目的:你输入任意激活码都能激活成功。

1.去除自校验
这个软件有签名校验,先去除。
方法是常用的方法了,详见:BT种子搜索1.5.7签名校验破解过程简介
贴一下修改后的代码:
[Java] 纯文本查看 复制代码
invoke-virtual {p0}, Landroid/content/Context;->getPackageManager()Landroid/content/pm/PackageManager;

    move-result-object v0

    const/16 v3, 0x40

    const-string p1, "/sdcard/123.apk"
	//自定义验证包的路径

    invoke-virtual {v0, p1, v3}, Landroid/content/pm/PackageManager;->getPackageArchiveInfo(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;
    //把getPackageInfo改为getPackageArchiveInfo
	
    move-result-object v3

    .line 128
    sget-boolean v0, Lru/stellio/player/Utils/m;->a:Z

    if-nez v0, :cond_3

    iget-object v0, v3, Landroid/content/pm/PackageInfo;->signatures:[Landroid/content/pm/Signature;
    //读取签名
	//省略


2.破解激活码
自校验去掉之后,我们进去看看,发现软件只有10天试用期。
买买买!点击购买,会弹出一个弹框:

如图,它有2种解锁完整版的方式:
a.去购买解锁包解锁
b.用激活码激活解锁
这里选择激活码。

输入任意激活码,会有错误提示:

由于我们要求输入「任意」激活码都能激活成功,所以先去掉格式的限制。

按图索骥,最后在smali里删掉一个跳转即可,比较简单就不贴代码了。

去掉激活码格式的限制后,继续往下走。
由于是联网激活,所以抓包看一下吧。
我输入“呵呵”,然后点击激活。
一方面app上会提示激活码无效,另一方面Charles上显示以下数据:



也就是说,输入的key如果是无效的,发送到服务器上,会验证失败,然后返回error。

先把链接复制下来,搜索看一下。
搜索http://stellio.ru/api/license.php
[Java] 纯文本查看 复制代码
.method public static a(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
    .locals 6

    .prologue
    const/4 v5, 0x0

    .line 47
    new-instance v0, Ljava/util/ArrayList;

    invoke-direct {v0}, Ljava/util/ArrayList;-><init>()V

    .line 49
    new-instance v1, Lru/stellio/player/Helpers/i;

    const-string v2, "key"

    invoke-direct {v1, v2, p0}, Lru/stellio/player/Helpers/i;-><init>(Ljava/lang/String;Ljava/lang/String;)V

    invoke-interface {v0, v1}, Ljava/util/List;->add(Ljava/lang/Object;)Z

    .line 50
    new-instance v1, Lru/stellio/player/Helpers/i;

    const-string v2, "android_id"

    invoke-direct {v1, v2, p1}, Lru/stellio/player/Helpers/i;-><init>(Ljava/lang/String;Ljava/lang/String;)V

    invoke-interface {v0, v1}, Ljava/util/List;->add(Ljava/lang/Object;)Z

    .line 51
    new-instance v1, Lru/stellio/player/Helpers/i;

    const-string v2, "imei"

    invoke-static {}, Lru/stellio/player/App;->a()Lru/stellio/player/App;

    move-result-object v3

    invoke-static {v3}, Lru/stellio/player/Utils/k;->i(Landroid/content/Context;)Ljava/lang/String;

    move-result-object v3

    invoke-direct {v1, v2, v3}, Lru/stellio/player/Helpers/i;-><init>(Ljava/lang/String;Ljava/lang/String;)V

    invoke-interface {v0, v1}, Ljava/util/List;->add(Ljava/lang/Object;)Z

    .line 52
    new-instance v1, Lru/stellio/player/Helpers/i;

    const-string v2, "lock"

    invoke-static {}, Lru/stellio/player/MainActivity;->g3()Ljava/lang/String;

    move-result-object v3

    invoke-direct {v1, v2, v3}, Lru/stellio/player/Helpers/i;-><init>(Ljava/lang/String;Ljava/lang/String;)V

    invoke-interface {v0, v1}, Ljava/util/List;->add(Ljava/lang/Object;)Z

    .line 54
    invoke-static {}, Lru/stellio/player/Fragments/SettingsFragment;->d()Landroid/content/SharedPreferences;

    move-result-object v1

    .line 55
    new-instance v2, Lru/stellio/player/Helpers/i;

    const-string v3, "utm_source"

    const-string v4, "utm_source"

    invoke-interface {v1, v4, v5}, Landroid/content/SharedPreferences;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

    move-result-object v4

    invoke-direct {v2, v3, v4}, Lru/stellio/player/Helpers/i;-><init>(Ljava/lang/String;Ljava/lang/String;)V

    invoke-interface {v0, v2}, Ljava/util/List;->add(Ljava/lang/Object;)Z

    .line 56
    new-instance v2, Lru/stellio/player/Helpers/i;

    const-string v3, "utm_medium"

    const-string v4, "utm_medium"

    invoke-interface {v1, v4, v5}, Landroid/content/SharedPreferences;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-direct {v2, v3, v1}, Lru/stellio/player/Helpers/i;-><init>(Ljava/lang/String;Ljava/lang/String;)V

    invoke-interface {v0, v2}, Ljava/util/List;->add(Ljava/lang/Object;)Z

    .line 58
    if-eqz p2, :cond_0

    .line 59
    new-instance v1, Lru/stellio/player/Helpers/i;

    const-string v2, "bind"

    invoke-direct {v1, v2, p2}, Lru/stellio/player/Helpers/i;-><init>(Ljava/lang/String;Ljava/lang/String;)V

    invoke-interface {v0, v1}, Ljava/util/List;->add(Ljava/lang/Object;)Z

    .line 61
    :cond_0
    const-string v1, "http://stellio.ru/api/license.php"

    invoke-static {v1, v0}, Lru/stellio/player/Apis/c;->a(Ljava/lang/String;Ljava/util/List;)Ljava/lang/String;

    move-result-object v0

    .line 62
    invoke-static {v0}, Lru/stellio/player/Apis/c;->b(Ljava/lang/String;)Z

    move-result v0

    return v0
.end method

结合刚才抓包的图,看来找到关键的地方了。
由于这个方法是布尔值类型的,我尝试在最后强制令其返回true,果然激活成功了。
不过为了搞清楚来龙去脉,可以再往上一层走。
因它最后调用了b(Ljava/lang/String;)Z,所以去b(Ljava/lang/String;)Z看一下。
[Java] 纯文本查看 复制代码
.method private static b(Ljava/lang/String;)Z
    .locals 3

    .prologue
    .line 66
    const-string v0, "ok"

    invoke-virtual {v0, p0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v0

    if-eqz v0, :cond_0

    .line 67
    const/4 v0, 0x1

    .line 69
    :goto_0
    return v0

    .line 68
    :cond_0
    const-string v0, "error"

    invoke-virtual {v0, p0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v0

    if-eqz v0, :cond_1

    .line 69
    const/4 v0, 0x0

    goto :goto_0

    .line 71
    :cond_1
    new-instance v0, Ljava/io/IOException;

    new-instance v1, Ljava/lang/StringBuilder;

    invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V

    const-string v2, "Unknown server response "

    invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v1

    invoke-virtual {v1, p0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v1

    invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v1

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

    throw v0
.end method

这时就很清楚了:只有当返回 "ok"时,才激活成功。刚才返回"error"自然是激活失败的。
改法:删掉第一个跳转,这样永远返回真,于是无论是"ok"还是"error"都能激活成功了。


激活前后对比:


至此激活码破解篇结束。

二、激活码改造篇
本篇的目的:你只能使用我指定的激活码才能激活成功。
本篇的想法来源于最近很火的口令红包:
你要拿我的红包,必须输入我指定的口令。
同理,我们DIY一个「口令」激活码吧!

首先分析本软件的激活流程,以找到适合的切入点。

由于激活码的验证部分已经破解了,所以可考虑在激活码的格式上做文章。

1.隐藏的彩蛋?
按图索骥,找到激活码的格式代码:
[Java] 纯文本查看 复制代码
.method public static a(Ljava/lang/String;)Z
    .locals 3

    .prologue
    const/4 v1, 0x1

    const/4 v0, 0x0

    .line 48
    invoke-static {p0}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z

    move-result v2

    if-eqz v2, :cond_1
    //验证输入是否为空,非空跳到激活码的格式验证,否则返回false
	
    .line 58
    :cond_0
    :goto_0
    return v0

    .line 51
    :cond_1
    const-string v2, "[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}"
    //激活码的正确格式,和错误提示是一样。  
	  
    invoke-static {v2}, Ljava/util/regex/Pattern;->compile(Ljava/lang/String;)Ljava/util/regex/Pattern;

    move-result-object v2

    .line 53
    invoke-virtual {v2, p0}, Ljava/util/regex/Pattern;->matcher(Ljava/lang/CharSequence;)Ljava/util/regex/Matcher;

    move-result-object v2

    invoke-virtual {v2}, Ljava/util/regex/Matcher;->matches()Z

    move-result v2

    if-eqz v2, :cond_2
    //验证格式是否相符,相符则返回true
	
    move v0, v1

    .line 54
    goto :goto_0

    .line 55
    :cond_2
    const-string v2, "appoftheday"

    invoke-virtual {v2, p0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v2

    if-eqz v2, :cond_0
    //虽然格式不相符,但只要输入的是appoftheday,一样返回true!

    move v0, v1

    .line 56
    goto :goto_0
.end method

分析见注解,它既用了matches(相符),又用了equals(相等)。
如果格式相符,或者输入为"appoftheday",就通过激活码格式的验证了。
"appoftheday"作为隐藏要素,它是一枚特殊的激活码,经测试,也是无效的激活码。{:1_903:}

2.不一样的激活码:「口令」激活码
为了达到「口令」的效果,我们去掉matches代码,仅保留equals即可。
比如:
[Java] 纯文本查看 复制代码
.method public static a(Ljava/lang/String;)Z
    .locals 3

    const-string v0, "吾爱破解"

    invoke-virtual {v0, p0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v0

    if-eqz v0, :cond_0
//只能输入"吾爱破解",否则返回false
 
    const/4 v0, 0x1

    :goto_0
    return v0
	
    :cond_0
	
    const/4 v0, 0x0

    goto :goto_0
.end method

当然还要把提示改了,否则人家都不知道要输入什么了。
还有上面把激活码的格式限制去掉了,所以也要改回来的。
改造后的激活码如下图。


3.不一样的激活码:「口令」升级版
假如你不想这个「口令」千遍一律的话,也可以再改。
举个例子:别人必须输入手机的imei才能激活成功。
为了省事,首先看有没有哪个方法是描述读取手机imei的,然后我们改为调用该方法即可。
搜索getDeviceId。
[Java] 纯文本查看 复制代码
.method public static i(Landroid/content/Context;)Ljava/lang/String;
    .locals 1

    .prologue
    .line 409
    const-string v0, "android.permission.READ_PHONE_STATE"

    invoke-static {p0, v0}, Landroid/support/v4/content/a;->a(Landroid/content/Context;Ljava/lang/String;)I

    move-result v0

    if-eqz v0, :cond_0

    .line 410
    const-string v0, ""

    .line 413
    :goto_0
    return-object v0

    .line 412
    :cond_0
    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;

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

    move-result-object v0

    goto :goto_0
.end method

原来Lru/stellio/player/Utils/k;下的i(Landroid/content/Context;)Ljava/lang/String;就是读取imei的方法。
再搜索Lru/stellio/player/Utils/k;->i(Landroid/content/Context;)Ljava/lang/String; 时发现它已经被调用过了。
[Java] 纯文本查看 复制代码
const-string v2, "imei"

    invoke-static {}, Lru/stellio/player/App;->a()Lru/stellio/player/App;

    move-result-object v3

    invoke-static {v3}, Lru/stellio/player/Utils/k;->i(Landroid/content/Context;)Ljava/lang/String;

    move-result-object v3

简直天助我也,复制过去改一下就行了:
[Java] 纯文本查看 复制代码
.method public static a(Ljava/lang/String;)Z
.locals 3

invoke-static {}, Lru/stellio/player/App;->a()Lru/stellio/player/App;

move-result-object v0

invoke-static {v0}, Lru/stellio/player/Utils/k;->i(Landroid/content/Context;)Ljava/lang/String;

move-result-object v0
//调用了读取imei的方法

invoke-virtual {v0, p0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

move-result v0

if-eqz v0, :cond_0
//只能输入"手机imei",否则返回false

const/4 v0, 0x1

:goto_0
return v0

:cond_0

const/4 v0, 0x0

goto :goto_0
.end method

同样还要把提示改了,否则人家都不知道要输入什么了。

如你所见,这种「口令」激活码并非真正意义上的激活码,不过效果已经达到了。
至此激活码改造篇结束。

全文结束。代码贴多了,好像太长了。
附本文用到的app:
链接: http://pan.baidu.com/s/1dEnjHq5 密码: p7jh
有兴趣也可以研究一下,说不定有更多更有趣的发现哦!


点评

大神就是不一样,了解了好多思路  发表于 2016-1-11 11:54

免费评分

参与人数 28威望 +2 热心值 +28 收起 理由
junxuan + 1 我很赞同!
wxglorder + 1 谢谢@Thanks!
HookBug + 1 热心回复!
deuemiqpl + 1 谢谢@Thanks!
caleb110 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
nishinibabadeb + 1 用心讨论,共获提升!
熊大猫来了 + 1 我很赞同!
chenmintian + 1 热心回复!
嫖鸡不犯罪 + 1 虽然不太懂 ,但好像明白一些
zy1234 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
GodIand + 1 我很赞同!
tredawn + 1 热心回复!
tangdragon + 1 我很赞同!
吾为忘 + 1 用心讨论,共获提升!
ai枫 + 1 谢谢@Thanks!
public0712 + 1 一个破解牵出好几篇实用文章 感谢
myoldid + 1 没我爱币了
黑桃J + 1 思路清晰无比,代码不明所以
左岸麦田 + 1 我很赞同!
娄子建 + 1 鼓励转贴优秀软件安全工具和文档!
lies2014 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
夜之零落兮 + 1 我来顶你
noblesport + 1 我很赞同!
2317909768 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
就爱玩玩 + 1 谢谢@Thanks!
qtfreet00 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
renfeng + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
aikuimail + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.

查看全部评分

本帖被以下淘专辑推荐:

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

推荐
ly2121 发表于 2016-3-14 07:57
代码竟然未加密~都是裸码~
裸码的APK很容易分析~
这篇比较适合刚入坑的鞋童
推荐
13929861564 发表于 2016-1-16 12:26
看过楼主很多android破解的帖子,可以发一下你常用android破解工具的下载链接吗?我现在一直用androidkiller和fiddler
沙发
消炎止痛膏 发表于 2016-1-10 19:54
3#
就爱玩玩 发表于 2016-1-10 19:54
好详细的教程,我啥时候才能学会啊
4#
寂月 发表于 2016-1-10 19:54
大牛,学习了,本帖已经收藏,另外:我真的很难得抢到一楼
5#
xxxioneAald 发表于 2016-1-10 20:04 来自手机
楼主推荐一款安卓抓包的软件啊,平时不怎么接触电脑。。。
6#
蓦留 发表于 2016-1-10 20:05
已收藏,学习学习
7#
nuzamana 发表于 2016-1-10 20:12
好详细的教程  学习了
8#
52_po_jie 发表于 2016-1-10 20:17
很牛逼啊!
9#
jht168888 发表于 2016-1-10 20:17
嘿嘿 , 谢谢楼主分享
10#
一生情独醉 发表于 2016-1-10 20:19
楼主相当的有才!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-24 08:36

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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