<名刊会>逆向破解手记: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:}
言不达意,感谢观看!
赞一个
-----
那个123.apk不需要完整的apk,这样有点累赘,只需保留其中的AndroidManifest.xml和META-INF文件夹即可;
微博去SSO验证码抓包方法比较赞; 大神,, 在在用改之理反编译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 好6 的思路,仔细看看 简直掉渣了 学习了,多谢分享 很棒,学习了 谢谢楼主.支持楼主 只能羡慕大神 大神就是厉害 长知识了