首页
社区
课程
招聘
[原创]1,2,3题解
2015-1-26 14:18 2928

[原创]1,2,3题解

2015-1-26 14:18
2928
第一题:

apk拿来,直接扔jeb里面,看到如下信息:

            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();
                }


所以答案和表都输出在了log信息里面,直接logcat:

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

对比了一下自己的输入,发现就是个简单的置换密码,写了一个脚本:

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


第二题:
题目逆向之后发现主要的逻辑在native里面实现了,把libcrackme.so扔到ida里面进行逆向,得到:

signed int __fastcall Java_com_yaotong_crackme_MainActivity_securityCheck(JNIEnv *a1, jobject a2, char *a3)
{
  JNIEnv *v3; // r5@1
  char *v4; // r4@1
  char *v5; // r0@5
  char *v6; // r2@5
  int v7; // r3@6
  signed int v8; // r1@7

  v3 = a1;
  v4 = a3;
  if ( !byte_6359 )
  {
    sub_2494((int)&byte_6304, 8, (int)&unk_446B, (int)&unk_4468, 2u, 7);
    byte_6359 = 1;
  }
  if ( !unk_635A )
  {
    sub_24F4((int)&unk_636C, 25, (int)&unk_4530, (int)&unk_4474, 3u, 117);
    unk_635A = 1;
  }
  _android_log_print(4, (int)&byte_6304, (int)&unk_636C);
  v5 = (char *)((int (__fastcall *)(JNIEnv *, char *, _DWORD))(*v3)->GetStringUTFChars)(v3, v4, 0);
  v6 = wojiushidaan;
  while ( 1 )
  {
    v7 = (unsigned __int8)*v6;
    if ( v7 != (unsigned __int8)*v5 )
      break;
    ++v6;
    ++v5;
    v8 = 1;
    if ( !v7 )
      return v8;
  }
  return 0;
}


可以看到有一个wojiushidaan的地方,对输入进行了比较。但是输入答案发现是错的。那么可以猜测,之前的那个函数,应该是对这个地方进行了解密。
这时候自然就想到了,用gdb attach上去,下断点,输出答案。
aay@ubuntu:~$ adb shell
bash-4.3# ps -aef | grep crack
10066    19573   471  3 02:43 ?        00:00:01 com.yaotong.crackme
root     19724 19460  0 02:43 pts/5    00:00:00 grep crack
bash-4.3# gdb --pid 19573
GNU gdb (GDB) 7.8.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "armv7l-tizen-linux-gnueabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
Attaching to process 19573
Reading symbols from /system/bin/app_process...(no debugging symbols found)...done.
warning: Could not load shared library symbols for 145 libraries, e.g. libc.so.
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?
Reading symbols from /system/bin/linker...(no debugging symbols found)...done.
Loaded symbols for /system/bin/linker
0x400fb5f0 in ?? ()
(gdb) set solib-search-path /data/data/com.yaotong.crackme/lib/
Reading symbols from /data/app-lib/com.yaotong.crackme-1/libcrackme.so...(no debugging symbols found)...done.
Loaded symbols for /data/app-lib/com.yaotong.crackme-1/libcrackme.so
(gdb) b Java_com_yaotong_crackme_MainActivity_securityCheck
Breakpoint 1 at 0x63c0e1a8
(gdb) c
Continuing.


这时候开始,输入我们的密码,点输入:

Breakpoint 1, 0x63c0e1a8 in Java_com_yaotong_crackme_MainActivity_securityCheck () from /data/app-lib/com.yaotong.crackme-1/libcrackme.so
(gdb) display /i $pc
1: x/i $pc
=> 0x63c0e1a8 <Java_com_yaotong_crackme_MainActivity_securityCheck>:
    push        {r4, r5, r6, r7, r11, lr}
(gdb) ni
0x63c0e1ac in Java_com_yaotong_crackme_MainActivity_securityCheck ()
   from /data/app-lib/com.yaotong.crackme-1/libcrackme.so
1: x/i $pc
=> 0x63c0e1ac <Java_com_yaotong_crackme_MainActivity_securityCheck+4>:
    sub sp, sp, #8
(gdb)
。。。。。。。。。。。
(gdb)
0x63c0e2b4 in Java_com_yaotong_crackme_MainActivity_securityCheck ()
   from /data/app-lib/com.yaotong.crackme-1/libcrackme.so
3: x/s $r2  0x63c11450: "aiyou,bucuoo"
2: x/s $r1  0x68:       <error: Cannot access memory at address 0x68>
1: x/i $pc
=> 0x63c0e2b4 <Java_com_yaotong_crackme_MainActivity_securityCheck+268>:        bne     0x63c0e2d0 <Java_com_yaotong_crackme_MainActivity_s
ecurityCheck+296>

答案就出来了,"aiyou,bucuoo"

第三题:

由于对apk加壳与保护不熟悉,这道题目花了很多时间,走了一些弯路。

简单分析了一下这个程序,发现里面的classes.dex就是个空壳,所有的应用逻辑都做在了里面的so中。然后发现提供的三个so中,libmobisecy.so本身就是个dex文件,反汇编之后,发现这个文件里面实现了很多类和方法,但是实现的内容全部都是简单的throw了一个exception。这时候猜想,应该是在native的so加载之后,进行的解密,修复了业务逻辑,才执行的。这时候想到,在程序修复了业务逻辑之后,dump内存应该就可以了。

发现gdb 无法attach到运行中的程序,因为程序自己在运行的时候执行了ptrace调用,导致我们的gdb挂载不上去。这一步,我写了一个内核模块,hook了ptrace的系统调用,阻止程序ptrace自己。
另外发现,这个程序经常在结束之后,再恢复的时候,就结束,写内核模块的时候,就顺便把sys_kill也hook了一下。

内核模块核心代码如下:
asmlinkage int my_ptrace(long request, long pid, unsigned long addr, unsigned long data)
{
   if(getuid() == 10070){
       printk("ptraced : %ld %d %p %p state: %d\n",request,pid,addr,data, state);
       return 0;
   }
   return original_call(request, pid , addr , data);
}
asmlinkage long hook_sys_kill(int pid, int sig){
    int uid = getuid();
    if(uid == 10070){
        printk("ptraced : kill: %d %d uid: %d \n",pid,sig,uid);
        return 0;
    }
    return sys_kill(pid,sig);
}

这时候,就可以顺利的挂载到进程中进行调试了。
Attach上去之后,想到先把内存dump下来看看。
这时候发现,mapping映射里面,多了一个libmobisecx.so,并且被delete了。
然后发现,程序有时候会卡死,然后这个文件还没来得及delete,我就直接从目录里面把这个文件拷出来了。
对比了一下这个文件,发现几乎就是libmobisecy.so拷贝了一下,然后里面有些地方改动了一下,猜测应该是把文件里面的地址偏移给改了。
gdb上去之后,对照着,把这部分对应内存dump下来,然后扔到ida里面,发现里面的函数实现指向了不同的地址,这个地址空间跟原来的地址空间不连续。
根据地址偏移,在内存中把这部分也dump出来,然后扔ida里面进行分析。
这时候就有两个选择,一种是直接分析虚拟机的指令码,另一种是修复dex文件。
当时做题时,对dex文件结构不熟悉,就先选择了第一种,分析字节码的方案。然后也基本上逆向出来了大概,分析出来了最后的答案,但是,因为一个失误,被莫尔斯码的编码坑了,题目中的码表跟标准的码表不一致,而我图方便,直接网上搜了个工具转换过去的,始终输入答案都不正确,导致我后来一直纠结在修复dex文件的过程中。
逆向后的代码逻辑如下:

            label_118:
                char[] v1_6 = v5.toCharArray();
                v0_6 = v5.substring(0, 2).hashCode();
                if(v0_6 <= 3904) {
                    goto label_129;
                }

                this.b.sendEmptyMessage(4);
                return;
            label_129:
                if(v0_6 == 3618) {
                    if(v1_6[0] + v1_6[1] == 168) {
                        goto label_138;
                    }

                    goto label_171;
                    do {
                    label_138:
                        byte[] v5_1 = e.class.getAnnotation(f.class).a() + a.class.getAnnotation(f.class
                                ).a().getBytes();
                        if(v1_6.length - 2 == v5_1.length) {
                            v0_6 = 0;
                            while(true) {
                                if(v0_6 >= v5_1.length) {
                                    goto label_181;
                                }
                                else if(v1_6[v0_6 + 2] != v5_1[v0_6]) {
                                    v0_6 = 0;
                                }
                                else {
                                    ++v0_6;
                                    continue;
                                }

                                goto label_163;
                            }
                        }

                        goto label_170;
                    }
                    while(true);

经过简单的计算,可以得到,最后的答案为s57e1p,但是需要用题目中莫尔斯码的形式输入。
    static  {
        e.a = new HashMap();
        e.a("a", ". _");
        e.a("b", "_ . . .");
        e.a("c", "_ . _ .");
        e.a("d", "_ . .");
        e.a("e", ".");
        e.a("f", ". . _ .");
        e.a("g", "_ _ .");
        e.a("h", ". . . .");
        e.a("i", ". .");
        e.a("j", ". _ _ _");
        e.a("k", "_ . _");
        e.a("l", ". _ . .");
        e.a("m", "_ _");
        e.a("n", "_ .");
        e.a("o", "_ _ _");
        e.a("p", ". _ _ .");
        e.a("q", "_ _ . _");
        e.a("r", ". _ .");
        e.a("s", ". . .");
        e.a("t", "_");
        e.a("u", ". . _");
        e.a("v", ". . . _");
        e.a("w", ". _ _");
        e.a("x", "_ . . _");
        e.a("y", "_ . _ _");
        e.a("z", "_ _ . .");
        e.a("2", ". _ _ _ _");
        e.a("1", ". . _ _ _");
        e.a("3", ". . . _ _");
        e.a("4", ". . . . _");
        e.a("0", ". . . . .");
        e.a("6", "_ . . . .");
        e.a("9", "_ _ . . .");
        e.a("8", "_ _ _ . .");
        e.a("7", "_ _ _ _ .");
        e.a("5", "_ _ _ _ _");
    }

可以看到,数字的编码顺序被调整过了。~~>_<~~耽误了太多时间,第四题就来不及搞了。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回