吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 22583|回复: 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] 纯文本查看 复制代码
  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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
[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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
[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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
[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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
// (文件路径,获取数据地址,个数)
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, 2024-4-27 11:52

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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