安卓随记

Android逆向 随记

apk文件结构

文件 注释
assets 存放apk静态资源文件 如视频 音频 图片等
lib armeabi-v7a基本通用所有安卓设备、arm64-v8a只适用于64位的安卓设备、x86常见于安卓模拟器 其目录下的.so文件是c/c++编译的动态链接库文件
META-INF 保存应用的签名信息 签名信息可以验证apk文件的完整性
res 存放资源文件 包括图片 字符串等
AndroidMainfest.xml apk的应用清单信息 有应用名 版本 权限 引用的库文件等
classes.dex classes.dex是java源码编译后生成的java字节码文件 apk运行的主要逻辑
recourses.arsc 编译后的二进制资源文件 是一个映射表

 

smali语法

吾爱破解安卓逆向入门教程《安卓逆向这档事》三、初识smali,vip终结者_哔哩哔哩_bilibili

(在smali中所有操作必须经过寄存器来进行)

(其中本地寄存器用v开头数字结尾的符号来表示、参数寄存器使用p开头数字结尾的符号来表示(在非static函数中 p0代指“this”))

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//一个私有 静态 不可变的的方法    方法名            (参数)z 方法返回值类型
.method private static final onCreate$lambda-2(Lkotlin/jvm/internal/Ref$IntRef;Lcom/zj/wuaipojie/ui/ChallengeSecond;Landroid/widget/ImageView;Landroid/widget/ImageView;Landroid/widget/ImageView;Landroid/view/View;)Z
.registers 7 //寄存器数量

.line 33
iget p0, p0, Lkotlin/jvm/internal/Ref$IntRef;->element:I //读取p0

const/4 p5, 0x1 //p5 赋值 1

const/16 v0, 0xa //v0 赋值 0xa

if-ge p0, v0, :cond_15 //判断 p0 的值是否 ≥ v0 的值 跳转

.line 34 //常见Toast弹窗代码
move-object p0, p1

check-cast p0, Landroid/content/Context; //检查context对象引用

const-string v0, "\u8bf7\u5148\u83b7\u53d610\u4e2a\u786c\u5e01\u54e6" //弹窗文本信息

check-cast v0, Ljava/lang/CharSequence; //检查CharSequence对象引用

invoke-static {p1, v0, p5}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast; //将内容传递给p1

move-result-object p0 //在传给p0

invoke-virtual {p0}, Landroid/widget/Toast;->show()V //显示出弹窗信息

.line 36
:cond_15 //if-ge 跳转地址
invoke-virtual {p1}, Lcom/zj/wuaipojie/ui/ChallengeSecond;->isvip()Z //判断isvip方法的返回值是否为true

move-result p0 //赋值给p0

if-eqz p0, :cond_43 //判断 p0 是否等于 0 跳转

.line 37
check-cast p1, Landroid/content/Context;

const-string p0, "\u5f53\u524d\u5df2\u7ecf\u662f\u5927\u4f1a\u5458\u4e86\u54e6\uff01"

check-cast p0, Ljava/lang/CharSequence;

invoke-static {p1, p0, p5}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

move-result-object p0

invoke-virtual {p0}, Landroid/widget/Toast;->show()V

const p0, 0x7f0d0018

.line 38
invoke-virtual {p2, p0}, Landroid/widget/ImageView;->setImageResource(I)V

const p0, 0x7f0d0008

.line 39
invoke-virtual {p3, p0}, Landroid/widget/ImageView;->setImageResource(I)V

const p0, 0x7f0d000a

.line 40
invoke-virtual {p4, p0}, Landroid/widget/ImageView;->setImageResource(I)V

.line 41
sget-object p0, Lcom/zj/wuaipojie/util/SPUtils;->INSTANCE:Lcom/zj/wuaipojie/util/SPUtils;

const/4 p2, 0x2

const-string p3, "level"

invoke-virtual {p0, p1, p3, p2}, Lcom/zj/wuaipojie/util/SPUtils;->saveInt(Landroid/content/Context;Ljava/lang/String;I)V

goto :goto_50

.line 44
:cond_43
check-cast p1, Landroid/content/Context;

const-string p0, "\u8bf7\u5148\u5145\u503c\u5927\u4f1a\u5458\u54e6\uff01"

check-cast p0, Ljava/lang/CharSequence;

invoke-static {p1, p0, p5}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

move-result-object p0

invoke-virtual {p0}, Landroid/widget/Toast;->show()V

:goto_50
return p5 //返回p5值
.end method //f

密码

AES

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
48
49
50
public static String encrypt(String content, String skey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException {
if (skey == null) {
System.out.print("key为null");
return null;
}

if (skey.length() != 16) {
System.out.print("key长度不是16位");
return null;
}

byte[] raw = skey.getBytes(StandardCharsets.UTF_8);
SecretKeySpec skeyspec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//算法/模式/填充方式
cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
byte [] encrypted = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));

String result = Base64.getEncoder().encodeToString(encrypted);

return result;
}



public static String decrypt(String content, String skey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException {
if (skey == null) {
System.out.print("key为null");
return null;
}

if (skey.length() != 16) {
System.out.print("key长度不是16位");
return null;
}

byte[] raw = skey.getBytes(StandardCharsets.UTF_8);
SecretKeySpec skeyspec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//算法/模式/填充方式
cipher.init(Cipher.DECRYPT_MODE, skeyspec);
byte [] decrypted = Base64.getDecoder().decode(content.getBytes(StandardCharsets.UTF_8));

try {
byte[] original = cipher.doFinal(decrypted);
String originalstring = new String(original, "utf-8");
return originalstring;
} catch (Exception e) {
System.out.println(e.toString());
return null;
}
}

分组密码的填充

Algorithm mode padding
AES EBC、CBC、PCBC、CTR、CTS、CFB、CFBB-CFB128 NoPadding、ISO10126Padding、PKCS5Padding
AESWrap EBC NoPadding
ARCFOUR EBC NoPadding
Blowfish、DES、DESede、RC2 EBC、CBC、PCBC、CTR、CTS、CFB、CFBB-CFB128 NoPadding、ISO10126Padding、PKCS5Padding
DESedeWrap CBC NoPadding
PBEWithMD5AndDES、PBEWithMD5AndTripleDES、PBEWithSHA1AndDESede、PBEWithSHA1AndRC2_40 CBC PKCS5Padding
RSA ECB、NONE NoPadding、PKCS1Padding