欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]Android_Crackmes03_by_deurus破解小记

[原创]Android_Crackmes03_by_deurus破解小记

题记:破解这个Crackme是为了学习Android平台下的软件逆向技术,我是新手,所以就挑了个简单的进行分析。
先看看软件作者的要求:
Rules for the Crackme03 (Android) by deurus
===========================================
- Valid solutions are:
  - Make keygen + tuto and send to crackmes.de
Things to consider:
- Because this crackme need some info of phone, not run in emulator.
- Tested on HTC Magic with Android 2.2 but should be run in another android version.
主要是说,1> 写出keygen;2> 因为需要读取电话的某些信息,因而不能运行于模拟器中。但实际上只是不能运行于Google官方出的模拟器,而可以自定义硬件信息的模拟器是可以正常运行的,比如我们这次使用的天天模拟器。
特别说明:
因为是新手,所以大家如果发现文中有错误的地方,还望批评指正。
一、用到的工具
1. ApkIDE v3.3.3;
2. JEB v2.2.5;
3. 天天模拟器 v1.4.1047;
4. Android Studio v1.5 + DDMS + adb等;
二、静态分析
这里我们先通过静态分析来了解程序需要重点分析的地方在哪里,有没有可能只通过静态分析就可以得到有效的注册信息,以及是否存在爆破点等。
1. 用WinRAR打开该apk文件,发现里面没有lib文件夹,说明没有动态连接库文件需要分析,也说明程序的核心都在classes.dex文件里。
2. 分析过程
1> 在模拟器上安装并运行该Crackme,什么都不输入,直接点击Check按钮,提示“Min 4 chars”,如下图所示:

2> 根据上一步的提示,用ApkIDE打开Crackme03.apk文件,等待分析完毕后搜索"Min 4 chars",并在搜索结果里双击“const-string v23, " Min 4 chars"”,ApkIDE自动定位到HelloAndroid$2.smali文件中合适的位置,如下图所示:

3> 为了使反编译取得更佳的效果,我们使用JEB来反编译该apk,并根据“Min 4 chars”字符串定位到onClick函数,如下图:

对于上图中的
String v10 = HelloAndroid.this.findViewById(2131034116).getText().toString();

String v15 = HelloAndroid.this.findViewById(2131034118).getText().toString();
我们把数字2131034116转换为16进制后得到0x7F050004,把数字2131034118转换为16进制后得到0x7F050006。在资源文件的values/public.xml中,我们发现了如下信息:

<public id="0x7f050004" name="txt_name" type="id" />

......

<public id="0x7f050006" name="txt_serial" type="id" />

因此,我们可以把v10和v15分别重命名为name和serial(鼠标单击v10,然后按键盘上的n键,输入name即可,以下的重命名方法和此一样)。相应地,把v11重命名为nameLen。
一般情况下,我们把循环控制变量命名为i,j,k等,因此,我们在这里把v5重命名为i。
我们还知道getDeviceId()函数用于获取IMEI;getSimSerialNumber()函数用于获取ICCID,因此,我们把v6和v16分别重命名为imei和iccid,v19重命名为imeiSix。
重命名的最终结果如下图:

留意到下面的判断语句:
if(String.valueOf(tmp) + "-" + String.valueOf(((long)(Integer.parseInt(imeiSix) ^ Integer.parseInt(iccid.substring(0, 6))))) + "-" + imeiSix.equals(serial)) {

    Toast.makeText(HelloAndroid.this.getApplicationContext(), "God boy", 1).show();

}

else {

    Toast.makeText(HelloAndroid.this.getApplicationContext(), "Bad boy ", 1).show();

}

我们得知,如果String.valueOf(tmp) + "-" + String.valueOf(((long)(Integer.parseInt(imeiSix) ^ Integer.parseInt(iccid.substring(0, 6))))) + "-" + imeiSix的值等于我们输入的serial,那么显示"God boy"表示成功,不等则显示"Bad boy "表示失败。
4> 根据上面的判断语句,我们返回ApkIDE,在Dalvik指令中寻找判断点的位置。经过仔细分析,发觉下面的语句比较可疑:
.local v14, "serial":Ljava/lang/String;

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

move-result v22

if-eqz v22, :cond_2

如下图:

根据函数eaquals比较两个字符串的值是否相等推测v14为程序经过一系列计算后得到的真serial,而v15为输入的假serial。
为了验证我们的推测是否正确,我们修改HelloAndroid$2.smali文件,在其314行下面插入下面的Dalvik指令,以在DDMS(通过Windows中对sdk/tools/monitor.bat批处理脚本运行)输出v14和v15的值:
const-string v2, "=====v14====="

invoke-static {v2, v14}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I

const-string v2, "=====v15====="

invoke-static {v2, v15}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I


从而得到

在ApkIDE中保存修改后的内容,并点击菜单“编译”=>“编译生成Apk”,等待输出窗口提示成功编译并生成文件ApkIDE_Crackme03.apk后,把该apk文件安装到模拟器。
在运行程序前,我们在电脑上打开控制台,并输入adb connect 127.0.0.1:6555,然后运行DDMS,接着在模拟器中运行Crackme程序。
输入name为phrank,serial为112233后,点击Check按钮得到提示“Bad boy”,切换到DDMS查看输出的信息,能够发现有类似下面的两行信息:
08-23 14:42:01.378: V/=====v14=====(5122): 433116-591824-299725

08-23 14:42:01.378: V/=====v15=====(5122): 112233

显然,433116-591824-299725应该是真正的serial。重新把它输入到serial后点击Check按钮,提示”God Boy”,如下图:

上面说明我们的推测是正确的。
5> 根据上面的分析,修改源程序319行的指令if-eqz v22, :cond_2为if-nez v22, :cond_2是不是就可以达到爆破的目的呢?
但如果name继续为phrank,serail继续为433116-591824-299725呢?又或者serial为空呢?:D
6> 题外话
根据”Bad boy”推测这个”God boy”可能是笔误,应该为”Good boy”。
上面通过静态分析的方法我们得到了一组有效的注册信息,但并没有详细分析serial是怎么一步一步计算出来的;程序界面上的HardwareID 01和HardwareID 02我们可能已经推测出它们是硬件信息,但为什么要显示出来呢?在下一部分我们通过动态分析的方法来认识这个问题。
三、动态分析
本想用JEB直接调试的,但它总是提示“Could not attach to target”,所以,还是用Android Studio来调试,虽然稍微麻烦些。
使用Android Studio如何调试smali代码可以参考http://www.52pojie.cn/thread-505077-1-1.html和http://www.cnblogs.com/lanrenxinxin/p/4891424.html 。
1. 在ApkIDE中,打开AndroidManifest.xml文件,给<application android:icon="@drawable/icon">添加android:debuggable="true",得到:
<application android:icon="@drawable/icon" android:debuggable="true">
完整的AndroidManifest.xml文件内容如下:
<?xml version="1.0" encoding="utf-8" standalone="no"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.crackme03">

    <application android:icon="@drawable/icon" android:debuggable="true">

        <activity android:label="@string/app_name" android:name="com.example.helloandroid.HelloAndroid">

            <intent-filter>

                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>

            </intent-filter>

        </activity>

        <activity android:label="@string/app_name2" android:name="com.example.helloandroid.prueba2">

            <intent-filter>

                <action android:name="android.intent.action.MAIN"/>

            </intent-filter>

        </activity>

    </application>

    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>

</manifest>

保存后重新编译生成ApkIDE_Crackme03.apk文件并将其安装到模拟器。
2. 打开天天模拟器,并确认adb connect 127.0.0.1:6555正常工作着,然后在控制台执行命令
adb shell am start -D -n com.example.crackme03/com.example.helloandroid.HelloAndroid,目标程序会被启动并挂起,模拟器中会弹出等待调试的界面。其中,com.example.crackme03为package名,来源于AndroidManifest.xml文件中的<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.crackme03">,而com.example.helloandroid.HelloAndroid为Activity的名字,来源于AndroidManifest.xml文件中<activity android:label="@string/app_name" android:name="com.example.helloandroid.HelloAndroid"> android:name的值。
3. 用DDMS查看进程信息,得知目标程序的PID为3233,如下图:

4. 关闭DDMS,并在控制台中执行端口转发命令adb forward tcp:8700 jdwp:3233。其中3233就是上面通过DDMS得知的PID,其他照抄即可。
如果没有关闭DDMS而执行命令的话可能会得到错误提示error: cannot bind listener: cannot bind to 127.0.0.1:8700: Only one usage of each socket address (protocol/network address/port) is normally permitted. (10048),关闭DDMS后重新执行端口转发即可。
5. 把ApkIDE反编译结果的smali文件夹从ApkIDE的Work\com.example.crackme03拷贝到我们的分析目录(也可以不拷贝,直接使用),打开Android Studio,通过Import project(Eclipse ADT, Gradle, etc.)导入上面拷贝的smali目录的路径。
在Make Directory As/Sources root后,在Project Struct中设置java版本,如下图:

然后点击Run=>Edit configurations...菜单,设置添加Remote和设置端口8700,如下图:

6. 打开HelloAndroid$2.smali文件,定位到onClick,并在合适的地方下断点,Alt+Shift+F10运行,如下图所示:

根据需要,可以在界面的右下方的Watches中添加需要监视的变量,如v10等。
7. 分析过程
# virtual methods

.method public onClick(Landroid/view/View;)V

    .locals 25

    .param p1, "v"    # Landroid/view/View;

    .prologue

    .line 75

    move-object/from16 v0, p0   

    iget-object v0, v0, Lcom/example/helloandroid/HelloAndroid$2;->this$0:Lcom/example/helloandroid/HelloAndroid;

    move-object/from16 v22, v0

    const v23, 0x7f050004

    invoke-virtual/range {v22 .. v23}, Lcom/example/helloandroid/HelloAndroid;->findViewById(I)Landroid/view/View;

    move-result-object v9

    check-cast v9, Landroid/widget/EditText;

    .line 76

    .local v9, "name2":Landroid/widget/EditText;

    invoke-virtual {v9}, Landroid/widget/EditText;->getText()Landroid/text/Editable;

    move-result-object v22

    invoke-interface/range {v22 .. v22}, Landroid/text/Editable;->toString()Ljava/lang/String;

    move-result-object v10  // 这行得到name: phrank

    .line 77

    .local v10, "name3":Ljava/lang/String;

    invoke-virtual {v10}, Ljava/lang/String;->length()I

    move-result v11         // 得到name的长度nameLen: 6

    .line 78

    .local v11, "name3lenght":I

    const-string v12, ""

    .line 79

    .local v12, "name4":Ljava/lang/String;

    move-object/from16 v0, p0

    iget-object v0, v0, Lcom/example/helloandroid/HelloAndroid$2;->this$0:Lcom/example/helloandroid/HelloAndroid;

    move-object/from16 v22, v0

    const v23, 0x7f050006

    invoke-virtual/range {v22 .. v23}, Lcom/example/helloandroid/HelloAndroid;->findViewById(I)Landroid/view/View;

    move-result-object v21

    check-cast v21, Landroid/widget/EditText;

    .line 80

    .local v21, "txtserial":Landroid/widget/EditText;

    invoke-virtual/range {v21 .. v21}, Landroid/widget/EditText;->getText()Landroid/text/Editable;

    move-result-object v22

    invoke-interface/range {v22 .. v22}, Landroid/text/Editable;->toString()Ljava/lang/String;

    move-result-object v15      // 得到假serial: 112233

    .line 84

    .local v15, "serial_entered":Ljava/lang/String;

    const/16 v22, 0x4

    move v0, v11

    move/from16 v1, v22

    if-ge v0, v1, :cond_0   // nameLen 是否大于等于4

    .line 86

    :try_start_0

    move-object/from16 v0, p0

    iget-object v0, v0, Lcom/example/helloandroid/HelloAndroid$2;->this$0:Lcom/example/helloandroid/HelloAndroid;

    move-object/from16 v22, v0

    invoke-virtual/range {v22 .. v22}, Lcom/example/helloandroid/HelloAndroid;->getApplicationContext()Landroid/content/Context;

    move-result-object v22

    .line 87

    const-string v23, "Min 4 chars"

    const/16 v24, 0x1

    .line 86

    invoke-static/range {v22 .. v24}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v13

    .line 88

    .local v13, "notificacionToast":Landroid/widget/Toast;

    invoke-virtual {v13}, Landroid/widget/Toast;->show()V

    .line 129

    :goto_0

    return-void

    .line 92

    .end local v13    # "notificacionToast":Landroid/widget/Toast;

    :cond_0

    const/4 v5, 0x0

    .local v5, "i":I

    :goto_1

    invoke-virtual {v10}, Ljava/lang/String;->length()I

    move-result v22

    move v0, v5

    move/from16 v1, v22

    if-lt v0, v1, :cond_1

    .line 98    

    const/16 v22, 0x0   //  循环完毕后跳转到这里

    const/16 v23, 0x5

    move-object v0, v12

    move/from16 v1, v22

    move/from16 v2, v23

    invoke-virtual {v0, v1, v2}, Ljava/lang/String;->substring(II)Ljava/lang/String;    // 取tmp的前5个字符,v0[0:5] = "11210"

    move-result-object v12

    .line 99

    invoke-static {v12}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I             // 把上面的"11210"转换为整数类型,得11210

    move-result v22

    const v23, 0x6b016

    xor-int v22, v22, v23       // 上面的11210和0x6b016(十进制的438294)异或得:11210 xor 438294 = 433116

    invoke-static/range {v22 .. v22}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;  // 把433116转换为字符串,得"433116"

    move-result-object v12

    .line 100

    move-object/from16 v0, p0

    iget-object v0, v0, Lcom/example/helloandroid/HelloAndroid$2;->this$0:Lcom/example/helloandroid/HelloAndroid;

    move-object/from16 v22, v0

    const-string v23, "phone"

    invoke-virtual/range {v22 .. v23}, Lcom/example/helloandroid/HelloAndroid;->getSystemService(Ljava/lang/String;)Ljava/lang/Object;

    move-result-object v8

    check-cast v8, Landroid/telephony/TelephonyManager;

    .line 101

    .local v8, "mTelephonyMgr":Landroid/telephony/TelephonyManager;

    invoke-virtual {v8}, Landroid/telephony/TelephonyManager;->getDeviceId()Ljava/lang/String;  // 得到imei: "299725335498632"

    move-result-object v6

    .line 102

    .local v6, "imei2":Ljava/lang/String;

    invoke-virtual {v8}, Landroid/telephony/TelephonyManager;->getSimSerialNumber()Ljava/lang/String;   // 得到iccid: "89014103211118516789"

    move-result-object v16

    .line 103

    .local v16, "simsn":Ljava/lang/String;

    const-wide/16 v17, 0x0

    .line 104

    .local v17, "temp01":J

    const/16 v22, 0x0

    const/16 v23, 0x6

    move-object v0, v6

    move/from16 v1, v22

    move/from16 v2, v23

    invoke-virtual {v0, v1, v2}, Ljava/lang/String;->substring(II)Ljava/lang/String;    // 取imei的前6个字符,得

                                                                                        // 到imeiSix(就是上面的temp01,我们这

                                                                                        // 里使用我们自己的变量名): "299725"

    move-result-object v19

    .line 105

    .local v19, "temp02":Ljava/lang/String;

    const/16 v22, 0x0

    const/16 v23, 0x6

    move-object/from16 v0, v16

    move/from16 v1, v22

    move/from16 v2, v23

    invoke-virtual {v0, v1, v2}, Ljava/lang/String;->substring(II)Ljava/lang/String;    // 取iccid的前6个字符,得iccidSix: "890141"

                                                                                        // 对应于我们使用JEB反编译后的 iccid.substring(0, 6)

    move-result-object v20

    .line 106

    .local v20, "temp03":Ljava/lang/String;

    invoke-static/range {v19 .. v19}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I    // 把imeiSix字符串转换为整型,得299725

    move-result v22

    invoke-static/range {v20 .. v20}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I    // 把iccidSix转换为整型,得890141

    move-result v23

    xor-int v22, v22, v23   // 299725 xor 890141 = 591824

    move/from16 v0, v22

    int-to-long v0, v0

    move-wide/from16 v17, v0

    .line 107

    new-instance v22, Ljava/lang/StringBuilder;

    invoke-static {v12}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;

    move-result-object v23

    invoke-direct/range {v22 .. v23}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V

    const-string v23, "-"

    invoke-virtual/range {v22 .. v23}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v22  // 得到"433116-"

    invoke-static/range {v17 .. v18}, Ljava/lang/String;->valueOf(J)Ljava/lang/String;

    move-result-object v23

    invoke-virtual/range {v22 .. v23}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v22

    const-string v23, "-"

    invoke-virtual/range {v22 .. v23}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v22  // 得到"433116-591824-"

    move-object/from16 v0, v22

    move-object/from16 v1, v19

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

    move-result-object v22  // 得到"433116-591824-299725"

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

    move-result-object v14  // 这个v14就是我们在静态分析中通过DDMS输出的"433116-591824-299725"

    .line 109

    .local v14, "serial":Ljava/lang/String;

    invoke-virtual {v14, v15}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z  // 在这里比较v14和v15的值是否相等,也就是真serial和假serial作比较

    move-result v22 // true or false

    if-eqz v22, :cond_2     // 根据true or false进行跳转

    .line 111

    move-object/from16 v0, p0

    iget-object v0, v0, Lcom/example/helloandroid/HelloAndroid$2;->this$0:Lcom/example/helloandroid/HelloAndroid;

    move-object/from16 v22, v0

    invoke-virtual/range {v22 .. v22}, Lcom/example/helloandroid/HelloAndroid;->getApplicationContext()Landroid/content/Context;

    move-result-object v22

    .line 112

    const-string v23, "God boy"

    const/16 v24, 0x1

    .line 111

    invoke-static/range {v22 .. v24}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v13

    .line 113

    .restart local v13    # "notificacionToast":Landroid/widget/Toast;

    invoke-virtual {v13}, Landroid/widget/Toast;->show()V

    :try_end_0

    .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0

    goto/16 :goto_0

    .line 123

    .end local v5    # "i":I

    .end local v6    # "imei2":Ljava/lang/String;

    .end local v8    # "mTelephonyMgr":Landroid/telephony/TelephonyManager;

    .end local v13    # "notificacionToast":Landroid/widget/Toast;

    .end local v14    # "serial":Ljava/lang/String;

    .end local v16    # "simsn":Ljava/lang/String;

    .end local v17    # "temp01":J

    .end local v19    # "temp02":Ljava/lang/String;

    .end local v20    # "temp03":Ljava/lang/String;

    :catch_0

    move-exception v22

    move-object/from16 v4, v22

    .line 125

    .local v4, "ex":Ljava/lang/Exception;

    move-object/from16 v0, p0

    iget-object v0, v0, Lcom/example/helloandroid/HelloAndroid$2;->this$0:Lcom/example/helloandroid/HelloAndroid;

    move-object/from16 v22, v0

    invoke-virtual/range {v22 .. v22}, Lcom/example/helloandroid/HelloAndroid;->getApplicationContext()Landroid/content/Context;

    move-result-object v22

    .line 126

    const-string v23, "Another Error Ocurred :("

    const/16 v24, 0x1

    .line 125

    invoke-static/range {v22 .. v24}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v13

    .line 127

    .restart local v13    # "notificacionToast":Landroid/widget/Toast;

    invoke-virtual {v13}, Landroid/widget/Toast;->show()V

    goto/16 :goto_0

    .line 93

    .end local v4    # "ex":Ljava/lang/Exception;

    .end local v13    # "notificacionToast":Landroid/widget/Toast;

    .restart local v5    # "i":I

    :cond_1

    :try_start_1

    invoke-virtual {v10, v5}, Ljava/lang/String;->charAt(I)C    // name.charAt(i): 'p'(112), 'h'(104), 'r'(114), 'a'(97), 'n'(110), 'k'(107)

    move-result v3

    .line 94

    .local v3, "c":C

    move v7, v3

    .line 95

    .local v7, "j":I

    new-instance v22, Ljava/lang/StringBuilder;

    invoke-static {v12}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;

    move-result-object v23

    invoke-direct/range {v22 .. v23}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V

    move-object/from16 v0, v22

    move v1, v7

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

    move-result-object v22  // tmp: "112", "112104", "112104114", "11210411497", "11210411497110", "11210411497110107"

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

    move-result-object v12

    .line 92

    add-int/lit8 v5, v5, 0x1

    goto/16 :goto_1

    .line 116

    .end local v3    # "c":C

    .end local v7    # "j":I

    .restart local v6    # "imei2":Ljava/lang/String;

    .restart local v8    # "mTelephonyMgr":Landroid/telephony/TelephonyManager;

    .restart local v14    # "serial":Ljava/lang/String;

    .restart local v16    # "simsn":Ljava/lang/String;

    .restart local v17    # "temp01":J

    .restart local v19    # "temp02":Ljava/lang/String;

    .restart local v20    # "temp03":Ljava/lang/String;

    :cond_2

    move-object/from16 v0, p0   // 因为我们输入的假serial不正确,所以cond_2跳转到这里

    iget-object v0, v0, Lcom/example/helloandroid/HelloAndroid$2;->this$0:Lcom/example/helloandroid/HelloAndroid;

    move-object/from16 v22, v0

    invoke-virtual/range {v22 .. v22}, Lcom/example/helloandroid/HelloAndroid;->getApplicationContext()Landroid/content/Context;

    move-result-object v22

    .line 117

    const-string v23, "Bad boy "    // 要被提示的serial错误的字符串

    const/16 v24, 0x1

    .line 116

    invoke-static/range {v22 .. v24}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v13

    .line 118

    .restart local v13    # "notificacionToast":Landroid/widget/Toast;

    invoke-virtual {v13}, Landroid/widget/Toast;->show()V

    :try_end_1

    .catch Ljava/lang/Exception; {:try_start_1 .. :try_end_1} :catch_0

    goto/16 :goto_0

.end method


调试结束之前的Android Studio界面如下图:

整理下上面的分析过程:
1> 在循环中把name的每个字符转换为对应的整数形式的字符串"11210411497110107",并在串接后取其前5个字符,得到tmp: "11210",转换为整型后得11210;
2> 把11210和常数438294进行异或:11210 xor 438294 = 433116
3> 得到imei"299725335498632"和iccid"89014103211118516789";
4> 取imei的前6个字符得imeiSix: "299725";
5> 取iccid的前6个字符,得iccidSix: "890141";
6> imeiSix和iccidSix的整型形式相异或:299725 xor 890141 = 591824;
7> 使用"-"串接得到"433116-591824-299725"
分析的时候可多次在Watches窗口中添加vxx变量以观察寄存器的值。在JEB官方对调试功能的介绍一文(地址是https://www.pnfsoftware.com/blog/jeb-android-debuggers/)中得知JEB提供了Hover功能(我自己瞎取的名字),就是当鼠标放置于寄存器、变量、类名等上时显示相关的信息,包括寄存器和变量的值,这个简直是太方便了。目前调试功能还处于Beta版,不好用,让我们耐心地等待稳定版吧。
四、编写注册机
通过静态分析和动态分析,我们已经知道了serial的生成过程,为了验证我们的分析是否正确,我们编写一个注册机,代码如下:
import java.util.Scanner;

public class keygen {

    

    public static void main(String[] args)  throws Exception {

        System.out.print("Enter HardwareID 01:\t");

        Scanner scan = new Scanner(System.in);

        String imei = scan.nextLine();

        System.out.print("Enter HardwareID 02:\t");

        String iccid = scan.nextLine();

        System.out.print("Enter your name:\t");

        String name = scan.nextLine();

        

        if (name.length() < 4) {

            System.out.println("Min 4 chars\n");

            return;

        }

        

        String tmp = "";

        for (int i=0; i<name.length(); i++) {

            tmp = String.valueOf(tmp) + (int)(name.charAt(i));

        }

        tmp = String.valueOf(Integer.parseInt(tmp.substring(0, 5)) ^ 438294);

        String imeiSix = imei.substring(0, 6);

        String serial = String.valueOf(tmp) + "-" + String.valueOf(((long)(Integer.parseInt(imeiSix) ^ Integer.parseInt(iccid.substring(0, 6))))) + "-" + imeiSix;

        System.out.println("Your serial:\t\t" + serial);

    }

}


编译运行后可以试试输入不同的name而产生不同的serial,如另外一组:
Enter HardwareID 01:    299725335498632
Enter HardwareID 02:    89014103211118516789
Enter your name:        moon
Your serial:            432777-591824-299725
但可以发现当name为phrank和phrankmoon时生成的注册码是一样的,究其原因在于这一行:
invoke-virtual {v0, v1, v2}, Ljava/lang/String;->substring(II)Ljava/lang/String;    // 取tmp的前5个字符,v0[0:5] = "11210"

也就是说,tmp只取了name各字符转换为整型后并串接的字符串中的前5个字符"11210",因此,只有字母p和字母h真正参与了计算。
现在简单说一下程序界面上的HardwareID 01和HardwareID 02的作用,我推测是为了提供给他人,以方便他人检验注册机生成的serial是否正确。
五、后记
这个Crackme的算法简单,单纯的静态分析已经足够,动态分析主要是为了学习调试的方法。
还有一个就是感谢ApkIDE、Android Studio,JEB和天天模拟器的开发者以及背后工具的开发者,特别感谢currwin、maxking和scz对JEB所做的工作。
原Crackme在这里: Android_Crackmes03_by_deurus.zip

上传的附件 Min4Chars_small.PNG
Min4Chars_search.PNG
JEB_before_rename.png
rename_result.png
before_insert.PNG
insert_dalvik.PNG
Godboy.png
ddms_pid.png
java_sdk_version.png
remote_configuration.png
debug_getName.png
debugging_end.png
Android_Crackmes03_by_deurus.zip

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功