Android Apk解密工程初探(4)-- Bao力破解与简单逆变换

来源:互联网 发布:sha256算法实现原理 编辑:程序博客网 时间:2024/05/01 05:56

全文的Bao均为暴,由于Bao力这个词存在,所以不让发布,只有这样改着---⊙﹏⊙b汗

这一节要解密的apk要求输入用户名和序列号,如果匹配则通过Toast显示一个Lisence Correct! 否则 则显示 Lisence Uncorrect!

clip_image002

启动界面

clip_image004

错误的用户名和序列号

和前面的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中的表示

符号

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程序,得到反编译后的文件。

clip_image006

(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!”。如下图:

clip_image008

2、逆变换—写出注册机

阅读F1和F2函数的smali代码就不再重复了,这仅仅需要的是耐心,因为反编译出来的smali代码多跳转也多,相对比较难读,不过比汇编还是容易读懂一些。下面列举此apk使用的两个F1,F2函数的JAVA代码。完成其一函数大的逆转来帮助我们完成这个apk的注册机。

F1、F2函数

//F1函数部分,s1为输入的用户名

int i = 0,k1 = 0;;
char ch;
for (i = 0; i<s1.length();i++)
{
ch = s1.charAt(i);
if (ch < 'A') break;
if (ch > 'Z') ch -= 32;
k1 = k1 + ch;
}
10 k1 = k1 ^ 0x5678;

//F2函数部分,s2为输入的序列号

1 int k2 = 0;
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就是对应用户名的正确的序列号。

注册机的核心代码

 

int i = 0;
int k3 = 0;
char ch;
for (i = 0; i < s1.length(); i++)
{
    ch = s1.charAt(i);
    if (ch < 'A') break;
    if (ch > 'Z')
    ch -= 32;
10     k3 = k3 + ch;
11 }
12 k3 = k3 ^ 0x5678 ^ 0x1234;

//s1为用户名,k3为根据s1算出来的正确的序列号,单独写一个注册机,然后通过注册机计算”Ethan”的序列号,正确序列号为17724,验证通过。

clip_image010

正确的用户名和序列号

 

原apk放于共享资源中,需要的请自行前往下载。

原创粉丝点击