首页
社区
课程
招聘
菜鸟之2015MSC第一题解题思路(适合入门级别的超详细版)
2015-1-29 13:27 16478

菜鸟之2015MSC第一题解题思路(适合入门级别的超详细版)

2015-1-29 13:27
16478
第一次发表文章,有些小紧张,怕被大牛笑话.....超详细版见附件(图文并茂)
这里添加图片、设置字体颜色等好费劲,咱们这个论坛有没有直接展示doc文件的插件么,要是没有,迫切希望kanxue坛主能加个这个功能,这样上传文件就会好看好多,也非常方便。
下面是详细步骤(可惜就是没图片):
第一步:下面是软件运行后的界面和点击按钮后的错误提示。
    

第二步:下面我们从代码角度加以分析,反编译源文件,对软件运行流程有个大体了解,下面是MainActivity类中的方法。 
 
我们主要关注oncreate()方法中的按钮点击事件部分代码,因为猜测这里有逻辑判断及错误提示框,下面我们来找错误提示框。
 
查找错误提示框的方法:1.通过提示框API及其跳转逻辑定位大体位置。2.在通过显示内容验证(R文件String类中定位资源0x7f0a0011,找到 dialog_error_tips = 0x7f0a0011在String.xml中查找dialog_error_tips对应的字符串)。
 
 
猜测上面的showDialog() 即为正确的提示框,验证方法同上,进一步将线索聚焦到就是if的判断条件中,而条件中起决定作用的是s2.equals(s3),现在需要理清s1,s2和s3。   
 

第三步:要了解s1,s2必须分析getTableFromPic() 和getPwdFromPic(),而s3的分析必须看MainActivity.bytesToAliSmsCode(s1, s.getBytes("utf-8"))。
 

s1=getTableFromPic()的分析如下:s1实质就是读取图片资源到abyte0数组中,从位置0x15d81取768个字节到数组abyte1中,用utf-8编码成的字符串(s3从这个集合中选取非连续数据)。
 

s2= getPwdFromPic()的分析,这个方法和上面的s1=getTableFromPic()差不多,s2实质就是读取图片资源到byte数组中,从0x16481取18个字节到新数组,再用utf-8编码成的字符串。
       

s3 = MainActivity.bytesToAliSmsCode(s1, s.getBytes("utf-8"))的分析:s3实质就是s1字符串中制定下标(下标是用用户输入的数据转化来的)的字连接成的字符串。
  首先分析参数s为用户的输入String s = edit.getText().toString(); ,
s.getBytes("utf-8"):这行代码的意思是把用户输入的编码成字节数组作为参数,传递给bytesToAliSmsCode(string,byte[])处理,下面分析这个方法,
        
通过分析可以看出,用户输入的s字符串转换成数组,传到bytesToAliSmsCode(string,byte[])数组中用i做下标取数组abyte0[]中的数据,再把取出来的数据做0xff & abyte0[i]) 做运算后把结果作为下标用s1.charAt(结果)累加到Stringbuilder中生成字符串。实质就是用用户输入的数据转化成下标,提取s1中的字符。

第四步:MainActivity中oncreate()中的if判断就是决定成功失败的地方,主要就是判断s2和s3是否相等,通过前面我们知道s2是
 
修改添加输入测试下面两个方法,结合输出会发现结果如下
 
 
用用户输入的数字的ASCII值的十进制作为下标,table(s3)中取出数据和s2比较

阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

上传的附件:
收藏
点赞1
打赏
分享
最新回复 (15)
雪    币: 188
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
JackJoker 2015-1-29 13:41
2
0
学习一下
雪    币: 163
活跃值: (1288)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
学编程 1 2015-1-29 15:22
3
0
你用的是啥工具哈,有针对jd-jui进行处理过
雪    币: 1013
活跃值: (1397)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
aihacker 2015-1-29 15:38
4
0
apktool自己做了个bat直接反出来的
雪    币: 163
活跃值: (1288)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
学编程 1 2015-1-29 15:56
5
0
apktool 反出来的不都是smali代码吗?

jd-gui 反出来的,会有些错误的

str4 = MainActivity.access$0(str2, str1.getBytes("utf-8"));

// ERROR //
  protected String getPwdFromPic()
  {
    // Byte code:
    //   0: aconst_null
    //   1: astore_1
    //   2: ldc 79
    //   4: astore_2
    //   5: aload_0
    //   6: invokevirtual 83        com/example/simpleencryption/MainActivity:getResources        ()Landroid/content/res/Resources;
    //   9: invokevirtual 89        android/content/res/Resources:getAssets        ()Landroid/content/res/AssetManager;
    //   12: ldc 91
    //   14: invokevirtual 97        android/content/res/AssetManager:open        (Ljava/lang/String;)Ljava/io/InputStream;
    //   17: astore_1
    //   18: aload_1
    //   19: invokevirtual 102        java/io/InputStream:available        ()I
    //   22: istore 7
    //   24: iload 7
    //   26: newarray byte
    //   28: astore 8
    //   30: aload_1
    //   31: aload 8
    //   33: iconst_0
    //   34: iload 7
    //   36: invokevirtual 106        java/io/InputStream:read        ([BII)I
    //   39: pop
    //   40: bipush 18
    //   42: newarray byte
    //   44: astore 10
    //   46: aload 8
    //   48: ldc 107
    //   50: aload 10
    //   52: iconst_0
    //   53: bipush 18
    //   55: invokestatic 113        java/lang/System:arraycopy        (Ljava/lang/Object;ILjava/lang/Object;II)V
    //   58: new 22        java/lang/String
    //   61: dup
    //   62: aload 10
    //   64: ldc 115
    //   66: invokespecial 118        java/lang/String:<init>        ([BLjava/lang/String;)V
    //   69: astore 11
    //   71: aload_1
    //   72: ifnull +54 -> 126
    //   75: aload_1
    //   76: invokevirtual 121        java/io/InputStream:close        ()V
    //   79: aload 11
    //   81: astore_2
    //   82: aload_2
    //   83: areturn
    //   84: astore 5
    //   86: aload 5
    //   88: invokevirtual 124        java/lang/Exception:printStackTrace        ()V
    //   91: aload_1
    //   92: ifnull -10 -> 82
    //   95: aload_1
    //   96: invokevirtual 121        java/io/InputStream:close        ()V
    //   99: aload_2
    //   100: areturn
    //   101: astore 6
    //   103: aload_2
    //   104: areturn
    //   105: astore_3
    //   106: aload_1
    //   107: ifnull +7 -> 114
    //   110: aload_1
    //   111: invokevirtual 121        java/io/InputStream:close        ()V
    //   114: aload_3
    //   115: athrow
    //   116: astore 12
    //   118: aload 11
    //   120: areturn
    //   121: astore 4
    //   123: goto -9 -> 114
    //   126: aload 11
    //   128: areturn
    //
    // Exception table:
    //   from        to        target        type
    //   5        71        84        java/lang/Exception
    //   95        99        101        java/io/IOException
    //   5        71        105        finally
    //   86        91        105        finally
    //   75        79        116        java/io/IOException
    //   110        114        121        java/io/IOException
  }
雪    币: 21
活跃值: (169)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
cqccqc 2015-1-29 15:59
6
0
jeb decompiler
雪    币: 163
活跃值: (1288)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
学编程 1 2015-1-29 16:12
7
0
jeb decomplier 按Tab,看JAVA代码比jd-gui好多了。
不知道两者实现原理有啥区别。

楼主文档里的图片代码更好些,几乎是源代码了。
apktool能实现此等效果?
雪    币: 17649
活跃值: (4611)
能力值: ( LV15,RANK:1820 )
在线值:
发帖
回帖
粉丝
HHHso 22 2015-1-29 17:38
8
0
楼主精神可嘉,不过第一题接上调试器,由日志信息就可以得到了
DDMS调试得到调试信息日志,得到码表和密码,定义后续python脚本,执行,得到密码。
01-22 22:23:37.349: I/lil(28406): table:一乙二十丁厂七卜人入八九几儿了力乃刀又三于干亏士工土才寸下大丈与万上小口巾山千乞川亿个勺久凡及夕丸么广亡门义之尸弓己已子卫也女飞刃习叉马乡丰王井开夫天无元专云扎艺木五支厅不太犬区历尤友匹车巨牙屯比互切瓦止少日中冈贝内水见午牛手毛气升长仁什片仆化仇币仍仅斤爪反介父从今凶分乏公仓月氏勿欠风丹匀乌凤勾文六方火为斗忆订计户认心尺引丑巴孔队办以允予劝双书幻玉刊示末未击打巧正扑扒功扔去甘世古节本术可丙左厉右石布龙平灭轧东卡北占业旧帅归且旦目叶甲申叮电号田由史只央兄叼叫另叨叹四生失禾丘付仗代仙们仪白仔他斥瓜乎丛令用甩印乐
01-22 22:23:37.349: I/lil(28406): pw:义弓么丸广之581026
01-22 22:23:37.349: I/lil(28406): enPassword:么广亡门

def dowithdo():
  table=u'一乙二十丁厂七卜人入八九几儿了力乃刀又三于干亏士工土才寸下大丈与万上小口巾山千乞川亿个勺久凡及夕丸么广亡门义之尸弓己已子卫也女飞刃习叉马乡丰王井开夫天无元专云扎艺木五支厅不太犬区历尤友匹车巨牙屯比互切瓦止少日中冈贝内水见午牛手毛气升长仁什片仆化仇币仍仅斤爪反介父从今凶分乏公仓月氏勿欠风丹匀乌凤勾文六方火为斗忆订计户认心尺引丑巴孔队办以允予劝双书幻玉刊示末未击打巧正扑扒功扔去甘世古节本术可丙左厉右石布龙平灭轧东卡北占业旧帅归且旦目叶甲申叮电号田由史只央兄叼叫另叨叹四生失禾丘付仗代仙们仪白仔他斥瓜乎丛令用甩印乐'
  pw=u'义弓么丸广之'
  for pw_e in pw:
    print chr(table.find(pw_e))

dowithdo()

>>> dowithdo()
5
8
1
0
2
6
雪    币: 507
活跃值: (120)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
鬼谷子c 1 2015-1-29 18:51
9
0
第一题,apk中存在解密代码,直接使用即可的....不用转python写了
雪    币: 16
活跃值: (24)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
猫狗大战 2015-1-29 20:41
10
0
唉,大家都没尝试用jeb来解包么?

aliCodeToBytes就是解码算法。

然后copy到eclipse下,直接调用……
获取密码的:
cc.zip

下面是jeb直接反出来的:

package com.example.simpleencryption;

import android.app.Activity;
import android.app.AlertDialog$Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface$OnClickListener;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View$OnClickListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

public class MainActivity extends Activity {
    public MainActivity() {
        super();
    }

    static String access$0(String arg1, byte[] arg2) {
        return MainActivity.bytesToAliSmsCode(arg1, arg2);
    }

    static void access$1(MainActivity arg0) {
        arg0.showDialog();
    }

    private static byte[] aliCodeToBytes(String codeTable, String strCmd) {
        byte[] v1 = new byte[strCmd.length()];
        int v2;
        for(v2 = 0; v2 < strCmd.length(); ++v2) {
            v1[v2] = ((byte)codeTable.indexOf(strCmd.charAt(v2)));
        }

        return v1;
    }

    private static String bytesToAliSmsCode(String table, byte[] data) {
        StringBuilder v1 = new StringBuilder();
        int v0;
        for(v0 = 0; v0 < data.length; ++v0) {
            v1.append(table.charAt(data[v0] & 255));
        }

        return v1.toString();
    }

    protected String getPwdFromPic() {
        String v6;
        InputStream v3;
        String v5 = "";
        try {
            v3 = this.getResources().getAssets().open("logo.png");
            int v4 = v3.available();
            byte[] v0 = new byte[v4];
            v3.read(v0, 0, v4);
            byte[] v1 = new byte[18];
            System.arraycopy(v0, 91265, v1, 0, 18);
            v6 = new String(v1, "utf-8");
            if(v3 == null) {
                return v6;
            }
        }
        catch(Throwable v7) {
        label_30:
            if(v3 != null) {
                try {
                    v3.close();
                }
                catch(IOException v8) {
                }
            }

            throw v7;
        }
        catch(Exception v2) {
            try {
                v2.printStackTrace();
                if(v3 == null) {
                    return v5;
                }
            }
            catch(Throwable v7) {
                goto label_30;
            }

            try {
                v3.close();
            }
            catch(IOException v7_1) {
            }

            return v5;
        }

        try {
            v3.close();
            v5 = v6;
        }
        catch(IOException v7_1) {
            v5 = v6;
        }

        return v5;
    }

    protected String getTableFromPic() {
        String v6;
        InputStream v3;
        String v5 = "";
        try {
            v3 = this.getResources().getAssets().open("logo.png");
            int v4 = v3.available();
            byte[] v0 = new byte[v4];
            v3.read(v0, 0, v4);
            byte[] v1 = new byte[768];
            System.arraycopy(v0, 89473, v1, 0, 768);
            v6 = new String(v1, "utf-8");
            if(v3 == null) {
                return v6;
            }
        }
        catch(Throwable v7) {
        label_30:
            if(v3 != null) {
                try {
                    v3.close();
                }
                catch(IOException v8) {
                }
            }

            throw v7;
        }
        catch(Exception v2) {
            try {
                v2.printStackTrace();
                if(v3 == null) {
                    return v5;
                }
            }
            catch(Throwable v7) {
                goto label_30;
            }

            try {
                v3.close();
            }
            catch(IOException v7_1) {
            }

            return v5;
        }

        try {
            v3.close();
            v5 = v6;
        }
        catch(IOException v7_1) {
            v5 = v6;
        }

        return v5;
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.requestWindowFeature(1);
        this.setContentView(2130903064);
        this.findViewById(2131034174).setOnClickListener(new View$OnClickListener() {
            public void onClick(View v) {
                String v3 = this.val$edit.getText().toString();
                String v5 = MainActivity.this.getTableFromPic();
                String v4 = MainActivity.this.getPwdFromPic();
                Log.i("lil", "table:" + v5);
                Log.i("lil", "pw:" + v4);
                try {
                    String v2 = MainActivity.bytesToAliSmsCode(v5, v3.getBytes("utf-8"));
                    Log.i("lil", "enPassword:" + v2);
                }
                catch(UnsupportedEncodingException v1) {
                    v1.printStackTrace();
                }

                if(v4 == null || (v4.equals("")) || !v4.equals(v2)) {
                    AlertDialog$Builder v0 = new AlertDialog$Builder(MainActivity.this);
                    v0.setMessage(2131361809);
                    v0.setTitle(2131361808);
                    v0.setPositiveButton(2131361811, new DialogInterface$OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    });
                    v0.show();
                }
                else {
                    MainActivity.this.showDialog();
                }
            }
        });
    }

    private void showDialog() {
        AlertDialog$Builder v0 = new AlertDialog$Builder(((Context)this));
        v0.setMessage(2131361810);
        v0.setTitle(2131361808);
        v0.setPositiveButton(2131361811, new DialogInterface$OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        v0.show();
    }
}

上传的附件:
雪    币: 41
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
m筱米 2015-1-30 11:42
11
0
请问,jeb反编译工具给贡献一下呗。。。
雪    币: 16
活跃值: (24)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
猫狗大战 2015-1-30 11:54
12
0
直接论坛搜索jeb……
雪    币: 8
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
victory石头 2015-1-31 15:17
13
0
学习了。
雪    币: 17649
活跃值: (4611)
能力值: ( LV15,RANK:1820 )
在线值:
发帖
回帖
粉丝
HHHso 22 2015-2-1 20:24
14
0
哈哈,从效率那就得看是直接复制两个字符串调用下查找函数快,还是写代码调用它原来的代码块了。
一个追求速度(当然,如果不用python的人还得装个python那就没速度了),一个追求深层技术原理逆向。
雪    币: 8
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
victory石头 2015-3-8 15:23
15
0
怎么接调试器啊
雪    币: 17649
活跃值: (4611)
能力值: ( LV15,RANK:1820 )
在线值:
发帖
回帖
粉丝
HHHso 22 2015-3-9 12:19
16
0
Android开发环境一般有相应的调试功能,典型的如Eclipse配置的Android开发环境,接上设备即可得到设备输出的日志信息,不必做任何调试步骤。
游客
登录 | 注册 方可回帖
返回