一.easy-so
- jadx分析程序逻辑
可以看到关键在于cyberpeace.CheckString()函数
双击跟进之后可以发现是native层函数
- ida查看so文件
程序逻辑:- 将字符串保存到新的空间buffer中
- 第一个判断是将buffer的前16个字符和后16个字符进行交换
- 第二个判断是将buffer的2个相邻的字符互换位置
_BOOL8 __fastcall Java_com_testjava_jack_pingan2_cyberpeace_CheckString(__int64 a1, __int64 a2, __int64 a3)
{
const char *str; // r14
size_t len; // rax
int len2; // r15d
unsigned __int64 v6; // r12
char *newMem; // rax
char *buffer; // r13
bool v9; // cc
size_t v10; // r12
size_t i; // rbx
char tmp; // al
char tmp1; // al
size_t j; // rbx
char tmp2; // al
str = (*(*a1 + 1352LL))(a1, a3, 0LL);
len = strlen(str);
len2 = len;
v6 = ((len << 32) + 0x100000000LL) >> 32;
newMem = malloc(v6);
buffer = newMem;
v9 = v6 <= len2;
v10 = v6 - len2;
if ( v9 )
v10 = 0LL;
memset(&newMem[len2], 0, v10);
memcpy(buffer, str, len2);
if ( strlen(buffer) >= 2 )
{
i = 0LL;
do
{
tmp = buffer[i];
buffer[i] = buffer[i + 16];
buffer[i++ + 16] = tmp;
}
while ( strlen(buffer) >> 1 > i );
//32>>1 = 16 也就是说i<16时执行循环
}
tmp1 = *buffer;
if ( *buffer )
{
*buffer = buffer[1];
buffer[1] = tmp1;
if ( strlen(buffer) >= 3 )
{
j = 2LL;
do
{
tmp2 = buffer[j];
buffer[j] = buffer[j + 1];
buffer[j + 1] = tmp2;
j += 2LL;
}
while ( strlen(buffer) > j );
}
}
return strcmp(buffer, "f72c5a36569418a20907b55be5bf95ad") == 0;
}
注意,不同的so文件得到的反汇编结果不一样
一开始我使用arm64-v8a文件夹中的so文件得到的是这个结果,显然是错误的,这个循环最后会丢失一些数据
后来打开x86_64文件夹的so文件就正常了
- 解题脚本:
#include <stdio.h>
int main()
{
char flag[33] = "f72c5a36569418a20907b55be5bf95ad";
char tmp;
for (int i = 0; i < 32; i += 2) // 两两交换
{
tmp = flag[i];
flag[i] = flag[i + 1];
flag[i + 1] = tmp;
}
int i = 0;
do
{
tmp = flag[i];
flag[i] = flag[i + 16];
flag[i++ + 16] = tmp;
} while (i<16);
printf("flag{%s}",flag);
//flag{90705bb55efb59da7fc2a5636549812a}
return 0;
}
二.ezjni
- 程序逻辑分析
可以看到也是获取字符串然后加密- 获取字符串
- 进行base64加密(base表有更换)
- 调用ncheck这个native函数判断结果
base64encode函数,换表base64加密:
ncheck函数,这里应该和上一题easyso是一样的操作,只是由于反编译错误 - 先将前16和后16个字符进行交换
- 然后从头遍历,每两个字符一组互换位置
- 解题脚本:
先输出ncheck处理前的base串
#include <stdio.h>
int main()
{
char flag[33] = "MbT3sQgX039i3g==AQOoMQFPskB1Bsc7";
char tmp;
for (int i = 0; i < 32; i += 2) // 两两交换
{
tmp = flag[i];
flag[i] = flag[i + 1];
flag[i + 1] = tmp;
}
int i = 0;
do
{
tmp = flag[i];
flag[i] = flag[i + 16];
flag[i++ + 16] = tmp;
} while (i<16);
printf("%s",flag);
//QAoOQMPFks1BsB7cbM3TQsXg30i9g3==
return 0;
}
先输出base64表
public class test1{
private static final char[] table = {'i', '5', 'j', 'L', 'W', '7', 'S', '0', 'G', 'X', '6', 'u', 'f', '1', 'c', 'v', '3', 'n', 'y', '4', 'q', '8', 'e', 's', '2', 'Q', '+', 'b', 'd', 'k', 'Y', 'g', 'K', 'O', 'I', 'T', '/', 't', 'A', 'x', 'U', 'r', 'F', 'l', 'V', 'P', 'z', 'h', 'm', 'o', 'w', '9', 'B', 'H', 'C', 'M', 'D', 'p', 'E', 'a', 'J', 'R', 'Z', 'N'};
public static void main(String[] args) {
System.out.println("hello");
String s="hellk";
System.out.println(s);
for (int i=0;i<table.length;i++)
{
System.out.print(table[i]);
//i5jLW7S0GX6uf1cv3ny4q8es2Q+bdkYgKOIT/tAxUrFlVPzhmow9BHCMDpEaJRZN
}
}
}
然后用CyberChef嗦一下