吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 23746|回复: 58
收起左侧

[Android 原创] 某司面试三题

[复制链接]
Terrorblade 发表于 2015-8-19 21:59
0x00 前言
前一段时间,向某公司投了简历,我投的不是android逆向,但是我的简历却被转发,于是我只能硬着头皮上了。之前只是零星学过两个月的java,因为当时是大三到大四那个暑假过度期学的,我们那时已经开始找工作了,考研的也奔向自己心仪的学校面试什么的去了,所以很多人都缺勤,我也一样,没办法。因为对java的认识不够深,一直停留在源代码都被反编译出来了,也就无所谓逆向的观念中,而且,说真的,我并不是很喜欢java,感觉它好冗余……但是接触了这3道题之后,观点还是有所改变的,所以才决定抛砖引玉,把我的一些愚见写出来,向大家学习一下!


0x01 smali爆破
趁着AVD还在启动中,这里先吐槽一下BlueStacks,妹子的,被这模拟器给坑惨了,先是没有root,然后又是跟ddms各种不配合,搞的我有些问题憋了两三天可能都憋不出来,然后就是android SDK,换了好多个版本,才运行了起来,之前就是一直黑屏,有一个“android”字样在主屏闪动,一直进不到主界面……当然,还有其他很多问题,这里就不多说了,说多都是泪……

在apkIDE中,把apk反编译后,得到了smali代码,其实3道题,都没有对dex进行加密,所以很容易得到smali代码,但是,这题有一个函数出现了error,就是没法解析,如图1:
   1.png
       图1.关键函数反编译错误

Q1.这里到底用什么方式,让此函数反编译错误?

好,先不纠结这一环,来看看MainActivity.class的onCreate()函数,扫描一下,他是如何才能走向成功(感觉这题,很多都是一目了然,但是就是没法做到完美),上代码:
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
protected void onCreate(Bundle paramBundle)
{
  super.onCreate(paramBundle);
  setContentView(2130903064);
  this.meditText =((EditText)findViewById(2131034173));
  this.mButton =((Button)findViewById(2131034174));
  this.mButton.setOnClickListener(newView.OnClickListener()
  {
    public void onClick(ViewparamAnonymousView)
    {
      String str1 =MainActivity.this.meditText.getText().toString();
      String str3 =MainActivity.this.cccccc();
      String str2 =MainActivity.this.gagagfffafa();
      paramAnonymousView = null;
      try
      {
        str1 =MainActivity.bytesToAliSmsCode(str3, str1.getBytes("utf-8"));
        paramAnonymousView = str1;
      }
      catch (UnsupportedEncodingExceptionlocalUnsupportedEncodingException)
      {
        for (;;)
        {
         localUnsupportedEncodingException.printStackTrace();
        }
        Toast.makeText(MainActivity.this,"恭喜你!登录成功", 0).show();
      }
      if ((str2 == null) ||(str2.equals("")) || (!str2.equals(paramAnonymousView)))
      {
        Toast.makeText(MainActivity.this,"密码错误!登录失败", 0).show();
        return;
      }
    }
  });
}


验证放在异常中,而不是在if判断,确实让人耳目一新,把思路整理一下:
1.  str1 = MainActivity.bytesToAliSmsCode(str3,str1.getBytes("utf-8"));这里我们知道,只要计算出str1就ok了
2.  但是他要和str3做相关计算,而String str3 = MainActivity.this.cccccc();,cccccc()就是这个没有反编译的出来的函数就是关键了
3.  if ((str2 == null) ||(str2.equals("")) || (!str2.equals(paramAnonymousView))),看到这句代码,验证好像是双线的,就是说String str2 = MainActivity.this.gagagfffafa();通过gagagfffafa()计算出str2也可以登陆成功!

接着,我们来看看如何爆破了,关键地方是line 41,如图2:
2.png
     图2.爆破关键点

Btw,52pojie论坛里好像都没有smali语法的汇总,这里粘贴一个:http://www.blogjava.net/midea0978/archive/2012/01/04/367847.html,虽然是英文,但是汇总得还是很好的,改完以后,编译生成apk,然后再安装,试试效果:
3.png
       图3.爆破成功

0x02 smali注入
在非虫的《Android软件安全与逆向分析》曾提到smali注入,就是一个程序可以通过Log()打印出真正的注册码,我们这里也来尝试一下,通过图2的注释,已经告诉大家,v1就是真正的注册码,那么我们只需要打印出v1的值,也就得到注册码了,好,看下面的语句:
         const-stringv5, "SN"
         invoke-static{v5, v1}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I

把上面两句添加进MainActivity$1.smali中,如图4:
    4.png
          图4.添加注入代码

但是,我遇到了问题,起初,我以为是gb2312格式编码的问题,然后我换成了utf-8,如图5:
5.png
      图5.改变格式编码为utf-8
                                                                                                               
重新编译并且安装,测试效果如图6:
   6.png
                图6.乱码

Q2.smali注入后,为什么是乱码?

0x03 java keygen
OK,这道题,其实要求写注册机的,开头也说了,我只零星学过两个月java,所以……注册机我写了,但是没编译通过,这里也把我的代码贴上,不怕献丑,只想求教!
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
importjava.io.BufferedReader;
importjava.io.ByteArrayInputStream;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.io.UnsupportedEncodingException;
importjavax.annotation.Resources;
importjavax.naming.Context;
//importandroid.content.Context;
publicclass Keygen
{
    public static Context context;
    public static void main(String[] args)throws UnsupportedEncodingException
    {
        // TODO Auto-generated method stub
        String one = cccccc();          //略显蛋疼
        String two = "Terrorblade";
        String result = null;
        result = bytesToAliSmsCode(one,two.getBytes("utf-8"));
        System.out.println(result);
    }
    
    public static StringbytesToAliSmsCode(String paramString, byte[] paramArrayOfByte)
    {
        StringBuilder localStringBuilder = newStringBuilder();
        int i = 0;
        for (;;)
        {
            if (i >= paramArrayOfByte.length)
            {
                return localStringBuilder.toString();
            }
             
            //直接复制,却有下面的异常!
            //Exception in thread"main" java.lang.NullPointerException
            localStringBuilder.append(paramString.charAt(paramArrayOfByte& 0xFF));
            i += 1;
        }
    }
    
    protected static String cccccc()
    {
        int v3 = 0x0;
        //Resourcs p0 = getResources(); //这里不知道怎么回事
        String v11 = "abcdefghddddd";
        try
        {
            //InputStream is =context.getResources().getAssets().open(v11);  //getResources()什么鸡吧?前面得有context!
            InputStream is = newByteArrayInputStream(v11.getBytes());
            v3 = is.available();
            byte[] v1 = new byte[v3] ;
            is.read(v1, 0, v3);
            byte[] v2 = new byte[0x300];
             
            //java.lang.ArrayIndexOutOfBoundsException
            System.arraycopy(v1, 0x15d81, v2,0x0, 0x300);  //89473, 768
             
            //下面这些实在不懂什么意思了
            //new-instance v7,Ljava/lang/String;           #新实例
            // invoke-direct {v7, v2, v10},Ljava/lang/String;-><init>([BLjava/lang/String;)V
             
            //遂强制转换
            String v7 = new String(v2,"utf-8");
            return v7;        
             
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        //try 取自[url=http://www.cnblogs.com/greatverve/archive/2012/03/08/android-assets.html]http://www.cnblogs.com/greatverve/archive/2012/03/08/android-assets.html[/url]
         
        return null;
    }
    
}


Q3.第48行,getResources()到底是怎么用的?
Q4. 直接贴出来,数组越界&空指针?
java.lang.ArrayIndexOutOfBoundsException
    at java.lang.System.arraycopy(Native Method)
    at Keygen.cccccc(Keygen.java:60)
    at Keygen.main(Keygen.java:19)
Exceptionin thread "main" java.lang.NullPointerException
    at Keygen.bytesToAliSmsCode(Keygen.java:39)
    at Keygen.main(Keygen.java:22)
Q5.注册机可以参照gagagfffafa()的,开头也说了,可能是双线认证,我试过照着gagagfffafa()写,麻烦也不小,那gagagfffafa()是否也是算法函数呢?
0x04 后序
第一篇,感觉有点虎头蛇尾,不过,精彩的永远在后面,请大家继续支持!

传送门:
某司面试题二:so调试 & 汉诺塔:
http://www.52pojie.cn/thread-403063-1-1.html
某司面试题三:fork & ptrace:
http://www.52pojie.cn/thread-403089-1-1.html

本题所有文件:
第一题.rar (911.54 KB, 下载次数: 152)

点评

第一题并不会显示注册码,是通过注册码去查表,最后输出的其实是中间码  发表于 2015-8-21 09:38

免费评分

参与人数 5威望 +2 热心值 +5 收起 理由
superu + 1 谢谢@Thanks!
qtfreet00 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
lifushan0 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.
Ericky + 1 + 1 可以一并把2,3题放上来 让大家都看看
Pizza + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩.

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| Terrorblade 发表于 2015-8-19 23:01

某司面试题二:so调试 & 汉诺塔

本帖最后由 Terrorblade 于 2015-8-20 01:10 编辑

0x00 前言
终于摆脱了冗余的java,来到了与ARM汇编正面交锋的第二题,验证代码在libclacSn.so文件的Java_com_ucweb_crackme140522_MainActivity_clacSnFuntion中,这里不得不说一句,计算的英文单词是calculate,能把calc写成clac,还有就是Function,这也能写成Funtion ,一个大公司,如此不严谨,看着也是有点醉了……

0x01 so调试前奏
本来这部分不应该赘述的,网上已经有很多了,我再说,也觉得是浪费我自己的时间,我当时看的是乌云知识库的一篇文章,还有就是52pojie的http://www.52pojie.cn/thread-293648-1-1.html,但是这两篇文章,有些细节都没有说清楚,至少,我在参照这两篇文章调戏cm2的时候,还是遇到不少问题的,另外,为了整个系列的完整性,最终,还是决定把so调试的过程加入文章!

1.以调试模式启动程序,命令:
amstart -D -n com.ucweb.crackme140522/.MainActivity
1.png
图1.启动程序

2.启动android_server,这个文件在ida的dbgsrv文件夹中,需要上传到avd中,这里不多说,这些细节那两篇绝对说过的,命令:
/data/local/tmp/android_server
2.png
图2.已经在监听23946端口了

3.启动ddms,就是sdk目录中的ddms.bat
3.png
图3.启动ddms

4.端口转发,另外启动一个cmd,执行命令:
4.png
图4.端口转发

5.此时可以启动ida了,debugger->attach ->remote arm linux  /android debugger, 然后:
5.png
图5. 勾上3项

6.选中要调试的进程后,千万记得在debugger->debugger options中再次选中,那3项:
6.png
图6.再次选中3项

7.回到cmd,输入jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700,回车

8.然后在ida中F9,接着就是选择本地文件映射:
7.png
图7.选择映射

9.计算出Java_com_ucweb_crackme140522_MainActivity_clacSnFuntion的地址,F2,再F9运行,期间会出现一个不相关的so文件,cancel就是了

0x02 算法
因为已经调试过了,所以我站在一个已知者角度调试,不多废话,看到起始处,F7进去
0000267C018 BL      loc_21B4        ; 起始处

然后直接F4到loc_23E8:
[Asm] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
libclacSn.so:AD9F83E8loc_AD9F83E8                           ; CODE XREF:libclacSn.so:JNI_OnLoad+598j
libclacSn.so:AD9F83E8LDRB            R2, [R6,R3]            ; imei
libclacSn.so:AD9F83ECLDRB            R1, [R10,R3]           ; un,username
libclacSn.so:AD9F83F0EOR             R2, R1, R2             ; 逻辑异或
libclacSn.so:AD9F83F4STRB            R2, [R6,R3]            ; 计算结果,保存在R6中
libclacSn.so:AD9F83F8ADD             R3, R3, #1             ; Rd = Op1 + Op2
libclacSn.so:AD9F83FCCMP             R3, R4                 ; R4为un长度
libclacSn.so:AD9F8400BNE             loc_AD9F83E8           ; Branch


F4到loc_2404,此时先看看R6的计算结果:
[Asm] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
[heap]:B89C69D8DCB 0x64 ; d
[heap]:B89C69D9DCB 0x55 ; U
[heap]:B89C69DADCB 0x42 ; B
[heap]:B89C69DBDCB 0x42 ; B
[heap]:B89C69DCDCB 0x5F ; _
[heap]:B89C69DDDCB 0x42 ; B
[heap]:B89C69DEDCB 0x52 ; R
[heap]:B89C69DFDCB 0x5C ; \
[heap]:B89C69E0DCB 0x51 ; Q
[heap]:B89C69E1DCB 0x54 ; T
[heap]:B89C69E2DCB 0x55 ; U
[heap]:B89C69E3DCB 0x30 ; 0
[heap]:B89C69E4DCB 0x30 ; 0
[heap]:B89C69E5DCB 0x30 ; 0
[heap]:B89C69E6DCB 0x30 ; 0
这里只有15位,后面会有0x80补全16位!

看loc_2404代码:
[Asm] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
libclacSn.so:AD9F8404loc_AD9F8404                           ;CODE XREF: libclacSn.so:JNI_OnLoad+578j
libclacSn.so:AD9F8404MOV             R0, R9                 ; Rd = Op2
libclacSn.so:AD9F8408BLX             R11                    ; Branch with Link andExchange (register indirect)
libclacSn.so:AD9F840CLDR             R3, [SP,#0x50]         ; Load from Memory
libclacSn.so:AD9F8410LDR             R0, =0x66666667        ; Load from Memory
libclacSn.so:AD9F8414ADD             R4, SP, #0x1AC         ; Rd = Op1 + Op2
libclacSn.so:AD9F8418MOV             R2, R3,ASR#31          ; Rd = Op2
libclacSn.so:AD9F841CSMULL           R12, R1, R0, R3        ; Signed Multiply long
libclacSn.so:AD9F8420LDR             R0, [R6]               ; Load from Memory
libclacSn.so:AD9F8424RSB             R2, R2, R1,ASR#3       ; Rd = Op2 - Op1
libclacSn.so:AD9F8428LDR             R1, [SP,#0x10]         ; Load from Memory
libclacSn.so:AD9F842CMOV             R3, #0                 ; Rd = Op2
libclacSn.so:AD9F8430ADD             R12, R4, #4            ; Rd = Op1 + Op2
libclacSn.so:AD9F8434STR             R3, [R12],#4           ; Store to Memory
libclacSn.so:AD9F8438STR             R3, [R12],#4           ; Store to Memory
libclacSn.so:AD9F843CEOR             LR, R2, R1             ; Rd = Op1 ^ Op2
libclacSn.so:AD9F8440EOR             LR, R0, LR             ; Rd = Op1 ^ Op2
libclacSn.so:AD9F8444STR             R3, [R12],#4           ; Store to Memory
libclacSn.so:AD9F8448STR             LR, [R6]               ; Store to Memory
libclacSn.so:AD9F844CSTR             R3, [R12]              ; Store to Memory
libclacSn.so:AD9F8450LDR             R12, =0x67452301       ; Load from Memory
libclacSn.so:AD9F8454ADD             R5, SP, #0x154         ; Rd = Op1 + Op2
libclacSn.so:AD9F8458LDR             R2, [SP,#0x14]         ; Load from Memory
libclacSn.so:AD9F845CSTR             R12, [SP,#0x154]       ; Store to Memory
libclacSn.so:AD9F8460ADD             R12, R12,#0x88000000  ; Rd = Op1 + Op2
libclacSn.so:AD9F8464ADD             R12, R12, #0x880000    ; Rd = Op1 + Op2
libclacSn.so:AD9F8468ADD             R12, R12, #0x8800      ; Rd = Op1 + Op2
libclacSn.so:AD9F846CADD             R12, R12, #0x88        ; Rd = Op1 + Op2
libclacSn.so:AD9F8470STR             R12, [SP,#0x158]       ; Store to Memory
libclacSn.so:AD9F8474LDR             R12, =0x98BADCFE       ; Load from Memory
libclacSn.so:AD9F8478MOV             R0, R5                 ; Rd = Op2
libclacSn.so:AD9F847CMOV             R1, R6                 ; Rd = Op2
libclacSn.so:AD9F8480STR             R12, [SP,#0x15C]       ; Store to Memory
libclacSn.so:AD9F8484LDR             R12, =0x10325476       ; Load from Memory
libclacSn.so:AD9F8488ADD             R10, SP, #0x1D4        ; Rd = Op1 + Op2
libclacSn.so:AD9F848CSTR             R3, [SP,#0x164]        ; Store to Memory
libclacSn.so:AD9F8490STR             R12, [SP,#0x160]       ; Store to Memory
libclacSn.so:AD9F8494STR             R3, [SP,#0x1AC]        ; Store to Memory
libclacSn.so:AD9F8498STR             R3, [SP,#0x168]        ; Store to Memory
libclacSn.so:AD9F849CBL              unk_AD9F7B78           ; 通过上面的计算,得到R5,虽说是通过计算,但是R5的内容是固定的:
libclacSn.so:AD9F849C                                        ; [stack]:BEE8D42CDCB    1
libclacSn.so:AD9F849C                                        ;[stack]:BEE8D42D DCB 0x23 ; #
libclacSn.so:AD9F849C                                        ;[stack]:BEE8D42E DCB 0x45 ; E
libclacSn.so:AD9F849C                                        ;[stack]:BEE8D42F DCB 0x67 ; g
libclacSn.so:AD9F849C                                        ;[stack]:BEE8D430 DCB 0x89 ;
libclacSn.so:AD9F849C                                        ;[stack]:BEE8D431 DCB 0xAB ;
libclacSn.so:AD9F849C                                        ;[stack]:BEE8D432 DCB 0xCD ;
libclacSn.so:AD9F849C                                        ;[stack]:BEE8D433 DCB 0xEF ;
libclacSn.so:AD9F849C                                        ; [stack]:BEE8D434DCB 0xFE ;
libclacSn.so:AD9F849C                                        ;[stack]:BEE8D435 DCB 0xDC ;
libclacSn.so:AD9F849C                                        ;[stack]:BEE8D436 DCB 0xBA ;
libclacSn.so:AD9F849C                                        ; [stack]:BEE8D437 DCB 0x98 ;
libclacSn.so:AD9F849C                                        ;[stack]:BEE8D438 DCB 0x76 ; v
libclacSn.so:AD9F849C                                        ;[stack]:BEE8D439 DCB 0x54 ; T
libclacSn.so:AD9F849C                                       ;[stack]:BEE8D43A DCB 0x32 ; 2
libclacSn.so:AD9F849C                                        ;[stack]:BEE8D43B DCB 0x10
libclacSn.so:AD9F849C                                        ; 一个byte数组的逆序
libclacSn.so:AD9F84A0MOV             R0, R10                ; Rd = Op2
libclacSn.so:AD9F84A4ADD             R1, R5, #0x10          ; Rd = Op1 + Op2
libclacSn.so:AD9F84A8MOV             R2, #8                 ; Rd = Op2
libclacSn.so:AD9F84ACBL              unk_AD9F7C64           ; Branch with Link
libclacSn.so:AD9F84B0LDR             R2, [SP,#0x164]        ; Load from Memory
libclacSn.so:AD9F84B4LDR             R3, =0x4A70            ; Load from Memory
libclacSn.so:AD9F84B8MOV             R0, R5                 ; Rd = Op2
libclacSn.so:AD9F84BCMOV             R2, R2,LSR#3           ; Rd = Op2
libclacSn.so:AD9F84C0AND             R2, R2, #0x3F          ; Rd = Op1 & Op2
libclacSn.so:AD9F84C4ADD             R3, PC, R3             ; Rd = Op1 + Op2
libclacSn.so:AD9F84C8CMP             R2, #0x37              ; Set cond. codes on Op1 - Op2
libclacSn.so:AD9F84CCSUB             R3, R3, #0xFF0         ; Rd = Op1 - Op2
libclacSn.so:AD9F84D0SUB             R1, R3, #8             ; Rd = Op1 - Op2
libclacSn.so:AD9F84D4RSBLS           R2, R2, #0x38          ; Rd = Op2 - Op1
libclacSn.so:AD9F84D8RSBHI           R2, R2, #0x78          ; Rd = Op2 - Op1
libclacSn.so:AD9F84DCBL              unk_AD9F7B78           ; Branch with Link
libclacSn.so:AD9F84E0MOV             R0, R5                 ; Rd = Op2
libclacSn.so:AD9F84E4MOV             R1, R10                ; Rd = Op2
libclacSn.so:AD9F84E8MOV             R2, #8                 ; Rd = Op2
libclacSn.so:AD9F84ECBL              unk_AD9F7B78           ; 这里R5发生改变,F7一探究竟
libclacSn.so:AD9F84F0MOV             R2, #0x10              ; Rd = Op2
libclacSn.so:AD9F84F4MOV             R0, R4                 ; Rd = Op2
libclacSn.so:AD9F84F8MOV             R1, R5                 ; Rd = Op2
libclacSn.so:AD9F84FCBL              unk_AD9F7C64           ; R5的内容复制给R4
libclacSn.so:AD9F8500ADD             R2, R5, #0x58          ; Rd = Op1 + Op2
libclacSn.so:AD9F8504MOV             R3, #0                 ; Rd = Op2


F7进入loc_1B78之后,直接F4来到loc_1BF0,这里是算法所在:
[Asm] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
libclacSn.so:AD9F712CLDRB            R7, [R1,#2]            ; iu的第3位,iu即imei^un
libclacSn.so:AD9F7130LDRB            R8, [R1,#1]            ; iu第2位
libclacSn.so:AD9F7134LDRB            R6, [R1]               ; iu的第1位
libclacSn.so:AD9F7138LDRB            R5, [R1,#3]            ; iu第4位
libclacSn.so:AD9F713CMOV             R7, R7,LSL#16          ; lsl为逻辑左移
libclacSn.so:AD9F7140ORR             R7, R7, R8,LSL#8       ; Rd = Op1 | Op2
libclacSn.so:AD9F7144ORR             R6, R7, R6             ; Rd = Op1 | Op2
libclacSn.so:AD9F7148ADD             R1, R1, #4             ; Rd = Op1 + Op2
libclacSn.so:AD9F714CORR             R5, R6, R5,LSL#24      ; Rd = Op1 | Op2
libclacSn.so:AD9F7150CMP             R1, R10                ; 16位比较完为止
libclacSn.so:AD9F7154STR             R5, [R4],#4            ; Store to Memory
libclacSn.so:AD9F7158BNE             loc_AD9F712C           ; Branch
libclacSn.so:AD9F715CLDR             R7, [SP,#0x18]         ; iu前四位
libclacSn.so:AD9F7160LDR             R6, [SP,#0xC]          ; 16byte的后四位,即76,54,32,10
libclacSn.so:AD9F7164LDR             R1, =0xD76AA478        ; Load from Memory
libclacSn.so:AD9F7168LDR             R8, [SP,#0x10]         ; iu后四位
libclacSn.so:AD9F716CBIC             R5, R6, R3             ; Rd = Op1 & ~Op2
libclacSn.so:AD9F7170AND             R4, R2, R3             ; Rd = Op1 & Op2
libclacSn.so:AD9F7174ADD             R1, R7, R1             ; Rd = Op1 + Op2
libclacSn.so:AD9F7178ADD             R1, R1, R8             ; Rd = Op1 + Op2
libclacSn.so:AD9F717CLDR             R9, [SP,#0x1C]         ; iu的四分之二
libclacSn.so:AD9F7180ORR             R4, R5, R4             ; Rd = Op1 | Op2
libclacSn.so:AD9F7184LDR             R5, =0xE8C7B756        ; Load from Memory
libclacSn.so:AD9F7188LDR             R10, [SP,#0xC]         ; Load from Memory
libclacSn.so:AD9F718CADD             R4, R1, R4             ; 16byte的后4位
libclacSn.so:AD9F7190ADD             R4, R3, R4,ROR#25      ; Rd = Op1 + Op2
libclacSn.so:AD9F7194BIC             R6, R2, R4             ; Rd = Op1 & ~Op2
libclacSn.so:AD9F7198AND             R1, R4, R3             ; Rd = Op1 & Op2
libclacSn.so:AD9F719CADD             R5, R9, R5             ; Rd = Op1 + Op2
libclacSn.so:AD9F71A0ADD             R5, R5, R10            ; Rd = Op1 + Op2
libclacSn.so:AD9F71A4LDR             R11, [SP,#0x20]        ; iu的四分之三
libclacSn.so:AD9F71A8ORR             R1, R6, R1             ; Rd = Op1 | Op2
libclacSn.so:AD9F71ACLDR             R8, =0x242070DB        ; Load from Memory
libclacSn.so:AD9F71B0ADD             R1, R5, R1             ; Rd = Op1 + Op2
libclacSn.so:AD9F71B4ADD             R1, R4, R1,ROR#20      ; Rd = Op1 + Op2
libclacSn.so:AD9F71B8AND             R5, R1, R4             ; Rd = Op1 & Op2
libclacSn.so:AD9F71BCBIC             R6, R3, R1             ; Rd = Op1 & ~Op2
libclacSn.so:AD9F71C0ADD             R8, R11, R8            ; Rd = Op1 + Op2
libclacSn.so:AD9F71C4ADD             R8, R8, R2             ; Rd = Op1 + Op2
libclacSn.so:AD9F71C8ORR             R6, R6, R5             ; Rd = Op1 | Op2
libclacSn.so:AD9F71CCADD             R6, R8, R6             ; Rd = Op1 + Op2
libclacSn.so:AD9F71D0LDR             R5, =0xC1BDCEEE        ; Load from Memory
libclacSn.so:AD9F71D4LDR             R8, [SP,#0x24]         ; iu后4位
.
.
.
中间是个汉诺塔计算过程,最终计算结果会保存在r6,r2,r3,r4,所以去到下面代码,待会再回头分析这里
.
.
.
libclacSn.so:AD9F7A80STR             R6, [R0,#0xC]          ; Store to Memory
libclacSn.so:AD9F7A84STR             R3, [R0,#4]            ; Store to Memory
libclacSn.so:AD9F7A88STR             R2, [R0,#8]            ; Store to Memory
libclacSn.so:AD9F7A8CSTR             R4, [R0]               ; Store to Memory
libclacSn.so:AD9F7A90ADD             R2, R12, #0x40         ; Rd = Op1 + Op2
libclacSn.so:AD9F7A94MOV             R3, #0                 ; Rd = Op2


存储后,R0的内容:
[Asm] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
[stack]:BEE8D454DCB 0xB2 ;
[stack]:BEE8D455DCB 0x52 ; R
[stack]:BEE8D456DCB 0x7A ; z
[stack]:BEE8D457DCB 0x16
[stack]:BEE8D458DCB    0
[stack]:BEE8D459DCB 0xD5 ;
[stack]:BEE8D45ADCB 0x8A ;
[stack]:BEE8D45BDCB 0x99 ;
[stack]:BEE8D45CDCB 0x5F ; _
[stack]:BEE8D45DDCB 0x21 ; !
[stack]:BEE8D45EDCB 0x1C
[stack]:BEE8D45FDCB 0x96 ;
[stack]:BEE8D460DCB 0xA2 ;
[stack]:BEE8D461DCB 0x48 ; H
[stack]:BEE8D462DCB 0xB8 ;
[stack]:BEE8D463DCB 0x3C ; <


跳出算法的关键部分以后,后续还有一些运算:
[Asm] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
libclacSn.so:AD9F851Cloc_AD9F851C                           ;CODE XREF: libclacSn.so:JNI_OnLoad+6D0j
libclacSn.so:AD9F851CLDRB            R0, [R4,R3]            ; 注册码第一运算
libclacSn.so:AD9F8520ADD             R1, R2, #1             ; Rd = Op1 + Op2
libclacSn.so:AD9F8524EOR             R2, R2, R0             ; Rd = Op1 ^ Op2
libclacSn.so:AD9F8528STRB            R2, [R7,R3]            ; 结果存储R7中
libclacSn.so:AD9F852CADD             R3, R3, #1             ; Rd = Op1 + Op2
libclacSn.so:AD9F8530CMP             R3, #0x10              ; 比较16次
libclacSn.so:AD9F8534AND             R2, R1, #0xFF          ; Rd = Op1 & Op2
libclacSn.so:AD9F8538BNE             loc_AD9F851C           ; Branch
libclacSn.so:AD9F853CNOP                                    ;No Operation
libclacSn.so:AD9F8540LDR             R10, =(unk_AD9F9C58 -0xAD9F8554) ; Load from Memory
libclacSn.so:AD9F8544LDR             R5, [SP,#4]            ; Load from Memory
libclacSn.so:AD9F8548MOV             R4, #0                 ; Rd = Op2
libclacSn.so:AD9F854CADD             R10, PC, R10 ;unk_AD9F9C58 ; Rd = Op1 + Op2
libclacSn.so:AD9F8550
libclacSn.so:AD9F8550loc_AD9F8550                           ;CODE XREF: libclacSn.so:JNI_OnLoad+70Cj
libclacSn.so:AD9F8550LDRB            R2, [R7,R4]            ; 注册码第二次运算
libclacSn.so:AD9F8554ADD             R3, R4, #0x10          ; Rd = Op1 + Op2
libclacSn.so:AD9F8558MOV             R0, R5                 ; Rd = Op2
libclacSn.so:AD9F855CADD             R4, R4, #1             ; Rd = Op1 + Op2
libclacSn.so:AD9F8560EOR             R2, R2, R3             ; Rd = Op1 ^ Op2
libclacSn.so:AD9F8564MOV             R1, R10                ; Rd = Op2
libclacSn.so:AD9F8568BL              sprintf                ; 将计算得出的16byte数据,直接拼接成string
libclacSn.so:AD9F856CCMP             R4, #0x10              ; Set cond. codes on Op1 - Op2
libclacSn.so:AD9F8570ADD             R5, R5, #2             ; Rd = Op1 + Op2
libclacSn.so:AD9F8574BNE             loc_AD9F8550           ; Branch
libclacSn.so:AD9F8578MOV             R0, R9                 ; Rd = Op2
libclacSn.so:AD9F857CBLX             R11                    ; Branch with Link andExchange (register indirect)
libclacSn.so:AD9F8580LDR             R1, [SP,#0x50]         ; Load from Memory
libclacSn.so:AD9F8584LDR             R0, =0x66666667        ; Load from Memory
libclacSn.so:AD9F8588LDR             R12, [SP,#0x10]        ; Load from Memory
libclacSn.so:AD9F858CMOV             R3, R1,ASR#31          ; Rd = Op2
libclacSn.so:AD9F8590SMULL           R7, R2, R0, R1         ; Signed Multiply long
libclacSn.so:AD9F8594MOV             R0, R6                 ; Rd = Op2
libclacSn.so:AD9F8598RSB             R3, R3, R2,ASR#3       ;Rd = Op2 - Op1
libclacSn.so:AD9F859CLDR             R2, [SP,#0x54]         ; Load from Memory
libclacSn.so:AD9F85A0EOR             R3, R12, R3            ; Rd = Op1 ^ Op2
libclacSn.so:AD9F85A4EOR             R3, R2, R3             ; Rd = Op1 ^ Op2
libclacSn.so:AD9F85A8STR             R3, [SP,#0x54]         ; Store to Memory
libclacSn.so:AD9F85ACBL              free                   ; Branch with Link
libclacSn.so:AD9F85B0LDR             R0, [SP,#4]            ; Load from Memory
libclacSn.so:AD9F85B4LDR             R1, [SP,#0xC]          ; Load from Memory
libclacSn.so:AD9F85B8MOV             R2, R4                 ; Rd = Op2
libclacSn.so:AD9F85BCBL              memcmp                 ; 这里进行比较,R1存储着假码
libclacSn.so:AD9F85C0CMP             R0, #0                 ; Set cond. codes on Op1 -Op2
libclacSn.so:AD9F85C4BNE             loc_AD9F8340           ; Branch
libclacSn.so:AD9F85C8NOP                                    ;No Operation
libclacSn.so:AD9F85CCMOV             R0, #1                 ; Rd = Op2
libclacSn.so:AD9F85D0B               loc_AD9F8344           ; Branch


来看看loc_25B0中,R0的内容:
[Asm] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[stack]:BEE8D354DCB 0x42 ; B
[stack]:BEE8D355DCB 0x32 ; 2
[stack]:BEE8D356DCB 0x35 ; 5
[stack]:BEE8D357DCB 0x32 ; 2
[stack]:BEE8D358DCB 0x37 ; 7
[stack]:BEE8D359DCB 0x41 ; A
[stack]:BEE8D35ADCB 0x31 ; 1
[stack]:BEE8D35BDCB 0x36 ; 6
[stack]:BEE8D35CDCB 0x30 ; 0
[stack]:BEE8D35DDCB 0x30 ; 0
[stack]:BEE8D35EDCB 0x44 ; D
[stack]:BEE8D35FDCB 0x35 ; 5
[stack]:BEE8D360DCB 0x38 ; 8
[stack]:BEE8D361DCB 0x41 ; A
[stack]:BEE8D362DCB 0x39 ; 9
[stack]:BEE8D363DCB 0x39 ; 9
[stack]:BEE8D364DCB 0x35 ; 5
[stack]:BEE8D365DCB 0x46 ; F
[stack]:BEE8D366DCB 0x32 ; 2
[stack]:BEE8D367DCB 0x31 ; 1
[stack]:BEE8D368DCB 0x31 ; 1
[stack]:BEE8D369DCB 0x43 ; C
[stack]:BEE8D36ADCB 0x39 ; 9
[stack]:BEE8D36BDCB 0x36 ; 6
[stack]:BEE8D36CDCB 0x41 ; A
[stack]:BEE8D36DDCB 0x32 ; 2
[stack]:BEE8D36EDCB 0x34 ; 4
[stack]:BEE8D36FDCB 0x38 ; 8
[stack]:BEE8D370DCB 0x42 ; B
[stack]:BEE8D371DCB 0x38 ; 8
[stack]:BEE8D372DCB 0x33 ; 3
[stack]:BEE8D373DCB 0x43 ; C


至此,我们可以试一试,我们找到的注册码B2527A1600D58A995F211C96A248B83C,取前16位,验证结果如下:
8.png
图8.验证成功!

这里确实验证成功了,但是这个过程中会有彩蛋,只有自己走过一遍,看看能不能得到真正的注册码,才能知道彩蛋到底是什么!

最后,我们来说算法的关键部分sub_1100,先在ida中看看F5后的类C代码:
[C] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
int__fastcall sub_1100(int result, int a2)
{
  int v2; // r2@1
  int v3; // r3@1
  int *v4; // r12@1
  int v5; // r10@1
  int *v6; // r4@1
  int v7; // r5@2
  int v8; // r6@2
  int v9; // r4@3
  int v10; // off@3
  int v11; // r1@3
  int v12; // off@3
  int v13; // r6@3
  int v14; // off@3
  int v15; // r5@3
  int v16; // off@3
  int v17; // r4@3
  int v18; // off@3
  int v19; // r1@3
  int v20; // off@3
  int v21; // r6@3
  int v22; // off@3
  int v23; // r5@3
  int v24; // off@3
  int v25; // r4@3
  int v26; // off@3
  int v27; // r1@3
  int v28; // off@3
  int v29; // r6@3
  int v30; // off@3
  int v31; // r5@3
  int v32; // off@3
  int v33; // r4@3
  int v34; // off@3
  int v35; // r1@3
  int v36; // off@3
  int v37; // r10@3
  int v38; // r6@3
  int v39; // off@3
  int v40; // r8@3
  int v41; // r5@3
  int v42; // off@3
  int v43; // r8@3
  int v44; // r10@3
  int v45; // off@3
  int v46; // r9@3
  int v47; // off@3
  int v48; // r8@3
  int v49; // off@3
  int v50; // r4@3
  int v51; // off@3
  int v52; // r1@3
  int v53; // off@3
  int v54; // r6@3
  int v55; // off@3
  int v56; // r5@3
  int v57; // off@3
  int v58; // r4@3
  int v59; // off@3
  int v60; // r1@3
  int v61; // off@3
  int v62; // r6@3
  int v63; // off@3
  int v64; // r5@3
  int v65; // off@3
  int v66; // r4@3
  int v67; // off@3
  int v68; // r1@3
  int v69; // off@3
  int v70; // r8@3
  int v71; // off@3
  int v72; // r6@3
  int v73; // off@3
  int v74; // r5@3
  int v75; // off@3
  int v76; // r4@3
  int v77; // off@3
  int v78; // r1@3
  int v79; // off@3
  int v80; // r6@3
  int v81; // off@3
  int v82; // r5@3
  int v83; // off@3
  int v84; // r4@3
  int v85; // off@3
  int v86; // r1@3
  int v87; // off@3
  int v88; // r6@3
  int v89; // off@3
  int v90; // r5@3
  int v91; // off@3
  int v92; // r4@3
  int v93; // off@3
  int v94; // r1@3
  int v95; // off@3
  int v96; // r6@3
  int v97; // off@3
  int v98; // r5@3
  int v99; // off@3
  int v100; // r4@3
  int v101; // off@3
  int v102; // r1@3
  int v103; // off@3
  int v104; // r6@3
  int v105; // off@3
  int v106; // r5@3
  int v107; // off@3
  int v108; // r4@3
  int v109; // off@3
  int v110; // r1@3
  int v111; // off@3
  int v112; // r6@3
  int v113; // off@3
  int v114; // r5@3
  int v115; // off@3
  int v116; // r4@3
  int v117; // off@3
  int v118; // r7@3
  int v119; // off@3
  int v120; // r1@3
  int v121; // off@3
  int v122; // r5@3
  int v123; // off@3
  int v124; // r4@3
  int v125; // off@3
  int v126; // r6@3
  int v127; // off@3
  int v128; // r1@3
  int v129; // off@3
  int v130; // r5@3
  int v131; // off@3
  int v132; // r4@3
  int v133; // off@3
  int v134; // r6@3
  int v135; // off@3
  int v136; // off@3
  int v137; // r2@3
  int v138; // r3@3
  int v139; // off@3
  int v140; // [sp+Ch] [bp-6Ch]@1
  int v141; // [sp+10h] [bp-68h]@1
  int v142; // [sp+18h] [bp-60h]@1
  int v143; // [sp+1Ch] [bp-5Ch]@3
  int v144; // [sp+20h] [bp-58h]@3
  int v145; // [sp+24h] [bp-54h]@3
  int v146; // [sp+28h] [bp-50h]@3
  int v147; // [sp+2Ch] [bp-4Ch]@3
  int v148; // [sp+30h] [bp-48h]@3
  int v149; // [sp+34h] [bp-44h]@3
  int v150; // [sp+38h] [bp-40h]@3
  int v151; // [sp+3Ch] [bp-3Ch]@3
  int v152; // [sp+40h] [bp-38h]@3
  int v153; // [sp+44h] [bp-34h]@3
  int v154; // [sp+48h] [bp-30h]@3
  int v155; // [sp+4Ch] [bp-2Ch]@3
  int v156; // [sp+50h] [bp-28h]@3
  int v157; // [sp+54h] [bp-24h]@3
  int v158; // [sp+58h] [bp-20h]@4
 
  v141 = *(_DWORD *)result;                     // R4
  v2 = *(_DWORD *)(result + 8);                 // R2
  v3 = *(_DWORD *)(result + 4);                 // R3
  v4 = &v142;
  v140 = *(_DWORD *)(result + 12);              // R6
  v5 = a2 + 64;                                 // R2, R12,#0x40
  v6 = &v142;
  do
  {
    v7 = *(_BYTE *)(a2 + 3);                    // LDRB            R5, [R1,#3]
    v8 = (*(_BYTE *)(a2 + 2) << 16) |(*(_BYTE *)(a2 + 1) << 8) | *(_BYTE *)a2;
    a2 += 4;
    *v6 = v8 | (v7 << 24);                      // ORR             R5, R6, R5,LSL#24
    ++v6;
  }
  while ( a2 != v5 );
  v10 = __ROR4__(v142 - 680876936 + v141 +(v140 & ~v3 | v2 & v3), 25);
  v9 = v3 + v10;
  v12 = __ROR4__(v143 - 389564586 + v140 + (v2& ~(v3 + v10) | (v3 + v10) & v3), 20);
  v11 = v9 + v12;
  v14 = __ROR4__(v144 + 606105819 + v2 + (v3& ~(v9 + v12) | (v9 + v12) & v9), 15);
  v13 = v11 + v14;
  v16 = __ROR4__(v145 - 1044525330 + v3 + (v9& ~(v11 + v14) | (v11 + v14) & v11), 10);
  v15 = v13 + v16;
  v18 = __ROR4__(v146 - 176418897 + v9 + (v11 &~(v13 + v16) | (v13 + v16) & v13), 25);
  v17 = v15 + v18;
  v20 = __ROR4__(v147 + 1200080426 + v11 + (v13& ~(v15 + v18) | (v15 + v18) & v15), 20);
  v19 = v17 + v20;
  v22 = __ROR4__(v148 - 1473231341 + v13 + (v15& ~(v17 + v20) | (v17 + v20) & v17), 15);
  v21 = v19 + v22;
  v24 = __ROR4__(v149 - 45705983 + v15 + (v17& ~(v19 + v22) | (v19 + v22) & v19), 10);
  v23 = v21 + v24;
  v26 = __ROR4__(v150 + 1770035416 + v17 + (v19& ~(v21 + v24) | (v21 + v24) & v21), 25);
  v25 = v23 + v26;
  v28 = __ROR4__(v151 - 1958414417 + v19 + (v21& ~(v23 + v26) | (v23 + v26) & v23), 20);
  v27 = v25 + v28;
  v30 = __ROR4__(v152 - 42063 + v21 + (v23& ~(v25 + v28) | (v25 + v28) & v25), 15);
  v29 = v27 + v30;
  v32 = __ROR4__(v153 - 1990404162 + v23 + (v25& ~(v27 + v30) | (v27 + v30) & v27), 10);
  v31 = v29 + v32;
  v34 = __ROR4__(v154 + 1804603682 + v25 + (v27& ~(v29 + v32) | (v29 + v32) & v29), 25);
  v33 = v31 + v34;
  v36 = __ROR4__(v155 - 40341101 + v27 + (v29& ~(v31 + v34) | (v31 + v34) & v31), 20);
  v35 = v33 + v36;
  v37 = ~(v33 + v36);
  v39 = __ROR4__(v156 - 1502002290 + v29 + (v37& v31 | (v33 + v36) & v33), 15);
  v38 = v35 + v39;
  v40 = ~(v35 + v39);
  v42 = __ROR4__(v157 + 1236535329 + v31 + (v40& v33 | (v35 + v39) & v35), 10);
  v41 = v38 + v42;
  v43 = (v38 + v42) & v40;
  v45 = __ROR4__(v143 - 165796510 + v33 + ((v38+ v42) & v35 | v38 & v37), 27);
  v44 = v41 + v45;
  v47 = __ROR4__(v148 - 1069501632 + v35 +((v41 + v45) & v38 | v43), 23);
  v46 = v44 + v47;
  v49 = __ROR4__(v153 + 643717713 + v38 + ((v44+ v47) & v41 | v44 & ~v41), 18);
  v48 = v46 + v49;
  v51 = __ROR4__(v142 - 373897302 + v41 + ((v46+ v49) & v44 | v46 & ~v44), 12);
  v50 = v48 + v51;
  v53 = __ROR4__(v147 - 701558691 + v44 + ((v48+ v51) & v46 | v48 & ~v46), 27);
  v52 = v50 + v53;
  v55 = __ROR4__(v152 + 38016083 + v46 + ((v50+ v53) & v48 | v50 & ~v48), 23);
  v54 = v52 + v55;
  v57 = __ROR4__(v157 - 660478335 + v48 + ((v52+ v55) & v50 | v52 & ~v50), 18);
  v56 = v54 + v57;
  v59 = __ROR4__(v146 - 405537848 + v50 + ((v54+ v57) & v52 | v54 & ~v52), 12);
  v58 = v56 + v59;
  v61 = __ROR4__(v151 + 568446438 + v52 + ((v56+ v59) & v54 | v56 & ~v54), 27);
  v60 = v58 + v61;
  v63 = __ROR4__(v156 - 1019803690 + v54 +((v58 + v61) & v56 | v58 & ~v56), 23);
  v62 = v60 + v63;
  v65 = __ROR4__(v145 - 187363961 + v56 + ((v60+ v63) & v58 | v60 & ~v58), 18);
  v64 = v62 + v65;
  v67 = __ROR4__(v150 + 1163531501 + v58 +((v62 + v65) & v60 | v62 & ~v60), 12);
  v66 = v64 + v67;
  v69 = __ROR4__(v155 - 1444681467 + v60 +((v64 + v67) & v62 | v64 & ~v62), 27);
  v68 = v66 + v69;
  v71 = __ROR4__(v144 - 51403784 + v62 + ((v66+ v69) & v64 | v66 & ~v64), 23);
  v70 = v68 + v71;
  v73 = __ROR4__(v149 + 1735328473 + v64 +((v68 + v71) & v66 | v68 & ~v66), 18);
  v72 = v70 + v73;
  v75 = __ROR4__(v154 - 1926607734 + v66 +((v70 + v73) & v68 | v70 & ~v68), 12);
  v74 = v72 + v75;
  v77 = __ROR4__(v147 - 378558 + v68 + (v72 ^v70 ^ (v72 + v75)), 28);
  v76 = v74 + v77;
  v79 = __ROR4__(v150 - 2022574463 + v70 + (v74^ v72 ^ (v74 + v77)), 21);
  v78 = v76 + v79;
  v81 = __ROR4__(v153 + 1839030562 + v72 + (v76^ v74 ^ (v76 + v79)), 16);
  v80 = v78 + v81;
  v83 = __ROR4__(v156 - 35309556 + v74 + (v78 ^v76 ^ (v78 + v81)), 9);
  v82 = v80 + v83;
  v85 = __ROR4__(v143 - 1530992060 + v76 + (v80^ v78 ^ (v80 + v83)), 28);
  v84 = v82 + v85;
  v87 = __ROR4__(v146 + 1272893353 + v78 + (v82^ v80 ^ (v82 + v85)), 21);
  v86 = v84 + v87;
  v89 = __ROR4__(v149 - 155497632 + v80 + (v84^ v82 ^ (v84 + v87)), 16);
  v88 = v86 + v89;
  v91 = __ROR4__(v152 - 1094730640 + v82 + (v86^ v84 ^ (v86 + v89)), 9);
  v90 = v88 + v91;
  v93 = __ROR4__(v155 + 681279174 + v84 + (v88^ v86 ^ (v88 + v91)), 28);
  v92 = v90 + v93;
  v95 = __ROR4__(v142 - 358537222 + v86 + (v90^ v88 ^ (v90 + v93)), 21);
  v94 = v92 + v95;
  v97 = __ROR4__(v145 - 722521979 + v88 + (v92^ v90 ^ (v92 + v95)), 16);
  v96 = v94 + v97;
  v99 = __ROR4__(v148 + 76029189 + v90 + (v94 ^v92 ^ (v94 + v97)), 9);
  v98 = v96 + v99;
  v101 = __ROR4__(v151 - 640364487 + v92 + (v96^ v94 ^ (v96 + v99)), 28);
  v100 = v98 + v101;
  v103 = __ROR4__(v154 - 421815835 + v94 + (v98^ v96 ^ (v98 + v101)), 21);
  v102 = v100 + v103;
  v105 = __ROR4__(v157 + 530742520 + v96 +(v100 ^ v98 ^ (v100 + v103)), 16);
  v104 = v102 + v105;
  v107 = __ROR4__(v144 - 995338651 + v98 +(v102 ^ v100 ^ (v102 + v105)), 9);
  v106 = v104 + v107;
  v109 = __ROR4__(v142 - 198630844 + v100 +(((v104 + v107) | ~v102) ^ v104), 26);
  v108 = v106 + v109;
  v111 = __ROR4__(v149 + 1126891415 + v102 +(((v106 + v109) | ~v104) ^ v106), 22);
  v110 = v108 + v111;
  v113 = __ROR4__(v156 - 1416354905 + v104 +(((v108 + v111) | ~v106) ^ v108), 17);
  v112 = v110 + v113;
  v115 = __ROR4__(v147 - 57434055 + v106 +(((v110 + v113) | ~v108) ^ v110), 11);
  v114 = v112 + v115;
  v117 = __ROR4__(v154 + 1700485571 + v108 +(((v112 + v115) | ~v110) ^ v112), 26);
  v116 = v114 + v117;
  v119 = __ROR4__(v145 - 1894986606 + v110 + (((v114+ v117) | ~v112) ^ v114), 22);
  v118 = v116 + v119;
  v121 = __ROR4__(v152 - 1051523 + v112 +(((v116 + v119) | ~v114) ^ v116), 17);
  v120 = v118 + v121;
  v123 = __ROR4__(v143 - 2054922799 + v114 +(((v118 + v121) | ~v116) ^ v118), 11);
  v122 = v120 + v123;
  v125 = __ROR4__(v150 + 1873313359 + v116 +(((v120 + v123) | ~v118) ^ v120), 26);
  v124 = v122 + v125;
  v127 = __ROR4__(v157 - 30611744 + v118 +(((v122 + v125) | ~v120) ^ v122), 22);
  v126 = v124 + v127;
  v129 = __ROR4__(v148 - 1560198380 + v120 +(((v124 + v127) | ~v122) ^ v124), 17);
  v128 = v126 + v129;
  v131 = __ROR4__(v155 + 1309151649 + v122 +(((v126 + v129) | ~v124) ^ v126), 11);
  v130 = v128 + v131;
  v133 = __ROR4__(v146 - 145523070 + v124 +(((v128 + v131) | ~v126) ^ v128), 26);
  v132 = v130 + v133;
  v135 = __ROR4__(v153 - 1120210379 + v126 +(((v130 + v133) | ~v128) ^ v130), 22);
  v134 = v132 + v135;
  v136 = __ROR4__(v144 + 718787259 + v128 +(((v132 + v135) | ~v130) ^ v132), 17);
  v137 = v2 + v134 + v136;
  v138 = v134 + v136 + v3;
  v139 = __ROR4__(v151 - 343485551 + v130 +(((v134 + v136) | ~v132) ^ v134), 11);
  *(_DWORD *)(result + 12) = v140 + v134;       // STR             R6, [R0,#0xC]
  *(_DWORD *)(result + 4) = v138 + v139;        // STR             R3, [R0,#4]
  *(_DWORD *)(result + 8) = v137;               // STR             R2, [R0,#8]
  *(_DWORD *)result = v141 + v132;              // STR             R4, [R0]
  do
  {
    *(_BYTE *)v4 = 0;
    v4 = (int *)((char *)v4 + 1);
  }
  while ( v4 != &v158 );
  return result;
}


算法不难,但是很冗余!!我们以计算R6的地址为例:
R6 =v140 + v134
   = *(_DWORD *)(result + 12) + v132 + v135
   = *(_DWORD *)(result + 12) + v130 + v133 +__ROR4__(v153 - 1120210379 + v126 + (((v130 + v133) | ~v128) ^ v130), 22)
   = ..
要计算R6,要递归向上,这就有点汉诺塔一样,得逐级向上找到比自己小那一块,如果人肉这样逆推的话,非要弄到猴年马月,实在是没这个毅力……若说想要走一点小捷径,那还是有的,就是利用脚本,监控每个参与运算的变量,但仍然耗时巨大,所以,干脆直接进入下一题算了……
汉诺塔.gif


0x03
后序
传送门:
某司面试题一:smali & java keygen:
http://www.52pojie.cn/thread-403032-1-1.html

某司面试题三:fork & ptrace:
http://www.52pojie.cn/thread-403089-1-1.html

本题所有文件:
第二题.rar (806.5 KB, 下载次数: 74)







免费评分

参与人数 2热心值 +2 收起 理由
jacky520510 + 1 我很赞同!
qtfreet00 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.

查看全部评分

 楼主| Terrorblade 发表于 2015-8-20 00:34

某司面试三题

本帖最后由 PoJie_小雨 于 2015-8-20 13:06 编辑

0x00 前言
第三题终于不用再写注册机,只要追到注册码。但是这道题,从头到尾,都是一个巨大的骗局,它充满了迷惑和各种anti_debug,不明所以者,一旦深陷其中,就如同中了幻术一般,我也一样,水平不高,致使这道题没有得到完美的解答……
                              
0x01 IDA
中的静态注解
废话不多说,我们先来看看cm的关键函数--Java_com_ucweb_crackme3_MainActivity_checkPasswd,下面是通过ida F5后得到的类C代码:
[C] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
int __fastcall Java_com_ucweb_crackme3_MainActivity_checkPasswd(int a1, int a2,int a3)
{
  int v3; // r7@1
  int v4; // r10@1
  void *v5; // r7@1
  __pid_t v6; // r0@3
  int v7; // r6@3
  __int32 v8; // r7@6
  __int32 v9; // r10@7
  int result; // r0@11
  int v11; // r5@14
  int v12; // r0@14
  bool v13; // cf@14
  int v14; // [sp+1Ch] [bp-48h]@1
  int v15; // [sp+20h] [bp-44h]@1
  int v16; // [sp+24h] [bp-40h]@1
  int v17; // [sp+28h] [bp-3Ch]@1
  int v18; // [sp+2Ch] [bp-38h]@1
  int v19; // [sp+30h] [bp-34h]@1
  int v20; // [sp+34h] [bp-30h]@1
  int v21; // [sp+38h] [bp-2Ch]@1
  int v22; // [sp+3Ch] [bp-28h]@1
  int v23; // [sp+40h] [bp-24h]@1
  int v24; // [sp+44h] [bp-20h]@1
  int v25; // [sp+48h] [bp-1Ch]@1
  int v26; // [sp+4Ch] [bp-18h]@1
  int v27; // [sp+50h] [bp-14h]@1
  int v28; // [sp+54h] [bp-10h]@1
  char *argv; // [sp+58h] [bp-Ch]@17
  void *v30; // [sp+5Ch] [bp-8h]@17
  int v31; // [sp+60h] [bp-4h]@17
  signed int v32; // [sp+64h] [bp+0h]@1
  signed int v33; // [sp+68h] [bp+4h]@1
  signedint v34; // [sp+6Ch] [bp+8h]@1
  signed int v35; // [sp+70h] [bp+Ch]@1
  signed int v36; // [sp+74h] [bp+10h]@1
  signed int v37; // [sp+78h] [bp+14h]@1
  signed int v38; // [sp+7Ch] [bp+18h]@1
  signed int v39; // [sp+80h] [bp+1Ch]@1
  signed int v40; // [sp+84h] [bp+20h]@1
  signed int v41; // [sp+88h] [bp+24h]@1
  char v42; // [sp+8Ch] [bp+28h]@1
  _BYTE v43[3]; // [sp+8Dh] [bp+29h]@1
  int v44; // [sp+264h] [bp+200h]@1
  int v45; // [sp+268h] [bp+204h]@1
  int v46; // [sp+26Ch] [bp+208h]@1
  int v47; // [sp+270h] [bp+20Ch]@1
  int v48; // [sp+274h] [bp+210h]@1
  int v49; // [sp+278h] [bp+214h]@1
  int v50; // [sp+27Ch] [bp+218h]@1
  int v51; // [sp+280h] [bp+21Ch]@1
  int v52; // [sp+284h] [bp+220h]@1
  int v53; // [sp+288h] [bp+224h]@1
  int v54; // [sp+28Ch] [bp+228h]@1
  int v55; // [sp+290h] [bp+22Ch]@1
  int v56; // [sp+294h] [bp+230h]@1
  signed int v57; // [sp+298h] [bp+234h]@1
  signed int v58; // [sp+29Ch] [bp+238h]@1
  signed int v59; // [sp+2A0h] [bp+23Ch]@1
  int v60; // [sp+2A4h] [bp+240h]@1
  signed int v61; // [sp+2A8h] [bp+244h]@1
  signed int v62; // [sp+2ACh] [bp+248h]@1
  signed int v63; // [sp+2B0h] [bp+24Ch]@1
  int v64; // [sp+2B4h] [bp+250h]@1
 
  v3 = a1;
  v4 = a3;
  v60 = -390266736;
  v61 = -508559360;
  v62 = 1362099998;
  v63 = -369094003;
  v56 = -1382015835;
  v57 = 694420221;
  v58 = -2030879789;
  v59 = 1685670803;
  v32 = 1952539695;
  v33 = 1633955681;
  v34 = 1664049524;
  v35 = 1965976943;
  v25 = 0;
  v26 = 0;
  v27 = 0;
  v64 = _stack_chk_guard;
  v28 = 0;
  v36 = 1650816867;
  v37 = 1634886446;
  v38 = 1701669731;
  v39 = 1919102771;
  v42 = 0;
  v40 = 1835754337;
  v41 = 1651864421;
  v24 = 0;
  memset(v43, 0, 0x1D7u);
  v15 = 0;
  v16 = 0;
  v17 = 0;
  v45 = 0;
  v18 = 0;
  v46 = 0;
  v19 = 0;
  v47 = 0;
  v20 = 0;
  v48 = 0;
  v21 = 0;
  v49 = 0;
  v53 = 0;
  v22 = 0;
  v50 = 0;
  v54 = 0;
  v55 = 0;
  v23 = 0;
  v51 = 0;
  v14 = 0;
  v44 = 0;
  v52 = 0;
  v5 = sub_B0C(v3, v4);                         //"getBytes",
                                               // "(Ljava/lang/String;)[B");
                                               // memcpy 等
  if ( v5 && !sub_1280((const char*)&v32, &_data_start, (size_t)&unk_13CFC) )// fopen, fwrite,fclose, chmod
  {
LABEL_11:
    result = 0;
    goto LABEL_12;
  }
  v6 = fork();                                  // fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,
                                               // 也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量
                                                // 不同,两个进程也可以做不同的事
  v7 = v6;
  if ( v6 )
  {
    if ( v6 > 0 )
    {
      sleep(1u);
      if ( ptrace(PTRACE_ATTACH, v7) < 0)      // 跟踪指定pid 进程。pid表示被跟踪进程。被跟踪进程将成为当前进程
                                               // 的子进程,并进入中止状态
                                               // 成功返回0。错误返回-1。errno被设置
        exit(-1);                               // 无论在程序中的什么位置,只要执行到exit系统调用,进程就会停止剩
                                               // 下的所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运
                                                // 行
      waitpid(v7, 0, 2);                        // pid_t waitpid(pid_tpid,int * status,int options)
      v8 = sub_AA4(v7,(int)&unk_163AC);        // returnptrace(PTRACE_GETREGS, a1, 0, a2)
      if ( !v8 )
      {
        while ( 2 )
        {
          sub_A4C(v7, dword_163E8,(int)&v44, 32);// result = ptrace(PTRACE_PEEKTEXT, v5, v8 + v6, 0)
                                               // 从内存地址中读取一个字节,pid表示被跟踪的子进程,内存地址由
                                                // addr给出,data为用户变量地址用于返回读到的数据
          v9 = v8;
          do
          {
            if ( !memcmp((char *)&v44 + v8,&v60, 0x10u) )
            {
              sub_A4C(v7, dword_163E0,(int)&v14, 40);
              v19 += 388;
              sub_D50(v7, dword_163E0,(int)&v14, 40);// dest = ptrace(PTRACE_POKETEXT, v5, v8 + v6, dest)
                                               // 往内存地址中写入一个字节。pid表示被跟踪的子进程,内存地址由
                                               // addr给出,data为所要写入的数据
              sub_A4C(v7, v19 + 74996,(int)&v24, 20);
              v11 = (int)malloc(v25 + 1);
              sub_A4C(v7, v24, v11, v25);
              sub_A20(v11, v25);                // 一个循环,偏就是走到这里segmentation 异常
                                                // SIGSEGV 11 C 无效的内存引用,或发生段错误时发送给它的信号
              sub_D50(v7, v24, v11, v25);
              sub_DB8(v7);                      // result =ptrace(PTRACE_CONT, a1)
                                               // 继续执行
                                               // 这里有sig trap
              sub_AA4(v7, (int)&unk_163AC);
              sub_A4C(v7, v27, (int)&v52,16);
              ptrace(PTRACE_KILL, v7, 0,0);    // 杀掉子进程,使它退出。pid表示被跟踪的子进程
              wait(0);
              unlink((const char *)&v32);       // 删除一个文件的目录项并减少它的链接数,若成功则返回0,否则返
                                               // 回-1,调用了unlink以后仍然可以对文件进行读写操作, 删除目录相并
                                               // 减少一个连接数,如果链接数为0并且没有任何进程打开该文件,该文
                                                // 件内容才能被真正删除,但是若又进程打开了该文件,则文件暂时不删
                                               // 除直到所有打开该文件的进程都结束时文件才能被删除
              v12 = memcmp(&v56, &v52,0x10u);
              v13 = (unsigned int)v12 <= 1;
              result = 1 - v12;
              if ( !v13 )
                result = 0;
              goto LABEL_12;
            }
            v9 += 4;
            v8 = v9;
          }
          while ( v9 != 16 );
          sub_DB8(v7);
          v8 = sub_AA4(v7, (int)&unk_163AC);
          if ( !v8 )
            continue;
          break;
        }
      }
    }
    goto LABEL_11;
  }
  v30 = v5;
  argv = (char *)&v32;
  v31 = 0;
  execv((const char *)&v32,&argv);             // 装入并运行其它程序的函数
  result = v7;
LABEL_12:
  if ( v64 != _stack_chk_guard )
    _stack_chk_fail(result);
  return result;
}

接着我们回到标题—fork& ptrace,先来了解一下fork(),见上面代码的125行:
1.png
图1.fork()的注解

关于fork(),远没有那么简单,一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。说到这,大家应该已经意识到了,这个cm是双进程,因为有子进程(child process)的存在,在接下来的调试中,会时常遇到SIGCHLD这个信号,给调试带来很大的干扰!关于fork(),大家可以参考:http://blog.csdn.net/jason314/article/details/5640969

接着,再来说说ptrace(),按照见名知义,各位同学应该已经知道他就是跟踪进程的函数,ptrace 提供了一种父进程可以控制子进程运行,并可以检查和改变它的核心image。它主要用于实现断点调试。一个被跟踪的进程运行中,直到发生一个信号。则进程被中止,并且通知其父进程。在进程中止的状态下,进程的内存空间可以被读写。父进程还可以使子进程继续执行,并选择是否是否忽略引起中止的信号。关于ptrace()的各个参数详细参见:http://blog.sina.com.cn/s/blog_4ac74e9a0100n7w1.html

可以说,fork() 配合上ptrace()给调试带来很多让人头疼的异常,他们一般都是以信号signal的形式出现,关于linux的信号,大家可以参考:http://www.blogjava.net/wayne/archive/2011/10/09/360255.html。所以说,要调戏这个cm,需要很深的基础,我基础不好,因此,不懂的地方,基本都加了注释!

0x02 CM的初探以及修改
在真正进入cm3的调戏之前,播个小插曲,因为cm2的成功经验,致使在破解cm3的时候,形成一种思维定势,那就是假的注册码通过memcmp()与真的注册码进行比较,那么memcmp的三个参数中,其中之一就是真的注册码。经验虽好,但有时,人们太过于仰赖自己的经验的话,经验会害死人!

进入调试,如何调戏so文件,在cm2的分析过程中已经赘述过了,这里不再赘述。先来看看一个奇怪的string,在没有选择 Auto comments的情况下,仍然会出现:
2.png
图2.crackmesub

这个文件是个elf文件,但是他没有后缀,到后面会用到这个文件,我多次调试之后,在“Choose process to attach to”窗口会看到:
3.png
图3.crackmesub还带着我输入的假SN,应该就是进程的参数了

单步至F7C的时候,有个函数,进去看看:
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
void *__fastcall sub_B0C(inta1, int a2)
{
  int v2; // r5@1
  int v3; // r4@1
  int v4; // r7@1
  int v5; // r6@1
  int v6; // r0@1
  int v7; // r6@1
  size_t v8; // r7@1
  const void *v9; // r8@1
  void *v10; // r5@2
 
  v2 = a2;
  v3 = a1;
  v4 = (*(int (**)(void))(*(_DWORD *)a1 +24))();
  v5 = (*(int (__fastcall **)(int,_DWORD))(*(_DWORD *)v3 + 668))(v3, "utf-8");
  v6 = (*(int (__fastcall **)(int, int, _DWORD,_DWORD))(*(_DWORD *)v3 + 132))(
         v3,
         v4,
         "getBytes",
         "(Ljava/lang/String;)[B");
  v7 = (*(int (__fastcall **)(int, int, int,int))(*(_DWORD *)v3 + 136))(v3, v2, v6, v5);
  v8 = (*(int (__fastcall **)(int,int))(*(_DWORD *)v3 + 684))(v3, v7);
  v9 = (const void *)(*(int (__fastcall**)(int, int, _DWORD))(*(_DWORD *)v3 + 736))(v3, v7, 0);
  if ( (signed int)v8 > 0 )
  {
    v10 = malloc(v8 + 1);
    memcpy(v10, v9, v8);
    *((_BYTE *)v10 + v8) = 0;
  }
  else
  {
    v10 = 0;
  }
  (*(void (__fastcall **)(int, int, const void*, _DWORD))(*(_DWORD *)v3 + 768))(v3, v7, v9, 0);
  return v10;
}
走过,发现R0已经存着我们输入的假注册码了,通过上面的类C代码也可以发现,他就是用于读取我们输入的注册码!

接着来到FA0,就是sub_1280,这个函数就是往crackmesub里写入了80K的垃圾数据!

到FC0的时候,弹出一个信号框:
4.png
图4.sigchld 子进程发生变化

因为在FAC,就有一句bl fork了,这里形成了子进程!
继续单步,这时候,异常出现了:
5.png
图5.异常

无视之后,我们居然跳到了libc.so(这个相当于OD里所说的系统领空,此时不能按crtl+F7--run until return,按这个组合键会跑飞,要按F9才能回到程序领空,即libcheck),不管他,F9回到libcheck.so!

到FDC之后,有一个跳转,这里先给大家,看关于跳转的语法汇总:
6.png
图6.条件码表

因为,我是一边调试,一边跟进写文章,这样很麻烦,所以在这里声明,动态调试的是左图,即我已经修改过的so文件,右边的ida为原始的so文件。好,我们继续看FDC这个跳转:
7.png
图7. 把blt改成bgt

通过图6,我们知道,blt的相反就是bgt,所以,我们把blt改成bgt,问题是,怎么改呢,ida不像od灵活,可以直接修改汇编代码,我们需要把汇编代码转换成HEX形式的opcode才能修改,所以,我们调出opcode:
8.png
图8.调出opcode

好了,可以看到bltloc_11B8的opcode是750000BA,我们可以搜索bgt,如图9:
9.png
图9.搜索bgt

因为是littleendian,所以我们把750000BA改成750000CA,然后,就是回到apkide,“编译生成apk”->“安装生成的apk”,步骤非常麻烦,而且,后面还有要改的地方,我们这里暂时不在apkide里操作……

接着要把1008的BNE改成BEQ,因为默认跳到loc_1068后,离程序结束就不远,我们需要看到他的流程:
10.png
图10.修改1008

接着来到loc_1030,终于看到翘首以盼的memcmp()了,然而这里是个死循环,我们需要跳刀真正的验证地址,所以把loc_1038改成BNE,之后,就来关键的loc_108C了

在loc_108C中,引用了sub_A4C、sub_D50、sub_A20、sub_DB8、sub_AA4,见下图:
11.png
图11. loc_108C的内部结构

其中sub_A20会触发 SIGSEGV 异常,sub_DB8会触发SIGTRAP,异常我不再重现截图了,可以直接nop掉,然后我们看这行:v12 = memcmp(&v56,&v52, 0x10u);如果这里再不比较注册码真假的话, Java_com_ucweb_crackme3_MainActivity_checkPasswd这个函数就要走到尽头了,鼠标点击v56 ,发现v56 = -1382015835,v52 = 0,两个参数与被nop的sub_A20和sub_DB8并没有交叉,所以nop掉这两函数,并不影响注册码的最终计算,下面是单步到loc_1180时,两个字符串的比较:
12.png
图12. 最终比较

寄存器R0和R1都不是0123456789abcdef,而且二者也不像阿里移动安全挑战赛的第二题那样,会出现“aiyou,bucuoo”这样acsii值,不急,我接着往下走,btw,loc_1190也需要nop掉。

往下走到loc_1194:
13.png
图13 execv

然后,F8过execv之后,我就可以看到如图3的crackmesub的进程了,没什么,继续F8直到走出libcheck.so,进入到libdvm.so,此时,我们已经走出Java_com_ucweb_crackme3_MainActivity_checkPasswd,可以肆无忌惮地F9了,因为,我们已经跳过程序验证注册码的范围了,一直F9,然后把视线转移到avd里面:
14.png
    图14.success!

这一系列调试过程,可以参见已经录制好的视频—“没有SN.exe”,我明明没有爆破,但是为什么会突兀的出现了“Success!”?上高中的时候,我生化学的不错,在做化学推断题的时候,老师经常挂在嘴边的一句话就是:大胆假设,小心求证。这里我们可以大胆地假设,这道题没有严格意义的密码,就是说,密码可以被绕过!

0x03 小心求证
1.MainActivity.class
[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.ucweb.crackme3;
 
import android.app.Activity;
import android.os.Bundle;
importandroid.text.Editable;
import android.view.View;
importandroid.view.View.OnClickListener;
import android.widget.Button;
importandroid.widget.EditText;
import android.widget.Toast;
 
public class MainActivity
  extends Activity
{
  public Button btn_enter;
  public EditText edit;
 
  static
  {
    System.loadLibrary("check");
  }
 
  public native boolean checkPasswd(StringparamString);
 
  protected void onCreate(Bundle paramBundle)
  {
    super.onCreate(paramBundle);
    setContentView(2130903040);
    this.edit =((EditText)findViewById(2131099648));
    this.btn_enter =((Button)findViewById(2131099649));
    this.btn_enter.setOnClickListener(newView.OnClickListener()
    {
      public void onClick(ViewparamAnonymousView)
      {
       MainActivity.this.btn_enter.setClickable(false);
        if (MainActivity.this.edit.getText().toString().length()<= 0)
        {
          Toast.makeText(MainActivity.this,"Please enter the password", 1).show();
          return;
        }
        if(!MainActivity.this.checkPasswd(MainActivity.this.edit.getText().toString())) {
          Toast.makeText(MainActivity.this,"Error!", 0).show();
        }
        for (;;)
        {
         MainActivity.this.btn_enter.setClickable(true);
          return;
          Toast.makeText(MainActivity.this,"Success!", 0).show();
        }
      }
    });
  }
}
注意最后那个无限循环,弹出"Success!"与否,与checkPasswd无关!这样的代码是很不严谨的,就像那种后台验证不严格的登陆验证程序,可以用 'or'='or' 绕过认证,即可登陆后台!

2.smali代码爆破
15.png
图15.smali爆破点

3.crackmesub
之前有提过crackmesub,那么这个crackmesub到底是什么,我们用adb pull/data/data/com.ucweb.crackme3/crackmesub,把这个文件下载到pc中,这个文件没有后缀,用ida打开如下图:
16.png
图16.打开出错

17.png
图17.重定位到一个非法符号!

18.png
图18.包含非标准重定位

Skipping之后,什么都没有:
19.png
图19.什么都没有

因为在前面也说过,是在sub_1280中写入了80K的垃圾数据进入crackmesub中的,文件应该是没有加过密的,因为sub_1280的分析如下:
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// (文件路径,获取数据地址,个数)
size_t __fastcall sub_1280(const char *a1, const void *a2, size_t a3)
{
  const void *v3; // r6@1
  size_t v4; // r7@1
  const char *v5; // r5@1
  FILE *v6; // r4@1
  size_t v7; // r6@2
 
  v3 = a2;
  v4 = a3;
  v5 = a1;
  v6 = fopen(a1, (const char*)&off_1C10);
  if ( v6 )
  {
    // v6是写入位置
    v7 = fwrite(v3, 1u, v4, v6);
   fclose(v6);
    chmod(v5, 0x1EDu);
  }
  else
  {
    v7 = 0;
  }
  return v7;
}


可以看到,写进去都是垃圾!
当时我有一个想法,就是注册码可能存在于crackmesub中,于是用010 editor打开crackmesub:
20.png
21.png
图20.没有,什么都没有!
  
至此,不知该如何继续了,我觉得这道题没有严格意义的注册码,那他到底怎样才会出现“success!”呢,我觉得是把流程完全走一遍,3个需要修改的跳转都要改,还有3个需要nop的sub,能出现“success!”,应该是要判断crackmesub文件的存在,并且有crackmesub这个进程的存在,因为,先看如下代码:
22.png
图21. 杀掉crackmesub进程&删除crackmesub文件

unlink()不一定能删掉crackmesub,但是crackmesub进程是会被ptrace(PTRACE_KILL, …)干掉的,所以,要通过execv()使crackmesub进程重新复活,让流程顺利进入libdvm.so中,让他执行classes.dex中指令即可成功!

0x04 后序
终于完结了,学习那么久,终于有一点成果,虽然果实并不丰满,但毕竟见证一段学习经历,从开始搭建环境起,就遇到了各种莫名其妙的error,让人摸不着头脑,不知道大家有没有过一种错觉,那就是遇到问题,但是却不知道如何具体的阐述问题,然后再百度,因为问题描述的不够精确,所以度娘没法给出solution,在做这三道题过程中,我就经常有这种感觉。也是因为非虫的《Android软件安全与逆向分析》给了帮助,才勉强对付完这3题……晚安!


本题所有文件:
链接:http://pan.baidu.com/s/1o6lABpg 密码:x5st






免费评分

参与人数 1热心值 +1 收起 理由
supperlitt + 1 拜读楼主大作,感谢,感谢。

查看全部评分

2317909768 发表于 2015-8-20 10:42
头像被屏蔽
helius 发表于 2015-8-19 22:15
提示: 作者被禁止或删除 内容自动屏蔽
A00 发表于 2015-8-19 23:35
非常厉害啊,学到了
头像被屏蔽
helius 发表于 2015-8-19 23:43
提示: 作者被禁止或删除 内容自动屏蔽
 楼主| Terrorblade 发表于 2015-8-19 23:46
helius 发表于 2015-8-19 23:43
现在公司的面试题都那么霸道吗

如果你眼尖的话,你就知道这家公司是什么公司了(字里行间已透漏)!
绝世王子 发表于 2015-8-19 23:56
谢谢楼主的无私奉献!!!!!!
绝世王子 发表于 2015-8-20 06:06
好东西必须要顶起来啊
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-7-11 08:18

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表