【攻防世界】mobile-黑客精神
Marce1

准备花一周时间把攻防世界上的mobile方向的题做一做,大部分都是套了个安卓壳子的逆向签到题,这一道比较值得记录。

image-20250522160646773

静态分析

image-20250522160624146

jadx里看到两个activity,进应用入口看一眼

image-20250522160746073

检查myapp类下的m字段的值来决定直接进work还是先注册。估计m是个静态变量,进myapp看看

image-20250522160940669

果然如此,估计initSN在动态加载了so实现,处理的赋值。用ida分析一下链接模块

image-20250522161212588

如果是一般的链接题进ida之后就能在函数栏里看到动态链接的方法,例如com_gdufs_xman_MyApp_initSN,但是这个链接库找不到。JNI_OnLoad是.so文件加载的入口点,趁此看看它做了哪些事:

1
if ( !(*vm)->GetEnv(vm, (void **)&g_env, 65542) )
  • 尝试获取JNI环境,65542对应JNI_VERSION_1_6
  • 成功获取环境后存储在变量g_env中
1
j___android_log_print(2, "com.gdufs.xman", "JNI_OnLoad()");
  • 通过Android日志系统输出调试信息,标签为com.gdufs.xman,级别为2

这时候肯定要问,这个安卓日志系统怎么看?因为这些调试信息我们从来没在使用应用或者frida的CLI里看到过

如果做过正向开发,就知道可以直接在AS的Logcat视图里看到,我们也可以在adb里通过命令行看

1
adb logcat <log_level>:<tag>

这个之后再试试。

1
native_class = (*(int (__fastcall **)(int, const char *))(*(_DWORD *)g_env + 24))(g_env, "com/gdufs/xman/MyApp");

通过JNI函数FindClass(g_env+24)查找java类com/gdufs/xman/MyApp

1
2
3
4
5
*(int (__fastcall **)(int, int, char **, int))(*(_DWORD *)g_env + 860))(
g_env,
native_class,
off_5004, // "initSN"
3)

通过JNI函数RegisterNatvies(g_env+860)注册本地方法,其中第三个参数off_5004代表方法名数组,第四个参数3代表注册的方法数量。

j___android_log_print就是输出日志。

至此,我们就知道实际上链接加载的方法实现就在off_5004中

image-20250522162712759

.data段,DCD相当于x86中的dd代表一字,相似的还有dcb,dcw,dcq,实际数据长度和db,dw,dq相同——在arm汇编中一字32位,但是表示数据长度的伪指令还是和一字16位的x86相同,真令人迷惑。

很容易看出这其实是三个方法结构体,第一个字段代表返回值,()V就是void,(Ljava/lang/String;)V就是字符串;第二个字段相当于native层中对应的C/C++函数。第三个就是函数地址的修正。所以我们就可以看出:实际上动态链接的三个函数就是链接模块中的n1 n2 n3

我们关注的是initSN,进入n1看看:

image-20250522165630070

原先调用initSN的时候本没有传入参数,但是静态分析很容易就能看出来,a1就是m。函数流程就是读取/sdcard/reg.dat中的内容,与EoPAoY62@ElRD相同则将m赋1。寻找一下关于写入/sdcard/reg.dat的代码,在n2 saveSN中有提及——回头去看MainActivity中的逻辑,会发现saveSN在第一次注册的时候被调用,传入的参数是用户输入的字符串。

image-20250522170309961

看来s就是我们传入的字符串,这个函数会对s挎挎一顿处理,然后将处理后的s写入/sdcard/.reg.dat

鉴于这个处理也不难分析,我通过算法逆向来解题

解题

算法逆向

将原字符串三个三个一组,依次与特定字符异或

简单复制粘贴一下,异或的字符都是固定的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main(){
char W3_arE_whO_we_ARE[] = "W3_arE_whO_we_ARE";
int n2016 = 2016;
int i;
for(i = 0; i <30; i++){
n2016 = (n2016 + 3) % 13;
char b0 = W3_arE_whO_we_ARE[n2016 + 3];
n2016 = (n2016 + 5) % 16;
char b1 = W3_arE_whO_we_ARE[n2016 + 1];
n2016 = (n2016 + 7) % 15;
char b2 = W3_arE_whO_we_ARE[n2016 + 2];
printf("b0: %c b1: %c b2: %c ", b0, b1, b2);
}
}

输出结果:

image-20250522180418950

就是w _ a的循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
target = 'EoPAoY62@ElRD'
en = ['w', '_', 'a']
result = []

for c in range(len(target)):
i = ord(target[c])
found = False
for o in range(32, 127):
if (o ^ i) == ord(en[c % 3]):
result.append(chr(o))
found = True
break
if not found:
result.append('?')

print(''.join(result))

最终的结果就是201608Am!2333

由 Hexo 驱动 & 主题 Keep
总字数 47.9k 访客数 访问量