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层
- 直接上伪代码
这里第三个参数我改成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
- 分析关键代码逻辑
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