2017年陕西省网络空间安全技术大赛·Mobile T3

0x00XTU

apk链接: https://pan.baidu.com/s/1OC9R6lOAKa31hjY4zZucmQ 密码: 83ag

0x01JAVA层

  • 简要分析一下click监听事件,找到关键判断方法encrypt()
this.button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if (GetString.encrypt(MainActivity.this.editText.getText().toString().trim())) {
                    Toast.makeText(MainActivity.this, "OK", 0).show();
                } else {
                    Toast.makeText(MainActivity.this, "Error", 0).show();
                }
            }
        });
    }
  • 我们点进去看看,native声明,我们直接分析XTU.so文件
package com.example.xtu;
 
public class GetString {
    public static native boolean encrypt(String str);
 
    public static native String getString();
 
    public static native String sendData(String str);
 
    static {
        System.loadLibrary("XTU");
    }
}

0x02Native层

  1. 直接上伪代码
    这里第三个参数我改成jstring类型,名称改成input,都可以通过右键Y/N实现
    signed int __fastcall Java_com_example_xtu_GetString_encrypt(_JNIEnv *a1, int a2, jstring input)
    {
      _JNIEnv *v3; // r4@1
      jstring v4; // r7@1
      int v5; // r6@1
      int v6; // r0@1
      const char *v7; // r5@1
      const char *v8; // r6@1
      char *s; // ST04_4@1
      size_t v10; // r4@1
      size_t v11; // r7@1
      char *v12; // r4@1
      char *v13; // r7@1
      size_t v14; // r0@1
      size_t i; // r6@1
      int v16; // r3@4
      char *v18; // [sp+8h] [bp-60h]@1
      char dest; // [sp+14h] [bp-54h]@1
    
      v3 = a1;
      v4 = input;
      v5 = _JNIEnv::NewStringUTF(a1, "yInS567!bcNOUV8vwCDefXYZadoPQRGx13ghTpqrsHklm2EFtuJKLzMijAB094W");
      v6 = _JNIEnv::NewStringUTF(v3, "Welc0meT0XTUCTF");
      v7 = (const char *)_JNIEnv::GetStringUTFChars(v3, v6, 0);
      v8 = (const char *)_JNIEnv::GetStringUTFChars(v3, v5, 0);
      s = (char *)_JNIEnv::GetStringUTFChars(v3, v4, 0);
      v10 = j_j_strlen(v7);
      v11 = j_j_strlen(v8);
      v12 = (char *)j_operator new[](v10 + 1);
      v13 = (char *)j_operator new[](v11 + 1);
      v14 = j_j_strlen(s);
      v18 = (char *)j_operator new[](v14 + 1);
      j_j_memcpy(&dest, &unk_2018, 0x3Cu);            //拷贝unk_2018的内容给dest,长度为0x3C
      j_j_strcpy(v12, v7);
      j_j_strcpy(v13, v8);
      j_j_strcpy(v18, s);
      for ( i = 0; i < j_j_strlen(v7); ++i )
        v12[i] = v13[*((_DWORD *)&dest + i)];           
      v16 = 0;
      while ( (unsigned __int8)v18[v16] == (unsigned __int8)v12[v16] )
      {
        if ( ++v16 == 15 )
          return 1;
      }
      return 0;
    }

    上面的unk_2018双击进去,能看到如下
    经过memcpy以后,int dest[] = {0x39,0x20,7,0xA,0x20,0x29,0x13,2,0x3A,0xC,0x11,0x31,0x3B,0xB,7};

    .rodata:00002018 ; ===========================================================================
    .rodata:00002018
    .rodata:00002018 ; Segment type: Pure data
    .rodata:00002018                 AREA .rodata, DATA, READONLY
    .rodata:00002018                 ; ORG 0x2018
    .rodata:00002018 unk_2018        DCB 0x39 ; 9            ; DATA XREF: Java_com_example_xtu_GetString_encrypt+76o
    .rodata:00002018                                         ; .text:off_E6Co ...
    .rodata:00002019                 DCB    0
    .rodata:0000201A                 DCB    0
    .rodata:0000201B                 DCB    0
    .rodata:0000201C                 DCB 0x20
    .rodata:0000201D                 DCB    0
    .rodata:0000201E                 DCB    0
    .rodata:0000201F                 DCB    0
    .rodata:00002020                 DCB    7
    .rodata:00002021                 DCB    0
    .rodata:00002022                 DCB    0
    .rodata:00002023                 DCB    0
    .rodata:00002024                 DCB  0xA
    .rodata:00002025                 DCB    0
    .rodata:00002026                 DCB    0
    .rodata:00002027                 DCB    0
    .rodata:00002028                 DCB 0x20
    .rodata:00002029                 DCB    0
    .rodata:0000202A                 DCB    0
    .rodata:0000202B                 DCB    0
    .rodata:0000202C                 DCB 0x29 ; )
    .rodata:0000202D                 DCB    0
    .rodata:0000202E                 DCB    0
    .rodata:0000202F                 DCB    0
    .rodata:00002030                 DCB 0x13
    .rodata:00002031                 DCB    0
    .rodata:00002032                 DCB    0
    .rodata:00002033                 DCB    0
    .rodata:00002034                 DCB    2
    .rodata:00002035                 DCB    0
    .rodata:00002036                 DCB    0
    .rodata:00002037                 DCB    0
    .rodata:00002038                 DCB 0x3A ; :
    .rodata:00002039                 DCB    0
    .rodata:0000203A                 DCB    0
    .rodata:0000203B                 DCB    0
    .rodata:0000203C                 DCB  0xC
    .rodata:0000203D                 DCB    0
    .rodata:0000203E                 DCB    0
    .rodata:0000203F                 DCB    0
    .rodata:00002040                 DCB 0x11
    .rodata:00002041                 DCB    0
    .rodata:00002042                 DCB    0
    .rodata:00002043                 DCB    0
    .rodata:00002044                 DCB 0x31 ; 1
    .rodata:00002045                 DCB    0
    .rodata:00002046                 DCB    0
    .rodata:00002047                 DCB    0
    .rodata:00002048                 DCB 0x3B ; ;
    .rodata:00002049                 DCB    0
    .rodata:0000204A                 DCB    0
    .rodata:0000204B                 DCB    0
    .rodata:0000204C                 DCB  0xB
    .rodata:0000204D                 DCB    0
    .rodata:0000204E                 DCB    0
    .rodata:0000204F                 DCB    0
    .rodata:00002050                 DCB    7
    .rodata:00002051                 DCB    0
    .rodata:00002052                 DCB    0
    .rodata:00002053                 DCB    0
  2. 分析关键代码逻辑
      for ( i = 0; i < j_j_strlen(v7); ++i )              //v7是v6转化为char *类型以后取长度,即15
        v12[i] = v13[*((_DWORD *)&dest + i)];             //v13即上面v5的一大串字符串;v12是长度和v6一样的开辟出来的新的内存空间
      v16 = 0;
      while ( (unsigned __int8)v18[v16] == (unsigned __int8)v12[v16] )   //v18是我输入的input的一份拷贝,在此验证每一位是否匹配
      {
        if ( ++v16 == 15 )
          return 1;
      }
      return 0;

0x03 C语言代码实现

  • 还是比较容易实现的,dest作为arr的下标索引,打印指定序列的字符即可
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
	char arr[] = "yInS567!bcNOUV8vwCDefXYZadoPQRGx13ghTpqrsHklm2EFtuJKLzMijAB094W";
	int dest[] = {0x39,0x20,7,0xA,0x20,0x29,0x13,2,0x3A,0xC,0x11,0x31,0x3B,0xB,7};
	char s[] = "";
	for(int i=0; i<15; i++){
		s[i] = arr[dest[i]];
	}
	printf("%s",s);
	system("pause");
}
  • Caputure the flag:{A1!N1HenBUCu0O!}
    附上成功截图:


0x04总结

        这是我操作so层的第三题,刚开始看到反汇编伪代码变量很多,很慌,不知如何下手分析。这题给了一个很好的引子,就三个原字符串:
input,"yInS567!bcNOUV8vwCDefXYZadoPQRGx13ghTpqrsHklm2EFtuJKLzMijAB094W","Welc0meT0XTUCTF";
然后是每个都转化成char*赋值给一堆v...,再又是strlen求每个数组的长度赋值给一堆v....,然后是通过数组长度开辟新的空间,再之后通过strcpy把原来的字符串进行一份拷贝,再进行后面关键比较的操作。
        变量多,但队形整齐,点击点中一个变量,比如v6,那么该方法内所有v6都被高亮,可以以此分析逻辑。

        参考链接:https://www.52pojie.cn/thread-604320-1-1.html

猜你喜欢

转载自blog.csdn.net/guchenjun789/article/details/79532324
T3
今日推荐