spguangz 发表于 2015-11-24 12:07

<名刊会>逆向破解手记:qq&新浪微博授权登录验证的分析和破解

<名刊会>是一款看杂志的手机app。我们不仅可以在软件的书籍里学到知识,还可以在其破解的过程中学到其他东西哦。
它有3个破解点:
1.破解微博授权登录验证
2.破解qq授权登录验证
3.破解会员特权

如图,从qq或新浪微博快速登录时都会对安装包进行验证。
就像2道门,一旦验证失败,我将被拒于门外。
所以先破掉它们。
http://www.52pojie.cn/static/image/hrline/4.gifhttp://www.52pojie.cn/static/image/hrline/4.gif

1.第一道门--微博授权登录验证
安装二次打包过的安装包,点击微博登录。
会发现不能登录并有错误提示:sso package or sign error
说明已被发现安装包是假货了。

在smali里搜索该提示,无果。应该是网络验证了。

1-1 微博授权登录验证破解方法一
淡然在<开心消消乐>简单的逆向破解过程一文中提到:
一般来说,一个程序要想支持QQ和新浪微博的接口登录,都必须事先将自己签名的MD5放到接口的后台官网来申请登录SDK,如果签名不一致则拒接登录。所以要解除它们的登录限制,可在反编译的SDK的Smali文件中,让它读取正版包的签名信息。所以这里用到的方法是常用的"自定义验证包路径"。具体操作如下:
1.把真包改名为123.apk,然后放到sdcard里。即路径为/sdcard/123.apk
2.搜索pm/PackageManager;->getPackageInfo
3.自定义安装包路径,并将getPackageInfo改为getPackageArchiveInfo,
   意思是根据自定义的路径读取该apk的签名。
一个修改好的例子如下:
iget-object v2, v2, Landroid/content/pm/ResolveInfo;->activityInfo:Landroid/content/pm/ActivityInfo;

    iget-object v2, v2, Landroid/content/pm/ActivityInfo;->packageName:Ljava/lang/String;

    const-string v2, "/sdcard/123.apk"
    //自定义安装包路径

    .line 61
    const/16 v3, 0x40

    :try_start_0
    invoke-virtual {v1, v2, v3}, Landroid/content/pm/PackageManager;->getPackageArchiveInfo(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;
//修改为getPackageArchiveInfo

move-result-object v1
因为是破解微博的登录验证,所以只在带有weibo的smali里修改即可。

回编译--测试--可以成功登录了。

1-2 微博授权登录验证破解方法二
1-1的方法略显麻烦,所以探索出一种简单点的方法。
就是通过运行真包和假包,在登录微博时分别进行抓包操作,分析两者的差异


明显感觉key_hash就是关键了,进行搜索。

还记得刚才那句错误提示吗?sso package or sign error
所以直接改带有sso字眼的那个smali,令key_hash为真包的key_hash即可。

const-string v1, "key_hash"

    iget-object v2, p0, Lcom/sina/weibo/sdk/auth/sso/b;->i:Lcom/sina/weibo/sdk/auth/a;

    invoke-virtual {v2}, Lcom/sina/weibo/sdk/auth/a;->e()Ljava/lang/String;

    move-result-object v2
   
    const-string v2, "62b2279963932cb2c4c50116c3370c14"
    //令读取到的key_hash为真包的key_hash

    invoke-virtual {v0, v1, v2}, Lcom/sina/weibo/sdk/net/h;->b(Ljava/lang/String;Ljava/lang/String;)V
或者通过修改跳转,跳过key_hash的验证也行:

if-ne v1, p2, :cond_2
    //改为goto :cond_2,以跳过key_hash的验证

    const-string v1, "packagename"

    iget-object v2, p0, Lcom/sina/weibo/sdk/auth/sso/b;->i:Lcom/sina/weibo/sdk/auth/a;

    invoke-virtual {v2}, Lcom/sina/weibo/sdk/auth/a;->d()Ljava/lang/String;

    move-result-object v2

    invoke-virtual {v0, v1, v2}, Lcom/sina/weibo/sdk/net/h;->b(Ljava/lang/String;Ljava/lang/String;)V

    .line 109
    const-string v1, "key_hash"

    iget-object v2, p0, Lcom/sina/weibo/sdk/auth/sso/b;->i:Lcom/sina/weibo/sdk/auth/a;

    invoke-virtual {v2}, Lcom/sina/weibo/sdk/auth/a;->e()Ljava/lang/String;

    move-result-object v2

    invoke-virtual {v0, v1, v2}, Lcom/sina/weibo/sdk/net/h;->b(Ljava/lang/String;Ljava/lang/String;)V

    .line 112
    :cond_2
    new-instance v1, Ljava/lang/StringBuilder;


//省略
回编译--测试--可以成功登录了。
http://www.52pojie.cn/static/image/hrline/4.gifhttp://www.52pojie.cn/static/image/hrline/4.gif
2.第二道门--qq授权登录验证
安装二次打包过的安装包,点击qq登录。
会发现不能登录并提示是山寨版。


先尝试1-1的"自定义验证包路径"的方法,发现并不奏效。
而且通过抓包也找不到关键的信息,所以试试别的方法。
看看log寻找关键,点击qq登录时,有一处红色的log:
Tag: openSDK_LOG
Message: OpenUi, onActivityResult, onError = 100044
搜索OpenUi, onActivityResult, onError =
来到这里:

:cond_3
    const-string v1, "openSDK_LOG"

    new-instance v2, Ljava/lang/StringBuilder;

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

    const-string v3, "OpenUi, onActivityResult,"

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

    move-result-object v2

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

    move-result-object v2

    invoke-static {v1, v2}, Lcom/tencent/open/a/f;->e(Ljava/lang/String;Ljava/lang/String;)V

    .line 158
    const-string v1, "key_error_msg"

    invoke-virtual {p0, v1}, Landroid/content/Intent;->getStringExtra(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    .line 159
    const-string v2, "key_error_detail"

    invoke-virtual {p0, v2}, Landroid/content/Intent;->getStringExtra(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v2

    .line 160
    new-instance v3, Lcom/tencent/tauth/UiError;

    invoke-direct {v3, v0, v1, v2}, Lcom/tencent/tauth/UiError;-><init>(ILjava/lang/String;Ljava/lang/String;)V

    invoke-interface {p1, v3}, Lcom/tencent/tauth/IUiListener;->onError(Lcom/tencent/tauth/UiError;)V

    goto :goto_0
:cond_3最后是调用onError(Lcom/tencent/tauth/UiError;)V,使验证出错。
再往上看几行,看到:

:cond_2
    const-string v0, "openSDK_LOG"

    const-string v1, "OpenUi, onActivityResult, onComplete"

    invoke-static {v0, v1}, Lcom/tencent/open/a/f;->b(Ljava/lang/String;Ljava/lang/String;)V

    .line 154
    new-instance v0, Lorg/json/JSONObject;

    invoke-direct {v0}, Lorg/json/JSONObject;-><init>()V

    invoke-interface {p1, v0}, Lcom/tencent/tauth/IUiListener;->onComplete(Ljava/lang/Object;)V

    goto :goto_0
:cond_2最后是调用onComplete(Ljava/lang/Object;)V,即完成验证。
所以在:cond_3的开头,添加一个跳转goto :cond_2。
如此,令本来走到onError的代码,改跳到onComplete,以完成验证。
回编译后,经测试,虽然还会弹出那个错误码提示,但还是能成功登录的。
http://www.52pojie.cn/static/image/hrline/4.gifhttp://www.52pojie.cn/static/image/hrline/4.gif
3.破解会员
两道门都破掉后,接下来开始破解会员。

先看提示:

通过几次搜索后,轻松找到关键:

check-cast v0, Lcom/qikan/dy/lydingyue/modal/Content;

    invoke-virtual {v0}, Lcom/qikan/dy/lydingyue/modal/Content;->getId()Ljava/lang/String;

    move-result-object v0

    invoke-virtual {v1, v2, v0}, Lcom/qikan/dy/lydingyue/modal/User;->isValid(Ljava/lang/String;Ljava/lang/String;)Z

    move-result v0
//判断是不是会员

    if-nez v0, :cond_0
//不是会员则往下走,否则跳到:cond_0

    .line 347
    invoke-static {p1}, Lcom/qikan/dy/lydingyue/util/i;->a(Landroid/content/Context;)V
//这是上面的提示框

    .line 358
    :goto_0
    return-void

    .line 351
    :cond_0
    new-instance v0, Landroid/content/Intent;

    const-class v1, Lcom/qikan/dy/lydingyue/activity/ArticleActivity;

//省略
所以,isValid是判断会员的地方。


或者,通过抓包能看到更详细的信息:

{
        "Code": "0000",
        "Msg": "操作成功",
        "AuthCode": "1L0ytR5vziMyG...", //授权码
        "UserName": "spguangzhcbcgd", //用户名
        "Email": "xxxx@qq.com",//邮箱
        "UserMobile": "",
        "PayItem": "Month",            //支付方式:包月
        "ValidTime": "2015-12-17 0:57:10",//会员到期时间
        "IsValid": 1,                            //是不是会员:是           "LoginForm": 2                      //登录方式:2
}最后做如下修改即为会员版了:

.method public isValid(Ljava/lang/String;Ljava/lang/String;)Z
    .locals 2

    .prologue
    const/4 v0, 0x1

    .line 228
    iget v1, p0, Lcom/qikan/dy/lydingyue/modal/User;->isValid:I

    if-ne v1, v0, :cond_0

    .line 232
    :goto_0
const/4 v0, 0x1
//强制返回真,一直是会员

    return v0

    :cond_0
    new-instance v0, Ljava/lang/StringBuilder;

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

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

    move-result-object v0

    const-string v1, ","

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

    move-result-object v0

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

    move-result-object v0

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

    move-result-object v0

    invoke-direct {p0, v0}, Lcom/qikan/dy/lydingyue/modal/User;->isInTen(Ljava/lang/String;)Z

    move-result v0

    goto :goto_0
.end method

至此完成<名刊会>的所有破解。{:301_1003:}
言不达意,感谢观看!

淡然出尘 发表于 2016-2-29 15:24

赞一个
-----
那个123.apk不需要完整的apk,这样有点累赘,只需保留其中的AndroidManifest.xml和META-INF文件夹即可;
微博去SSO验证码抓包方法比较赞;

十一大魔王i 发表于 2016-2-29 12:21

大神,, 在在用改之理反编译008... 提示失败,
代码如下,,
失败:Exception in thread "main" brut.androlib.AndrolibException: brut.directory.DirectoryException: java.util.zip.ZipException: invalid CEN header (bad signature)
        at brut.androlib.ApkDecoder.hasResources(ApkDecoder.java:293)
        at brut.androlib.ApkDecoder.decode(ApkDecoder.java:91)
        at brut.apktool.Main.cmdDecode(Main.java:165)
        at brut.apktool.Main.main(Main.java:81)
Caused by: brut.directory.DirectoryException: java.util.zip.ZipException: invalid CEN header (bad signature)
        at brut.directory.ZipRODirectory.<init>(ZipRODirectory.java:55)
        at brut.directory.ZipRODirectory.<init>(ZipRODirectory.java:38)
        at brut.androlib.res.util.ExtFile.getDirectory(ExtFile.java:55)
        at brut.androlib.ApkDecoder.hasResources(ApkDecoder.java:291)
        ... 3 more
Caused by: java.util.zip.ZipException: invalid CEN header (bad signature)
        at java.util.zip.ZipFile.open(Native Method)
        at java.util.zip.ZipFile.<init>(ZipFile.java:219)
        at java.util.zip.ZipFile.<init>(ZipFile.java:149)
        at java.util.zip.ZipFile.<init>(ZipFile.java:163)
        at brut.directory.ZipRODirectory.<init>(ZipRODirectory.java:53)
        ... 6 more

飘零的殇 发表于 2015-11-24 12:11

好6 的思路,仔细看看

hellokits 发表于 2015-11-24 12:20

御神箭之翼 发表于 2015-11-24 12:28

简直掉渣了

windwing1883 发表于 2015-11-24 13:03

学习了,多谢分享

蚍蜉撼象 发表于 2015-11-24 13:04

很棒,学习了

395145609zxl 发表于 2015-11-24 17:38

谢谢楼主.支持楼主

就爱玩玩 发表于 2015-11-24 19:11

只能羡慕大神

xugong 发表于 2015-11-24 19:39

大神就是厉害

程维佳 发表于 2015-11-24 23:33

长知识了
页: [1] 2 3 4
查看完整版本: <名刊会>逆向破解手记:qq&新浪微博授权登录验证的分析和破解