全文的Bao均为暴,由于Bao力这个词存在,所以不让发布,只有这样改着---⊙﹏⊙b汗
这一节要解密的apk要求输入用户名和序列号,如果匹配则通过Toast显示一个Lisence Correct! 否则 则显示 Lisence Uncorrect!
启动界面
错误的用户名和序列号
和前面的apk不同的是,这个apk要求输入用户名和序列号,且采用了前文的第三种序列号保护验证模式,即采用了:
F1(用户名) = F2(序列号)
1、通过Bao破破解程序
通常来说,若F1、F2其一可逆转。找出正确序列号的方法就是要找出这么一种F1或F2的逆变换。若F1或F2函数比较简单,找出逆变换写出注册机是可行的,这也是很多cracker追求的解密方式,且此方法不破坏原apk的完整性。但有些时候,为了追求迅速解密软件的序列号保护,很多人会选择使用Bao破解。Bao力破解的着手点在最终的比较代码上。不管采用哪种序列号的保护验证模式,最后必然会存在这么一种类似的比较的方式。以伪代码贴出:
if A 等于 B
{
//验证正确
//do something
}
else
{
//验证失败
//do something
}
Bao力破解的要点在于修改判断语句的条件。把“等于”改成“不等于”,或者是把“不等于”改成“等于”。那么此时,随便输入错误的用户名和序列号,就能进入到“验证正确”的板块去,从而成功的注册软件。
在汇编语言中,Bao力破解也是类似的原理。
je或jz //相等则跳(机器码是74或84)
jne或jnz //不相等则跳(机器码是75或85)
常见的修改就是把对比部分的机器码中74改成75或者84改成85,在反编译的smali文件中,也是类似的。
符号 | smali语法 | Bao力破解修改 |
== | if-eq | if-eq改成if-ne |
!= | if-ne | if-ne 改成 if-eq |
equals | if-eqz | if-eqz改成 if-nez |
!equals | if-nez | if-nez 改成if-eqz |
Bao力破解CrackMe-F1F2的过程:
(1)、使用apktool反编译CrackMe-F1F Apk程序,得到反编译后的文件。
(2)、在smali源码中找到判断比较的入口,修改判断条件。
//若不相等,则跳转到cond_4,此处就是密文的比较
.line 80
if-ne v2, v3, :cond_4
..
//cond_4处,使用Toast显示Lisence Uncorrect!
:cond_4
..
const-string v7, "Lisence Uncorrect/uff01"
…
invoke-virtual {v6}, Landroid/widget/Toast;->show()V
我们就是把上面的
if-ne v2, v3, :cond_4
修改成
if-eq v2, v3, :cond_4
至此该apk序列号Bao力破解的核心步骤就完成了。
(3)、使用apktool和signapk打包并签名apk。
(4)、上传到虚拟机中测试。
使用adb push到虚拟机中进行测试,随便在用户名和序列号输入框中输入任意的非正确组合,均能显示“Lisence Correct!”。如下图:
2、逆变换—写出注册机
阅读F1和F2函数的smali代码就不再重复了,这仅仅需要的是耐心,因为反编译出来的smali代码多跳转也多,相对比较难读,不过比汇编还是容易读懂一些。下面列举此apk使用的两个F1,F2函数的JAVA代码。完成其一函数大的逆转来帮助我们完成这个apk的注册机。
F1、F2函数
//F1函数部分,s1为输入的用户名
2 char ch;
3 for (i = 0 ; i < s1 . length ();i + + )
4 {
5 ch = s1 . charAt(i);
6 if (ch < ' A ' ) break ;
7 if (ch > ' Z ' ) ch - = 32 ;
8 k1 = k1 + ch;
9 }
10 k1 = k1 ^ 0x5678;
//F2函数部分,s2为输入的序列号
2 for (i = 0 ;i < s2 . length (); i + + )
3 {
4 ch = s2 . charAt(i);
5 ch – = 48 ;
6 k2 = k2 * 10 + ch;
7 }
8 k2 = k2 ^ 0x1234;
原apk就是这样,若k1==k2,那么验证成功,否则验证失败。
可以看出 F2函数的循环部分,仅仅是把序列号s2从字符串转换为整型,存于k2中,此处的k2我们成为k2[序列号]。最后做异或运算,从而得出密文,覆盖于k2中,此处的k2成为k2[密文]。在异或运算中,若存在
c = a xor b (对应到F2函数中的最后一步,即 k2[密文] = k2[序列号] xor 0x1234)
则a=c xor b (对应着k2[序列号] = k2[密文] xor 0x1234)
也就是说通过 密文 xor 0x1234 就能得到序列号
在F1函数的结果也就是密文。所以,注册机的写法也就出来了:把F1的结果 xor 0x1234就是对应用户名的正确的序列号。
注册机的核心代码
2 int k3 = 0 ;
3 char ch;
4 for (i = 0 ; i < s1 . length (); i + + )
5 {
6 ch = s1 . charAt(i);
7 if (ch < ' A ' ) break ;
8 if (ch > ' Z ' )
9 ch - = 32 ;
10 k3 = k3 + ch;
11 }
12 k3 = k3 ^ 0x5678 ^ 0x1234 ;
//s1为用户名,k3为根据s1算出来的正确的序列号,单独写一个注册机,然后通过注册机计算”Ethan”的序列号,正确序列号为17724,验证通过。
正确的用户名和序列号
原apk放于共享资源中,需要的请自行前往下载。