安卓逆向刷题笔记
本文会持续更新
BUU-findit
题目链接:https://buuoj.cn/challenges#findit
xml里找到函数入口

可看到Java层逻辑

直接看到有两行关键代码
1 2 3 4 5 6 7
| new char[]{'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e'}[i] new char[]{'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}'}[v1]
找到两个关键字符串! ThisIsTheFlagHome 和 pvkq{m164675262033l4m49lnp7p9mnk28k75}
|
pvkq{m164675262033l4m49lnp7p9mnk28k75}
这玩意一眼凯撒位移吧,十位解密之后得到flag
flag{c164675262033b4c49bdf7f9cda28a75}
BUU-简单注册器
题目链接:https://buuoj.cn/challenges#%E7%AE%80%E5%8D%95%E6%B3%A8%E5%86%8C%E5%99%A8
xml里找到函数入口

点进去看主要逻辑

发现输入的判断条件
1 2 3
| if (xx.length() != 32 || xx.charAt(31) != 'a' || xx.charAt(1) != 'b' || (xx.charAt(0) + xx.charAt(2)) - 48 != 56) { flag = 0; }
|
可以直接按照以上判断条件输入符合的32位字符,点击按钮出flag,或者运行以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| char[] x = "dd2940c04462b4dd7c450528835cca15".toCharArray();
x[2] = (char) ((x[2] + x[3]) - 50);
x[4] = (char) ((x[2] + x[5]) - 48);
x[30] = (char) ((x[31] + x[9]) - 48);
x[14] = (char) ((x[27] + x[28]) - 97);
for (int i = 0; i < 16; i++) {
char a = x[31 - i];
x[31 - i] = x[i];
x[i] = a;
}
|
总的来说,该代码生成的flag与用户输入无关,只要输入满足条件,程序就会对固定的字符串(x = "dd2940c04462b4dd7c450528835cca15"
)进行处理,因此直接运行代码或构造符合条件的输入均可得到正确flag
攻防世界-mobile easy-so
题目链接:https://adworld.xctf.org.cn/media/file/task/456c1dab04b24036ba1d6e32a08dc882.apk
xml里找到函数入口

点进去查看主要逻辑

发现逻辑校验关键函数CheckString
,进去之后发现是调了so层的cyberpeace
函数

在IDA里反编译so文件,分析关键函数逻辑

主要逻辑就是将获取到的字符串进行一系列变换和f72c5a36569418a20907b55be5bf95ad
作比较,所以要写一段逆运算的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include <stdio.h> #include <string.h> #include <stdlib.h>
void reverse_operations(const char *input) { size_t len = strlen(input); char *output = (char *)malloc(len + 1); strcpy(output, input);
if (len >= 3) { for (size_t i = 2; i < len; i += 2) { char temp = output[i]; output[i] = output[i + 1]; output[i + 1] = temp; } }
if (len >= 2) { char temp = output[0]; output[0] = output[1]; output[1] = temp; }
if (len >= 2) { size_t half_len = len >> 1; for (size_t i = 0; i < half_len; i++) { char temp = output[i]; output[i] = output[half_len + i]; output[half_len + i] = temp; } }
printf("Original string: %s/n", output); free(output); }
int main() { const char *flag = "f72c5a36569418a20907b55be5bf95ad"; reverse_operations(flag); return 0; }
|
包上flag{}包裹,flag{90705bb55efb59da7fc2a5636549812a}
攻防世界-mobile 基础Android
题目链接:https://adworld.xctf.org.cn/media/file/task/6a0484a135bb44ba8fdcf829b5d9865b.apk
xml里找到函数入口

点进去分析主要逻辑:通过checkPassword
函数对比字符串,成功后显示Good,Please go on!并进入MainActivity2

分析checkPassword
函数逻辑

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| 根据代码逻辑,字符的转换是:
pass[len] = (char) (((255 - len) - 100) - pass[len]);
我们需要使 `pass[len]` 转换后等于 `'0'`,即 ASCII 值为 48。 设 `x` 为原字符的 ASCII 值,可以得到方程:
(255 - len - 100) - x = 48`
简化后为:
x = 255 - len - 100 - 48 x = 107 - len`
因此,原字符的 ASCII 值应为 `107 - len`。根据 `len` 从 0 到 11,得到的字符应为:
- `len = 0` -> `107` -> `'k'` - `len = 1` -> `106` -> `'j'` - `len = 2` -> `105` -> `'i'` - `len = 3` -> `104` -> `'h'` - `len = 4` -> `103` -> `'g'` - `len = 5` -> `102` -> `'f'` - `len = 6` -> `101` -> `'e'` - `len = 7` -> `100` -> `'d'` - `len = 8` -> `99` -> `'c'` - `len = 9` -> `98` -> `'b'` - `len = 10` -> `97` -> `'a'` - `len = 11` -> `96` -> '`' (反引号)
所以,一个有效的字符串是 "kjihgfedcba`",长度为 12
|
输入后进入下一界面
![Screenshot_2025-02-23-21-51-43-34_8e9213dd12c701caf40fa4cb254e198a[1].jpg](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
根据代码逻辑此时来到了MainActivity2
,分析逻辑

可以看到发送了一个广播,那么在xml布局文件里能看到被定义的广播接收器

看到关键字符串:android.is.very.fun
,输入后即可得到flag
![Screenshot_2025-02-23-21-55-58-11_8e9213dd12c701caf40fa4cb254e198a[1].jpg](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
flag{08067-wlecome}
PS:android:name="android.is.very.fun"
是自定义的广播动作,当其他组件发送一个包含 android.is.very.fun
动作的意图时,这个接收器就会被触发,所以与实际发送内容是无关的
NewStarCTF 2023 Week2-AndroDbgme
题目链接:
这道题jadx打开会炸,高版本jeb反编译是正常的,分析MainActivity
主要逻辑

发现只要动调就会出flag

那么在xml里的application
加上一条件android:debuggable=”true”
使app支持动调
![Screenshot_2025-02-26-23-25-26-25_9e8df3d0c7c1f50248b6ee043a653d26[1].jpg](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
保存后需要自签名一下
![Screenshot_2025-02-26-23-24-53-33_9e8df3d0c7c1f50248b6ee043a653d26[1].jpg](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
之后安装新的app
![Screenshot_2025-02-26-23-25-00-82_9e8df3d0c7c1f50248b6ee043a653d26[1].jpg](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
jadx双击进程即可启动动调


此时在app里任意输入点击按钮即可得到flag
![Screenshot_2025-02-26-22-50-02-73_7ca81305321c94afdc4b991336a8af21[1].jpg](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
flag{Let_1t_run_@t_f1rs7_m@ybe_th3_b3st}