├── .gitignore
├── README.md
├── bangcle_tool
├── .classpath
├── .project
├── .settings
│ ├── org.eclipse.core.resources.prefs
│ └── org.eclipse.core.runtime.prefs
├── Bangcle.jar
├── libs
│ ├── dom4j-2.0.0-RC1-sources.jar
│ ├── dom4j-2.0.0-RC1.jar
│ └── zip4j_1.3.2.jar
├── src
│ └── com
│ │ └── fengyue
│ │ └── bangcle
│ │ ├── AESUtil.java
│ │ ├── FileUtil.java
│ │ ├── Main.java
│ │ ├── SystemCommand.java
│ │ └── ZipUtil.java
└── tools
│ ├── apktool.jar
│ ├── libdexload_a64.so
│ ├── libdexload_arm.so
│ ├── signapk.jar
│ ├── smali
│ └── com
│ │ └── storm
│ │ └── fengyue
│ │ ├── Native.smali
│ │ └── StubApplication.smali
│ ├── testkey.pk8
│ └── testkey.x509.pem
└── jni
├── .editorconfig
├── Android.mk
├── Application.mk
├── aes.c
├── aes.h
├── aes.hpp
├── byte_load.cpp
├── byte_load.h
├── common.h
├── dex_header.h
├── elfGotHook
├── .editorconfig
├── Android.mk
├── Application.mk
├── def.h
├── elf_arm.h
├── elf_reader.cpp
├── elf_reader.h
├── hooker.cpp
├── logger.h
├── tools.cpp
└── tools.h
├── hook_instance.cpp
├── hook_instance.h
├── log.txt
├── packe_bak.cpp
├── packer.cpp
├── packer.h
├── utils.cpp
└── utils.h
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 | *.apk
14 |
15 | # Compiled Dynamic libraries
16 | *.so
17 | *.dylib
18 | *.dll
19 |
20 | # Fortran module files
21 | *.mod
22 | *.smod
23 |
24 | # Compiled Static libraries
25 | *.lai
26 | *.la
27 | *.a
28 | *.lib
29 |
30 | # Executables
31 | *.exe
32 | *.out
33 | *.app
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # About
2 |
3 | Bangcle is a Android Protector
4 |
5 | It use the second generation Android Hardening Protection, load the encrypted dex file from memory dynamically
6 |
7 | ## Compatibility
8 |
9 | Support Android Version
10 |
11 | - 4.4
12 | - 5.0
13 | - 5.1
14 | - 6.0
15 | - 7.0
16 | - 7.1
17 | - 8.0
18 | - 8.1
19 |
20 | ### How to use
21 |
22 | Enter **bangcle_tool** directory
23 | Run this command to protect you App
24 |
25 | ```java
26 | java -jar Bangcle.jar b AppName
27 | ```
28 |
29 | The encrypted Apk is located at **output** folder
30 |
31 |
32 |
--------------------------------------------------------------------------------
/bangcle_tool/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/bangcle_tool/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | bangcle_tool
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/bangcle_tool/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding/=UTF-8
3 |
--------------------------------------------------------------------------------
/bangcle_tool/.settings/org.eclipse.core.runtime.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | line.separator=\r\n
3 |
--------------------------------------------------------------------------------
/bangcle_tool/Bangcle.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KuNgia09/Bangcle/76f84a741bdfc25504992327c8addcf4f000e403/bangcle_tool/Bangcle.jar
--------------------------------------------------------------------------------
/bangcle_tool/libs/dom4j-2.0.0-RC1-sources.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KuNgia09/Bangcle/76f84a741bdfc25504992327c8addcf4f000e403/bangcle_tool/libs/dom4j-2.0.0-RC1-sources.jar
--------------------------------------------------------------------------------
/bangcle_tool/libs/dom4j-2.0.0-RC1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KuNgia09/Bangcle/76f84a741bdfc25504992327c8addcf4f000e403/bangcle_tool/libs/dom4j-2.0.0-RC1.jar
--------------------------------------------------------------------------------
/bangcle_tool/libs/zip4j_1.3.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KuNgia09/Bangcle/76f84a741bdfc25504992327c8addcf4f000e403/bangcle_tool/libs/zip4j_1.3.2.jar
--------------------------------------------------------------------------------
/bangcle_tool/src/com/fengyue/bangcle/AESUtil.java:
--------------------------------------------------------------------------------
1 | package com.fengyue.bangcle;
2 |
3 | import java.util.Arrays;
4 |
5 | import javax.crypto.Cipher;
6 | import javax.crypto.spec.IvParameterSpec;
7 | import javax.crypto.spec.SecretKeySpec;
8 |
9 | import sun.misc.BASE64Decoder;
10 | import sun.misc.BASE64Encoder;
11 |
12 | public class AESUtil {
13 |
14 | //初始向量
15 | public static final String VIPARA = "1234567812345678"; //AES 为16bytes. DES 为8bytes
16 | //编码方式
17 | public static final String charset = "UTF-8";
18 | //私钥
19 | private static final String ASE_KEY="1234567812345678"; //AES固定格式为128/192/256 bits.即:16/24/32bytes。DES固定格式为128bits,即8bytes。
20 |
21 | private static String transformation = "AES/CBC/PKCS5Padding";
22 |
23 | private static String algorithm = "AES";
24 |
25 |
26 | public static byte[] encrypt(String content, String key) {
27 | try {
28 | SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
29 | IvParameterSpec iv = new IvParameterSpec(key.getBytes());
30 | Cipher cipher = Cipher.getInstance(transformation);
31 | byte[] byteContent = content.getBytes(charset);
32 |
33 | cipher.init(Cipher.ENCRYPT_MODE, skey, iv);// 初始化
34 | byte[] result = cipher.doFinal(byteContent);
35 | return result; // 加密
36 | } catch (Exception e) {
37 | e.printStackTrace();
38 | }
39 | return null;
40 | }
41 |
42 | public static byte[] encrypt(byte[] content, String key) {
43 | try {
44 | SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
45 | IvParameterSpec iv = new IvParameterSpec(key.getBytes());
46 | Cipher cipher = Cipher.getInstance(transformation);
47 |
48 | cipher.init(Cipher.ENCRYPT_MODE, skey, iv);// 初始化
49 | byte[] result = cipher.doFinal(content);
50 | return result; // 加密
51 | } catch (Exception e) {
52 | e.printStackTrace();
53 | }
54 | return null;
55 | }
56 |
57 |
58 |
59 | /**
60 | * 解密
61 | *
62 | * @param encrypted
63 | * @return
64 | */
65 | public static String decrypt(String encryptData) {
66 | try {
67 | byte[] tmp=new BASE64Decoder().decodeBuffer(encryptData);
68 | byte[] iv=new byte[16];
69 | Arrays.fill(iv, (byte)0);
70 | //IvParameterSpec zeroIv = new IvParameterSpec(iv);
71 | IvParameterSpec zeroIv = new IvParameterSpec(VIPARA.getBytes());
72 | SecretKeySpec key = new SecretKeySpec(
73 | ASE_KEY.getBytes(), "AES");
74 | Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
75 | //与加密时不同MODE:Cipher.DECRYPT_MODE
76 | cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
77 | byte[] decryptedData = cipher.doFinal(tmp);
78 | System.out.println("解密后 hex data:"+byte2hex(decryptedData));
79 | System.out.println("加密后 hex data len:"+decryptedData.length);
80 | return new String(decryptedData, charset);
81 | } catch (Exception e) {
82 | e.printStackTrace();
83 | return "";
84 | }
85 | }
86 |
87 | /**
88 | * 字节数组转成16进制字符串
89 | * @param b
90 | * @return
91 | */
92 | public static String byte2hex(byte[] b) { // 一个字节的数,
93 | StringBuffer sb = new StringBuffer(b.length * 2);
94 | String tmp = "";
95 | for (int n = 0; n < b.length; n++) {
96 | // 整数转成十六进制表示
97 | tmp = (Integer.toHexString(b[n] & 0XFF));
98 | if (tmp.length() == 1) {
99 | sb.append("0");
100 | }
101 | sb.append(tmp);
102 | }
103 | return sb.toString().toUpperCase(); // 转成大写
104 | }
105 |
106 | /**
107 | * 将hex字符串转换成字节数组
108 | * @param inputString
109 | * @return
110 | */
111 | private static byte[] hex2byte(String inputString) {
112 | if (inputString == null || inputString.length() < 2) {
113 | return new byte[0];
114 | }
115 | inputString = inputString.toLowerCase();
116 | int l = inputString.length() / 2;
117 | byte[] result = new byte[l];
118 | for (int i = 0; i < l; ++i) {
119 | String tmp = inputString.substring(2 * i, 2 * i + 2);
120 | result[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
121 | }
122 | return result;
123 | }
124 |
125 |
126 | }
--------------------------------------------------------------------------------
/bangcle_tool/src/com/fengyue/bangcle/FileUtil.java:
--------------------------------------------------------------------------------
1 | package com.fengyue.bangcle;
2 |
3 | import java.io.BufferedOutputStream;
4 | import java.io.ByteArrayOutputStream;
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.FileNotFoundException;
8 | import java.io.FileOutputStream;
9 | import java.io.IOException;
10 | import java.util.List;
11 |
12 | public class FileUtil {
13 |
14 | public static void delete(File file){
15 | if(file!=null&&file.exists()){
16 | if(file.isDirectory()){
17 | for(File f:file.listFiles()){
18 | delete(f);
19 | // System.out.println("已删除"+f.getAbsolutePath());
20 | }
21 | file.delete();
22 | // System.out.println("已删除"+file.getAbsolutePath());
23 | }else{
24 | file.delete();
25 | // System.out.println("已删除"+file.getAbsolutePath());
26 | }
27 | }
28 | }
29 |
30 | public static void copyDir(String oldPath, String newPath) throws IOException {
31 | File file = new File(oldPath);
32 | String[] filePath = file.list();
33 |
34 | if (!(new File(newPath)).exists()) {
35 | (new File(newPath)).mkdir();
36 | }
37 |
38 | for (int i = 0; i < filePath.length; i++) {
39 | if ((new File(oldPath + File.separator + filePath[i])).isDirectory()) {
40 | copyDir(oldPath + File.separator + filePath[i], newPath + File.separator + filePath[i]);
41 | }
42 |
43 | if (new File(oldPath + File.separator + filePath[i]).isFile()) {
44 | copyFile(oldPath + File.separator + filePath[i], newPath + File.separator + filePath[i]);
45 | }
46 |
47 | }
48 | }
49 |
50 | public static void copyFile(String source, String dest) throws IOException {
51 | FileInputStream is = null;
52 | FileOutputStream os = null;
53 | try {
54 | is= new FileInputStream(source);
55 | os = new FileOutputStream(dest);
56 | byte[] buffer = new byte[1024];
57 | int length;
58 | while ((length = is.read(buffer)) > 0) {
59 | os.write(buffer, 0, length);
60 | }
61 | } finally {
62 | is.close();
63 | os.close();
64 | }
65 |
66 | }
67 |
68 |
69 | public static void ListFiles(String path,List list) {
70 | File dir = new File(path);
71 | if (dir.exists()) {
72 |
73 | if (dir.isDirectory()) {
74 | File[] childs = dir.listFiles();
75 | for (File f : childs) {
76 | ListFiles(f.getAbsolutePath(),null);
77 | }
78 | }
79 | System.out.println("ListFiles----" + dir.getAbsolutePath()+" isDirectory ? "+dir.isDirectory());
80 | }
81 | }
82 |
83 |
84 | /**
85 | * 读取文件内容到数组
86 | *
87 | * @param filePath
88 | * @return
89 | */
90 | public static byte[] getFileByte(String filePath) {
91 | byte[] retBuffer = null;
92 | FileInputStream fis = null;
93 | ByteArrayOutputStream bos = null;
94 | try {
95 | File file = new File(filePath);
96 | fis = new FileInputStream(file);
97 | bos = new ByteArrayOutputStream(8192);
98 | byte[] b = new byte[8192];
99 | int n;
100 | while ((n = fis.read(b)) != -1) {
101 | bos.write(b, 0, n);
102 | }
103 | bos.flush();
104 | retBuffer = bos.toByteArray();
105 | } catch (FileNotFoundException e) {
106 | e.printStackTrace();
107 | } catch (IOException e) {
108 | e.printStackTrace();
109 | } finally {
110 | if (fis != null) {
111 | try {
112 | fis.close();
113 | } catch (IOException e) {
114 | e.printStackTrace();
115 | }
116 | }
117 | if (bos != null) {
118 | try {
119 | bos.close();
120 | } catch (IOException e) {
121 | e.printStackTrace();
122 | }
123 | }
124 |
125 | }
126 | return retBuffer;
127 | }
128 |
129 |
130 | /**
131 | * 根据byte数组,生成文件
132 | *
133 | * @param bfile
134 | * @param filePath
135 | * @param fileName
136 | */
137 | public static void byteToFile(byte[] bfile, String filePath, String fileName) {
138 | BufferedOutputStream bos = null;
139 | FileOutputStream fos = null;
140 | File file = null;
141 | try {
142 | File dir = new File(filePath);
143 | if (!dir.exists() && dir.isDirectory()) {//判断文件目录是否存在
144 | System.out.println(filePath + "目录不存在");
145 | dir.mkdirs();
146 | }
147 | file = new File(filePath + File.separator + fileName);
148 | //System.out.println(file.getAbsolutePath());
149 | fos = new FileOutputStream(file);
150 | bos = new BufferedOutputStream(fos);
151 | bos.write(bfile);
152 | bos.flush();
153 | } catch (Exception e) {
154 | e.printStackTrace();
155 | } finally {
156 | if (bos != null) {
157 | try {
158 | bos.close();
159 | } catch (IOException e1) {
160 | e1.printStackTrace();
161 | }
162 | }
163 | if (fos != null) {
164 | try {
165 | fos.close();
166 | } catch (IOException e1) {
167 | e1.printStackTrace();
168 | }
169 | }
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/bangcle_tool/src/com/fengyue/bangcle/Main.java:
--------------------------------------------------------------------------------
1 | package com.fengyue.bangcle;
2 |
3 | import java.io.File;
4 | import java.io.FileOutputStream;
5 | import java.io.IOException;
6 | import java.io.OutputStream;
7 | import java.text.SimpleDateFormat;
8 | import java.util.Iterator;
9 |
10 | import org.dom4j.Attribute;
11 | import org.dom4j.Document;
12 | import org.dom4j.DocumentException;
13 | import org.dom4j.Element;
14 | import org.dom4j.io.OutputFormat;
15 | import org.dom4j.io.SAXReader;
16 | import org.dom4j.io.XMLWriter;
17 |
18 | /**
19 | *
20 | * @author Administrator
21 | *
22 | */
23 | public class Main {
24 | private static final String DEX_APP_NAME = "com.storm.fengyue.StubApplication";
25 | private static final String AES_KEY="1234567812345678";
26 | private static final SimpleDateFormat sdf = new SimpleDateFormat(
27 | "yyyyMMddHHmmss");
28 | private static Config config;
29 | private static String soName="libdexload";
30 | /**
31 | * @param args
32 | * @throws IOException
33 | */
34 | public static void main(String[] args) {
35 | System.out.println("----------Bangcle Automation----------------");
36 | System.out.println(System.getProperty("user.dir"));
37 | String cmd = args[0];
38 | if (!"b".equals(cmd)) {
39 | System.out.println("usage:java -jar Bangcle.jar b apkName");
40 | return;
41 | }
42 |
43 | String apkName = args[1];
44 | // String apkName="msgnow-release.apk";
45 | // String apkName="unpack_permmgr.apk";
46 | // String apkName="com.aispeech.weiyu_2.apk";
47 | String apkPath=getWorkPath()+File.separator+apkName;
48 |
49 |
50 | // 反编译目录
51 | String workPath=getWorkPath();
52 | String toolsPath=workPath+File.separator+"tools";
53 | int pos=apkName.lastIndexOf(".");
54 | String decompiledDirName=apkName.substring(0,pos);
55 | System.out.println("apkPath:" + apkPath+ " decompiledDirName:"+decompiledDirName);
56 |
57 |
58 | // 删除反编译目录
59 | File outputFolder = new File(workPath + File.separator+"output");
60 | if(!outputFolder.exists()){
61 | outputFolder.mkdir();
62 | System.out.println("创建生成目录:"+outputFolder.getAbsolutePath());
63 | }
64 | File decompiledFile = new File(outputFolder.getAbsolutePath() +File.separator+ decompiledDirName);
65 | String decompiledPath=decompiledFile.getAbsolutePath();
66 | if (decompiledFile.exists()) {
67 | FileUtil.delete(decompiledFile);
68 | System.out.println("已删除" + decompiledFile.getAbsolutePath());
69 | }
70 | // 创建反编译目录
71 | boolean decompiled = false;
72 | try {
73 | long startTime = System.currentTimeMillis();
74 | System.out.println("正在反编译" + apkPath);
75 |
76 | // 确保apktool.jar放在工作目录下
77 | SystemCommand.execute("java -jar tools/apktool.jar d " + apkPath+" -o "+decompiledFile.getAbsolutePath()+" -s -f");
78 |
79 | System.out.println("反编译结束,生成目录" + decompiledFile.getAbsolutePath());
80 |
81 | decompiled = true;
82 | } catch (InterruptedException e) {
83 | // TODO Auto-generated catch block
84 | e.printStackTrace();
85 | } catch (IOException e) {
86 | // TODO Auto-generated catch block
87 | e.printStackTrace();
88 | }
89 |
90 | //extract classes.dex
91 | String assetDir=decompiledPath+File.separator+"assets";
92 | File file_asset=new File(assetDir);
93 | if(!file_asset.exists()){
94 | file_asset.mkdirs();
95 |
96 | }
97 |
98 |
99 | String rawdex=decompiledPath+File.separator+"classes.dex";
100 |
101 | //encrypt raw dex
102 | byte[] data=FileUtil.getFileByte(rawdex);
103 | byte[] encrypt_data=AESUtil.encrypt(data, AES_KEY);
104 | System.out.println("AES encrypt classes.dex finished");
105 | FileUtil.byteToFile(encrypt_data, assetDir, "jiami.dat");
106 |
107 | System.out.println("copy jiami.dat to assets dir finished");
108 | //delete orig raw dex
109 | FileUtil.delete(new File(rawdex));
110 |
111 | try {
112 | //将libdexload.so 复制到 assets目录下
113 | FileUtil.copyFile(toolsPath+File.separator+soName+"_arm.so",assetDir+File.separator+soName+"_arm.so" );
114 | FileUtil.copyFile(toolsPath+File.separator+soName+"_a64.so",assetDir+File.separator+soName+"_a64.so" );
115 | } catch (IOException e2) {
116 | // TODO Auto-generated catch block
117 | e2.printStackTrace();
118 | }
119 |
120 | try {
121 | FileUtil.copyDir(toolsPath+File.separator+"smali", decompiledPath+File.separator+"smali");
122 | } catch (IOException e1) {
123 | // TODO Auto-generated catch block
124 | e1.printStackTrace();
125 | }
126 |
127 | if (decompiled) {
128 | if (alterAndroidMainifest(decompiledFile.getAbsolutePath())) {
129 |
130 | try {
131 | String apkNewName=decompiledDirName+"_unsigned.apk";
132 | String apkNewSignName=decompiledDirName+"_signed.apk";
133 | String outputPath=workPath+File.separator+"output"+File.separator+apkNewName;
134 | String outputSignPath=workPath+File.separator+"output"+File.separator+apkNewSignName;
135 | SystemCommand.execute("java -jar tools/apktool.jar b "
136 | + decompiledPath+ " -o "+outputPath);
137 | System.out.println("重编译完成");
138 | System.out.println("正在签名Apk");
139 | signApk_x509(outputPath,outputSignPath);
140 | System.out.println("重签名完成");
141 | System.out.println("加固Apk目录:"+outputSignPath);
142 |
143 | } catch (IOException e) {
144 | // TODO Auto-generated catch block
145 | e.printStackTrace();
146 | } catch (InterruptedException e) {
147 | // TODO Auto-generated catch block
148 | e.printStackTrace();
149 | } catch (Exception e) {
150 | // TODO Auto-generated catch block
151 | e.printStackTrace();
152 | }
153 | }
154 | } else {
155 | System.out.println("反编译失败");
156 | }
157 | }
158 |
159 | private static void signApk_x509(String unsignedApkPath, String signedApkPath){
160 | try {
161 | String command="java -jar tools/signapk.jar tools/testkey.x509.pem tools/testkey.pk8"+" "+unsignedApkPath+" "+signedApkPath;
162 |
163 | SystemCommand.execute(command);
164 | } catch (IOException e) {
165 | // TODO Auto-generated catch block
166 | e.printStackTrace();
167 | } catch (InterruptedException e) {
168 | // TODO Auto-generated catch block
169 | e.printStackTrace();
170 | }
171 |
172 | }
173 |
174 |
175 |
176 |
177 | /**
178 | * 执行此方法确保,jarsigner的路径被添加到系统环境变量中
179 | *
180 | * @param unsignedApkPath
181 | * 未签名的apk的路径
182 | * @param signedApkPath
183 | * 生成的签名apk的路径
184 | * @throws IOException
185 | * @throws InterruptedException
186 | */
187 | private static void signApk(String unsignedApkPath, String signedApkPath)
188 | throws IOException, InterruptedException {
189 |
190 | String signCommand = "jarsigner -verbose -keystore "
191 | + getConfig().signaturePath
192 | + " "
193 | + "-storepass "
194 | + getConfig().storePwd
195 | + " -keypass "
196 | + getConfig().aliasPwd
197 | + " "
198 | + "-sigfile CERT -digestalg SHA1 -sigalg MD5withRSA -signedjar "
199 | + signedApkPath + " " + unsignedApkPath + " "
200 | + getConfig().alias;
201 | //System.out.println("cmd:" + signCommand);
202 | ;
203 | SystemCommand.execute(signCommand);
204 | System.out.println("签名后的apk路径:" + signedApkPath);
205 | }
206 |
207 |
208 | /**
209 | * 修改AndroidMinifest.xml中的Application Class为脱壳的Application Class名
210 | * 在Application标签中增加原Application Class名
211 | *
212 | * @param workPath
213 | */
214 | private static boolean alterAndroidMainifest(String workPath) {
215 | // TODO Auto-generated method stub
216 | String manifestFileName = "AndroidManifest.xml";
217 | File manifestFile = new File(workPath + "\\" + manifestFileName);
218 | if (!manifestFile.exists()) {
219 | System.err.println("找不到" + manifestFile.getAbsolutePath());
220 | return false;
221 | }
222 | SAXReader reader = new SAXReader();
223 | reader.setEncoding("UTF-8");
224 | try {
225 | Document document = reader.read(manifestFile);
226 | Element root = document.getRootElement();
227 |
228 | System.out.println("当前包名:" + root.attribute("package").getText());
229 | Element applicationEle = root.element("application");
230 | System.out.println("遍历application标签的属性:");
231 | Iterator attrIterator = applicationEle
232 | .attributeIterator();
233 | String APP_NAME = null;
234 | boolean find_application=false;
235 | while (attrIterator.hasNext()) {
236 | Attribute attr = attrIterator.next();
237 | System.out.println(attr.getNamespacePrefix() + ":"
238 | + attr.getName() + " = " + attr.getValue());
239 | //寻找android:name标签
240 | if ("android".equals(attr.getNamespacePrefix())
241 | && "name".equals(attr.getName())) {
242 | APP_NAME = attr.getValue();
243 | attr.setValue(DEX_APP_NAME);
244 | find_application=true;
245 | System.out.println("orig application name:" + APP_NAME);
246 | System.out.println("new application name:" + attr.getValue());
247 | break;
248 | }
249 | }
250 | //如果apk没有原始的application
251 | if(!find_application){
252 | System.out.println("no orig application");
253 | applicationEle.addAttribute("android:name",DEX_APP_NAME);
254 | }
255 | //保存原始的application
256 | else{
257 | Element mataDataEle = applicationEle.addElement("meta-data");
258 | mataDataEle.addAttribute("android:name", "APP_NAME");
259 | mataDataEle.addAttribute("android:value", APP_NAME);
260 | }
261 |
262 |
263 | manifestFile.delete();
264 |
265 | //处理中文字符的乱码
266 | //参考:https://blog.csdn.net/zhengdesheng19930211/article/details/64443572
267 | // java.io.Writer wr=new java.io.OutputStreamWriter(new java.io.FileOutputStream(manifestFile.getAbsolutePath()),"UTF-8");
268 | // document.write(wr);
269 | // wr.close();
270 |
271 | //下列方式不能处理中文字符 ,虽然这里设置了编码 但是保存的文件还是ANSI格式
272 | // OutputFormat format = OutputFormat.createPrettyPrint();
273 | // format.setEncoding("UTF-8");// 设置编码
274 | // Writer filewriter = new FileWriter(manifestFile.getAbsolutePath());
275 | // System.out.println("manifest path:"+manifestFile.getAbsolutePath());
276 | // XMLWriter xmlwriter = new XMLWriter(filewriter, format);
277 | // xmlwriter.write(document);
278 | // xmlwriter.close();
279 | // System.out.println("修改Manifest成功");
280 |
281 | //处理中文乱码
282 | //参考:https://blog.csdn.net/zl594389970/article/details/53353813
283 | System.out.println("使用方式3写入xml");
284 | OutputFormat format = OutputFormat.createPrettyPrint();
285 | format.setEncoding("UTF-8");// 设置编码
286 | OutputStream out = new FileOutputStream(manifestFile.getAbsolutePath());
287 | System.out.println("manifest path:"+manifestFile.getAbsolutePath());
288 | XMLWriter xmlwriter = new XMLWriter(out, format);
289 | xmlwriter.write(document);
290 | xmlwriter.close();
291 |
292 |
293 | System.out.println("修改Manifest成功");
294 | return true;
295 | } catch (DocumentException e) {
296 | // TODO Auto-generated catch block
297 | e.printStackTrace();
298 | } catch (IOException e) {
299 | // TODO Auto-generated catch block
300 | e.printStackTrace();
301 | }
302 |
303 | return false;
304 | }
305 |
306 | private static Config getConfig() {
307 | if (config != null) {
308 | return config;
309 | }
310 |
311 | File signerConfigFile = new File(getWorkPath() + "\\" + "config.xml");
312 | if (!signerConfigFile.exists()) {
313 | System.err.println("找不到" + signerConfigFile.getAbsolutePath());
314 | return null;
315 | }
316 | // 读取XML
317 | SAXReader reader = new SAXReader();
318 | try {
319 | Document document = reader.read(signerConfigFile);
320 | Element root = document.getRootElement();
321 | Element signaturePathEle = root.element("signature-path");
322 | String signaturePath = signaturePathEle.getText();
323 |
324 | Element storePwdEle = root.element("store-pwd");
325 | String storePwd = storePwdEle.getText();
326 |
327 | Element aliasEle = root.element("alias");
328 | String alias = aliasEle.getText();
329 |
330 | Element aliasPwdEle = root.element("alias-pwd");
331 | String aliasPwd = aliasPwdEle.getText();
332 |
333 | System.out.println("signature-path:" + signaturePath
334 | + " store-pwd:" + storePwd + " alias:" + alias
335 | + " aliasPwd:" + aliasPwd );
336 | config = new Config();
337 | config.signaturePath = signaturePath;
338 | config.storePwd = storePwd;
339 | config.alias = alias;
340 | config.aliasPwd = aliasPwd;
341 | } catch (DocumentException e) {
342 | // TODO Auto-generated catch block
343 | e.printStackTrace();
344 | }
345 |
346 | return config;
347 | }
348 |
349 | private static String getWorkPath() {
350 | return System.getProperty("user.dir");
351 | }
352 |
353 | static class Config {
354 | public String signaturePath;
355 | public String storePwd;
356 | public String alias;
357 | public String aliasPwd;
358 | public String winRARPath;
359 | }
360 | }
361 |
--------------------------------------------------------------------------------
/bangcle_tool/src/com/fengyue/bangcle/SystemCommand.java:
--------------------------------------------------------------------------------
1 | package com.fengyue.bangcle;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStreamReader;
6 |
7 | public class SystemCommand {
8 |
9 | public static void execute(String command) throws IOException, InterruptedException {
10 | Runtime runtime = Runtime.getRuntime();
11 | System.out.println("execute " + command);
12 | Process pr = runtime.exec("cmd /c "+command);
13 | BufferedReader input = new BufferedReader(new InputStreamReader(
14 | pr.getInputStream()));
15 |
16 | String line = null;
17 |
18 | while ((line = input.readLine()) != null) {
19 | System.out.println(line);
20 | }
21 |
22 | int exitVal = pr.waitFor();
23 | System.out.println("Exited with error code " + exitVal);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/bangcle_tool/src/com/fengyue/bangcle/ZipUtil.java:
--------------------------------------------------------------------------------
1 | package com.fengyue.bangcle;
2 |
3 | import java.io.File;
4 | import java.io.FileOutputStream;
5 | import java.io.InputStream;
6 | import java.util.zip.ZipEntry;
7 | import java.util.zip.ZipFile;
8 |
9 | import sun.rmi.runtime.Log;
10 |
11 |
12 |
13 | public class ZipUtil {
14 |
15 | public static int extract(String str, String str2, String str3) {
16 | System.out.println("ZipUtil.extract para zipPath:" + str);
17 | System.out.println("ZipUtil.extract para entryName:" + str2);
18 | System.out.println("ZipUtil.extract para filePath:" + str3);
19 | try {
20 | File file = new File(str3);
21 | if (file.exists()) {
22 | file.delete();
23 | }
24 | FileOutputStream fileOutputStream = new FileOutputStream(file);
25 | ZipFile zipFile = new ZipFile(new File(str));
26 | ZipEntry entry = zipFile.getEntry(str2);
27 | if (entry == null) {
28 | System.out.println("ZipUtil.extract zip error:entryName not exist");
29 | }
30 | InputStream inputStream = zipFile.getInputStream(entry);
31 | byte[] bArr = new byte[1024];
32 | while (true) {
33 | int read = inputStream.read(bArr);
34 | if (read > 0) {
35 | fileOutputStream.write(bArr, 0, read);
36 | } else {
37 | fileOutputStream.close();
38 | inputStream.close();
39 | zipFile.close();
40 | return 0;
41 | }
42 | }
43 | } catch (Exception e) {
44 | System.out.println("ZipUtil.extract exception");
45 | if (e.getMessage() != null) {
46 | System.out.println(e.getMessage());
47 | }
48 | System.out.println(e.toString());
49 | return 1;
50 | }
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/bangcle_tool/tools/apktool.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KuNgia09/Bangcle/76f84a741bdfc25504992327c8addcf4f000e403/bangcle_tool/tools/apktool.jar
--------------------------------------------------------------------------------
/bangcle_tool/tools/libdexload_a64.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KuNgia09/Bangcle/76f84a741bdfc25504992327c8addcf4f000e403/bangcle_tool/tools/libdexload_a64.so
--------------------------------------------------------------------------------
/bangcle_tool/tools/libdexload_arm.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KuNgia09/Bangcle/76f84a741bdfc25504992327c8addcf4f000e403/bangcle_tool/tools/libdexload_arm.so
--------------------------------------------------------------------------------
/bangcle_tool/tools/signapk.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KuNgia09/Bangcle/76f84a741bdfc25504992327c8addcf4f000e403/bangcle_tool/tools/signapk.jar
--------------------------------------------------------------------------------
/bangcle_tool/tools/smali/com/storm/fengyue/Native.smali:
--------------------------------------------------------------------------------
1 | .class public Lcom/storm/fengyue/Native;
2 | .super Ljava/lang/Object;
3 | .source "Native.java"
4 |
5 |
6 | # direct methods
7 | .method public constructor ()V
8 | .locals 0
9 |
10 | .prologue
11 | .line 5
12 | invoke-direct {p0}, Ljava/lang/Object;->()V
13 |
14 | return-void
15 | .end method
16 |
17 | .method public static native attachBaseContext(Landroid/content/Context;)V
18 | .end method
19 |
20 | .method public static native onCreate(Landroid/content/Context;)V
21 | .end method
22 |
--------------------------------------------------------------------------------
/bangcle_tool/tools/smali/com/storm/fengyue/StubApplication.smali:
--------------------------------------------------------------------------------
1 | .class public Lcom/storm/fengyue/StubApplication;
2 | .super Landroid/app/Application;
3 | .source "StubApplication.java"
4 |
5 |
6 | # static fields
7 | .field public static TAG:Ljava/lang/String;
8 |
9 | .field public static soName:Ljava/lang/String;
10 |
11 |
12 | # direct methods
13 | .method static constructor ()V
14 | .locals 1
15 |
16 | .prologue
17 | .line 16
18 | const-string v0, "fengyue"
19 |
20 | sput-object v0, Lcom/storm/fengyue/StubApplication;->TAG:Ljava/lang/String;
21 |
22 | .line 17
23 | const-string v0, "libdexload"
24 |
25 | sput-object v0, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
26 |
27 | return-void
28 | .end method
29 |
30 | .method public constructor ()V
31 | .locals 0
32 |
33 | .prologue
34 | .line 15
35 | invoke-direct {p0}, Landroid/app/Application;->()V
36 |
37 | return-void
38 | .end method
39 |
40 | .method public static copy(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
41 | .locals 17
42 | .param p0, "context" # Landroid/content/Context;
43 | .param p1, "asset_soname" # Ljava/lang/String;
44 | .param p2, "str2" # Ljava/lang/String;
45 | .param p3, "str3" # Ljava/lang/String;
46 |
47 | .prologue
48 | .line 46
49 | new-instance v14, Ljava/lang/StringBuilder;
50 |
51 | invoke-static/range {p2 .. p2}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
52 |
53 | move-result-object v15
54 |
55 | invoke-direct {v14, v15}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
56 |
57 | sget-object v15, Ljava/io/File;->separator:Ljava/lang/String;
58 |
59 | invoke-virtual {v14, v15}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
60 |
61 | move-result-object v14
62 |
63 | move-object/from16 v0, p3
64 |
65 | invoke-virtual {v14, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
66 |
67 | move-result-object v14
68 |
69 | invoke-virtual {v14}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
70 |
71 | move-result-object v13
72 |
73 | .line 47
74 | .local v13, "so_dest":Ljava/lang/String;
75 | new-instance v6, Ljava/io/File;
76 |
77 | move-object/from16 v0, p2
78 |
79 | invoke-direct {v6, v0}, Ljava/io/File;->(Ljava/lang/String;)V
80 |
81 | .line 48
82 | .local v6, "file":Ljava/io/File;
83 | invoke-virtual {v6}, Ljava/io/File;->exists()Z
84 |
85 | move-result v14
86 |
87 | if-nez v14, :cond_0
88 |
89 | .line 49
90 | invoke-virtual {v6}, Ljava/io/File;->mkdir()Z
91 |
92 | .line 51
93 | :cond_0
94 | new-instance v6, Ljava/io/File;
95 |
96 | .end local v6 # "file":Ljava/io/File;
97 | invoke-direct {v6, v13}, Ljava/io/File;->(Ljava/lang/String;)V
98 |
99 | .line 53
100 | .restart local v6 # "file":Ljava/io/File;
101 | :try_start_0
102 | invoke-virtual {v6}, Ljava/io/File;->exists()Z
103 |
104 | move-result v14
105 |
106 | if-eqz v14, :cond_2
107 |
108 | .line 55
109 | invoke-virtual/range {p0 .. p0}, Landroid/content/Context;->getResources()Landroid/content/res/Resources;
110 |
111 | move-result-object v14
112 |
113 | invoke-virtual {v14}, Landroid/content/res/Resources;->getAssets()Landroid/content/res/AssetManager;
114 |
115 | move-result-object v14
116 |
117 | move-object/from16 v0, p1
118 |
119 | invoke-virtual {v14, v0}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream;
120 |
121 | move-result-object v9
122 |
123 | .line 56
124 | .local v9, "open":Ljava/io/InputStream;
125 | new-instance v7, Ljava/io/FileInputStream;
126 |
127 | invoke-direct {v7, v6}, Ljava/io/FileInputStream;->(Ljava/io/File;)V
128 |
129 | .line 57
130 | .local v7, "fileInputStream":Ljava/io/InputStream;
131 | new-instance v2, Ljava/io/BufferedInputStream;
132 |
133 | invoke-direct {v2, v9}, Ljava/io/BufferedInputStream;->(Ljava/io/InputStream;)V
134 |
135 | .line 58
136 | .local v2, "bufferedInputStream":Ljava/io/BufferedInputStream;
137 | new-instance v3, Ljava/io/BufferedInputStream;
138 |
139 | invoke-direct {v3, v7}, Ljava/io/BufferedInputStream;->(Ljava/io/InputStream;)V
140 |
141 | .line 59
142 | .local v3, "bufferedInputStream2":Ljava/io/BufferedInputStream;
143 | sget-object v14, Lcom/storm/fengyue/StubApplication;->TAG:Ljava/lang/String;
144 |
145 | const-string v15, "check is same file"
146 |
147 | invoke-static {v14, v15}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
148 |
149 | .line 60
150 | invoke-static {v2, v3}, Lcom/storm/fengyue/StubApplication;->isSameFile(Ljava/io/BufferedInputStream;Ljava/io/BufferedInputStream;)Z
151 |
152 | move-result v14
153 |
154 | if-eqz v14, :cond_1
155 |
156 | .line 61
157 | const/4 v12, 0x1
158 |
159 | .line 65
160 | .local v12, "result":Z
161 | :goto_0
162 | invoke-virtual {v9}, Ljava/io/InputStream;->close()V
163 |
164 | .line 66
165 | invoke-virtual {v7}, Ljava/io/InputStream;->close()V
166 |
167 | .line 67
168 | invoke-virtual {v2}, Ljava/io/BufferedInputStream;->close()V
169 |
170 | .line 68
171 | invoke-virtual {v3}, Ljava/io/BufferedInputStream;->close()V
172 |
173 | .line 69
174 | if-eqz v12, :cond_2
175 |
176 | .line 95
177 | .end local v2 # "bufferedInputStream":Ljava/io/BufferedInputStream;
178 | .end local v3 # "bufferedInputStream2":Ljava/io/BufferedInputStream;
179 | .end local v7 # "fileInputStream":Ljava/io/InputStream;
180 | .end local v9 # "open":Ljava/io/InputStream;
181 | .end local v12 # "result":Z
182 | :goto_1
183 | return v12
184 |
185 | .line 63
186 | .restart local v2 # "bufferedInputStream":Ljava/io/BufferedInputStream;
187 | .restart local v3 # "bufferedInputStream2":Ljava/io/BufferedInputStream;
188 | .restart local v7 # "fileInputStream":Ljava/io/InputStream;
189 | .restart local v9 # "open":Ljava/io/InputStream;
190 | :cond_1
191 | const/4 v12, 0x0
192 |
193 | .restart local v12 # "result":Z
194 | goto :goto_0
195 |
196 | .line 73
197 | .end local v2 # "bufferedInputStream":Ljava/io/BufferedInputStream;
198 | .end local v3 # "bufferedInputStream2":Ljava/io/BufferedInputStream;
199 | .end local v7 # "fileInputStream":Ljava/io/InputStream;
200 | .end local v9 # "open":Ljava/io/InputStream;
201 | .end local v12 # "result":Z
202 | :cond_2
203 | invoke-virtual/range {p0 .. p0}, Landroid/content/Context;->getResources()Landroid/content/res/Resources;
204 |
205 | move-result-object v14
206 |
207 | invoke-virtual {v14}, Landroid/content/res/Resources;->getAssets()Landroid/content/res/AssetManager;
208 |
209 | move-result-object v14
210 |
211 | move-object/from16 v0, p1
212 |
213 | invoke-virtual {v14, v0}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream;
214 |
215 | move-result-object v10
216 |
217 | .line 74
218 | .local v10, "open2":Ljava/io/InputStream;
219 | new-instance v8, Ljava/io/FileOutputStream;
220 |
221 | invoke-direct {v8, v13}, Ljava/io/FileOutputStream;->(Ljava/lang/String;)V
222 |
223 | .line 75
224 | .local v8, "fileOutputStream":Ljava/io/FileOutputStream;
225 | const/16 v14, 0x1c00
226 |
227 | new-array v1, v14, [B
228 |
229 | .line 77
230 | .local v1, "bArr":[B
231 | :goto_2
232 | invoke-virtual {v10, v1}, Ljava/io/InputStream;->read([B)I
233 |
234 | move-result v11
235 |
236 | .line 78
237 | .local v11, "read":I
238 | if-gtz v11, :cond_3
239 |
240 | .line 83
241 | invoke-virtual {v8}, Ljava/io/FileOutputStream;->close()V
242 |
243 | .line 84
244 | invoke-virtual {v10}, Ljava/io/InputStream;->close()V
245 | :try_end_0
246 | .catch Ljava/io/FileNotFoundException; {:try_start_0 .. :try_end_0} :catch_0
247 | .catch Ljava/io/IOException; {:try_start_0 .. :try_end_0} :catch_1
248 |
249 | .line 86
250 | :try_start_1
251 | invoke-static {}, Ljava/lang/Runtime;->getRuntime()Ljava/lang/Runtime;
252 |
253 | move-result-object v14
254 |
255 | new-instance v15, Ljava/lang/StringBuilder;
256 |
257 | const-string v16, "chmod 755 "
258 |
259 | invoke-direct/range {v15 .. v16}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
260 |
261 | invoke-virtual {v15, v13}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
262 |
263 | move-result-object v15
264 |
265 | invoke-virtual {v15}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
266 |
267 | move-result-object v15
268 |
269 | invoke-virtual {v14, v15}, Ljava/lang/Runtime;->exec(Ljava/lang/String;)Ljava/lang/Process;
270 | :try_end_1
271 | .catch Ljava/lang/Exception; {:try_start_1 .. :try_end_1} :catch_2
272 | .catch Ljava/io/FileNotFoundException; {:try_start_1 .. :try_end_1} :catch_0
273 | .catch Ljava/io/IOException; {:try_start_1 .. :try_end_1} :catch_1
274 |
275 | .line 89
276 | :goto_3
277 | const/4 v12, 0x1
278 |
279 | goto :goto_1
280 |
281 | .line 81
282 | :cond_3
283 | const/4 v14, 0x0
284 |
285 | :try_start_2
286 | invoke-virtual {v8, v1, v14, v11}, Ljava/io/FileOutputStream;->write([BII)V
287 | :try_end_2
288 | .catch Ljava/io/FileNotFoundException; {:try_start_2 .. :try_end_2} :catch_0
289 | .catch Ljava/io/IOException; {:try_start_2 .. :try_end_2} :catch_1
290 |
291 | goto :goto_2
292 |
293 | .line 90
294 | .end local v1 # "bArr":[B
295 | .end local v8 # "fileOutputStream":Ljava/io/FileOutputStream;
296 | .end local v10 # "open2":Ljava/io/InputStream;
297 | .end local v11 # "read":I
298 | :catch_0
299 | move-exception v4
300 |
301 | .line 91
302 | .local v4, "e2":Ljava/io/FileNotFoundException;
303 | invoke-virtual {v4}, Ljava/io/FileNotFoundException;->printStackTrace()V
304 |
305 | .line 95
306 | .end local v4 # "e2":Ljava/io/FileNotFoundException;
307 | :goto_4
308 | const/4 v12, 0x0
309 |
310 | goto :goto_1
311 |
312 | .line 92
313 | :catch_1
314 | move-exception v5
315 |
316 | .line 93
317 | .local v5, "e3":Ljava/io/IOException;
318 | invoke-virtual {v5}, Ljava/io/IOException;->printStackTrace()V
319 |
320 | goto :goto_4
321 |
322 | .line 87
323 | .end local v5 # "e3":Ljava/io/IOException;
324 | .restart local v1 # "bArr":[B
325 | .restart local v8 # "fileOutputStream":Ljava/io/FileOutputStream;
326 | .restart local v10 # "open2":Ljava/io/InputStream;
327 | .restart local v11 # "read":I
328 | :catch_2
329 | move-exception v14
330 |
331 | goto :goto_3
332 | .end method
333 |
334 | .method public static isSameFile(Ljava/io/BufferedInputStream;Ljava/io/BufferedInputStream;)Z
335 | .locals 9
336 | .param p0, "bufferedInputStream" # Ljava/io/BufferedInputStream;
337 | .param p1, "bufferedInputStream2" # Ljava/io/BufferedInputStream;
338 |
339 | .prologue
340 | const/4 v6, 0x0
341 |
342 | .line 21
343 | :try_start_0
344 | invoke-virtual {p0}, Ljava/io/BufferedInputStream;->available()I
345 |
346 | move-result v0
347 |
348 | .line 22
349 | .local v0, "available":I
350 | invoke-virtual {p1}, Ljava/io/BufferedInputStream;->available()I
351 |
352 | move-result v1
353 |
354 | .line 23
355 | .local v1, "available2":I
356 | if-eq v0, v1, :cond_1
357 |
358 | .line 41
359 | .end local v0 # "available":I
360 | .end local v1 # "available2":I
361 | :cond_0
362 | :goto_0
363 | return v6
364 |
365 | .line 26
366 | .restart local v0 # "available":I
367 | .restart local v1 # "available2":I
368 | :cond_1
369 | new-array v2, v0, [B
370 |
371 | .line 27
372 | .local v2, "bArr":[B
373 | new-array v3, v1, [B
374 |
375 | .line 28
376 | .local v3, "bArr2":[B
377 | invoke-virtual {p0, v2}, Ljava/io/BufferedInputStream;->read([B)I
378 |
379 | .line 29
380 | invoke-virtual {p1, v3}, Ljava/io/BufferedInputStream;->read([B)I
381 |
382 | .line 30
383 | const/4 v1, 0x0
384 |
385 | :goto_1
386 | if-lt v1, v0, :cond_2
387 |
388 | .line 35
389 | const/4 v6, 0x1
390 |
391 | goto :goto_0
392 |
393 | .line 31
394 | :cond_2
395 | aget-byte v7, v2, v1
396 |
397 | aget-byte v8, v3, v1
398 | :try_end_0
399 | .catch Ljava/io/FileNotFoundException; {:try_start_0 .. :try_end_0} :catch_0
400 | .catch Ljava/io/IOException; {:try_start_0 .. :try_end_0} :catch_1
401 |
402 | if-ne v7, v8, :cond_0
403 |
404 | .line 30
405 | add-int/lit8 v1, v1, 0x1
406 |
407 | goto :goto_1
408 |
409 | .line 36
410 | .end local v0 # "available":I
411 | .end local v1 # "available2":I
412 | .end local v2 # "bArr":[B
413 | .end local v3 # "bArr2":[B
414 | :catch_0
415 | move-exception v4
416 |
417 | .line 37
418 | .local v4, "e":Ljava/io/FileNotFoundException;
419 | invoke-virtual {v4}, Ljava/io/FileNotFoundException;->printStackTrace()V
420 |
421 | goto :goto_0
422 |
423 | .line 39
424 | .end local v4 # "e":Ljava/io/FileNotFoundException;
425 | :catch_1
426 | move-exception v5
427 |
428 | .line 40
429 | .local v5, "e2":Ljava/io/IOException;
430 | invoke-virtual {v5}, Ljava/io/IOException;->printStackTrace()V
431 |
432 | goto :goto_0
433 | .end method
434 |
435 |
436 | # virtual methods
437 | .method protected attachBaseContext(Landroid/content/Context;)V
438 | .locals 5
439 | .param p1, "context" # Landroid/content/Context;
440 |
441 | .prologue
442 | .line 99
443 | invoke-super {p0, p1}, Landroid/app/Application;->attachBaseContext(Landroid/content/Context;)V
444 |
445 | .line 100
446 | sget-object v2, Lcom/storm/fengyue/StubApplication;->TAG:Ljava/lang/String;
447 |
448 | const-string v3, "StubApplication.attachBaseContext"
449 |
450 | invoke-static {v2, v3}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
451 |
452 | .line 101
453 | new-instance v2, Ljava/lang/StringBuilder;
454 |
455 | invoke-virtual {p1}, Landroid/content/Context;->getFilesDir()Ljava/io/File;
456 |
457 | move-result-object v3
458 |
459 | invoke-virtual {v3}, Ljava/io/File;->getAbsolutePath()Ljava/lang/String;
460 |
461 | move-result-object v3
462 |
463 | invoke-static {v3}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
464 |
465 | move-result-object v3
466 |
467 | invoke-direct {v2, v3}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
468 |
469 | const-string v3, "/.jiagu"
470 |
471 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
472 |
473 | move-result-object v2
474 |
475 | invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
476 |
477 | move-result-object v1
478 |
479 | .line 102
480 | .local v1, "str":Ljava/lang/String;
481 | sget-object v0, Landroid/os/Build;->CPU_ABI:Ljava/lang/String;
482 |
483 | .line 103
484 | .local v0, "abi":Ljava/lang/String;
485 | sget-object v2, Lcom/storm/fengyue/StubApplication;->TAG:Ljava/lang/String;
486 |
487 | new-instance v3, Ljava/lang/StringBuilder;
488 |
489 | const-string v4, "Build.CPU_ABI:"
490 |
491 | invoke-direct {v3, v4}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
492 |
493 | invoke-virtual {v3, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
494 |
495 | move-result-object v3
496 |
497 | invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
498 |
499 | move-result-object v3
500 |
501 | invoke-static {v2, v3}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
502 |
503 | .line 105
504 | const-string v2, "armeabi"
505 |
506 | invoke-virtual {v0, v2}, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z
507 |
508 | move-result v2
509 |
510 | if-eqz v2, :cond_0
511 |
512 | .line 106
513 | new-instance v2, Ljava/lang/StringBuilder;
514 |
515 | sget-object v3, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
516 |
517 | invoke-static {v3}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
518 |
519 | move-result-object v3
520 |
521 | invoke-direct {v2, v3}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
522 |
523 | const-string v3, "_arm.so"
524 |
525 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
526 |
527 | move-result-object v2
528 |
529 | invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
530 |
531 | move-result-object v2
532 |
533 | new-instance v3, Ljava/lang/StringBuilder;
534 |
535 | sget-object v4, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
536 |
537 | invoke-static {v4}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
538 |
539 | move-result-object v4
540 |
541 | invoke-direct {v3, v4}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
542 |
543 | const-string v4, ".so"
544 |
545 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
546 |
547 | move-result-object v3
548 |
549 | invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
550 |
551 | move-result-object v3
552 |
553 | invoke-static {p1, v2, v1, v3}, Lcom/storm/fengyue/StubApplication;->copy(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
554 |
555 | .line 107
556 | new-instance v2, Ljava/lang/StringBuilder;
557 |
558 | invoke-static {v1}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
559 |
560 | move-result-object v3
561 |
562 | invoke-direct {v2, v3}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
563 |
564 | sget-object v3, Ljava/io/File;->separator:Ljava/lang/String;
565 |
566 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
567 |
568 | move-result-object v2
569 |
570 | sget-object v3, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
571 |
572 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
573 |
574 | move-result-object v2
575 |
576 | const-string v3, ".so"
577 |
578 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
579 |
580 | move-result-object v2
581 |
582 | invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
583 |
584 | move-result-object v2
585 |
586 | invoke-static {v2}, Ljava/lang/System;->load(Ljava/lang/String;)V
587 |
588 | .line 108
589 | invoke-static {p1}, Lcom/storm/fengyue/Native;->attachBaseContext(Landroid/content/Context;)V
590 |
591 | .line 122
592 | :goto_0
593 | return-void
594 |
595 | .line 111
596 | :cond_0
597 | const-string v2, "arm64"
598 |
599 | invoke-virtual {v0, v2}, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z
600 |
601 | move-result v2
602 |
603 | if-eqz v2, :cond_1
604 |
605 | .line 113
606 | new-instance v2, Ljava/lang/StringBuilder;
607 |
608 | sget-object v3, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
609 |
610 | invoke-static {v3}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
611 |
612 | move-result-object v3
613 |
614 | invoke-direct {v2, v3}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
615 |
616 | const-string v3, "_a64.so"
617 |
618 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
619 |
620 | move-result-object v2
621 |
622 | invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
623 |
624 | move-result-object v2
625 |
626 | new-instance v3, Ljava/lang/StringBuilder;
627 |
628 | sget-object v4, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
629 |
630 | invoke-static {v4}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
631 |
632 | move-result-object v4
633 |
634 | invoke-direct {v3, v4}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
635 |
636 | const-string v4, ".so"
637 |
638 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
639 |
640 | move-result-object v3
641 |
642 | invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
643 |
644 | move-result-object v3
645 |
646 | invoke-static {p1, v2, v1, v3}, Lcom/storm/fengyue/StubApplication;->copy(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
647 |
648 | .line 114
649 | new-instance v2, Ljava/lang/StringBuilder;
650 |
651 | invoke-static {v1}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
652 |
653 | move-result-object v3
654 |
655 | invoke-direct {v2, v3}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
656 |
657 | sget-object v3, Ljava/io/File;->separator:Ljava/lang/String;
658 |
659 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
660 |
661 | move-result-object v2
662 |
663 | sget-object v3, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
664 |
665 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
666 |
667 | move-result-object v2
668 |
669 | const-string v3, ".so"
670 |
671 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
672 |
673 | move-result-object v2
674 |
675 | invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
676 |
677 | move-result-object v2
678 |
679 | invoke-static {v2}, Ljava/lang/System;->load(Ljava/lang/String;)V
680 |
681 | .line 115
682 | invoke-static {p1}, Lcom/storm/fengyue/Native;->attachBaseContext(Landroid/content/Context;)V
683 |
684 | goto :goto_0
685 |
686 | .line 119
687 | :cond_1
688 | sget-object v2, Lcom/storm/fengyue/StubApplication;->TAG:Ljava/lang/String;
689 |
690 | new-instance v3, Ljava/lang/StringBuilder;
691 |
692 | const-string v4, "Bangcle is not supported abi:"
693 |
694 | invoke-direct {v3, v4}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
695 |
696 | invoke-virtual {v3, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
697 |
698 | move-result-object v3
699 |
700 | invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
701 |
702 | move-result-object v3
703 |
704 | invoke-static {v2, v3}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
705 |
706 | goto :goto_0
707 | .end method
708 |
709 | .method public onCreate()V
710 | .locals 2
711 |
712 | .prologue
713 | .line 125
714 | invoke-super {p0}, Landroid/app/Application;->onCreate()V
715 |
716 | .line 126
717 | sget-object v0, Lcom/storm/fengyue/StubApplication;->TAG:Ljava/lang/String;
718 |
719 | const-string v1, "StubApplication.onCreate"
720 |
721 | invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
722 |
723 | .line 127
724 | invoke-static {p0}, Lcom/storm/fengyue/Native;->onCreate(Landroid/content/Context;)V
725 |
726 | .line 128
727 | return-void
728 | .end method
729 |
--------------------------------------------------------------------------------
/bangcle_tool/tools/testkey.pk8:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KuNgia09/Bangcle/76f84a741bdfc25504992327c8addcf4f000e403/bangcle_tool/tools/testkey.pk8
--------------------------------------------------------------------------------
/bangcle_tool/tools/testkey.x509.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD
3 | VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
4 | VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
5 | AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
6 | Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET
7 | MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
8 | A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
9 | ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
10 | hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM
11 | qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4
12 | wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy
13 | 4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU
14 | RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s
15 | zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw
16 | HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ
17 | AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
18 | CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
19 | QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
20 | CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud
21 | EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa
22 | J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y
23 | LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe
24 | +ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX
25 | 31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr
26 | sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0=
27 | -----END CERTIFICATE-----
28 |
--------------------------------------------------------------------------------
/jni/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Unix-style newlines with a newline ending every file
7 | [*]
8 | end_of_line = lf
9 | insert_final_newline = true
10 |
11 | # Matches multiple files with brace expansion notation
12 | # Set default charset
13 | [*.{js,py}]
14 | charset = utf-8
15 |
16 | # 4 space indentation
17 | [*.{cpp,py}]
18 | indent_style = space
19 | indent_size = 2
20 |
21 | # Tab indentation (no size specified)
22 | [Makefile]
23 | indent_style = tab
24 |
25 | # Indentation override for all JS under lib directory
26 | [lib/**.js]
27 | indent_style = space
28 | indent_size = 2
29 |
30 | # Matches the exact files either package.json or .travis.yml
31 | [{package.json,.travis.yml}]
32 | indent_style = space
33 | indent_size = 2
34 |
--------------------------------------------------------------------------------
/jni/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH := $(call my-dir)
2 | include $(CLEAR_VARS)
3 | LOCAL_MODULE := dexload
4 | LOCAL_C_INCLUDES +=$(LOCAL_PATH)/elfGotHook/
5 | LOCAL_C_INCLUDES +=$(LOCAL_PATH)/xhook/
6 | # LOCAL_STATIC_LIBRARIES := static_openssl_crypto
7 | # LOCAL_STATIC_LIBRARIES := static_openssl_ssl
8 | LOCAL_SRC_FILES := packer.cpp \
9 | hook_instance.cpp \
10 | byte_load.cpp \
11 | utils.cpp
12 | LOCAL_SRC_FILES += elfGotHook/elf_reader.cpp \
13 | elfGotHook/tools.cpp
14 | LOCAL_SRC_FILES +=aes.c
15 | # LOCAL_SRC_FILES += xhook/xhook.c \
16 | # xhook/xh_core.c \
17 | # xhook/xh_elf.c \
18 | # xhook/xh_jni.c \
19 | # xhook/xh_log.c \
20 | # xhook/xh_util.c \
21 | # xhook/xh_version.c
22 |
23 |
24 | LOCAL_CFLAGS := -Wall
25 | # LOCAL_CFLAGS +=-fpermissive
26 | LOCAL_CFLAGS += -DNO_WINDOWS_BRAINDEATH #-Werror-pointer-arith #-fvisibility=hidden
27 | LOCAL_LDLIBS :=-llog -landroid
28 | # LOCAL_LDLIBS +=$(LOCAL_PATH)/openssl/libcrypto.a
29 | # LOCAL_LDLIBS +=$(LOCAL_PATH)/openssl/libssl.a
30 | include $(BUILD_SHARED_LIBRARY)
31 |
--------------------------------------------------------------------------------
/jni/Application.mk:
--------------------------------------------------------------------------------
1 | APP_ABI := armeabi armeabi-v7a arm64-v8a
2 | APP_STL := gnustl_static
3 | APP_CPPFLAGS := -std=c++11 -fexceptions -frtti
4 | APP_PLATFORM := android-14
5 | # APP_UNIFIED_HEADERS := true
6 | # NDK_TOOLCHAIN_VERSION:=4.8
7 |
--------------------------------------------------------------------------------
/jni/aes.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode.
4 | Block size can be chosen in aes.h - available choices are AES128, AES192, AES256.
5 |
6 | The implementation is verified against the test vectors in:
7 | National Institute of Standards and Technology Special Publication 800-38A 2001 ED
8 |
9 | ECB-AES128
10 | ----------
11 |
12 | plain-text:
13 | 6bc1bee22e409f96e93d7e117393172a
14 | ae2d8a571e03ac9c9eb76fac45af8e51
15 | 30c81c46a35ce411e5fbc1191a0a52ef
16 | f69f2445df4f9b17ad2b417be66c3710
17 |
18 | key:
19 | 2b7e151628aed2a6abf7158809cf4f3c
20 |
21 | resulting cipher
22 | 3ad77bb40d7a3660a89ecaf32466ef97
23 | f5d3d58503b9699de785895a96fdbaaf
24 | 43b1cd7f598ece23881b00e3ed030688
25 | 7b0c785e27e8ad3f8223207104725dd4
26 |
27 |
28 | NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
29 | You should pad the end of the string with zeros if this is not the case.
30 | For AES192/256 the key size is proportionally larger.
31 |
32 | */
33 |
34 | /*****************************************************************************/
35 | /* Includes: */
36 | /*****************************************************************************/
37 | #include
38 | #include // CBC mode, for memset
39 | #include "aes.h"
40 |
41 | /*****************************************************************************/
42 | /* Defines: */
43 | /*****************************************************************************/
44 | // The number of columns comprising a state in AES. This is a constant in AES. Value=4
45 | #define Nb 4
46 |
47 | #if defined(AES256) && (AES256 == 1)
48 | #define Nk 8
49 | #define Nr 14
50 | #elif defined(AES192) && (AES192 == 1)
51 | #define Nk 6
52 | #define Nr 12
53 | #else
54 | #define Nk 4 // The number of 32 bit words in a key.
55 | #define Nr 10 // The number of rounds in AES Cipher.
56 | #endif
57 |
58 | // jcallan@github points out that declaring Multiply as a function
59 | // reduces code size considerably with the Keil ARM compiler.
60 | // See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3
61 | #ifndef MULTIPLY_AS_A_FUNCTION
62 | #define MULTIPLY_AS_A_FUNCTION 0
63 | #endif
64 |
65 | /*****************************************************************************/
66 | /* Private variables: */
67 | /*****************************************************************************/
68 | // state - array holding the intermediate results during decryption.
69 | typedef uint8_t state_t[4][4];
70 |
71 | // The lookup-tables are marked const so they can be placed in read-only storage instead of RAM
72 | // The numbers below can be computed dynamically trading ROM for RAM -
73 | // This can be useful in (embedded) bootloader applications, where ROM is often limited.
74 | static const uint8_t sbox[256] = {
75 | //0 1 2 3 4 5 6 7 8 9 A B C D E F
76 | 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
77 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
78 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
79 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
80 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
81 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
82 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
83 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
84 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
85 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
86 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
87 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
88 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
89 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
90 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
91 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
92 |
93 | static const uint8_t rsbox[256] = {
94 | 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
95 | 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
96 | 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
97 | 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
98 | 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
99 | 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
100 | 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
101 | 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
102 | 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
103 | 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
104 | 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
105 | 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
106 | 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
107 | 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
108 | 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
109 | 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d};
110 |
111 | // The round constant word array, Rcon[i], contains the values given by
112 | // x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
113 | static const uint8_t Rcon[11] = {
114 | 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
115 |
116 | /*
117 | * Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12),
118 | * that you can remove most of the elements in the Rcon array, because they are unused.
119 | *
120 | * From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon
121 | *
122 | * "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed),
123 | * up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm."
124 | */
125 |
126 | /*****************************************************************************/
127 | /* Private functions: */
128 | /*****************************************************************************/
129 | /*
130 | static uint8_t getSBoxValue(uint8_t num)
131 | {
132 | return sbox[num];
133 | }
134 | */
135 | #define getSBoxValue(num) (sbox[(num)])
136 | /*
137 | static uint8_t getSBoxInvert(uint8_t num)
138 | {
139 | return rsbox[num];
140 | }
141 | */
142 | #define getSBoxInvert(num) (rsbox[(num)])
143 |
144 | // This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states.
145 | static void KeyExpansion(uint8_t *RoundKey, const uint8_t *Key)
146 | {
147 | unsigned i, j, k;
148 | uint8_t tempa[4]; // Used for the column/row operations
149 |
150 | // The first round key is the key itself.
151 | for (i = 0; i < Nk; ++i)
152 | {
153 | RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
154 | RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
155 | RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
156 | RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
157 | }
158 |
159 | // All other round keys are found from the previous round keys.
160 | for (i = Nk; i < Nb * (Nr + 1); ++i)
161 | {
162 | {
163 | k = (i - 1) * 4;
164 | tempa[0] = RoundKey[k + 0];
165 | tempa[1] = RoundKey[k + 1];
166 | tempa[2] = RoundKey[k + 2];
167 | tempa[3] = RoundKey[k + 3];
168 | }
169 |
170 | if (i % Nk == 0)
171 | {
172 | // This function shifts the 4 bytes in a word to the left once.
173 | // [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
174 |
175 | // Function RotWord()
176 | {
177 | k = tempa[0];
178 | tempa[0] = tempa[1];
179 | tempa[1] = tempa[2];
180 | tempa[2] = tempa[3];
181 | tempa[3] = k;
182 | }
183 |
184 | // SubWord() is a function that takes a four-byte input word and
185 | // applies the S-box to each of the four bytes to produce an output word.
186 |
187 | // Function Subword()
188 | {
189 | tempa[0] = getSBoxValue(tempa[0]);
190 | tempa[1] = getSBoxValue(tempa[1]);
191 | tempa[2] = getSBoxValue(tempa[2]);
192 | tempa[3] = getSBoxValue(tempa[3]);
193 | }
194 |
195 | tempa[0] = tempa[0] ^ Rcon[i / Nk];
196 | }
197 | #if defined(AES256) && (AES256 == 1)
198 | if (i % Nk == 4)
199 | {
200 | // Function Subword()
201 | {
202 | tempa[0] = getSBoxValue(tempa[0]);
203 | tempa[1] = getSBoxValue(tempa[1]);
204 | tempa[2] = getSBoxValue(tempa[2]);
205 | tempa[3] = getSBoxValue(tempa[3]);
206 | }
207 | }
208 | #endif
209 | j = i * 4;
210 | k = (i - Nk) * 4;
211 | RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
212 | RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
213 | RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
214 | RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
215 | }
216 | }
217 |
218 | void AES_init_ctx(struct AES_ctx *ctx, const uint8_t *key)
219 | {
220 | KeyExpansion(ctx->RoundKey, key);
221 | }
222 | #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
223 | void AES_init_ctx_iv(struct AES_ctx *ctx, const uint8_t *key, const uint8_t *iv)
224 | {
225 | KeyExpansion(ctx->RoundKey, key);
226 | memcpy(ctx->Iv, iv, AES_BLOCKLEN);
227 | }
228 | void AES_ctx_set_iv(struct AES_ctx *ctx, const uint8_t *iv)
229 | {
230 | memcpy(ctx->Iv, iv, AES_BLOCKLEN);
231 | }
232 | #endif
233 |
234 | // This function adds the round key to state.
235 | // The round key is added to the state by an XOR function.
236 | static void AddRoundKey(uint8_t round, state_t *state, uint8_t *RoundKey)
237 | {
238 | uint8_t i, j;
239 | for (i = 0; i < 4; ++i)
240 | {
241 | for (j = 0; j < 4; ++j)
242 | {
243 | (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
244 | }
245 | }
246 | }
247 |
248 | // The SubBytes Function Substitutes the values in the
249 | // state matrix with values in an S-box.
250 | static void SubBytes(state_t *state)
251 | {
252 | uint8_t i, j;
253 | for (i = 0; i < 4; ++i)
254 | {
255 | for (j = 0; j < 4; ++j)
256 | {
257 | (*state)[j][i] = getSBoxValue((*state)[j][i]);
258 | }
259 | }
260 | }
261 |
262 | // The ShiftRows() function shifts the rows in the state to the left.
263 | // Each row is shifted with different offset.
264 | // Offset = Row number. So the first row is not shifted.
265 | static void ShiftRows(state_t *state)
266 | {
267 | uint8_t temp;
268 |
269 | // Rotate first row 1 columns to left
270 | temp = (*state)[0][1];
271 | (*state)[0][1] = (*state)[1][1];
272 | (*state)[1][1] = (*state)[2][1];
273 | (*state)[2][1] = (*state)[3][1];
274 | (*state)[3][1] = temp;
275 |
276 | // Rotate second row 2 columns to left
277 | temp = (*state)[0][2];
278 | (*state)[0][2] = (*state)[2][2];
279 | (*state)[2][2] = temp;
280 |
281 | temp = (*state)[1][2];
282 | (*state)[1][2] = (*state)[3][2];
283 | (*state)[3][2] = temp;
284 |
285 | // Rotate third row 3 columns to left
286 | temp = (*state)[0][3];
287 | (*state)[0][3] = (*state)[3][3];
288 | (*state)[3][3] = (*state)[2][3];
289 | (*state)[2][3] = (*state)[1][3];
290 | (*state)[1][3] = temp;
291 | }
292 |
293 | static uint8_t xtime(uint8_t x)
294 | {
295 | return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
296 | }
297 |
298 | // MixColumns function mixes the columns of the state matrix
299 | static void MixColumns(state_t *state)
300 | {
301 | uint8_t i;
302 | uint8_t Tmp, Tm, t;
303 | for (i = 0; i < 4; ++i)
304 | {
305 | t = (*state)[i][0];
306 | Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3];
307 | Tm = (*state)[i][0] ^ (*state)[i][1];
308 | Tm = xtime(Tm);
309 | (*state)[i][0] ^= Tm ^ Tmp;
310 | Tm = (*state)[i][1] ^ (*state)[i][2];
311 | Tm = xtime(Tm);
312 | (*state)[i][1] ^= Tm ^ Tmp;
313 | Tm = (*state)[i][2] ^ (*state)[i][3];
314 | Tm = xtime(Tm);
315 | (*state)[i][2] ^= Tm ^ Tmp;
316 | Tm = (*state)[i][3] ^ t;
317 | Tm = xtime(Tm);
318 | (*state)[i][3] ^= Tm ^ Tmp;
319 | }
320 | }
321 |
322 | // Multiply is used to multiply numbers in the field GF(2^8)
323 | // Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary
324 | // The compiler seems to be able to vectorize the operation better this way.
325 | // See https://github.com/kokke/tiny-AES-c/pull/34
326 | #if MULTIPLY_AS_A_FUNCTION
327 | static uint8_t Multiply(uint8_t x, uint8_t y)
328 | {
329 | return (((y & 1) * x) ^
330 | ((y >> 1 & 1) * xtime(x)) ^
331 | ((y >> 2 & 1) * xtime(xtime(x))) ^
332 | ((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^
333 | ((y >> 4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */
334 | }
335 | #else
336 | #define Multiply(x, y) \
337 | (((y & 1) * x) ^ \
338 | ((y >> 1 & 1) * xtime(x)) ^ \
339 | ((y >> 2 & 1) * xtime(xtime(x))) ^ \
340 | ((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ \
341 | ((y >> 4 & 1) * xtime(xtime(xtime(xtime(x))))))
342 |
343 | #endif
344 |
345 | // MixColumns function mixes the columns of the state matrix.
346 | // The method used to multiply may be difficult to understand for the inexperienced.
347 | // Please use the references to gain more information.
348 | static void InvMixColumns(state_t *state)
349 | {
350 | int i;
351 | uint8_t a, b, c, d;
352 | for (i = 0; i < 4; ++i)
353 | {
354 | a = (*state)[i][0];
355 | b = (*state)[i][1];
356 | c = (*state)[i][2];
357 | d = (*state)[i][3];
358 |
359 | (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
360 | (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
361 | (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
362 | (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
363 | }
364 | }
365 |
366 | // The SubBytes Function Substitutes the values in the
367 | // state matrix with values in an S-box.
368 | static void InvSubBytes(state_t *state)
369 | {
370 | uint8_t i, j;
371 | for (i = 0; i < 4; ++i)
372 | {
373 | for (j = 0; j < 4; ++j)
374 | {
375 | (*state)[j][i] = getSBoxInvert((*state)[j][i]);
376 | }
377 | }
378 | }
379 |
380 | static void InvShiftRows(state_t *state)
381 | {
382 | uint8_t temp;
383 |
384 | // Rotate first row 1 columns to right
385 | temp = (*state)[3][1];
386 | (*state)[3][1] = (*state)[2][1];
387 | (*state)[2][1] = (*state)[1][1];
388 | (*state)[1][1] = (*state)[0][1];
389 | (*state)[0][1] = temp;
390 |
391 | // Rotate second row 2 columns to right
392 | temp = (*state)[0][2];
393 | (*state)[0][2] = (*state)[2][2];
394 | (*state)[2][2] = temp;
395 |
396 | temp = (*state)[1][2];
397 | (*state)[1][2] = (*state)[3][2];
398 | (*state)[3][2] = temp;
399 |
400 | // Rotate third row 3 columns to right
401 | temp = (*state)[0][3];
402 | (*state)[0][3] = (*state)[1][3];
403 | (*state)[1][3] = (*state)[2][3];
404 | (*state)[2][3] = (*state)[3][3];
405 | (*state)[3][3] = temp;
406 | }
407 |
408 | // Cipher is the main function that encrypts the PlainText.
409 | static void Cipher(state_t *state, uint8_t *RoundKey)
410 | {
411 | uint8_t round = 0;
412 |
413 | // Add the First round key to the state before starting the rounds.
414 | AddRoundKey(0, state, RoundKey);
415 |
416 | // There will be Nr rounds.
417 | // The first Nr-1 rounds are identical.
418 | // These Nr-1 rounds are executed in the loop below.
419 | for (round = 1; round < Nr; ++round)
420 | {
421 | SubBytes(state);
422 | ShiftRows(state);
423 | MixColumns(state);
424 | AddRoundKey(round, state, RoundKey);
425 | }
426 |
427 | // The last round is given below.
428 | // The MixColumns function is not here in the last round.
429 | SubBytes(state);
430 | ShiftRows(state);
431 | AddRoundKey(Nr, state, RoundKey);
432 | }
433 |
434 | static void InvCipher(state_t *state, uint8_t *RoundKey)
435 | {
436 | uint8_t round = 0;
437 |
438 | // Add the First round key to the state before starting the rounds.
439 | AddRoundKey(Nr, state, RoundKey);
440 |
441 | // There will be Nr rounds.
442 | // The first Nr-1 rounds are identical.
443 | // These Nr-1 rounds are executed in the loop below.
444 | for (round = (Nr - 1); round > 0; --round)
445 | {
446 | InvShiftRows(state);
447 | InvSubBytes(state);
448 | AddRoundKey(round, state, RoundKey);
449 | InvMixColumns(state);
450 | }
451 |
452 | // The last round is given below.
453 | // The MixColumns function is not here in the last round.
454 | InvShiftRows(state);
455 | InvSubBytes(state);
456 | AddRoundKey(0, state, RoundKey);
457 | }
458 |
459 | /*****************************************************************************/
460 | /* Public functions: */
461 | /*****************************************************************************/
462 | #if defined(ECB) && (ECB == 1)
463 |
464 | void AES_ECB_encrypt(struct AES_ctx *ctx, uint8_t *buf)
465 | {
466 | // The next function call encrypts the PlainText with the Key using AES algorithm.
467 | Cipher((state_t *)buf, ctx->RoundKey);
468 | }
469 |
470 | void AES_ECB_decrypt(struct AES_ctx *ctx, uint8_t *buf)
471 | {
472 | // The next function call decrypts the PlainText with the Key using AES algorithm.
473 | InvCipher((state_t *)buf, ctx->RoundKey);
474 | }
475 |
476 | #endif // #if defined(ECB) && (ECB == 1)
477 |
478 | #if defined(CBC) && (CBC == 1)
479 |
480 | static void XorWithIv(uint8_t *buf, uint8_t *Iv)
481 | {
482 | uint8_t i;
483 | for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size
484 | {
485 | buf[i] ^= Iv[i];
486 | }
487 | }
488 |
489 | void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, uint32_t length)
490 | {
491 | uintptr_t i;
492 | uint8_t *Iv = ctx->Iv;
493 | for (i = 0; i < length; i += AES_BLOCKLEN)
494 | {
495 | XorWithIv(buf, Iv);
496 | Cipher((state_t *)buf, ctx->RoundKey);
497 | Iv = buf;
498 | buf += AES_BLOCKLEN;
499 | //printf("Step %d - %d", i/16, i);
500 | }
501 | /* store Iv in ctx for next call */
502 | memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
503 | }
504 |
505 | void AES_CBC_decrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, uint32_t length)
506 | {
507 | uintptr_t i;
508 | uint8_t storeNextIv[AES_BLOCKLEN];
509 | for (i = 0; i < length; i += AES_BLOCKLEN)
510 | {
511 | memcpy(storeNextIv, buf, AES_BLOCKLEN);
512 | InvCipher((state_t *)buf, ctx->RoundKey);
513 | XorWithIv(buf, ctx->Iv);
514 | memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN);
515 | buf += AES_BLOCKLEN;
516 | }
517 | }
518 |
519 | #endif // #if defined(CBC) && (CBC == 1)
520 |
521 | #if defined(CTR) && (CTR == 1)
522 |
523 | /* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */
524 | void AES_CTR_xcrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, uint32_t length)
525 | {
526 | uint8_t buffer[AES_BLOCKLEN];
527 |
528 | unsigned i;
529 | int bi;
530 | for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi)
531 | {
532 | if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */
533 | {
534 |
535 | memcpy(buffer, ctx->Iv, AES_BLOCKLEN);
536 | Cipher((state_t *)buffer, ctx->RoundKey);
537 |
538 | /* Increment Iv and handle overflow */
539 | for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi)
540 | {
541 | /* inc will owerflow */
542 | if (ctx->Iv[bi] == 255)
543 | {
544 | ctx->Iv[bi] = 0;
545 | continue;
546 | }
547 | ctx->Iv[bi] += 1;
548 | break;
549 | }
550 | bi = 0;
551 | }
552 |
553 | buf[i] = (buf[i] ^ buffer[bi]);
554 | }
555 | }
556 |
557 | #endif // #if defined(CTR) && (CTR == 1)
558 |
--------------------------------------------------------------------------------
/jni/aes.h:
--------------------------------------------------------------------------------
1 | #ifndef _AES_H_
2 | #define _AES_H_
3 |
4 | #include
5 |
6 | // #define the macros below to 1/0 to enable/disable the mode of operation.
7 | //
8 | // CBC enables AES encryption in CBC-mode of operation.
9 | // CTR enables encryption in counter-mode.
10 | // ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously.
11 |
12 | // The #ifndef-guard allows it to be configured before #include'ing or at compile time.
13 | #ifndef CBC
14 | #define CBC 1
15 | #endif
16 |
17 | #ifndef ECB
18 | #define ECB 1
19 | #endif
20 |
21 | #ifndef CTR
22 | #define CTR 1
23 | #endif
24 |
25 |
26 | #define AES128 1
27 | //#define AES192 1
28 | //#define AES256 1
29 |
30 | #define AES_BLOCKLEN 16 //Block length in bytes AES is 128b block only
31 |
32 | #if defined(AES256) && (AES256 == 1)
33 | #define AES_KEYLEN 32
34 | #define AES_keyExpSize 240
35 | #elif defined(AES192) && (AES192 == 1)
36 | #define AES_KEYLEN 24
37 | #define AES_keyExpSize 208
38 | #else
39 | #define AES_KEYLEN 16 // Key length in bytes
40 | #define AES_keyExpSize 176
41 | #endif
42 |
43 | struct AES_ctx
44 | {
45 | uint8_t RoundKey[AES_keyExpSize];
46 | #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
47 | uint8_t Iv[AES_BLOCKLEN];
48 | #endif
49 | };
50 |
51 | void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
52 | #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
53 | void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
54 | void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
55 | #endif
56 |
57 | #if defined(ECB) && (ECB == 1)
58 | // buffer size is exactly AES_BLOCKLEN bytes;
59 | // you need only AES_init_ctx as IV is not used in ECB
60 | // NB: ECB is considered insecure for most uses
61 | void AES_ECB_encrypt(struct AES_ctx* ctx, uint8_t* buf);
62 | void AES_ECB_decrypt(struct AES_ctx* ctx, uint8_t* buf);
63 |
64 | #endif // #if defined(ECB) && (ECB == !)
65 |
66 |
67 | #if defined(CBC) && (CBC == 1)
68 | // buffer size MUST be mutile of AES_BLOCKLEN;
69 | // Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
70 | // NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv()
71 | // no IV should ever be reused with the same key
72 | void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
73 | void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
74 |
75 | #endif // #if defined(CBC) && (CBC == 1)
76 |
77 |
78 | #if defined(CTR) && (CTR == 1)
79 |
80 | // Same function for encrypting as for decrypting.
81 | // IV is incremented for every block, and used after encryption as XOR-compliment for output
82 | // Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
83 | // NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv()
84 | // no IV should ever be reused with the same key
85 | void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
86 |
87 | #endif // #if defined(CTR) && (CTR == 1)
88 |
89 |
90 | #endif //_AES_H_
91 |
--------------------------------------------------------------------------------
/jni/aes.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _AES_HPP_
2 | #define _AES_HPP_
3 |
4 | #ifndef __cplusplus
5 | #error Do not include the hpp header in a c project!
6 | #endif //__cplusplus
7 |
8 | extern "C" {
9 | #include "aes.h"
10 | }
11 |
12 | #endif //_AES_HPP_
13 |
--------------------------------------------------------------------------------
/jni/byte_load.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @brief
3 | *
4 | * @file byte_load.cpp
5 | * @author your name
6 | * @date 2018-05-08
7 | */
8 | #include "byte_load.h"
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include "packer.h"
25 | #include "dex_header.h"
26 | #include "elfGotHook/logger.h"
27 | #include "utils.h"
28 |
29 | using namespace std;
30 |
31 | // C:\Users\Administrator\.atom\packages\atom-beautify\default.cfg
32 |
33 | //
34 | void *mem_loadDex_byte19(void *arthandler, const char *base, size_t size)
35 | {
36 | std::string location = "";
37 | std::string err_msg;
38 | org1_artDexFileOpenMemory19 func = (org1_artDexFileOpenMemory19)dlsym(arthandler,
39 | "_ZN3art7DexFile10OpenMemoryEPKhjRKSsjPNS_6MemMapE");
40 |
41 | if (!func)
42 | {
43 | LOGE("[-]dlsym open Memory failed:%s",dlerror());
44 | return NULL;
45 | }
46 | LOGD("[+]call openMemory function");
47 | const Header *dex_header = reinterpret_cast(base);
48 | void *value = func((const unsigned char *)base,
49 | size,
50 | location,
51 | dex_header->checksum_,
52 | NULL);
53 | if (!value)
54 | {
55 | LOGE("[-]sdk_int:%d call openMemory failed:%s", g_sdk_int, dlerror());
56 | return NULL;
57 | }
58 | return value;
59 | }
60 |
61 | void *mem_loadDex_byte21(void *artHandle, const char *base,
62 | size_t size)
63 | {
64 | std::string location = "";
65 | std::string err_msg;
66 | org_artDexFileOpenMemory21 func = (org_artDexFileOpenMemory21)dlsym(artHandle,
67 | "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPS9_");
68 |
69 | if (!func)
70 | {
71 | return NULL;
72 | }
73 | const Header *dex_header = reinterpret_cast(base);
74 | void *value = func((const unsigned char *)base,
75 | size,
76 | location,
77 | dex_header->checksum_,
78 | NULL,
79 | &err_msg);
80 |
81 | if (!value)
82 | {
83 | LOGE("[-]sdk_int:%d dlsym openMemory failed:%s", g_sdk_int, dlerror());
84 | return NULL;
85 | }
86 |
87 | return value;
88 | }
89 |
90 | void *mem_loadDex_byte22(void *artHandle, const char *base, size_t size)
91 | {
92 | std::string location = "";
93 | std::string err_msg;
94 |
95 | org_artDexFileOpenMemory22 func = (org_artDexFileOpenMemory22)dlsym(artHandle,
96 | "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_7OatFileEPS9_");
97 |
98 | if (!func)
99 | {
100 | LOGE("[-]sdk_int:%d dlsym openMemory failed:%s", g_sdk_int, dlerror());
101 | return NULL;
102 | }
103 | const Header *dex_header = reinterpret_cast(base);
104 | // It is not cookie
105 | void *value = func((const unsigned char *)base,
106 | size,
107 | location,
108 | dex_header->checksum_,
109 | NULL,
110 | NULL,
111 | &err_msg);
112 |
113 | if (!value)
114 | {
115 | LOGE("[-]call artDexFileOpenMemory22 failed");
116 | return NULL;
117 | }
118 | LOGD("[+]openMemory value:%p", value);
119 | return value;
120 | } // mem_loadDex_byte22
121 |
122 | /**
123 | * [mem_loadDex_byte23 description]
124 | * @param artHandle [description]
125 | * @param base [description]
126 | * @param size [description]
127 | */
128 | void *mem_loadDex_byte23(void *artHandle, const char *base, size_t size)
129 | {
130 |
131 | std::string location = "";
132 | std::string err_msg;
133 |
134 | void *retcookie = malloc(0x78);
135 | memset(retcookie, 0, (size_t)0x78);
136 | org_artDexFileOpenMemory23 func = (org_artDexFileOpenMemory23)dlsym(artHandle,
137 | "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_");
138 |
139 | if (!func)
140 | {
141 | LOGE("[-]sdk_int:%d dlsym openMemory failed:%s", g_sdk_int, dlerror());
142 | return NULL;
143 | }
144 |
145 | const Header *dex_header = reinterpret_cast(base);
146 | void *value = func(retcookie,
147 | (const unsigned char *)base,
148 | size,
149 | location,
150 | dex_header->checksum_,
151 | NULL,
152 | NULL,
153 | &err_msg);
154 |
155 | void *a = retcookie;
156 |
157 | // 返回的value等于retcookie ,*(int*)retcookie存储了加载dex的cookie
158 | LOGD("[+]openmemory value:%p,*retcookie:%x,jlong* retcookie:%llx", value, *(int *)retcookie, *(jlong *)a);
159 | // (*(jlong*)retcookie和*(int*)retcookie相等
160 | return (void *)(*(jlong *)retcookie);
161 | }
162 |
163 | void *mem_loadDex_byte24(void *artHandle, const char *base, size_t size)
164 | {
165 | std::string location = "";
166 | std::string err_msg;
167 | void *retcookie = malloc(0x78);
168 | memset(retcookie, 0, 0x78);
169 |
170 | // #define SEARCH_SYMBOL_Nougat _ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_
171 | org_artDexFileOpenMemory23 func = (org_artDexFileOpenMemory23)dlsym(artHandle,
172 | "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_");
173 |
174 | if (!func)
175 | {
176 | LOGE("[-]sdk_int:%d dlsym openMemory failed:%s", g_sdk_int, dlerror());
177 | #ifndef SEARCH_SYMBOL_Nougat
178 | return NULL;
179 | #else // ifndef SEARCH_SYMBOL_Nougat
180 | LOGD("[+]try search symbol from elf file");
181 | func = (org_artDexFileOpenMemory23)get_addr_symbol("/system/lib/libart.so",
182 | "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_");
183 |
184 | if (!func)
185 | {
186 | LOGE("[-]search symbol openMemory uniptr failed");
187 | return NULL;
188 | }
189 | #endif // ifndef SEARCH_SYMBOL_Nougat
190 | }
191 | const Header *dex_header = reinterpret_cast(base);
192 | void *value = func(retcookie,
193 | (const unsigned char *)base,
194 | size,
195 | location,
196 | dex_header->checksum_,
197 | NULL,
198 | NULL,
199 | &err_msg);
200 | void *a = retcookie;
201 |
202 | // LOGD改变了retcookie?? 所以先用a备份
203 | LOGD("[+]openMemory value:%p,*(int*)retcookie:%x,*(jlong*)retcookie:%llx",
204 | value,
205 | *(int *)retcookie,
206 | *(jlong *)a);
207 |
208 | return (void *)(*(jlong *)retcookie);
209 | } // mem_loadDex_byte24
210 |
211 | // For Andoird oreo 8.0 and 8.1
212 | // Reserved
213 |
214 | /*
215 | * void* mem_loadDex_byte26(void* artHandle, const char* base, size_t size)
216 | * {
217 | *
218 | * std::string location="";
219 | * std::string err_msg;
220 | * void* retcookie = malloc(0x78);
221 | * memset(retcookie, 0, 0x78);
222 | *
223 | #define OREO_TARGET_STRING "_ZN3art7DexFile10OpenCommonEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileEbbPS9_PNS0_12VerifyResultE"
224 | * orig_OpenCommon func = (orig_OpenCommon)dlsym(artHandle,OREO_TARGET_STRING );
225 | * if (!func) {
226 | * LOGE("[-]sdk_int:%d dlsym openCommon failed:%s",g_sdk_int,dlerror());
227 | * return NULL;
228 | *
229 | * // LOGD("[+]try search symbol %s from elf
230 | * file",(char*)OREO_TARGET_STRING);
231 | * //
232 | * func=(org_artDexFileOpenMemory23)get_addr_symbol("/system/lib/libart.so",OREO_TARGET_STRING);
233 | * // if (!func) {
234 | * // LOGE("[-]search symbol %s addr failed",OREO_TARGET_STRING);
235 | * // return NULL;
236 | * // }
237 | * }
238 | * else {
239 | * LOGD("[+]sdk_int:%d,dlsym openCommon :%p",g_sdk_int,func);
240 | * return NULL;
241 | * }
242 | * const Header* dex_header = reinterpret_cast(base);
243 | * void* value=func(retcookie,(const unsigned char *)base, size, location,
244 | * dex_header->checksum_, NULL,false,false, &err_msg,NULL);
245 | * void* a=retcookie;
246 | * //LOGD改变了retcookie?? 所以先用a备份
247 | * LOGD("[+]openCommon
248 | * value:%p,*(int*)retcookie:%x,*(jlong*)retcookie:%llx",value,*(int*)retcookie,*(jlong*)a);
249 | *
250 | * return (void*)(*(jlong*)retcookie);
251 | *
252 | * }
253 | */
254 |
--------------------------------------------------------------------------------
/jni/byte_load.h:
--------------------------------------------------------------------------------
1 | #ifndef _BYTE_LOADER_H
2 | #define _BYTE_LOADER_H
3 |
4 | #include
5 | #include
6 | #include "dex_header.h"
7 |
8 | typedef void *(*org1_artDexFileOpenMemory19)(unsigned char const *base, unsigned int size,
9 | std::string const &location,
10 | unsigned int location_checksum, void *mem_map);
11 | typedef void *(*org_artDexFileOpenMemory21)(const uint8_t *base, size_t size,
12 | const std::string &location, uint32_t location_checksum,
13 | void *mem_map, std::string *error_msg);
14 |
15 | typedef void *(*org_artDexFileOpenMemory22)(const uint8_t *base, size_t size,
16 | const std::string &location, uint32_t location_checksum,
17 | void *mem_map, const void *oat_file, std::string *error_msg);
18 |
19 | typedef void *(*org_artDexFileOpenMemory23)(void *retcookie, const uint8_t *base,
20 | size_t size, const std::string &location,
21 | uint32_t location_checksum, void *mem_map, const void *oat_dex_file, std::string *error_msg);
22 |
23 | typedef void *(*orig_OpenCommon)(void *retcookie, const uint8_t *base, size_t size,
24 | const std::string &location, uint32_t location_checksum,
25 | const void *oat_dex_file, bool verify,
26 | bool verify_checksum, std::string *error_msg, void *verify_result);
27 |
28 | void *mem_loadDex_byte19(void *arthandler, const char *base, size_t size);
29 | void *mem_loadDex_byte21(void *arthandler, const char *base, size_t size);
30 | void *mem_loadDex_byte22(void *arthandler, const char *base, size_t size);
31 | void *mem_loadDex_byte23(void *arthandler, const char *base, size_t size);
32 | void *mem_loadDex_byte24(void *arthandler, const char *base, size_t size);
33 | void *mem_loadDex_byte26(void *arthandler, const char *base, size_t size);
34 |
35 | #endif
36 |
--------------------------------------------------------------------------------
/jni/common.h:
--------------------------------------------------------------------------------
1 | #ifndef DALVIK_COMMON_H_
2 | #define DALVIK_COMMON_H_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | static union
10 | {
11 | char c[4];
12 | unsigned long mylong;
13 | }
14 | endian_test = {{ 'l', '?', '?', 'b' }
15 | };
16 | #define ENDIANNESS ((char)endian_test.mylong)
17 |
18 | // #if ENDIANNESS == "l"
19 | #define HAVE_LITTLE_ENDIAN
20 | // #else
21 | // #define HAVE_BIG_ENDIAN
22 | // #endif
23 |
24 | #if defined(HAVE_ENDIAN_H)
25 | # include
26 | #else /*not HAVE_ENDIAN_H*/
27 | # define __BIG_ENDIAN 4321
28 | # define __LITTLE_ENDIAN 1234
29 | # if defined(HAVE_LITTLE_ENDIAN)
30 | # define __BYTE_ORDER __LITTLE_ENDIAN
31 | # else
32 | # define __BYTE_ORDER __BIG_ENDIAN
33 | # endif
34 | #endif /*not HAVE_ENDIAN_H*/
35 |
36 | #if !defined(NDEBUG) && defined(WITH_DALVIK_ASSERT)
37 | # undef assert
38 | # define assert(x) \
39 | ((x) ? ((void)0) : (ALOGE("ASSERT FAILED (%s:%d): %s", \
40 | __FILE__, __LINE__, # x), *(int *)39 = 39, (void)0))
41 | #endif
42 |
43 | #define MIN(x, y) (((x) < (y)) ? (x) : (y))
44 | #define MAX(x, y) (((x) > (y)) ? (x) : (y))
45 |
46 | #define LIKELY(exp) (__builtin_expect((exp) != 0, true))
47 | #define UNLIKELY(exp) (__builtin_expect((exp) != 0, false))
48 |
49 | #define ALIGN_UP(x, n) (((size_t)(x) + (n) - 1) & ~((n) - 1))
50 | #define ALIGN_DOWN(x, n) ((size_t)(x) & - (n))
51 | #define ALIGN_UP_TO_PAGE_SIZE(p) ALIGN_UP(p, SYSTEM_PAGE_SIZE)
52 | #define ALIGN_DOWN_TO_PAGE_SIZE(p) ALIGN_DOWN(p, SYSTEM_PAGE_SIZE)
53 |
54 | #define CLZ(x) __builtin_clz(x)
55 |
56 | /*
57 | * If "very verbose" logging is enabled, make it equivalent to ALOGV.
58 | * Otherwise, make it disappear.
59 | *
60 | * Define this above the #include "Dalvik.h" to enable for only a
61 | * single file.
62 | */
63 | /* #define VERY_VERBOSE_LOG */
64 | #if defined(VERY_VERBOSE_LOG)
65 | # define LOGVV ALOGV
66 | # define IF_LOGVV() IF_ALOGV()
67 | #else
68 | # define LOGVV(...) ((void)0)
69 | # define IF_LOGVV() if (false)
70 | #endif
71 |
72 |
73 | /*
74 | * These match the definitions in the VM specification.
75 | */
76 | typedef uint8_t u1;
77 | typedef uint16_t u2;
78 | typedef uint32_t u4;
79 | typedef uint64_t u8;
80 | typedef int8_t s1;
81 | typedef int16_t s2;
82 | typedef int32_t s4;
83 | typedef int64_t s8;
84 |
85 | /*
86 | * Storage for primitive types and object references.
87 | *
88 | * Some parts of the code (notably object field access) assume that values
89 | * are "left aligned", i.e. given "JValue jv", "jv.i" and "*((s4*)&jv)"
90 | * yield the same result. This seems to be guaranteed by gcc on big- and
91 | * little-endian systems.
92 | */
93 |
94 | #define OFFSETOF_MEMBER(t, f) \
95 | (reinterpret_cast( \
96 | &reinterpret_cast(16)->f) \
97 | - reinterpret_cast(16))
98 |
99 | #define NELEM(x) ((int)(sizeof(x) / sizeof((x)[0])))
100 |
101 | union JValue
102 | {
103 | #if defined(HAVE_LITTLE_ENDIAN)
104 | u1 z;
105 | s1 b;
106 | u2 c;
107 | s2 s;
108 | s4 i;
109 | s8 j;
110 | float f;
111 | double d;
112 | void *l;
113 | #endif
114 | #if defined(HAVE_BIG_ENDIAN)
115 | struct
116 | {
117 | u1_z[3];
118 | u1z;
119 | };
120 | struct
121 | {
122 | s1_b[3];
123 | s1b;
124 | };
125 | struct
126 | {
127 | u2_c;
128 | u2c;
129 | };
130 | struct
131 | {
132 | s2_s;
133 | s2s;
134 | };
135 | s4 i;
136 | s8 j;
137 | float f;
138 | double d;
139 | void *l;
140 | #endif // if defined(HAVE_BIG_ENDIAN)
141 | };
142 |
143 | /*
144 | * Array objects have these additional fields.
145 | *
146 | * We don't currently store the size of each element. Usually it's implied
147 | * by the instruction. If necessary, the width can be derived from
148 | * the first char of obj->clazz->descriptor.
149 | */
150 |
151 | /*typedef struct {
152 | * void* clazz;
153 | * u4 lock;
154 | * }Object;*/
155 |
156 | typedef struct
157 | {
158 | void *clazz;
159 | u4 lock;
160 | u4 length;
161 | u1 *contents;
162 | } ArrayObject;
163 |
164 | /*typedef struct {
165 | * u4 instanceData[1];
166 | * int length() const;
167 | * int utfLength() const;
168 | * ArrayObject* array() const;
169 | * const u2* chars() const;
170 | * }StringObject;*/
171 |
172 | #endif // DALVIK_COMMON_H_
173 |
--------------------------------------------------------------------------------
/jni/dex_header.h:
--------------------------------------------------------------------------------
1 | #ifndef _DEXHEADER_H
2 | #define _DEXHEADER_H
3 |
4 | #include
5 |
6 | static const size_t kSha1DigestSize = 20;
7 |
8 | // Raw header_item.
9 | struct Header
10 | {
11 | uint8_t magic_[8];
12 | uint32_t checksum_; // See also location_checksum_
13 | uint8_t signature_[kSha1DigestSize];
14 | uint32_t file_size_; // size of entire file
15 | uint32_t header_size_; // offset to start of next section
16 | uint32_t endian_tag_;
17 | uint32_t link_size_; // unused
18 | uint32_t link_off_; // unused
19 | uint32_t map_off_; // unused
20 | uint32_t string_ids_size_; // number of StringIds
21 | uint32_t string_ids_off_; // file offset of StringIds array
22 | uint32_t type_ids_size_; // number of TypeIds, we don't support more than 65535
23 | uint32_t type_ids_off_; // file offset of TypeIds array
24 | uint32_t proto_ids_size_; // number of ProtoIds, we don't support more than 65535
25 | uint32_t proto_ids_off_; // file offset of ProtoIds array
26 | uint32_t field_ids_size_; // number of FieldIds
27 | uint32_t field_ids_off_; // file offset of FieldIds array
28 | uint32_t method_ids_size_; // number of MethodIds
29 | uint32_t method_ids_off_; // file offset of MethodIds array
30 | uint32_t class_defs_size_; // number of ClassDefs
31 | uint32_t class_defs_off_; // file offset of ClassDef array
32 | uint32_t data_size_; // unused
33 | uint32_t data_off_; // unused
34 | };
35 |
36 | #endif // ifndef _DEXHEADER_H
37 |
--------------------------------------------------------------------------------
/jni/elfGotHook/.editorconfig:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KuNgia09/Bangcle/76f84a741bdfc25504992327c8addcf4f000e403/jni/elfGotHook/.editorconfig
--------------------------------------------------------------------------------
/jni/elfGotHook/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH := $(call my-dir)
2 |
3 | include $(CLEAR_VARS)
4 | LOCAL_MODULE := elfHooker
5 | LOCAL_CFLAGS := -pie -fPIE
6 | LOCAL_LDFLAGS := -pie -fPIE
7 | LOCAL_LDLIBS := -llog -lEGL
8 | LOCAL_CPPFLAGS := -std=c++11
9 | LOCAL_C_INCLUDES := $(LOCAL_PATH)
10 | LOCAL_SRC_FILES := hooker.cpp \
11 | elf_reader.cpp \
12 | tools.cpp
13 |
14 | include $(BUILD_SHARED_LIBRARY)
15 |
--------------------------------------------------------------------------------
/jni/elfGotHook/Application.mk:
--------------------------------------------------------------------------------
1 | APP_ABI := armeabi armeabi-v7a arm64-v8a
2 | APP_STL := gnustl_static
3 | # APP_CPPFLAGS := -std=c++11 -fexceptions -frtti
4 | APP_PLATFORM := android-14
5 | # APP_UNIFIED_HEADERS := true
6 | # NDK_TOOLCHAIN_VERSION:=4.8
7 |
--------------------------------------------------------------------------------
/jni/elfGotHook/def.h:
--------------------------------------------------------------------------------
1 | #ifndef INJECTDEMO_DEF_H
2 | #define INJECTDEMO_DEF_H
3 |
4 | #include
5 | #include
6 |
7 | //首先定义两个辅助宏
8 | #define PRINT_MACRO_HELPER(x) # x
9 | #define PRINT_MACRO(x) # x "=" PRINT_MACRO_HELPER(x)
10 |
11 | //编译阶段打印宏内容
12 |
13 |
14 |
15 | #if __ANDROID_API__ <= 14
16 | #define PT_TLS 7
17 | #define PT_GNU_EH_FRAME 0x6474e550
18 | #define PT_GNU_STACK (PT_LOOS + 0x474e551)
19 | #endif
20 |
21 | #define PT_GNU_RELRO 0x6474e552
22 | #define PT_ARM_EXIDX (PT_LOPROC + 1)
23 |
24 | #define SO_NAME_LEN 128
25 |
26 | #if __ANDROID_API__ < 21
27 | #define DT_LOOS 0x6000000d
28 | #define DT_HIOS 0x6ffff000
29 | #define DT_VALRNGLO 0x6ffffd00
30 | #define DT_VALRNGHI 0x6ffffdff
31 | #define DT_ADDRRNGLO 0x6ffffe00
32 | #define DT_ADDRRNGHI 0x6ffffeff
33 | #define DT_VERSYM 0x6ffffff0
34 | #define DT_RELACOUNT 0x6ffffff9
35 | #define DT_RELCOUNT 0x6ffffffa
36 | #define DT_FLAGS_1 0x6ffffffb
37 | #define DT_VERDEF 0x6ffffffc
38 | #define DT_VERDEFNUM 0x6ffffffd
39 | #define DT_VERNEED 0x6ffffffe
40 | #define DT_VERNEEDNUM 0x6fffffff
41 | #endif
42 |
43 | #define DT_INIT_ARRAY 25
44 | #define DT_FINI_ARRAY 26
45 | #define DT_INIT_ARRAYSZ 27
46 | #define DT_FINI_ARRAYSZ 28
47 | #define DT_RUNPATH 29
48 | #define DT_FLAGS 30
49 | #define DT_PREINIT_ARRAY 32
50 | #define DT_PREINIT_ARRAYSZ 33
51 | #define DT_ANDROID_REL (DT_LOOS + 2)
52 | #define DT_ANDROID_RELSZ (DT_LOOS + 3)
53 | #define DT_ANDROID_RELA (DT_LOOS + 4)
54 | #define DT_ANDROID_RELASZ (DT_LOOS + 5)
55 | #define DT_GNU_HASH 0x6ffffef5
56 |
57 | #define powerof2(x) ((((x) - 1) & (x)) == 0)
58 |
59 | // Returns the address of the page containing address 'x'.
60 | #define PAGE_START(x) ((x) & PAGE_MASK)
61 |
62 | // Returns the address of the next page after address 'x', unless 'x' is
63 | // itself at the start of a page.
64 | #define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE - 1))
65 |
66 | #define MAYBE_MAP_FLAG(x, from, to) (((x) & (from)) ? (to) : 0)
67 | #define PFLAGS_TO_PROT(x) \
68 | (MAYBE_MAP_FLAG((x), PF_X, PROT_EXEC) | \
69 | MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
70 | MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
71 |
72 | #if defined(__aarch64__) || defined(__x86_64__)
73 | #define USE_RELA 1
74 | #endif
75 |
76 |
77 | #pragma message(PRINT_MACRO(__ANDROID_API__))
78 | #if defined(__LP64__)
79 | #define ElfW(what) Elf64_ ## what
80 | #define ELF_R_SYM(i) ELF64_R_SYM(i)
81 | #define ELF_R_TYPE(i) ELF64_R_TYPE(i)
82 | #else
83 |
84 | typedef Elf32_Word Elf32_Xword;
85 | #define ElfW(what) Elf32_ ## what
86 | // #if __ANDROID_API__ > 19
87 | #define ELF_R_SYM(i) ELF32_R_SYM(i)
88 | #define ELF_R_TYPE(i) ELF32_R_TYPE(i)
89 | // #endif
90 | #endif
91 |
92 | #if defined(__arm__)
93 | #include
94 |
95 | #define R_GENERIC_JUMP_SLOT R_ARM_JUMP_SLOT
96 | #define R_GENERIC_GLOB_DAT R_ARM_GLOB_DAT
97 | #define R_GENERIC_RELATIVE R_ARM_RELATIVE
98 | #define R_GENERIC_IRELATIVE R_ARM_IRELATIVE
99 | #define R_GENERIC_ABS R_ARM_ABS32
100 | #elif defined(__aarch64__)
101 | #define R_AARCH64_IRELATIVE 1032
102 |
103 | #define R_GENERIC_JUMP_SLOT R_AARCH64_JUMP_SLOT
104 | #define R_GENERIC_GLOB_DAT R_AARCH64_GLOB_DAT
105 | #define R_GENERIC_RELATIVE R_AARCH64_RELATIVE
106 | #define R_GENERIC_IRELATIVE R_AARCH64_IRELATIVE
107 | #define R_GENERIC_ABS R_AARCH64_ABS64
108 | #endif
109 |
110 | #endif //INJECTDEMO_DEF_H
111 |
--------------------------------------------------------------------------------
/jni/elfGotHook/elf_arm.h:
--------------------------------------------------------------------------------
1 | /* $NetBSD: elf_machdep.h,v 1.17 2014/02/25 19:20:09 matt Exp $ */
2 |
3 | #ifndef _ARM_ELF_MACHDEP_H_
4 | #define _ARM_ELF_MACHDEP_H_
5 |
6 | /* Android-added. */
7 | #define R_ARM_IRELATIVE 160
8 |
9 | /* Processor specific flags for the ELF header e_flags field. */
10 | #define EF_ARM_RELEXEC 0x00000001
11 | #define EF_ARM_HASENTRY 0x00000002
12 | #define EF_ARM_INTERWORK 0x00000004 /* GNU binutils 000413 */
13 | #define EF_ARM_SYMSARESORTED 0x00000004 /* ARM ELF A08 */
14 | #define EF_ARM_APCS_26 0x00000008 /* GNU binutils 000413 */
15 | #define EF_ARM_DYNSYMSUSESEGIDX 0x00000008 /* ARM ELF B01 */
16 | #define EF_ARM_APCS_FLOAT 0x00000010 /* GNU binutils 000413 */
17 | #define EF_ARM_MAPSYMSFIRST 0x00000010 /* ARM ELF B01 */
18 | #define EF_ARM_PIC 0x00000020
19 | #define EF_ARM_ALIGN8 0x00000040 /* 8-bit structure alignment. */
20 | #define EF_ARM_NEW_ABI 0x00000080
21 | #define EF_ARM_OLD_ABI 0x00000100
22 | #define EF_ARM_SOFT_FLOAT 0x00000200
23 | #define EF_ARM_BE8 0x00800000
24 | #define EF_ARM_EABIMASK 0xff000000
25 | #define EF_ARM_EABI_VER1 0x01000000
26 | #define EF_ARM_EABI_VER2 0x02000000
27 | #define EF_ARM_EABI_VER3 0x03000000
28 | #define EF_ARM_EABI_VER4 0x04000000
29 | #define EF_ARM_EABI_VER5 0x05000000
30 |
31 | /* Processor specific relocation types */
32 |
33 | #define R_ARM_NONE 0
34 | #define R_ARM_PC24 1
35 | #define R_ARM_ABS32 2
36 | #define R_ARM_REL32 3
37 | #define R_ARM_PC13 4
38 | #define R_ARM_ABS16 5
39 | #define R_ARM_ABS12 6
40 | #define R_ARM_THM_ABS5 7
41 | #define R_ARM_ABS8 8
42 | #define R_ARM_SBREL32 9
43 | #define R_ARM_THM_PC22 10
44 | #define R_ARM_THM_PC8 11
45 | #define R_ARM_AMP_VCALL9 12
46 | #define R_ARM_SWI24 13
47 | #define R_ARM_THM_SWI8 14
48 | #define R_ARM_XPC25 15
49 | #define R_ARM_THM_XPC22 16
50 |
51 | /* TLS relocations */
52 | #define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */
53 | #define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */
54 | #define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */
55 |
56 | /* 20-31 are reserved for ARM Linux. */
57 | #define R_ARM_COPY 20
58 | #define R_ARM_GLOB_DAT 21
59 | #define R_ARM_JUMP_SLOT 22
60 | #define R_ARM_RELATIVE 23
61 | #define R_ARM_GOTOFF 24
62 | #define R_ARM_GOTPC 25
63 | #define R_ARM_GOT32 26
64 | #define R_ARM_PLT32 27
65 | #define R_ARM_CALL 28
66 | #define R_ARM_JUMP24 29
67 | #define R_ARM_THM_JUMP24 30
68 | #define R_ARM_BASE_ABS 31
69 | #define R_ARM_ALU_PCREL_7_0 32
70 | #define R_ARM_ALU_PCREL_15_8 33
71 | #define R_ARM_ALU_PCREL_23_15 34
72 | #define R_ARM_ALU_SBREL_11_0 35
73 | #define R_ARM_ALU_SBREL_19_12 36
74 | #define R_ARM_ALU_SBREL_27_20 37 // depcreated
75 | #define R_ARM_TARGET1 38
76 | #define R_ARM_SBREL31 39 // deprecated
77 | #define R_ARM_V4BX 40
78 | #define R_ARM_TARGET2 41
79 | #define R_ARM_PREL31 42
80 | #define R_ARM_MOVW_ABS_NC 43
81 | #define R_ARM_MOVT_ABS 44
82 | #define R_ARM_MOVW_PREL_NC 45
83 | #define R_ARM_MOVT_PREL 46
84 | #define R_ARM_THM_MOVW_ABS_NC 47
85 | #define R_ARM_THM_MOVT_ABS 48
86 | #define R_ARM_THM_MOVW_PREL_NC 49
87 | #define R_ARM_THM_MOVT_PREL 50
88 |
89 | /* 96-111 are reserved to G++. */
90 | #define R_ARM_GNU_VTENTRY 100
91 | #define R_ARM_GNU_VTINHERIT 101
92 | #define R_ARM_THM_PC11 102
93 | #define R_ARM_THM_PC9 103
94 |
95 | /* More TLS relocations */
96 | #define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic */
97 | #define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic */
98 | #define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS */
99 | #define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of */
100 | #define R_ARM_TLS_LE32 108
101 | #define R_ARM_TLS_LDO12 109
102 | #define R_ARM_TLS_LE12 110
103 | #define R_ARM_TLS_IE12GP 111
104 |
105 | /* 112-127 are reserved for private experiments. */
106 |
107 | #define R_ARM_RXPC25 249
108 | #define R_ARM_RSBREL32 250
109 | #define R_ARM_THM_RPC22 251
110 | #define R_ARM_RREL32 252
111 | #define R_ARM_RABS32 253
112 | #define R_ARM_RPC24 254
113 | #define R_ARM_RBASE 255
114 |
115 | /* Processor specific program header flags */
116 | #define PF_ARM_SB 0x10000000
117 | #define PF_ARM_PI 0x20000000
118 | #define PF_ARM_ENTRY 0x80000000
119 |
120 | /* Processor specific program header types */
121 | #define PT_ARM_EXIDX (PT_LOPROC + 1)
122 |
123 | /* Processor specific section header flags */
124 | #define SHF_ENTRYSECT 0x10000000
125 | #define SHF_COMDEF 0x80000000
126 |
127 | /* Processor specific symbol types */
128 | #define STT_ARM_TFUNC STT_LOPROC
129 |
130 | #endif /* _ARM_ELF_MACHDEP_H_ */
131 |
--------------------------------------------------------------------------------
/jni/elfGotHook/elf_reader.cpp:
--------------------------------------------------------------------------------
1 | #include "elf_reader.h"
2 | #include "tools.h"
3 |
4 | static const char *ELF_CLASS_MAP[] = {
5 | "None",
6 | "ELF32",
7 | "ELF64",
8 | "Unknown"};
9 |
10 | static const char *ELF_DATA_MAP[] = {
11 | "None",
12 | "little endian",
13 | "big endian",
14 | "Unknown"};
15 |
16 | static const char *ELF_VERSION_MAP[] = {
17 | "None",
18 | "Current",
19 | "Unknown"};
20 |
21 | static const struct Elf_Program_Type_Map
22 | {
23 | const char *name;
24 | ElfW(Word) value;
25 | } ELF_PROGRAM_TYPE_MAP[] = {
26 | {"PT_NULL", PT_NULL},
27 | {"PT_LOAD", PT_LOAD},
28 | {"PT_DYNAMIC", PT_DYNAMIC},
29 | {"PT_INTERP", PT_INTERP},
30 | {"PT_NOTE", PT_NOTE},
31 | {"PT_SHLIB", PT_SHLIB},
32 | {"PT_PHDR", PT_PHDR},
33 | {"PT_TLS", PT_TLS},
34 | {"PT_LOOS", PT_LOOS},
35 | {"PT_HIOS", PT_HIOS},
36 | {"PT_LOPROC", PT_LOPROC},
37 | {"PT_HIPROC", PT_HIPROC},
38 | {"PT_GNU_EH_FRAME", PT_GNU_EH_FRAME},
39 | {"PT_GNU_STACK", PT_GNU_STACK},
40 | {"PT_GNU_RELRO", PT_GNU_RELRO},
41 | {"PT_ARM_EXIDX", PT_ARM_EXIDX}};
42 |
43 | static const struct Elf_Dynamic_Type_Map
44 | {
45 | const char *name;
46 | ElfW(Xword) value;
47 | } ELF_DYNAMIC_TYPE_MAP[] = {
48 | {"DT_NULL", DT_NULL},
49 | {"DT_NEEDED", DT_NEEDED},
50 | {"DT_PLTRELSZ", DT_PLTRELSZ},
51 | {"DT_PLTGOT", DT_PLTGOT},
52 | {"DT_HASH", DT_HASH},
53 | {"DT_STRTAB", DT_STRTAB},
54 | {"DT_SYMTAB", DT_SYMTAB},
55 | {"DT_RELA", DT_RELA},
56 | {"DT_RELASZ", DT_RELASZ},
57 | {"DT_RELAENT", DT_RELAENT},
58 | {"DT_STRSZ", DT_STRSZ},
59 | {"DT_SYMENT", DT_SYMENT},
60 | {"DT_INIT", DT_INIT},
61 | {"DT_FINI", DT_FINI},
62 | {"DT_SONAME", DT_SONAME},
63 | {"DT_RPATH", DT_RPATH},
64 | {"DT_SYMBOLIC", DT_SYMBOLIC},
65 | {"DT_REL", DT_REL},
66 | {"DT_RELSZ", DT_RELSZ},
67 | {"DT_RELENT", DT_RELENT},
68 | {"DT_PLTREL", DT_PLTREL},
69 | {"DT_DEBUG", DT_DEBUG},
70 | {"DT_TEXTREL", DT_TEXTREL},
71 | {"DT_JMPREL", DT_JMPREL},
72 | {"DT_BIND_NOW", DT_BIND_NOW},
73 | {"DT_INIT_ARRAY", DT_INIT_ARRAY},
74 | {"DT_FINI_ARRAY", DT_FINI_ARRAY},
75 | {"DT_INIT_ARRAYSZ", DT_INIT_ARRAYSZ},
76 | {"DT_FINI_ARRAYSZ", DT_FINI_ARRAYSZ},
77 | {"DT_RUNPATH", DT_RUNPATH},
78 | {"DT_FLAGS", DT_FLAGS},
79 | {"DT_PREINIT_ARRAY", DT_PREINIT_ARRAY},
80 | {"DT_PREINIT_ARRAYSZ", DT_PREINIT_ARRAYSZ},
81 | {"DT_ANDROID_REL", DT_ANDROID_REL},
82 | {"DT_ANDROID_RELSZ", DT_ANDROID_RELSZ},
83 | {"DT_ANDROID_RELA", DT_ANDROID_RELA},
84 | {"DT_ANDROID_RELASZ", DT_ANDROID_RELASZ},
85 | {"DT_HIOS", DT_HIOS},
86 | {"DT_VALRNGLO", DT_VALRNGLO},
87 | {"DT_VALRNGHI", DT_VALRNGHI},
88 | {"DT_ADDRRNGLO", DT_ADDRRNGLO},
89 | {"DT_ADDRRNGHI", DT_ADDRRNGHI},
90 | {"DT_VERSYM", DT_VERSYM},
91 | {"DT_RELACOUNT", DT_RELACOUNT},
92 | {"DT_RELCOUNT", DT_RELCOUNT},
93 | {"DT_FLAGS_1", DT_FLAGS_1},
94 | {"DT_VERDEF", DT_VERDEF},
95 | {"DT_VERDEFNUM", DT_VERDEFNUM},
96 | {"DT_VERNEED", DT_VERNEED},
97 | {"DT_VERNEEDNUM", DT_VERNEEDNUM},
98 | {"DT_GNU_HASH", DT_GNU_HASH},
99 | {"DT_LOPROC", DT_LOPROC},
100 | {"DT_HIPROC", DT_HIPROC}};
101 |
102 | const static struct Elf_Dynamic_Rel_Type_Map
103 | {
104 | const char *name;
105 | ElfW(Xword) value;
106 | } ELF_DYNAMIC_REL_TYPE_MAP[] = {
107 | #if defined(__arm__)
108 | {"R_ARM_NONE", R_ARM_NONE},
109 | {"R_ARM_PC24", R_ARM_PC24},
110 | {"R_ARM_ABS32", R_ARM_ABS32},
111 | {"R_ARM_REL32", R_ARM_REL32},
112 | {"R_ARM_PC13", R_ARM_PC13},
113 | {"R_ARM_ABS16", R_ARM_ABS16},
114 | {"R_ARM_ABS12", R_ARM_ABS12},
115 | {"R_ARM_THM_ABS5", R_ARM_THM_ABS5},
116 | {"R_ARM_ABS8", R_ARM_ABS8},
117 | {"R_ARM_SBREL32", R_ARM_SBREL32},
118 | {"R_ARM_THM_PC22", R_ARM_THM_PC22},
119 | {"R_ARM_THM_PC8", R_ARM_THM_PC8},
120 | {"R_ARM_AMP_VCALL9", R_ARM_AMP_VCALL9},
121 | {"R_ARM_SWI24", R_ARM_SWI24},
122 | {"R_ARM_THM_SWI8", R_ARM_THM_SWI8},
123 | {"R_ARM_XPC25", R_ARM_XPC25},
124 | {"R_ARM_THM_XPC22", R_ARM_THM_XPC22},
125 | {"R_ARM_TLS_DTPMOD32", R_ARM_TLS_DTPMOD32},
126 | {"R_ARM_TLS_DTPOFF32", R_ARM_TLS_DTPOFF32},
127 | {"R_ARM_TLS_TPOFF32", R_ARM_TLS_TPOFF32},
128 | {"R_ARM_COPY", R_ARM_COPY},
129 | {"R_ARM_GLOB_DAT", R_ARM_GLOB_DAT},
130 | {"R_ARM_JUMP_SLOT", R_ARM_JUMP_SLOT},
131 | {"R_ARM_RELATIVE", R_ARM_RELATIVE},
132 | {"R_ARM_GOTOFF", R_ARM_GOTOFF},
133 | {"R_ARM_GOTPC", R_ARM_GOTPC},
134 | {"R_ARM_GOT32", R_ARM_GOT32},
135 | {"R_ARM_PLT32", R_ARM_PLT32},
136 | {"R_ARM_CALL", R_ARM_CALL},
137 | {"R_ARM_JUMP24", R_ARM_JUMP24},
138 | {"R_ARM_THM_JUMP24", R_ARM_THM_JUMP24},
139 | {"R_ARM_BASE_ABS", R_ARM_BASE_ABS},
140 | {"R_ARM_ALU_PCREL_7_0", R_ARM_ALU_PCREL_7_0},
141 | {"R_ARM_ALU_PCREL_15_8", R_ARM_ALU_PCREL_15_8},
142 | {"R_ARM_ALU_PCREL_23_15", R_ARM_ALU_PCREL_23_15},
143 | {"R_ARM_ALU_SBREL_11_0", R_ARM_ALU_SBREL_11_0},
144 | {"R_ARM_ALU_SBREL_19_12", R_ARM_ALU_SBREL_19_12},
145 | {"R_ARM_ALU_SBREL_27_20", R_ARM_ALU_SBREL_27_20},
146 | {"R_ARM_TARGET1", R_ARM_TARGET1},
147 | {"R_ARM_SBREL31", R_ARM_SBREL31},
148 | {"R_ARM_V4BX", R_ARM_V4BX},
149 | {"R_ARM_TARGET2", R_ARM_TARGET2},
150 | {"R_ARM_PREL31", R_ARM_PREL31},
151 | {"R_ARM_MOVW_ABS_NC", R_ARM_MOVW_ABS_NC},
152 | {"R_ARM_MOVT_ABS", R_ARM_MOVT_ABS},
153 | {"R_ARM_MOVW_PREL_NC", R_ARM_MOVW_PREL_NC},
154 | {"R_ARM_MOVT_PREL", R_ARM_MOVT_PREL},
155 | {"R_ARM_THM_MOVW_ABS_NC", R_ARM_THM_MOVW_ABS_NC},
156 | {"R_ARM_THM_MOVT_ABS", R_ARM_THM_MOVT_ABS},
157 | {"R_ARM_THM_MOVW_PREL_NC", R_ARM_THM_MOVW_PREL_NC},
158 | {"R_ARM_THM_MOVT_PREL", R_ARM_THM_MOVT_PREL},
159 | {"R_ARM_GNU_VTENTRY", R_ARM_GNU_VTENTRY},
160 | {"R_ARM_GNU_VTINHERIT", R_ARM_GNU_VTINHERIT},
161 | {"R_ARM_THM_PC11", R_ARM_THM_PC11},
162 | {"R_ARM_THM_PC9", R_ARM_THM_PC9},
163 | {"R_ARM_TLS_GD32", R_ARM_TLS_GD32},
164 | {"R_ARM_TLS_LDM32", R_ARM_TLS_LDM32},
165 | {"R_ARM_TLS_LDO32", R_ARM_TLS_LDO32},
166 | {"R_ARM_TLS_IE32", R_ARM_TLS_IE32},
167 | {"R_ARM_TLS_LE32", R_ARM_TLS_LE32},
168 | {"R_ARM_TLS_LDO12", R_ARM_TLS_LDO12},
169 | {"R_ARM_TLS_LE12", R_ARM_TLS_LE12},
170 | {"R_ARM_TLS_IE12GP", R_ARM_TLS_IE12GP},
171 | {"R_ARM_IRELATIVE", R_ARM_IRELATIVE},
172 | {"R_ARM_RXPC25", R_ARM_RXPC25},
173 | {"R_ARM_RSBREL32", R_ARM_RSBREL32},
174 | {"R_ARM_THM_RPC22", R_ARM_THM_RPC22},
175 | {"R_ARM_RREL32", R_ARM_RREL32},
176 | {"R_ARM_RABS32", R_ARM_RABS32},
177 | {"R_ARM_RPC24", R_ARM_RPC24},
178 | {"R_ARM_RBASE", R_ARM_RBASE},
179 | #elif defined(__aarch64__)
180 | {"R_AARCH64_NONE", R_AARCH64_NONE},
181 | {"R_AARCH64_ABS64", R_AARCH64_ABS64},
182 | {"R_AARCH64_ABS32", R_AARCH64_ABS32},
183 | {"R_AARCH64_ABS16", R_AARCH64_ABS16},
184 | {"R_AARCH64_PREL64", R_AARCH64_PREL64},
185 | {"R_AARCH64_PREL32", R_AARCH64_PREL32},
186 | {"R_AARCH64_PREL16", R_AARCH64_PREL16},
187 | {"R_AARCH64_MOVW_UABS_G0", R_AARCH64_MOVW_UABS_G0},
188 | {"R_AARCH64_MOVW_UABS_G0_NC", R_AARCH64_MOVW_UABS_G0_NC},
189 | {"R_AARCH64_MOVW_UABS_G1", R_AARCH64_MOVW_UABS_G1},
190 | {"R_AARCH64_MOVW_UABS_G1_NC", R_AARCH64_MOVW_UABS_G1_NC},
191 | {"R_AARCH64_MOVW_UABS_G2", R_AARCH64_MOVW_UABS_G2},
192 | {"R_AARCH64_MOVW_UABS_G2_NC", R_AARCH64_MOVW_UABS_G2_NC},
193 | {"R_AARCH64_MOVW_UABS_G3", R_AARCH64_MOVW_UABS_G3},
194 | {"R_AARCH64_MOVW_SABS_G0", R_AARCH64_MOVW_SABS_G0},
195 | {"R_AARCH64_MOVW_SABS_G1", R_AARCH64_MOVW_SABS_G1},
196 | {"R_AARCH64_MOVW_SABS_G2", R_AARCH64_MOVW_SABS_G2},
197 | {"R_AARCH64_LD_PREL_LO19", R_AARCH64_LD_PREL_LO19},
198 | {"R_AARCH64_ADR_PREL_LO21", R_AARCH64_ADR_PREL_LO21},
199 | {"R_AARCH64_ADR_PREL_PG_HI21", R_AARCH64_ADR_PREL_PG_HI21},
200 | {"R_AARCH64_ADR_PREL_PG_HI21_NC", R_AARCH64_ADR_PREL_PG_HI21_NC},
201 | {"R_AARCH64_ADD_ABS_LO12_NC", R_AARCH64_ADD_ABS_LO12_NC},
202 | {"R_AARCH64_LDST8_ABS_LO12_NC", R_AARCH64_LDST8_ABS_LO12_NC},
203 | {"R_AARCH64_TSTBR14", R_AARCH64_TSTBR14},
204 | {"R_AARCH64_CONDBR19", R_AARCH64_CONDBR19},
205 | {"R_AARCH64_JUMP26", R_AARCH64_JUMP26},
206 | {"R_AARCH64_CALL26", R_AARCH64_CALL26},
207 | {"R_AARCH64_LDST16_ABS_LO12_NC", R_AARCH64_LDST16_ABS_LO12_NC},
208 | {"R_AARCH64_LDST32_ABS_LO12_NC", R_AARCH64_LDST32_ABS_LO12_NC},
209 | {"R_AARCH64_LDST64_ABS_LO12_NC", R_AARCH64_LDST64_ABS_LO12_NC},
210 | {"R_AARCH64_LDST128_ABS_LO12_NC", R_AARCH64_LDST128_ABS_LO12_NC},
211 | {"R_AARCH64_MOVW_PREL_G0", R_AARCH64_MOVW_PREL_G0},
212 | {"R_AARCH64_MOVW_PREL_G0_NC", R_AARCH64_MOVW_PREL_G0_NC},
213 | {"R_AARCH64_MOVW_PREL_G1", R_AARCH64_MOVW_PREL_G1},
214 | {"R_AARCH64_MOVW_PREL_G1_NC", R_AARCH64_MOVW_PREL_G1_NC},
215 | {"R_AARCH64_MOVW_PREL_G2", R_AARCH64_MOVW_PREL_G2},
216 | {"R_AARCH64_MOVW_PREL_G2_NC", R_AARCH64_MOVW_PREL_G2_NC},
217 | {"R_AARCH64_MOVW_PREL_G3", R_AARCH64_MOVW_PREL_G3},
218 | {"R_AARCH64_COPY", R_AARCH64_COPY},
219 | {"R_AARCH64_GLOB_DAT", R_AARCH64_GLOB_DAT},
220 | {"R_AARCH64_JUMP_SLOT", R_AARCH64_JUMP_SLOT},
221 | {"R_AARCH64_RELATIVE", R_AARCH64_RELATIVE},
222 | {"R_AARCH64_TLS_TPREL64", R_AARCH64_TLS_TPREL64},
223 | {"R_AARCH64_TLS_DTPREL32", R_AARCH64_TLS_DTPREL32},
224 | {"R_AARCH64_IRELATIVE", R_AARCH64_IRELATIVE},
225 | #endif
226 | };
227 |
228 | static const Elf_Program_Type_Map *map_elf_program_type(ElfW(Word) type)
229 | {
230 | for (size_t i = 0; i < sizeof(ELF_PROGRAM_TYPE_MAP) / sizeof(Elf_Program_Type_Map); i++)
231 | {
232 | if (ELF_PROGRAM_TYPE_MAP[i].value == type)
233 | {
234 | return &ELF_PROGRAM_TYPE_MAP[i];
235 | }
236 | }
237 | return NULL;
238 | }
239 |
240 | static const Elf_Dynamic_Type_Map *map_elf_dynamic_type(ElfW(Xword) type)
241 | {
242 | for (size_t i = 0; i < sizeof(ELF_DYNAMIC_TYPE_MAP) / sizeof(Elf_Dynamic_Type_Map); i++)
243 | {
244 | if (ELF_DYNAMIC_TYPE_MAP[i].value == type)
245 | {
246 | return &ELF_DYNAMIC_TYPE_MAP[i];
247 | }
248 | }
249 | return NULL;
250 | }
251 |
252 | static const Elf_Dynamic_Rel_Type_Map *map_elf_dynamic_rel_type(ElfW(Xword) type)
253 | {
254 | for (size_t i = 0; i < sizeof(ELF_DYNAMIC_REL_TYPE_MAP) / sizeof(Elf_Dynamic_Rel_Type_Map); i++)
255 | {
256 | if (ELF_DYNAMIC_REL_TYPE_MAP[i].value == type)
257 | {
258 | return &ELF_DYNAMIC_REL_TYPE_MAP[i];
259 | }
260 | }
261 | return NULL;
262 | }
263 |
264 | static void getProgramFlagString(ElfW(Word) flags, char *buffer)
265 | {
266 | int index = 0;
267 | const char RWX[] = {'R', 'W', 'X'};
268 |
269 | while (index < 3)
270 | {
271 | if (flags & 0x1)
272 | {
273 | buffer[index] = RWX[index];
274 | }
275 | else
276 | {
277 | buffer[index] = ' ';
278 | }
279 | flags >>= 1;
280 | index++;
281 | }
282 | buffer[index] = '\0';
283 | }
284 |
285 | ElfReader::ElfReader(const char *module, void *start) : moduleName(module), start(reinterpret_cast(start))
286 | {
287 | }
288 |
289 | int ElfReader::parse()
290 | {
291 | //转换为ELF32_Ehdr* 类型
292 | this->ehdr = reinterpret_cast(this->start);
293 | if (0 != verifyElfHeader())
294 | {
295 | return -1;
296 | }
297 | //读取程序头表的数目
298 | this->phdrNum = ehdr->e_phnum;
299 | //获取程序头表再内存中的地址
300 | this->phdr = reinterpret_cast(this->start + ehdr->e_phoff);
301 | //获取SegmentBaseAddress
302 | this->bias = getSegmentBaseAddress();
303 | if (0 == this->bias)
304 | {
305 | LOGE("failed to get segment base address");
306 | return -1;
307 | }
308 | //解析重定位表
309 | if (0 != parseDynamicSegment())
310 | {
311 | LOGE("failed to parse dynamic segment");
312 | return -1;
313 | }
314 | return 0;
315 | }
316 |
317 | int ElfReader::hook(const char *func_name, void *new_func, void **old_func)
318 | {
319 | uint32_t symidx = 0;
320 |
321 | ElfW(Sym) *sym = NULL;
322 |
323 | if (0 == findSymbolByName(func_name, &sym, &symidx))
324 | {
325 | void *addr;
326 | ElfW(Xword) r_info = 0;
327 | ElfW(Addr) r_offset = 0;
328 | #if defined(USE_RELA)
329 | ElfW(Rela) * curr;
330 | ElfW(Rela) * rel;
331 | #else
332 | ElfW(Rel) * curr;
333 | ElfW(Rel) * rel;
334 | #endif
335 | //pltRel是.rel.plt重定位表的地址
336 | rel = this->pltRel;
337 | for (uint32_t i = 0; i < this->pltRelCount; i++)
338 | {
339 | curr = rel + i;
340 | r_info = curr->r_info;
341 | r_offset = curr->r_offset;
342 | //判断当前重定位项的符号表索引是否等于要hook的符号表索引symidx
343 | if ((ELF_R_SYM(r_info) == symidx) && (ELF_R_TYPE(r_info) == R_GENERIC_JUMP_SLOT))
344 | {
345 | addr = reinterpret_cast((this->bias + r_offset));
346 | if (0 == hookInternally(addr, new_func, old_func))
347 | {
348 | LOGD("hook %s successfully in %s", func_name, this->moduleName);
349 | return 0;
350 | }
351 | break;
352 | }
353 | }
354 |
355 | rel = this->rel;
356 | for (uint32_t i = 0; i < this->relCount; i++)
357 | {
358 | r_info = rel->r_info;
359 | r_offset = rel->r_offset;
360 |
361 | if ((ELF_R_SYM(r_info) == symidx) && ((ELF_R_TYPE(r_info) == R_GENERIC_ABS) || (ELF_R_TYPE(r_info) == R_GENERIC_GLOB_DAT)))
362 | {
363 | addr = reinterpret_cast((this->bias + r_offset));
364 | if (0 == hookInternally(addr, new_func, old_func))
365 | {
366 | LOGD("hook %s successfully in %s", func_name, this->moduleName);
367 | return 0;
368 | }
369 | break;
370 | }
371 | }
372 | }
373 | LOGD("hook %s failure in %s", func_name, this->moduleName);
374 | return -1;
375 | }
376 |
377 | void ElfReader::dumpElfHeader()
378 | {
379 | LOGD("elf header:");
380 |
381 | size_t len;
382 | size_t size = 128;
383 | char buffer[size];
384 | snprintf(buffer, size, "magic: ");
385 | len = strlen(buffer);
386 | for (int i = 0; i < EI_NIDENT; i++)
387 | {
388 | snprintf(&buffer[len], size - len, "%02x ", ehdr->e_ident[i]);
389 | len = strlen(buffer);
390 | }
391 | snprintf(&buffer[len], size - len, "\n");
392 | LOGD("%s", buffer);
393 |
394 | uint8_t class_type = ehdr->e_ident[EI_CLASS];
395 | if (class_type > ELFCLASSNUM)
396 | {
397 | class_type = ELFCLASSNUM;
398 | }
399 | LOGD("class: %d (%s)", ehdr->e_ident[EI_CLASS], ELF_CLASS_MAP[class_type]);
400 |
401 | uint8_t data_type = ehdr->e_ident[EI_DATA];
402 | if (data_type > ELFDATA2MSB)
403 | {
404 | data_type = ELFDATA2MSB + 1;
405 | }
406 | LOGD("data: %d (%s)", ehdr->e_ident[EI_DATA], ELF_DATA_MAP[data_type]);
407 |
408 | uint8_t version_type = ehdr->e_ident[EI_VERSION];
409 | if (version_type > EV_CURRENT)
410 | {
411 | version_type = EV_CURRENT + 1;
412 | }
413 | LOGD("version: %d (%s)", ehdr->e_ident[EI_VERSION], ELF_VERSION_MAP[version_type]);
414 |
415 | LOGD("type: %s", ET_DYN == ehdr->e_type ? "DYN" : "Unknown");
416 | LOGD("machine: %s", EM_ARM == elfTargetMachine() ? "arm" : "arm64");
417 | LOGD("entry point address: %p", reinterpret_cast(ehdr->e_entry));
418 | #if defined(__LP64__)
419 | LOGD("start of program header: %llx", ehdr->e_phoff);
420 | LOGD("start of section header: %llx", ehdr->e_shoff);
421 | #else
422 | LOGD("start of program header: %x", ehdr->e_phoff);
423 | LOGD("start of section header: %x", ehdr->e_shoff);
424 | #endif
425 | LOGD("flags: %x", ehdr->e_flags);
426 | LOGD("size of this header: %d", ehdr->e_ehsize);
427 | LOGD("size of program header: %d", ehdr->e_phentsize);
428 | LOGD("number of program header: %d", ehdr->e_phnum);
429 | LOGD("size of section header: %d", ehdr->e_shentsize);
430 | LOGD("number of section header: %d", ehdr->e_shnum);
431 | LOGD("section header string table index: %d", ehdr->e_shstrndx);
432 | }
433 |
434 | void ElfReader::dumpProgramHeaders()
435 | {
436 | if (phdrNum > 0)
437 | {
438 | LOGD("program header dump:");
439 | #if defined(__LP64__)
440 | LOGD("Type Offset VirtAddr PhysAddr FileSize MemSize Props Align");
441 | #else
442 | LOGD("Type Offset VirtAddr PhysAddr FileSize MemSize Props Align");
443 | #endif
444 |
445 | ElfW(Phdr) * phdr;
446 | const Elf_Program_Type_Map *type;
447 | char buffer[4];
448 | for (ElfW(Half) i = 0; i < phdrNum; i++)
449 | {
450 | phdr = this->phdr + i;
451 | type = map_elf_program_type(phdr->p_type);
452 | getProgramFlagString(phdr->p_flags, buffer);
453 | #if defined(__LP64__)
454 | LOGD("%-20s %08llx %016llx %016llx %08llx %08llx %s %llx", NULL != type ? type->name : "Unknown", phdr->p_offset,
455 | phdr->p_vaddr, phdr->p_paddr, phdr->p_filesz, phdr->p_memsz, buffer, phdr->p_align);
456 | #else
457 | LOGD("%-20s %08x %08x %08x %08x %08x %s %x", NULL != type ? type->name : "Unknown", phdr->p_offset,
458 | phdr->p_vaddr, phdr->p_paddr, phdr->p_filesz, phdr->p_memsz, buffer, phdr->p_align);
459 | #endif
460 | }
461 | }
462 | }
463 |
464 | void ElfReader::dumpDynamicSegment()
465 | {
466 | ElfW(Phdr) *phdr = findSegmentByType(PT_DYNAMIC);
467 | if (NULL != phdr)
468 | {
469 | const Elf_Dynamic_Type_Map *type;
470 | ElfW(Dyn) *dyn = reinterpret_cast(this->bias + phdr->p_vaddr);
471 | LOGD("dump dynamic segment:");
472 | LOGD("Type Value/Addr");
473 | for (; DT_NULL != dyn->d_tag; dyn++)
474 | {
475 | type = map_elf_dynamic_type(dyn->d_tag);
476 | #if defined(__LP64__)
477 | LOGD("%-20s %llx", NULL != type ? type->name : "Unknown", dyn->d_un.d_val);
478 | #else
479 | LOGD("%-20s %x", NULL != type ? type->name : "Unknown", dyn->d_un.d_val);
480 | #endif
481 | }
482 | }
483 | }
484 |
485 | void ElfReader::dumpDynamicRel()
486 | {
487 | #if defined(USE_RELA)
488 | ElfW(Rela) * curr;
489 | ElfW(Rela) *rel = this->rel;
490 | ElfW(Rela) *pltRel = this->pltRel;
491 | #else
492 | ElfW(Rel) * curr;
493 | ElfW(Rel) *rel = this->rel;
494 | ElfW(Rel) *pltRel = this->pltRel;
495 | #endif
496 | ElfW(Addr) r_offset;
497 | ElfW(Xword) r_info;
498 | ElfW(Xword) symIdx;
499 | ElfW(Sym) * sym;
500 | const char *name;
501 | const Elf_Dynamic_Rel_Type_Map *map;
502 | if (NULL != rel)
503 | {
504 | #if defined(USE_RELA)
505 | LOGD("dump rela info:");
506 | #else
507 | LOGD("dump rel info:");
508 | #endif
509 | #if defined(__LP64__)
510 | LOGD("Offset Info Type Sym.value Sym.name");
511 | #else
512 | LOGD("Offset Info Type Sym.value Sym.name");
513 | #endif
514 | for (ElfW(Word) i = 0; i < this->relCount; i++)
515 | {
516 | curr = rel + i;
517 | r_offset = curr->r_offset;
518 | r_info = curr->r_info;
519 | symIdx = ELF_R_SYM(r_info);
520 | sym = this->symTable + symIdx;
521 | name = this->strTable + sym->st_name;
522 | map = map_elf_dynamic_rel_type(ELF_R_TYPE(r_info));
523 | #if defined(__LP64__)
524 | LOGD("%016llx %016llx %-35s %016llx %s", r_offset, r_info, NULL != map ? map->name : "Unknown", sym->st_value, name);
525 | #else
526 | LOGD("%08x %08x %-35s %08x %s", r_offset, r_info, NULL != map ? map->name : "Unknown", sym->st_value, name);
527 | #endif
528 | }
529 | }
530 |
531 | if (NULL != pltRel)
532 | {
533 | #if defined(USE_RELA)
534 | LOGD("dump plt.rela info:");
535 | #else
536 | LOGD("dump plt.rel info:");
537 | #endif
538 | #if defined(__LP64__)
539 | LOGD("Offset Info Type Sym.value Sym.name");
540 | #else
541 | LOGD("Offset Info Type Sym.value Sym.name");
542 | #endif
543 | for (ElfW(Word) i = 0; i < this->pltRelCount; i++)
544 | {
545 | curr = pltRel + i;
546 | r_offset = curr->r_offset;
547 | r_info = curr->r_info;
548 | symIdx = ELF_R_SYM(r_info);
549 | sym = this->symTable + symIdx;
550 | name = this->strTable + sym->st_name;
551 | map = map_elf_dynamic_rel_type(ELF_R_TYPE(r_info));
552 | #if defined(__LP64__)
553 | LOGD("%016llx %016llx %-35s %016llx %s", r_offset, r_info, NULL != map ? map->name : "Unknown", sym->st_value, name);
554 | #else
555 | LOGD("%08x %08x %-35s %08x %s", r_offset, r_info, NULL != map ? map->name : "Unknown", sym->st_value, name);
556 | #endif
557 | }
558 | }
559 | }
560 |
561 | /**
562 | * @brief 判断elf文件头
563 | *
564 | * @return int
565 | */
566 | int ElfReader::verifyElfHeader()
567 | {
568 | if (0 != memcmp(ehdr->e_ident, ELFMAG, SELFMAG))
569 | {
570 | LOGE("wrong elf format for magic");
571 | return -1;
572 | }
573 |
574 | int elf_class = ehdr->e_ident[EI_CLASS];
575 | #if defined(__LP64__)
576 | if (ELFCLASS64 != elf_class)
577 | {
578 | LOGE("wrong elf bit format for 64bit elf (%d)", elf_class);
579 | return -1;
580 | }
581 | #else
582 | if (ELFCLASS32 != elf_class)
583 | {
584 | LOGE("wrong elf bit format for 32bit elf (%d)", elf_class);
585 | return false;
586 | }
587 | #endif
588 |
589 | if (ELFDATA2LSB != ehdr->e_ident[EI_DATA])
590 | {
591 | LOGE("wrong elf format for not little-endian (%d)", ehdr->e_ident[EI_DATA]);
592 | return -1;
593 | }
594 |
595 | if (ET_DYN != ehdr->e_type)
596 | {
597 | LOGE("wrong elf format for e_type (%d)", ehdr->e_type);
598 | return -1;
599 | }
600 |
601 | if (EV_CURRENT != ehdr->e_version)
602 | {
603 | LOGE("wrong elf format for e_version (%d)", ehdr->e_version);
604 | return -1;
605 | }
606 |
607 | if (ehdr->e_machine != elfTargetMachine())
608 | {
609 | LOGE("wrong elf format for e_machine (%d)", ehdr->e_machine);
610 | return -1;
611 | }
612 |
613 | return 0;
614 | }
615 |
616 | int ElfReader::elfTargetMachine()
617 | {
618 | #if defined(__arm__)
619 | return EM_ARM;
620 | #elif defined(__aarch64__)
621 | return EM_AARCH64;
622 | #else
623 | #error "unknown architecture!"
624 | #endif
625 | }
626 |
627 | ElfW(Addr) ElfReader::getSegmentBaseAddress()
628 | {
629 | //寻找第一个PT_LOAD段在内存中的地址
630 | //一般来说 第一个PT_LOAD段的p_offset和p_vaddr都为0
631 |
632 | // get_elf_exec_load_bias()用于计算load_bias,
633 | // load_bias等于base_addr加上第一个PT_LOAD节的 offset - vaddr,
634 | // 然而绝大多数情况下,so动态库的第一个PT_LOAD的offset等于vaddr,
635 | // 也就意味着load_bias等于base_addr;
636 | // 不过,也有遇到过例外的情况,所以在处理elf内存对象时,
637 | // 要用load_bias作为基地址,而不是base_addr。
638 | // 两年前测试boyliang AllHookInOne的ELFHook代码时,在hook nexus5 android 6上的动态时遇到了这个问题。
639 | ElfW(Phdr) *phdr = findSegmentByType(PT_LOAD);
640 | if (NULL != phdr)
641 | {
642 | return this->start + phdr->p_offset - phdr->p_vaddr;
643 | }
644 | return 0;
645 | }
646 |
647 | ElfW(Phdr) * ElfReader::findSegmentByType(ElfW(Word) type)
648 | {
649 | if (phdrNum > 0)
650 | {
651 | ElfW(Phdr) *phdr = NULL;
652 | for (ElfW(Half) i = 0; i < phdrNum; i++)
653 | {
654 | phdr = this->phdr + i;
655 | if (phdr->p_type == type)
656 | {
657 | return phdr;
658 | }
659 | }
660 | }
661 | return NULL;
662 | }
663 |
664 | ElfW(Phdr) * ElfReader::findSegmentByAddress(void *addr)
665 | {
666 | if (phdrNum > 0)
667 | {
668 | ElfW(Addr) start;
669 | ElfW(Addr) end;
670 | ElfW(Addr) target = reinterpret_cast(addr);
671 | ElfW(Phdr) *phdr = NULL;
672 | for (ElfW(Half) i = 0; i < phdrNum; i++)
673 | {
674 | phdr = this->phdr + i;
675 | start = PAGE_START(this->bias + phdr->p_vaddr);
676 | end = PAGE_END(this->bias + phdr->p_vaddr + phdr->p_memsz);
677 | if ((target >= start) && (target <= end))
678 | {
679 | return phdr;
680 | }
681 | }
682 | }
683 | return NULL;
684 | }
685 |
686 | int ElfReader::parseDynamicSegment()
687 | {
688 | //寻找PT_DYNAMIC段的内存地址
689 | ElfW(Phdr) *phdr = findSegmentByType(PT_DYNAMIC);
690 | if (NULL != phdr)
691 | {
692 | //这里使用的是bias作为基址
693 | ElfW(Dyn) *dyn = reinterpret_cast(this->bias + phdr->p_vaddr);
694 | for (; DT_NULL != dyn->d_tag; dyn++)
695 | {
696 | switch (dyn->d_tag)
697 | {
698 | case DT_STRTAB:
699 | this->strTable = reinterpret_cast(this->bias + dyn->d_un.d_ptr);
700 | break;
701 |
702 | case DT_SYMTAB:
703 | this->symTable = reinterpret_cast(this->bias + dyn->d_un.d_ptr);
704 | break;
705 |
706 | #if !defined(USE_RELA)
707 | case DT_PLTREL:
708 | if (DT_RELA == dyn->d_un.d_val)
709 | {
710 | LOGE("unsupported DT_PLTREL in %s, expected DT_REL", this->moduleName);
711 | return -1;
712 | }
713 | break;
714 |
715 | case DT_RELA:
716 | LOGE("unsupported DT_RELA in %s", this->moduleName);
717 | return -1;
718 |
719 | case DT_RELASZ:
720 | LOGE("unsupported DT_RELASZ in %s", this->moduleName);
721 | return -1;
722 | //重定位表.rel.dyn的大小
723 | case DT_RELSZ:
724 | this->relCount = dyn->d_un.d_val / sizeof(ElfW(Rel));
725 | break;
726 | //与过程链接表关联的重定位(.rel.pt)条目的总大小(以字节为单位)
727 | case DT_PLTRELSZ:
728 | this->pltRelCount = dyn->d_un.d_val / sizeof(ElfW(Rel));
729 | break;
730 | //重定位表的偏移,与.rel.dyn section 对应
731 | case DT_REL:
732 | this->rel = reinterpret_cast(this->bias + dyn->d_un.d_ptr);
733 | break;
734 | //重定位条目的地址仅与过程链接表相关
735 | case DT_JMPREL:
736 | this->pltRel = reinterpret_cast(this->bias + dyn->d_un.d_ptr);
737 | break;
738 | #endif
739 | #if defined(USE_RELA)
740 | case DT_PLTREL:
741 | if (DT_REL == dyn->d_un.d_val)
742 | {
743 | LOGE("unsupported DT_PLTREL in %s, expected DT_RELA", this->moduleName);
744 | return -1;
745 | }
746 | break;
747 |
748 | case DT_REL:
749 | LOGE("unsupported DT_REL in %s", this->moduleName);
750 | return -1;
751 |
752 | case DT_RELSZ:
753 | LOGE("unsupported DT_RELSZ in %s", this->moduleName);
754 | return -1;
755 |
756 | case DT_RELASZ:
757 | this->relCount = dyn->d_un.d_val / sizeof(ElfW(Rela));
758 | break;
759 |
760 | case DT_PLTRELSZ:
761 | this->pltRelCount = dyn->d_un.d_val / sizeof(ElfW(Rela));
762 | break;
763 |
764 | case DT_RELA:
765 | this->rel = reinterpret_cast(this->bias + dyn->d_un.d_ptr);
766 | break;
767 |
768 | case DT_JMPREL:
769 | this->pltRel = reinterpret_cast(this->bias + dyn->d_un.d_ptr);
770 | break;
771 | #endif
772 | case DT_HASH:
773 | this->nbucket = reinterpret_cast(this->bias + dyn->d_un.d_ptr)[0];
774 | this->nchain = reinterpret_cast(this->bias + dyn->d_un.d_ptr)[1];
775 | this->bucket = reinterpret_cast(this->bias + dyn->d_un.d_ptr + 8);
776 | this->chain = reinterpret_cast(this->bias + dyn->d_un.d_ptr + 8 + this->nbucket * 4);
777 | break;
778 |
779 | case DT_GNU_HASH:
780 | this->gnuNBucket = reinterpret_cast(this->bias + dyn->d_un.d_ptr)[0];
781 | this->gnuSymndx = reinterpret_cast(this->bias + dyn->d_un.d_ptr)[1];
782 | this->gnuMaskwords = reinterpret_cast(this->bias + dyn->d_un.d_ptr)[2];
783 | this->gnuShift2 = reinterpret_cast(this->bias + dyn->d_un.d_ptr)[3];
784 | this->gnuBloomFilter = reinterpret_cast(this->bias + dyn->d_un.d_ptr + 16);
785 | this->gnuBucket = reinterpret_cast(this->gnuBloomFilter + this->gnuMaskwords);
786 | this->gnuChain = this->gnuBucket + this->gnuNBucket - this->gnuSymndx;
787 |
788 | if (!powerof2(this->gnuMaskwords))
789 | {
790 | LOGE("invalid maskwords for gnu_hash in %s: 0x%x, expecting power to two", this->moduleName, this->gnuMaskwords);
791 | return -1;
792 | }
793 | this->isGNUHash = true;
794 | --this->gnuMaskwords;
795 | break;
796 |
797 | default:
798 | break;
799 | }
800 | }
801 |
802 | if ((NULL == this->strTable) || (NULL == this->symTable))
803 | {
804 | LOGE("no DT_STRTAB or DT_SYMTAB found in %s", this->moduleName);
805 | return -1;
806 | }
807 |
808 | return 0;
809 | }
810 | return -1;
811 | }
812 |
813 | int ElfReader::findSymbolByName(const char *symbol, ElfW(Sym) * *sym, uint32_t *symidx)
814 | {
815 | if (this->isGNUHash)
816 | {
817 | if (0 == gnuLookup(symbol, sym, symidx))
818 | {
819 | return 0;
820 | }
821 |
822 | ElfW(Sym) * curr;
823 | for (uint32_t i = 0; i < this->gnuSymndx; i++)
824 | {
825 | curr = this->symTable + i;
826 | if (0 == strcmp(this->strTable + curr->st_name, symbol))
827 | {
828 | *symidx = i;
829 | *sym = curr;
830 | return 0;
831 | }
832 | }
833 | LOGE("not found %s in %s before gnu symbol index %d", symbol, this->moduleName, this->gnuSymndx);
834 | return -1;
835 | }
836 | return elfLookup(symbol, sym, symidx);
837 | }
838 |
839 | int ElfReader::elfLookup(const char *symbol, ElfW(Sym) * *sym, uint32_t *symidx)
840 | {
841 | if ((NULL == this->bucket) || (NULL == this->chain))
842 | {
843 | LOGE("elfLookup: no hash info found");
844 | return -1;
845 | }
846 |
847 | uint32_t hash = ElfHooker::elf_hash(symbol);
848 | ElfW(Sym) * ret;
849 | for (uint32_t n = this->bucket[hash % this->nbucket]; 0 != n; n = this->chain[n])
850 | {
851 | ret = this->symTable + n;
852 | if (0 == strcmp(this->strTable + ret->st_name, symbol))
853 | {
854 | *symidx = n;
855 | *sym = ret;
856 | return 0;
857 | }
858 | }
859 | LOGE("elfLookup: not found symbol %s in %s", symbol, this->moduleName);
860 | return -1;
861 | }
862 |
863 | int ElfReader::gnuLookup(const char *symbol, ElfW(Sym) * *sym, uint32_t *symidx)
864 | {
865 | uint32_t hash = ElfHooker::gnu_hash(symbol);
866 | uint32_t h2 = hash >> this->gnuShift2;
867 |
868 | uint32_t bloom_mask_bits = sizeof(ElfW(Addr)) * 8;
869 | uint32_t word_num = (hash / bloom_mask_bits) & this->gnuMaskwords;
870 |
871 | ElfW(Addr) bloom_word = this->gnuBloomFilter[word_num];
872 |
873 | *sym = NULL;
874 | *symidx = 0;
875 | if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0)
876 | {
877 | // LOGE("gnuLookup: not found symbol %s in %s", symbol, this->moduleName);
878 | return -1;
879 | }
880 |
881 | uint32_t n = this->gnuBucket[hash % this->gnuNBucket];
882 | if (n == 0)
883 | {
884 | // LOGE("gnuLookup: not found symbol %s in %s", symbol, this->moduleName);
885 | return -1;
886 | }
887 |
888 | do
889 | {
890 | ElfW(Sym) *s = this->symTable + n;
891 | if ((((this->gnuChain[n] ^ hash) >> 1) == 0) && (strcmp((this->strTable + s->st_name), symbol) == 0))
892 | {
893 | *symidx = n;
894 | *sym = s;
895 | return 0;
896 | }
897 | } while ((this->gnuChain[n++] & 1) == 0);
898 |
899 | // LOGE("gnuLookup: not found symbol %s in %s", symbol, this->moduleName);
900 | return -1;
901 | }
902 |
903 | int ElfReader::hookInternally(void *addr, void *new_func, void **old_func)
904 | {
905 | if (*(void **)addr == new_func)
906 | {
907 | LOGD("already been hooked");
908 | return 0;
909 | }
910 | //获取要hook的地址所在的PT段
911 | ElfW(Phdr) *phdr = findSegmentByAddress(addr);
912 | if (NULL == phdr)
913 | {
914 | LOGE("failed to find segment for address %p in %s", addr, this->moduleName);
915 | return -1;
916 | }
917 |
918 | int prot = PFLAGS_TO_PROT(phdr->p_flags);
919 | // LOGD("prot p_flags = %d", prot);
920 | prot &= ~PROT_EXEC;
921 | prot |= PROT_WRITE;
922 | ElfW(Addr) target = reinterpret_cast(addr);
923 | void *start = reinterpret_cast(PAGE_START(target));
924 | if (0 != mprotect(start, PAGE_SIZE, prot))
925 | {
926 | LOGE("failed to mprotect %p in %s", start, this->moduleName);
927 | return -1;
928 | }
929 | //保存原先的地址
930 | *old_func = *(void **)addr;
931 | //修改为新的hook地址
932 | *(void **)addr = new_func;
933 |
934 | // LOGD("plt addr = %lx", addr);
935 | ElfHooker::clear_cache(start, PAGE_SIZE);
936 | return 0;
937 | }
938 |
--------------------------------------------------------------------------------
/jni/elfGotHook/elf_reader.h:
--------------------------------------------------------------------------------
1 | #ifndef INJECTDEMO_ELF_READER_H
2 | #define INJECTDEMO_ELF_READER_H
3 |
4 | #include
5 | #include
6 |
7 | #include "def.h"
8 | #include "logger.h"
9 |
10 | class ElfReader
11 | {
12 | public:
13 | ElfReader(const char *module, void *start);
14 | int parse();
15 | int hook(const char *func_name, void *new_func, void **old_func);
16 | void dumpElfHeader();
17 | void dumpProgramHeaders();
18 | void dumpDynamicSegment();
19 | void dumpDynamicRel();
20 |
21 | private:
22 | int verifyElfHeader();
23 | int elfTargetMachine();
24 | ElfW(Addr) getSegmentBaseAddress();
25 | ElfW(Phdr) * findSegmentByType(ElfW(Word) type);
26 | ElfW(Phdr) * findSegmentByAddress(void *addr);
27 | int parseDynamicSegment();
28 | int findSymbolByName(const char *symbol, ElfW(Sym) * *sym, uint32_t *symidx);
29 | int elfLookup(const char *symbol, ElfW(Sym) * *sym, uint32_t *symidx);
30 | int gnuLookup(const char *symbol, ElfW(Sym) * *sym, uint32_t *symidx);
31 | int hookInternally(void *addr, void *new_func, void **old_func);
32 |
33 | private:
34 | const char *moduleName; //要hook的模块名
35 | ElfW(Addr) start; //ELF32_ADDR
36 | ElfW(Addr) bias;
37 | ElfW(Ehdr) * ehdr;
38 | ElfW(Half) phdrNum;
39 | ElfW(Phdr) * phdr;
40 |
41 | const char *strTable = NULL;
42 | ElfW(Sym) *symTable = NULL;
43 | ElfW(Xword) relCount = 0;
44 | ElfW(Xword) pltRelCount = 0;
45 | #if defined(USE_RELA)
46 | ElfW(Rela) *rel = NULL;
47 | ElfW(Rela) *pltRel = NULL;
48 | #else
49 | ElfW(Rel) *rel = NULL;
50 | ElfW(Rel) *pltRel = NULL;
51 | #endif
52 |
53 | //for elf hash
54 | uint32_t nbucket;
55 | uint32_t nchain;
56 | uint32_t *bucket;
57 | uint32_t *chain;
58 |
59 | //for gnu hash
60 | bool isGNUHash = false;
61 | uint32_t gnuNBucket;
62 | uint32_t gnuSymndx;
63 | uint32_t gnuMaskwords;
64 | uint32_t gnuShift2;
65 | uint32_t *gnuBucket;
66 | uint32_t *gnuChain;
67 | ElfW(Addr) * gnuBloomFilter;
68 | };
69 |
70 | #endif //INJECTDEMO_ELF_READER_H
71 |
--------------------------------------------------------------------------------
/jni/elfGotHook/hooker.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "tools.h"
5 | #include "elf_reader.h"
6 |
7 | #if defined(__arm__)
8 | #define LIBSF_PATH "/system/lib/libsurfaceflinger.so"
9 | #elif defined(__aarch64__)
10 | #define LIBSF_PATH "/system/lib64/libsurfaceflinger.so"
11 | #else
12 | #error "unknown architecture!"
13 | #endif
14 |
15 | typedef EGLBoolean (*t_eglSwapBuffers_fun)(EGLDisplay dpy, EGLSurface surf);
16 |
17 | static t_eglSwapBuffers_fun original = NULL;
18 | static t_eglSwapBuffers_fun original2 = NULL;
19 | static EGLBoolean new_eglSwapBuffers(EGLDisplay dpy, EGLSurface surf)
20 | {
21 | LOGD("new_eglSwapBuffers()");
22 | if (NULL == original)
23 | {
24 | LOGE("failed to get original eglSwapBuffers");
25 |
26 | return EGL_FALSE;
27 | }
28 |
29 | return original(dpy, surf);
30 | }
31 |
32 |
33 | void __attribute__ ((constructor)) hooker_main()
34 | {
35 | void *start = ElfHooker::get_module_base(getpid(), LIBSF_PATH);
36 |
37 | if (NULL == start)
38 | {
39 | return;
40 | }
41 |
42 |
43 | ElfReader elfReader(LIBSF_PATH, start);
44 | if (0 != elfReader.parse())
45 | {
46 | LOGE("failed to parse %s in %d maps at %p", LIBSF_PATH, getpid(), start);
47 | return;
48 | }
49 | elfReader.hook("eglSwapBuffers", reinterpret_cast(new_eglSwapBuffers),
50 | reinterpret_cast(&original));
51 | // elfReader.dumpElfHeader();
52 | // elfReader.dumpProgramHeaders();
53 | // elfReader.dumpDynamicSegment();
54 | // elfReader.dumpDynamicRel();
55 | }
56 |
--------------------------------------------------------------------------------
/jni/elfGotHook/logger.h:
--------------------------------------------------------------------------------
1 | #ifndef INJECTDEMO_LOGGER_H
2 | #define INJECTDEMO_LOGGER_H
3 |
4 | #include
5 |
6 | #define TAG "fengyue"
7 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__)
8 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__)
9 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__)
10 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__)
11 | #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__)
12 |
13 | #endif //INJECTDEMO_LOGGER_H
14 |
--------------------------------------------------------------------------------
/jni/elfGotHook/tools.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "tools.h"
3 |
4 | void *ElfHooker::get_module_base(pid_t pid, const char *module)
5 | {
6 | char buffer[1024];
7 |
8 | if (pid <= 0)
9 | {
10 | snprintf(buffer, 1024, "/proc/self/maps");
11 | }
12 | else
13 | {
14 | snprintf(buffer, 1024, "/proc/%d/maps", pid);
15 | }
16 |
17 | unsigned long module_start;
18 | unsigned long module_end;
19 | char so_name[SO_NAME_LEN];
20 | FILE *mapsFile = fopen(buffer, "r");
21 | if (NULL != mapsFile)
22 | {
23 | while (fgets(buffer, 1024, mapsFile))
24 | {
25 | // 7ad995c000-7ad9a18000 r-xp 00000000 103:09 1623 /system/lib64/libc.so
26 | if (sscanf(buffer, "%lx-%lx %*4s %*x %*x:%*x %*d %s", &module_start, &module_end, so_name) != 3)
27 | {
28 | continue;
29 | }
30 |
31 | if (0 == strncmp(so_name, module, strlen(module)))
32 | {
33 | fclose(mapsFile);
34 | return reinterpret_cast(module_start);
35 | }
36 | }
37 | }
38 | fclose(mapsFile);
39 | LOGE("failed to find module %s (%d)", module, pid);
40 | return NULL;
41 | }
42 |
43 | uint32_t ElfHooker::elf_hash(const char *symbol)
44 | {
45 | const uint8_t *name = reinterpret_cast(symbol);
46 | uint32_t h = 0, g;
47 |
48 | while (*name)
49 | {
50 | h = (h << 4) + *name++;
51 | g = h & 0xf0000000;
52 | h ^= g;
53 | h ^= g >> 24;
54 | }
55 |
56 | return h;
57 | }
58 |
59 | uint32_t ElfHooker::gnu_hash(const char *symbol)
60 | {
61 | uint32_t h = 5381;
62 | const uint8_t *name = reinterpret_cast(symbol);
63 |
64 | while (0 != *name)
65 | {
66 | h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c
67 | }
68 | return h;
69 | }
70 |
71 | void ElfHooker::clear_cache(void *addr, size_t len)
72 | {
73 | uint8_t *end = reinterpret_cast(addr) + len;
74 |
75 | // LOGD("clear cache %lx , %lx", addr, end);
76 |
77 | syscall(0xf0002, addr, end);
78 | }
79 |
--------------------------------------------------------------------------------
/jni/elfGotHook/tools.h:
--------------------------------------------------------------------------------
1 | #ifndef INJECTDEMO_TOOLS_H
2 | #define INJECTDEMO_TOOLS_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include "logger.h"
13 | #include "def.h"
14 |
15 | namespace ElfHooker {
16 | void* get_module_base(pid_t pid, const char* module);
17 | uint32_t elf_hash(const char* symbol);
18 | uint32_t gnu_hash(const char* symbol);
19 | void clear_cache(void *addr, size_t len);
20 | };
21 |
22 | #endif //INJECTDEMO_TOOLS_H
23 |
--------------------------------------------------------------------------------
/jni/hook_instance.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #include "elfGotHook/logger.h"
17 | #include "packer.h"
18 |
19 | #define kDexMagic "dex\n"
20 |
21 |
22 | int (*old_open)(const char *pathname, int flags, mode_t mode);
23 | int (*old_fstat)(int fildes, struct stat *buf);
24 | ssize_t (*old_read_chk)(int fd, void *buf, size_t nbytes, size_t buflen);
25 | ssize_t (*old_read)(int fd, void *buf, size_t count);
26 | void *(*old_mmap)(void *start, size_t length, int prot, int flags, int fd, off_t offset);
27 | int (*old_munmap)(void *start, size_t length);
28 | pid_t (*old_fork)(void);
29 |
30 |
31 | int new_open(const char *pathname, int flags, mode_t mode)
32 | {
33 | int result = old_open(pathname, flags, mode);
34 |
35 | if (strstr(pathname, g_fake_dex_magic))
36 | {
37 | LOGD("[+]my open pathname:%s,result:%d", pathname, result);
38 | if (result == -1)
39 | {
40 | LOGE("[-]my open failed error:%s", strerror(errno));
41 | }
42 | }
43 | return result;
44 | }
45 |
46 | int new_fstat(int fd, struct stat *buf)
47 | {
48 | int result = old_fstat(fd, buf);
49 |
50 | char fdlinkstr[128] = {0};
51 | char linkPath[256] = {0};
52 |
53 | memset(fdlinkstr, 0, 128);
54 | memset(linkPath, 0, 256);
55 |
56 | int pid = getpid();
57 | snprintf(fdlinkstr, 128, "/proc/%ld/fd/%d", pid, fd);
58 |
59 | if (readlink(fdlinkstr, linkPath, 256) >= 0)
60 | {
61 | // LOGD("[+]new fstat file:%s",linkPath);
62 | if (strstr(linkPath,(char*)g_fake_dex_magic))
63 | {
64 | buf->st_size = g_dex_size;
65 | LOGD("[+]fstat linkPath:%s,buf.size:%d", linkPath, buf->st_size);
66 | }
67 | }
68 | else
69 | {
70 | LOGD("[-]fun my fstat readlink error");
71 | }
72 | return result;
73 | }
74 |
75 | ssize_t new_read(int fd, void *buf, size_t count)
76 | {
77 | char fdlinkstr[128] = {0};
78 | char linkPath[256] = {0};
79 |
80 | memset(fdlinkstr, 0, 128);
81 | memset(linkPath, 0, 256);
82 | int pid = getpid();
83 | snprintf(fdlinkstr, 128, "/proc/%ld/fd/%d", pid, fd);
84 | if (readlink(fdlinkstr, linkPath, 256) >= 0)
85 | {
86 | // LOGD("[+]my read file:%s,count:%d",linkPath,count);
87 | if (strstr(linkPath,(char*)g_fake_dex_magic))
88 | {
89 | LOGD("[+]my read memcpy dex magic");
90 | memcpy(buf, kDexMagic, 4);
91 | return 4;
92 | }
93 | }
94 | else
95 | {
96 | LOGD("[-]my read readlink error");
97 | }
98 | return old_read(fd, buf, count);
99 | }
100 |
101 | ssize_t new_read_chk(int fd, void *buf, size_t nbytes, size_t buflen)
102 | {
103 | char fdlinkstr[128] = {0};
104 | char linkPath[256] = {0};
105 |
106 | memset(fdlinkstr, 0, 128);
107 | memset(linkPath, 0, 256);
108 | int pid = getpid();
109 | snprintf(fdlinkstr, 128, "/proc/%ld/fd/%d", pid, fd);
110 | if (readlink(fdlinkstr, linkPath, 256) >= 0)
111 | {
112 | // LOGD("[+]my read_chk file:%s,nbytes:%d,buflen:%d",linkPath,nbytes,buflen);
113 |
114 | // [+]my read_chk file:/data/data/com.ai
115 | // speech.weiyu/files/.jiagu/mini.dex,nbytes:4,buflen:-1
116 | // [+]my read_chk g_faked_dex_path:/data
117 | // /user/0/com.aispeech.weiyu/files/.jiagu/mini.dex
118 |
119 | // 这里不能使用strcmp比较 如果使用mini.dex作为fake_dex,mini_dex的位置为
120 | // /data/user/0/pkg_name/files/.jiagu/mini.dex
121 | // 但是使用readlink获取到的mini.dex路径为
122 | // /data/data/pkg_name/files/.jiagu/mini.dex
123 | if (strstr(linkPath,(char*)g_fake_dex_magic))
124 | {
125 | LOGD("[+]fun my read_chk memcpy dex magic");
126 | memcpy(buf, kDexMagic, 4);
127 | return 4;
128 | }
129 | }
130 | else
131 | {
132 | LOGD("[-]fun my read_chk readlink error");
133 | }
134 | return old_read_chk(fd, buf, nbytes, buflen);
135 | }
136 |
137 | void *new_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
138 | {
139 | char fdlinkstr[128] = {0};
140 | char linkPath[256] = {0};
141 |
142 | memset(fdlinkstr, 0, 128);
143 | memset(linkPath, 0, 256);
144 | int pid = (int)getpid();
145 | snprintf(fdlinkstr, 128, "/proc/%ld/fd/%d", pid, fd);
146 |
147 | if (readlink(fdlinkstr, linkPath, 256) < 0)
148 | {
149 | LOGD("[-]my mmap readlink error");
150 | return old_mmap(start, length, prot, flags, fd, offset);
151 | }
152 |
153 | if (strstr(linkPath,(char*)g_fake_dex_magic))
154 | {
155 | LOGD("[+]mmap linkpath:%s,size:%d", linkPath, length);
156 | return g_decrypt_base;
157 | }
158 | return old_mmap(start, length, prot, flags, fd, offset);
159 | }
160 |
161 | int new_munmap(void *start, size_t length)
162 | {
163 | if ((start == g_decrypt_base) || (length == g_page_size))
164 | {
165 | LOGD("[+]munmap start:%p,length:%d", start, length);
166 | return 0;
167 | }
168 | return old_munmap(start, length);
169 | }
170 |
171 | pid_t new_fork(void)
172 | {
173 | LOGD("[+]fun my fork called");
174 | return -1;
175 | }
176 |
--------------------------------------------------------------------------------
/jni/hook_instance.h:
--------------------------------------------------------------------------------
1 | #ifndef HOOK_INSTANCE_H
2 | #define HOOK_INSTANCE_H
3 |
4 | extern int (*old_open)(const char *, int, mode_t);
5 | extern int (*old_fstat)(int, struct stat *);
6 | extern ssize_t (*old_read_chk)(int, void *, size_t, size_t);
7 | extern ssize_t (*old_read)(int, void *, size_t);
8 | extern void *(*old_mmap)(void *, size_t, int, int, int, off_t);
9 | extern int (*old_munmap)(void *, size_t length);
10 | extern pid_t (*old_fork)(void);
11 |
12 | int hook(uint32_t addr, uint32_t fakeaddr, uint32_t **old_addr);
13 | int new_open(const char *pathname, int flags, mode_t mode);
14 | int new_fstat(int fildes, struct stat *buf);
15 | ssize_t
16 | new_read(int fd, void *buf, size_t count);
17 | ssize_t
18 | new_read_chk(int fd, void *buf, size_t nbytes, size_t buflen);
19 | void *
20 | new_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
21 | int new_munmap(void *start, size_t length);
22 | pid_t new_fork(void);
23 |
24 | #endif // ifndef HOOK_INSTANCE_H
25 |
--------------------------------------------------------------------------------
/jni/log.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KuNgia09/Bangcle/76f84a741bdfc25504992327c8addcf4f000e403/jni/log.txt
--------------------------------------------------------------------------------
/jni/packe_bak.cpp:
--------------------------------------------------------------------------------
1 | #include "packer.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | #include "common.h"
19 | #include "dex_header.h"
20 | #include "utils.h"
21 | #include "byte_load.h"
22 | #include "hook_instance.h"
23 | #include "elfGotHook/tools.h"
24 | #include "elfGotHook/elf_reader.h"
25 | // #include "openssl/openssl/aes.h"
26 |
27 | #define CBC 1
28 | #define CTR 1
29 | #define ECB 1
30 | #include "aes.hpp"
31 |
32 | // #define PAGE_MASK 0xfffff000
33 | // #define PAGE_START(x) ((x)&PAGE_MASK)
34 | #define PAGE_SIZE 4096
35 | #define PAGE_OFFSET(x) ((x) & ~PAGE_MASK)
36 | #define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE - 1))
37 |
38 | #if defined(__aarch64__)
39 | #define LIB_ART_PATH "/system/lib64/libart.so"
40 | #elif defined(__arm__)
41 | #define LIB_ART_PATH "/system/lib/libart.so"
42 | #else
43 | #define LIB_ART_PATH "/system/lib/libart.so"
44 | #endif
45 |
46 | #define REGREX ".*/libart\\.so$"
47 | #define JIAMI_MAGIC "jiami.dat"
48 | #define PACKER_MAGIC ".jiagu"
49 |
50 | // #define FETCH_MAIGIC "forever.dat"
51 |
52 | using namespace std;
53 |
54 | char g_jiagu_dir[256] = {0}; // 加密dex的所在目录
55 | bool g_isArt = false;
56 | int g_sdk_int = 0;
57 | const char *g_file_dir;
58 | const char *g_NativeLibDir;
59 | char *g_PackageResourcePath;
60 | char *g_pkgName;
61 | int g_dex_size = 0; // main.dex的真正大小
62 | int g_page_size = 0; // main.dex进行页面对齐后的大小
63 | char g_fake_dex_path[256] = {0};
64 | void *g_decrypt_base = NULL;
65 | void *g_ArtHandle = NULL;
66 |
67 | const char *AES_KEYCODE = "1234567812345678";
68 | const char *AES_IV = "1234567812345678";
69 |
70 | void native_attachBaseContext(JNIEnv *env, jobject obj, jobject ctx);
71 | void native_onCreate(JNIEnv *, jobject, jobject);
72 |
73 | unsigned char MINIDEX[292] = {
74 | 0x64, 0x65, 0x78, 0x0A, 0x30, 0x33, 0x35, 0x00, 0xD9, 0x24, 0x14, 0xFD, 0x2F, 0x81, 0x4D, 0x8B,
75 | 0x50, 0x48, 0x13, 0x1D, 0x8D, 0xA9, 0xCF, 0x1F, 0xF1, 0xF2, 0xDD, 0x06, 0xB4, 0x67, 0x70, 0xA1,
76 | 0x24, 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00,
77 | 0x00, 0x00, 0x00, 0x00, 0xD8, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
78 | 0x02, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 | 0x01, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00,
81 | 0xA4, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
83 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 | 0x00, 0x00, 0x00, 0x00, 0x0E, 0x4C, 0x63, 0x6F, 0x6D, 0x2F, 0x6D, 0x69, 0x78, 0x43, 0x6C, 0x61,
85 | 0x73, 0x73, 0x3B, 0x00, 0x12, 0x4C, 0x6A, 0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F,
86 | 0x4F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x3B, 0x00, 0x0D, 0x6D, 0x69, 0x78, 0x43, 0x6C, 0x61, 0x73,
87 | 0x73, 0x2E, 0x6A, 0x61, 0x76, 0x61, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
89 | 0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00,
90 | 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00,
91 | 0x03, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
92 | 0xD8, 0x00, 0x00, 0x00};
93 |
94 | void write_mix_dex(const char *minidex)
95 | {
96 | // If the file exists,skip
97 | if (access(minidex, F_OK) == -1)
98 | {
99 | FILE *file = fopen(minidex, "wb");
100 | fwrite(MINIDEX, 292, 1, file);
101 | fclose(file);
102 | LOGD("[+]mix dex saved at:%s", minidex);
103 | }
104 | }
105 |
106 | static JNINativeMethod methods[] = {
107 | {"attachBaseContext", "(Landroid/content/Context;)V", (void *)native_attachBaseContext},
108 | {"onCreate", "(Landroid/content/Context;)V", (void *)native_onCreate}};
109 |
110 | int jniRegisterNativeMethods(JNIEnv *env, const char *className, const JNINativeMethod *gMethods, int numMethods)
111 | {
112 | jclass clazz;
113 | int tmp;
114 |
115 | clazz = env->FindClass(className);
116 | if (clazz == NULL)
117 | {
118 | return -1;
119 | }
120 | if ((tmp = env->RegisterNatives(clazz, gMethods, numMethods)) < 0)
121 | {
122 | LOGE("[-]RegisterNatives failed");
123 | return -1;
124 | }
125 | return 0;
126 | }
127 |
128 | int lookup(JNINativeMethod *table, const char *name, const char *sig, void **fnPtrout)
129 | {
130 | int i = 0;
131 |
132 | while (table[i].name != NULL)
133 | {
134 | // LOGD("[+]lookup %d %s" ,i,table[i].name);
135 | if ((strcmp(name, table[i].name) == 0) &&
136 | (strcmp(sig, table[i].signature) == 0))
137 | {
138 | *fnPtrout = table[i].fnPtr;
139 | return 1;
140 | }
141 | i++;
142 | }
143 |
144 | return 0;
145 | }
146 |
147 | char *mmap_dex(const char *szDexPath)
148 | {
149 | int fd;
150 | struct stat buf = {0};
151 |
152 | fd = open(szDexPath, 0);
153 | if (!fd)
154 | {
155 | LOGE("[-]open %s failed:%s", szDexPath, strerror(errno));
156 | return NULL;
157 | }
158 | int status = stat(szDexPath, &buf);
159 | if (status == -1)
160 | {
161 | LOGE("[-]fstat %s failed", szDexPath);
162 | return NULL;
163 | }
164 |
165 | // 设置页面对齐
166 | g_dex_size = buf.st_size;
167 | char *dexBase = (char *)mmap(0, g_dex_size, 3, 2, fd, 0);
168 | close(fd);
169 | return dexBase;
170 | }
171 |
172 | #ifdef __cplusplus
173 | extern "C"
174 | {
175 | #endif
176 |
177 | void _init(void)
178 | {
179 | LOGD("This is DT_INIT");
180 | }
181 |
182 | #ifdef __cplusplus
183 | }
184 | #endif
185 |
186 | jint mem_loadDex_dvm(JNIEnv *env, char *szPath)
187 | {
188 | void (*openDexFile)(const u4 *args, union JValue *pResult);
189 | void *ldvm = (void *)dlopen("libdvm.so", 1);
190 | if (!ldvm)
191 | {
192 | LOGE("[-]could not dlopen dvm:%s", dlerror());
193 | }
194 | JNINativeMethod *dvm_dalvik_system_DexFile = (JNINativeMethod *)dlsym(ldvm, "dvm_dalvik_system_DexFile");
195 | if (0 == lookup(dvm_dalvik_system_DexFile, "openDexFile", "([B)I", (void **)&openDexFile))
196 | {
197 | LOGE("[-]dvm_dalvik_system_DexFile method does not found ");
198 | return 0;
199 | }
200 |
201 | char *arr;
202 | arr = (char *)malloc(16 + g_dex_size);
203 | ArrayObject *ao = (ArrayObject *)arr;
204 | // LOGD("sizeof ArrayObject:%d",sizeof(ArrayObject));
205 | ao->length = g_dex_size;
206 | memcpy(arr + 16, (char *)g_decrypt_base, g_dex_size);
207 | munmap((char *)g_decrypt_base, g_dex_size);
208 |
209 | u4 args[] = {(u4)(long)ao};
210 | union JValue pResult;
211 | if (openDexFile != NULL)
212 | {
213 | openDexFile(args, &pResult);
214 | jint mCookie = (jint)(long)pResult.l;
215 | return mCookie;
216 | }
217 | else
218 | {
219 | LOGE("[-]cannot get dvm_dalvik_system_DexFile addr");
220 | return 0;
221 | }
222 | }
223 |
224 | void make_dex_elements(JNIEnv *env, jobject classLoader, jobject dexFileobj)
225 | {
226 | jclass PathClassLoader = env->GetObjectClass(classLoader);
227 | jclass BaseDexClassLoader = env->GetSuperclass(PathClassLoader);
228 | // get pathList fieldid
229 | jfieldID pathListid = env->GetFieldID(BaseDexClassLoader, "pathList", "Ldalvik/system/DexPathList;");
230 | jobject pathList = env->GetObjectField(classLoader, pathListid);
231 |
232 | // get DexPathList Class
233 | jclass DexPathListClass = env->GetObjectClass(pathList);
234 | // get dexElements fieldid
235 | jfieldID dexElementsid = env->GetFieldID(DexPathListClass, "dexElements", "[Ldalvik/system/DexPathList$Element;");
236 | jobjectArray dexElement = static_cast(env->GetObjectField(pathList, dexElementsid));
237 |
238 | jint len = env->GetArrayLength(dexElement);
239 |
240 | LOGD("[+]Elements size:%d", len);
241 |
242 | jclass ElementClass = env->FindClass("dalvik/system/DexPathList$Element"); // dalvik/system/DexPathList$Element
243 | jmethodID Elementinit = env->GetMethodID(ElementClass, "",
244 | "(Ljava/io/File;ZLjava/io/File;Ldalvik/system/DexFile;)V");
245 | jboolean isDirectory = JNI_FALSE;
246 |
247 | jobject element_obj = env->NewObject(ElementClass, Elementinit, NULL, isDirectory, NULL, dexFileobj);
248 |
249 | // Get dexElement all values and add add each value to the new array
250 | jobjectArray new_dexElement = env->NewObjectArray(len + 1, ElementClass, NULL);
251 | for (int i = 0; i < len; ++i)
252 | {
253 | env->SetObjectArrayElement(new_dexElement, i, env->GetObjectArrayElement(dexElement, i));
254 | }
255 |
256 | env->SetObjectArrayElement(new_dexElement, len, element_obj);
257 | env->SetObjectField(pathList, dexElementsid, new_dexElement);
258 |
259 | env->DeleteLocalRef(element_obj);
260 | env->DeleteLocalRef(ElementClass);
261 | env->DeleteLocalRef(dexElement);
262 | env->DeleteLocalRef(DexPathListClass);
263 | env->DeleteLocalRef(pathList);
264 | env->DeleteLocalRef(BaseDexClassLoader);
265 | env->DeleteLocalRef(PathClassLoader);
266 | } // make_dex_elements
267 |
268 | // For Nougat
269 | void replace_cookie_N(JNIEnv *env, jobject mini_dex_obj, jlong value)
270 | {
271 | jclass DexFileClass = env->FindClass("dalvik/system/DexFile"); // "dalvik/system/DexPathList$Element"
272 | jfieldID field_mCookie;
273 | jobject mCookie;
274 |
275 | field_mCookie = env->GetFieldID(DexFileClass, "mCookie", "Ljava/lang/Object;");
276 | mCookie = env->GetObjectField(mini_dex_obj, field_mCookie);
277 |
278 | jboolean is_data_copy = 1;
279 | jsize arraylen = env->GetArrayLength((jarray)mCookie);
280 | LOGD("[+]g_sdk_int:%d,cookie arrayLen:%d", g_sdk_int, arraylen);
281 |
282 | jlong *mix_element = env->GetLongArrayElements((jlongArray)mCookie, &is_data_copy);
283 | jlong *c_dex_cookie = (jlong *)value;
284 |
285 | jlong *tmp = mix_element;
286 | *(tmp + 1) = value;
287 | // 更新mCookie
288 | env->ReleaseLongArrayElements((jlongArray)mCookie, mix_element, 0);
289 | if (env->ExceptionCheck())
290 | {
291 | LOGE("[-]g_sdk_int:%d Update cookie failed", g_sdk_int);
292 | return;
293 | }
294 |
295 | jlong *second_mix_element = env->GetLongArrayElements((jlongArray)mCookie, &is_data_copy);
296 | jlong ptr = *(second_mix_element + 1);
297 | int dexbase = *(int *)(ptr + 4);
298 | int dexsize = *(int *)(ptr + 8);
299 | LOGD("[+]Nougat after replace cookie dex base:%x,dexsize:%x", dexbase, dexsize);
300 | }
301 |
302 | void replace_cookie_M(JNIEnv *env, jobject mini_dex_obj, jlong value)
303 | {
304 | jclass DexFileClass = env->FindClass("dalvik/system/DexFile"); // "dalvik/system/DexPathList$Element"
305 | jfieldID field_mCookie;
306 | jobject mCookie;
307 |
308 | field_mCookie = env->GetFieldID(DexFileClass, "mCookie", "Ljava/lang/Object;");
309 | mCookie = env->GetObjectField(mini_dex_obj, field_mCookie);
310 |
311 | jboolean is_data_copy = 1;
312 | jsize arraylen = env->GetArrayLength((jarray)mCookie);
313 | LOGD("[+]g_sdk_int:%d,cookie arrayLen:%d", g_sdk_int, arraylen);
314 |
315 | jlong *mix_element = env->GetLongArrayElements((jlongArray)mCookie, &is_data_copy);
316 |
317 | // 这里的mix_element 等价于openMemory的返回值
318 | int ptr = *(int *)mix_element;
319 | int dexbase = *(int *)(ptr + 4);
320 | int dexsize = *(int *)(ptr + 8);
321 | LOGD("[+]mini dex array len :%d,dex magic:%x,dexsize:%x", arraylen, *(int *)dexbase, dexsize);
322 | // very important
323 | // jlong* tmp=mix_element;
324 | // *tmp=*c_dex_cookie;
325 | *mix_element = value;
326 | // 更新mCookie
327 | env->ReleaseLongArrayElements((jlongArray)mCookie, mix_element, 0);
328 | if (env->ExceptionCheck())
329 | {
330 | LOGE("[-]g_sdk_int:%d Update cookie failed", g_sdk_int);
331 | return;
332 | }
333 | jlong *second_mix_element = env->GetLongArrayElements((jlongArray)mCookie, &is_data_copy);
334 | ptr = *(int *)second_mix_element;
335 | dexbase = *(int *)(ptr + 4);
336 | dexsize = *(int *)(ptr + 8);
337 | LOGD("[+]second minidex dex dex magic:%x,dexsize:%x", *(int *)dexbase, dexsize);
338 | LOGD("[+]replace_cookie_one successful");
339 | } // replace_cookie_M
340 |
341 | char *get_path_frommaps(const char *pkgName, char *buffer, char *filter1, char *filter2)
342 | {
343 | int pid = getpid();
344 | char map[256] = {0};
345 |
346 | sprintf(map, "/proc/%d/maps", pid);
347 | FILE *fd = fopen(map, "r");
348 | if (!fd)
349 | {
350 | LOGE("[-]open %s failed", map);
351 | return NULL;
352 | }
353 |
354 | while (true)
355 | {
356 | char line_buffer[256] = {0};
357 | if (!fgets(line_buffer, 255, fd))
358 | {
359 | break;
360 | }
361 | // 寻找带有包名和.dex或.odex的行
362 | if (strstr(line_buffer, pkgName) && (strstr(line_buffer, filter1) || strstr(line_buffer, filter2)))
363 | {
364 | // LOGD("[+]targt line buffer:%s", line_buffer);
365 | char *p= strchr(line_buffer, '/');
366 | // 获取需要复制的长度
367 | // line_buffer结尾是一个换行符
368 | int len = strlen(line_buffer) - (p- (char *)line_buffer) - 1;
369 | memcpy(buffer, p, len);
370 | return buffer;
371 | }
372 | }
373 | fclose(fd);
374 | return NULL;
375 | }
376 |
377 | jobject load_dex_fromfile(JNIEnv *env, const char *inPath, const char *outPath)
378 | {
379 | jclass DexFileClass = env->FindClass("dalvik/system/DexFile"); // "dalvik/system/DexPathList$Element"
380 | // new DexFile==loadDex
381 | // loadDex方法比方法通用性更好
382 | // jmethodID init = env->GetMethodID(DexFileClass, "", "(Ljava/lang/String;Ljava/lang/String;I)V");
383 | jmethodID init = env->GetStaticMethodID(DexFileClass, "loadDex",
384 | "(Ljava/lang/String;Ljava/lang/String;I)Ldalvik/system/DexFile;");
385 |
386 | if (env->ExceptionCheck())
387 | {
388 | LOGE("[-]get loadDex methodID error");
389 | return 0;
390 | }
391 | jstring apk = env->NewStringUTF(inPath);
392 | jstring odex = env->NewStringUTF(outPath);
393 |
394 | jobject dexobj = env->CallStaticObjectMethod(DexFileClass, init, apk, odex, 0);
395 | if (env->ExceptionCheck())
396 | {
397 | LOGE("[-]loadDex %s dex failed", inPath);
398 | return 0;
399 | }
400 |
401 | env->DeleteLocalRef(DexFileClass);
402 | env->DeleteLocalRef(apk);
403 | env->DeleteLocalRef(odex);
404 |
405 | // try delete mixdexobj localRef
406 | // env->DeleteLocalRef(mixdexobj);
407 | return dexobj;
408 | }
409 |
410 | void *get_lib_handle(const char *lib_path)
411 | {
412 | void *handle_art = dlopen(lib_path, RTLD_NOW);
413 |
414 | if (!handle_art)
415 | {
416 | LOGE("[-]get %s handle failed:%s", lib_path, dlerror());
417 | return NULL;
418 | }
419 | return handle_art;
420 | }
421 |
422 | void write_file(const char *path, void *buffer, int size)
423 | {
424 | FILE *file = fopen(path, "wb");
425 |
426 | if (!file)
427 | {
428 | LOGE("[-]fopen %s error:%s", path, strerror(errno));
429 | return;
430 | }
431 | int return_write = fwrite(buffer, 1, size, file);
432 | if (return_write != size)
433 | {
434 | LOGE("[-]fwrite %s error:%s", path, strerror(errno));
435 | fclose(file);
436 | }
437 | else
438 | {
439 | LOGE("[+]fwrite decrypt data success");
440 | fflush(file);
441 | fclose(file);
442 | }
443 | }
444 |
445 | // char *aes_encrypt_cbc(char *in, int inLen, int *outLen)
446 | // {
447 | // char *inputData = NULL;
448 | // char *out;
449 | // //# define AES_BLOCK_SIZE 16
450 | // unsigned char Key[AES_BLOCK_SIZE + 1];
451 | // unsigned char ivec[AES_BLOCK_SIZE];
452 | // AES_KEY AesKey;
453 |
454 | // //设置密钥key
455 | // memset(Key, 0x00, sizeof(Key));
456 | // memcpy(Key, AES_KEYCODE, AES_BLOCK_SIZE);
457 |
458 | // int nBei = inLen / AES_BLOCK_SIZE + 1;
459 | // int nTotal = nBei * AES_BLOCK_SIZE;
460 |
461 | // *outLen = nTotal;
462 | // //使用PKCS7Padding
463 | // inputData = (char *)calloc(nTotal + 1, 1);
464 | // int nNumber;
465 | // if (inLen % 16)
466 | // {
467 | // nNumber = nTotal - inLen;
468 | // }
469 | // else
470 | // {
471 | // nNumber = 16;
472 | // }
473 |
474 | // memset(inputData, nNumber, nTotal);
475 | // memcpy(inputData, in, inLen);
476 |
477 | // out = (char *)calloc(nTotal + 1, sizeof(char));
478 | // if (out == NULL)
479 | // {
480 | // LOGE("[-]calloc out buffer error");
481 | // exit(-1);
482 | // }
483 |
484 | // //初始化key
485 | // memset(&AesKey, 0x00, sizeof(AES_KEY));
486 | // if (AES_set_encrypt_key(Key, 128, &AesKey) < 0)
487 | // {
488 | // //fprintf(stderr, "Unable to set encryption key in AES...\n");
489 | // LOGE("AES_set_encrypt_key error");
490 | // exit(-1);
491 | // }
492 | // memcpy(ivec, AES_IV, 16);
493 |
494 | // AES_cbc_encrypt((unsigned char *)inputData, (unsigned char *)out,
495 | // nTotal, &AesKey, ivec, AES_ENCRYPT);
496 |
497 | // if (inputData)
498 | // {
499 | // free(inputData);
500 | // }
501 | // return out;
502 | // }
503 |
504 | // //************************************
505 | // // Method: aes_decrypt_cbc
506 | // // Brief: 使用aes/cbc/pkcs5padding解密
507 | // // Access: public
508 | // // Returns: char* 返回解密buffer
509 | // // Qualifier:
510 | // // Parameter: char * in 待解密buffer
511 | // // Parameter: int inLen 待解密buffer len
512 | // // Parameter: int * outLen 返回解密buffer的数据长度
513 | // char *aes_decrypt_cbc(char *in, int inLen, int *outLen)
514 | // {
515 | // char *out;
516 | // //# define AES_BLOCK_SIZE 16
517 | // unsigned char Key[AES_BLOCK_SIZE + 1];
518 | // unsigned char ivec[AES_BLOCK_SIZE];
519 | // AES_KEY AesKey;
520 |
521 | // //设置密钥key
522 | // memset(Key, 0x00, sizeof(Key));
523 | // memcpy(Key, AES_KEYCODE, AES_BLOCK_SIZE);
524 | // memset(&AesKey, 0x00, sizeof(AES_KEY));
525 | // if (AES_set_decrypt_key(Key, 128, &AesKey) < 0)
526 | // { //设置解密密钥
527 | // fprintf(stderr, "Unable to set encryption key in AES...\n");
528 | // exit(-1);
529 | // }
530 | // memcpy(ivec, AES_IV, 16);
531 |
532 | // out = (char *)calloc(inLen + 1, sizeof(char));
533 | // if (out == NULL)
534 | // {
535 | // LOGE("[-]calloc decrypt buffer error");
536 | // exit(-1);
537 | // }
538 | // //解密
539 | // AES_cbc_encrypt((unsigned char *)in, (unsigned char *)out,
540 | // inLen, &AesKey, ivec, AES_DECRYPT);
541 |
542 | // //去掉padding字符串
543 | // //获取padding后的明文长度
544 | // int padLen = inLen;
545 | // //获取pad的值
546 | // int padValue = out[padLen - 1];
547 | // if ((padValue == 0) || (padValue > AES_BLOCK_SIZE))
548 | // {
549 | // //错误的padding,解密失败
550 | // LOGE("[-]decrypt failed");
551 | // return 0;
552 | // }
553 | // *outLen = padLen - padValue;
554 | // out[padLen - padValue] = '\0';
555 | // return out;
556 | // }
557 |
558 | char *tiny_aes_encrypt_cbc(char *in, int inLen, int *outLen)
559 | {
560 |
561 | #define AES_BLOCK_SIZE 16
562 | char *inputData = NULL;
563 | unsigned char Key[AES_BLOCK_SIZE + 1];
564 | unsigned char ivec[AES_BLOCK_SIZE];
565 |
566 | //设置密钥key
567 | memset(Key, 0x00, sizeof(Key));
568 | memcpy(Key, AES_KEYCODE, AES_BLOCK_SIZE);
569 |
570 | //设置ivec
571 | memcpy(ivec, AES_IV, 16);
572 |
573 | int nBei = inLen / AES_BLOCK_SIZE + 1;
574 | int nTotal = nBei * AES_BLOCK_SIZE;
575 |
576 | *outLen = nTotal;
577 |
578 | //使用PKCS5Padding
579 | inputData = (char *)calloc(nTotal + 1, 1);
580 | int nNumber;
581 | if (inLen % 16)
582 | {
583 | nNumber = nTotal - inLen;
584 | }
585 | else
586 | {
587 | nNumber = 16;
588 | }
589 | memset(inputData, nNumber, nTotal);
590 | memcpy(inputData, in, inLen);
591 |
592 | struct AES_ctx ctx;
593 | AES_init_ctx_iv(&ctx, Key, ivec);
594 | AES_CBC_encrypt_buffer(&ctx, (uint8_t *)inputData, (uint32_t)nTotal);
595 |
596 | return inputData;
597 | }
598 |
599 | char *tiny_aes_decrypt_cbc(char *in, int inLen, int *outLen)
600 | {
601 |
602 | #define AES_BLOCK_SIZE 16
603 | unsigned char Key[AES_BLOCK_SIZE + 1];
604 | unsigned char ivec[AES_BLOCK_SIZE];
605 |
606 | //设置密钥key
607 | memset(Key, 0x00, sizeof(Key));
608 | memcpy(Key, AES_KEYCODE, 16);
609 |
610 | memcpy(ivec, AES_IV, 16);
611 |
612 | struct AES_ctx ctx;
613 | AES_init_ctx_iv(&ctx, Key, ivec);
614 |
615 | AES_CBC_decrypt_buffer(&ctx, (uint8_t *)in, (uint32_t)inLen);
616 |
617 | //去掉padding字符串
618 | //获取padding后的明文长度
619 | int padLen = inLen;
620 | //获取pad的值
621 | int padValue = in[padLen - 1];
622 | LOGD("[+]padValue:%d", padValue);
623 |
624 | if ((padValue == 0) || (padValue > AES_BLOCK_SIZE))
625 | {
626 | //错误的padding,解密失败
627 | LOGE("[-]decrypt failed");
628 | return 0;
629 | }
630 | int realLen = padLen - padValue;
631 | *outLen = realLen;
632 | in[padLen - padValue] = '\0';
633 | // char saveFile[0x100] = {0};
634 | // sprintf(saveFile, "%s/dump.dex", g_jiagu_dir);
635 | // FILE *file = fopen(saveFile, "wb");
636 | // fwrite(in, 1, realLen, file);
637 | // fclose(file);
638 | // LOGD("[+]dump.dex saved at %s,size:%d", saveFile, realLen);
639 | return in;
640 | }
641 |
642 | char *parse_file(const char *encrypt_path, int &encrypt_size)
643 | {
644 | FILE *fp = fopen(encrypt_path, "rb+");
645 |
646 | if (!fp)
647 | {
648 | LOGE("[-]fopen %s error:%s", encrypt_path, strerror(errno));
649 | return NULL;
650 | }
651 | fseek(fp, 0L, SEEK_END);
652 | encrypt_size = ftell(fp);
653 | fseek(fp, 0L, SEEK_SET);
654 | char *base = (char *)calloc(encrypt_size + 1, sizeof(char));
655 | if (!base)
656 | {
657 | LOGE("calloc memory failed");
658 | fclose(fp);
659 | return NULL;
660 | }
661 | fread(base, 1, encrypt_size, fp);
662 | fclose(fp);
663 | return base;
664 | }
665 |
666 | void *openmemory_load_dex(void *art_handle, char *base, size_t size, int sdk_int)
667 | {
668 | void *c_dex_cookie;
669 | switch (sdk_int)
670 | {
671 | //android 4.4 art mode
672 | case 19:
673 | c_dex_cookie = mem_loadDex_byte19(art_handle, base, g_dex_size);
674 | break;
675 |
676 | case 21:
677 | c_dex_cookie = mem_loadDex_byte21(art_handle, base, g_dex_size);
678 | break;
679 |
680 | case 22:
681 | c_dex_cookie = mem_loadDex_byte22(art_handle, base, g_dex_size);
682 | break;
683 |
684 | case 23:
685 | c_dex_cookie = mem_loadDex_byte23(art_handle, base, g_dex_size);
686 | break;
687 |
688 | // 7.0 and 7.1
689 | case 24:
690 | case 25:
691 | //c_dex_cookie = mem_loadDex_byte24(g_ArtHandle, (char *)g_decrypt_base, (size_t)g_dex_size);
692 | c_dex_cookie = NULL;
693 | break;
694 |
695 | //8.0
696 | case 26:
697 | case 27:
698 | //reserved
699 | c_dex_cookie = NULL;
700 | break;
701 |
702 | default:
703 | c_dex_cookie = NULL;
704 | break;
705 | }
706 | return c_dex_cookie;
707 | }
708 |
709 | void replace_cookie(JNIEnv *env, jobject mini_dex_obj, void *c_dex_cookie, int sdk_int)
710 | {
711 | jfieldID cookie_field;
712 | jclass DexFileClass = env->FindClass("dalvik/system/DexFile");
713 | if (sdk_int == 19)
714 | {
715 | cookie_field = env->GetFieldID(DexFileClass, "mCookie", "I");
716 | LOGD("[+]sdk_int:%d,cookie_field:%p", g_sdk_int, cookie_field);
717 | env->SetIntField(mini_dex_obj, cookie_field, (int)(long)c_dex_cookie);
718 | }
719 | else if ((sdk_int == 21) || (sdk_int == 22))
720 | {
721 | unique_ptr> dex_files(new vector());
722 | cookie_field = env->GetFieldID(DexFileClass, "mCookie", "J");
723 | //将c_dex_cookie转换为java层的cookie
724 | //jlong realcookie=get_real_cookie(env,c_dex_cookie);
725 | dex_files.get()->push_back(c_dex_cookie);
726 | jlong mCookie = static_cast(reinterpret_cast(dex_files.release()));
727 | env->SetLongField(mini_dex_obj, cookie_field, mCookie);
728 | }
729 | else if (sdk_int == 23)
730 | {
731 | // cookie_field = env->GetFieldID(DexFileClass, "mCookie", "Ljava/lang/Object;");
732 | // dex_files.get()->push_back(c_dex_cookie);
733 | // jlong mCookie = static_cast(reinterpret_cast(dex_files.release()));
734 | // LOGD("c_dex_cookie:%x,mCookie:%x",c_dex_cookie,mCookie);
735 | // env->SetObjectField(mini_dex_obj, cookie_field, (jobject)mCookie);
736 | replace_cookie_M(env, mini_dex_obj, (jlong)c_dex_cookie);
737 | }
738 | else if (sdk_int >= 24)
739 | {
740 | //cookie_field = env->GetFieldID(DexFileClass, "mCookie", "Ljava/lang/Object;");
741 | replace_cookie_N(env, mini_dex_obj, (jlong)c_dex_cookie);
742 | }
743 | }
744 |
745 | jobject hook_load_dex_internally(JNIEnv *env, const char *art_path, char *inPath, char *outPath)
746 | {
747 | void *art_base = get_module_base(getpid(), art_path);
748 | if (!art_base)
749 | {
750 | LOGE("[-]get lib %s base failed", art_path);
751 | return NULL;
752 | }
753 |
754 | #if 1
755 | ElfReader elfReader(art_path, art_base);
756 | if (0 != elfReader.parse())
757 | {
758 | LOGE("failed to parse %s in %d maps at %p", LIB_ART_PATH, getpid(), art_base);
759 | return NULL;
760 | }
761 | elfReader.hook("open", (void *)new_open, (void **)&old_open);
762 | elfReader.hook("read", (void *)new_read, (void **)&old_read);
763 | elfReader.hook("mmap", (void *)new_mmap, (void **)&old_mmap);
764 | elfReader.hook("munmap", (void *)new_munmap, (void **)&old_munmap);
765 | elfReader.hook("__read_chk", (void *)new_read_chk, (void **)&old_read_chk);
766 | elfReader.hook("fstat", (void *)new_fstat, (void **)&old_fstat);
767 | elfReader.hook("fork", (void *)new_fork, (void **)&old_fork);
768 | LOGD("[+]Load fake dex inPath:%s,outPath:%s", inPath, outPath);
769 | jobject faked_dex_obj = load_dex_fromfile(env, inPath, outPath);
770 | LOGD("[+]Load fake dex finished");
771 | //恢复fork和fstat的hook
772 | elfReader.hook("fork", (void *)old_fork, (void **)&old_fork);
773 | elfReader.hook("fstat", (void *)old_fstat, (void **)&old_fstat);
774 | return faked_dex_obj;
775 | #endif
776 | }
777 |
778 |
779 | void mem_loadDex(JNIEnv *env, jobject ctx, const char *dex_path)
780 | {
781 | char inPath[256] = {0};
782 | char outPath[256] = {0};
783 | jobject mini_dex_obj = NULL;
784 | void *c_dex_cookie = NULL;
785 |
786 | jclass ApplicationClass = env->GetObjectClass(ctx);
787 | jmethodID getClassLoader = env->GetMethodID(ApplicationClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
788 | jobject classLoader = env->CallObjectMethod(ctx, getClassLoader);
789 |
790 | char szDexPath[256] = {0};
791 |
792 | sprintf((char *)szDexPath, dex_path, strlen(dex_path));
793 | LOGD("[+]Dex Path:%s", szDexPath);
794 | //读取加密dex
795 | int encrypt_size;
796 | char *encrypt_buffer = parse_file(szDexPath, encrypt_size);
797 | //check dex size
798 | if (!encrypt_size)
799 | {
800 | LOGE("[-]encrypt_size is 0");
801 | exit(-1);
802 | }
803 | else if (encrypt_size % 16)
804 | {
805 | LOGE("[-]encrypt_size is not mutiple 16");
806 | exit(-1);
807 | }
808 |
809 | int zero = open("/dev/zero", PROT_WRITE);
810 | g_decrypt_base = mmap(0, encrypt_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zero, 0);
811 | close(zero);
812 | if (g_decrypt_base == MAP_FAILED)
813 | {
814 | LOGE("[-]ANONYMOUS mmap failed:%s", strerror(errno));
815 | exit(-1);
816 | }
817 | //LOGD("[+]ANONYMOUS mmap addr:%p", g_decrypt_base);
818 | char decrypt_path[256] = {0};
819 | sprintf((char *)decrypt_path, "%s/decrypt.dat", g_jiagu_dir);
820 | //char *decrypt_buffer = aes_decrypt_cbc(encrypt_buffer, encrypt_size, &g_dex_size);
821 | char *decrypt_buffer = tiny_aes_decrypt_cbc(encrypt_buffer, encrypt_size, &g_dex_size);
822 | if (!decrypt_buffer)
823 | {
824 | LOGE("[-]aes_decrypt_cbc decrypt dex failed");
825 | exit(-1);
826 | }
827 |
828 | memcpy(g_decrypt_base, decrypt_buffer, g_dex_size);
829 | g_page_size = PAGE_END(g_dex_size);
830 | free(decrypt_buffer);
831 |
832 | LOGD("[+]After decrypt dex magic:0x%x,size:%d,page_size:%d", *(int *)g_decrypt_base, g_dex_size, g_page_size);
833 |
834 | if (!g_isArt)
835 | {
836 | jint mCookie = mem_loadDex_dvm(env, (char *)szDexPath);
837 | LOGD("[+]Dalvik dex cookie :0x%x", mCookie);
838 | jclass DexFileClass = env->FindClass("dalvik/system/DexFile");
839 | jfieldID cookie_field = env->GetFieldID(DexFileClass, "mCookie", "I");
840 | //replace cookie
841 | env->SetIntField(mini_dex_obj, cookie_field, mCookie);
842 | make_dex_elements(env, classLoader, mini_dex_obj);
843 | return;
844 | }
845 | else
846 | {
847 | sprintf(inPath, "%s/mini.dex", g_jiagu_dir);
848 | sprintf(outPath, "%s/mini.oat", g_jiagu_dir);
849 | write_mix_dex(inPath);
850 | g_ArtHandle = get_lib_handle(LIB_ART_PATH);
851 | if (g_ArtHandle)
852 | {
853 | c_dex_cookie = openmemory_load_dex(g_ArtHandle, (char *)g_decrypt_base, (size_t)g_dex_size, g_sdk_int);
854 | LOGD("[+]sdk_int :%d,c_dex_cookie:%p", g_sdk_int, c_dex_cookie);
855 | if (c_dex_cookie)
856 | {
857 | // 加载mini.dex
858 | mini_dex_obj = load_dex_fromfile(env, inPath, outPath);
859 | replace_cookie(env, mini_dex_obj, c_dex_cookie, g_sdk_int);
860 | make_dex_elements(env, classLoader, mini_dex_obj);
861 | LOGD("[+]using fast plan load dex finished");
862 | }
863 | else
864 | {
865 | // 执行方案二
866 | LOGD("[-]get c_dex_cookie failed! Try second plan");
867 | goto label:
868 | }
869 | }
870 | else
871 | {
872 | LOGD("[-]get art handle failed! Try second plan");
873 | label:
874 | get_path_frommaps(g_pkgName, (char *)g_fake_dex_path, (char *)".dex", (char *)".odex");
875 | LOGD("[+]faked_path:%s",(char*)g_fake_dex_path);
876 | // memcpy((char *)g_fake_dex_path, (char *)buffer, strlen((char *)inPath));
877 | mini_dex_obj = hook_load_dex_internally(env, (const char *)LIB_ART_PATH, (char *)g_fake_dex_path, outPath);
878 |
879 | make_dex_elements(env, classLoader, mini_dex_obj);
880 | LOGD("[+]using second plan load dex finished");
881 | }
882 |
883 | if (g_ArtHandle)
884 | {
885 | dlclose(g_ArtHandle);
886 | }
887 | return;
888 | }
889 | }
890 |
891 | void native_attachBaseContext(JNIEnv *env, jobject thiz, jobject ctx)
892 | {
893 | #if defined(__arm__)
894 | LOGD("[+]Running arm libdexload");
895 | #elif defined(__aarch64__)
896 | LOGD("[+]Running aarch64 libdexload");
897 |
898 | #endif
899 |
900 | jclass ApplicationClass = env->GetObjectClass(ctx);
901 | jmethodID getFilesDir = env->GetMethodID(ApplicationClass, "getFilesDir", "()Ljava/io/File;");
902 | jobject File_obj = env->CallObjectMethod(ctx, getFilesDir);
903 | jclass FileClass = env->GetObjectClass(File_obj);
904 |
905 | jmethodID getAbsolutePath = env->GetMethodID(FileClass, "getAbsolutePath", "()Ljava/lang/String;");
906 | jstring data_file_dir = static_cast(env->CallObjectMethod(File_obj, getAbsolutePath));
907 |
908 | g_file_dir = env->GetStringUTFChars(data_file_dir, NULL);
909 | //g_file_dir_backup=g_file_dir;
910 | LOGD("[+]FilesDir:%s", g_file_dir);
911 | env->DeleteLocalRef(data_file_dir);
912 | env->DeleteLocalRef(File_obj);
913 | env->DeleteLocalRef(FileClass);
914 |
915 | // NativeLibraryDir
916 | jmethodID getApplicationInfo = env->GetMethodID(ApplicationClass, "getApplicationInfo",
917 | "()Landroid/content/pm/ApplicationInfo;");
918 | jobject ApplicationInfo_obj = env->CallObjectMethod(ctx, getApplicationInfo);
919 | jclass ApplicationInfoClass = env->GetObjectClass(ApplicationInfo_obj);
920 | jfieldID nativeLibraryDir_field = env->GetFieldID(ApplicationInfoClass, "nativeLibraryDir", "Ljava/lang/String;");
921 | jstring nativeLibraryDir = (jstring)(env->GetObjectField(ApplicationInfo_obj, nativeLibraryDir_field));
922 |
923 | g_NativeLibDir = env->GetStringUTFChars(nativeLibraryDir, NULL);
924 | LOGD("[+]NativeLibDir:%s", g_NativeLibDir);
925 |
926 | env->DeleteLocalRef(nativeLibraryDir);
927 | env->DeleteLocalRef(ApplicationInfoClass);
928 | env->DeleteLocalRef(ApplicationInfo_obj);
929 |
930 | jmethodID getPackageResourcePath = env->GetMethodID(ApplicationClass, "getPackageResourcePath",
931 | "()Ljava/lang/String;");
932 |
933 | jstring mPackageFilePath = static_cast(env->CallObjectMethod(ctx, getPackageResourcePath));
934 | const char *cmPackageFilePath = env->GetStringUTFChars(mPackageFilePath, NULL);
935 | g_PackageResourcePath = const_cast(cmPackageFilePath);
936 | LOGD("[+]PackageResourcePath:%s", g_PackageResourcePath);
937 | env->DeleteLocalRef(mPackageFilePath);
938 |
939 | jmethodID getPackageName = env->GetMethodID(ApplicationClass, "getPackageName", "()Ljava/lang/String;");
940 | jstring PackageName = static_cast(env->CallObjectMethod(ctx, getPackageName));
941 | const char *packagename = env->GetStringUTFChars(PackageName, NULL);
942 | g_pkgName = (char *)packagename;
943 | LOGD("[+]g_pkgName :%s", g_pkgName);
944 | env->DeleteLocalRef(PackageName);
945 |
946 | char jiaguPath[256] = {0}; // 加密dex的存储路径
947 |
948 | sprintf(g_jiagu_dir, "%s/%s", g_file_dir, PACKER_MAGIC);
949 | sprintf(jiaguPath, "%s/%s", g_jiagu_dir, JIAMI_MAGIC);
950 | LOGD("[+]g_jiagu_dir:%s,jiaguPath:%s", g_jiagu_dir, jiaguPath);
951 | if (access(g_jiagu_dir, F_OK) != 0)
952 | {
953 | if (mkdir(g_jiagu_dir, 0755) == -1)
954 | {
955 | LOGE("[-]mkdir %s error:%s", g_jiagu_dir, strerror(errno));
956 | }
957 | }
958 | //从assets目录提取加密dex
959 | extract_file(env, ctx, jiaguPath, JIAMI_MAGIC);
960 | mem_loadDex(env, ctx, jiaguPath);
961 | } // native_attachBaseContext
962 |
963 | void native_onCreate(JNIEnv *env, jobject thiz, jobject instance)
964 | {
965 | LOGD("[+]native onCreate is called");
966 | jclass ProxyApplicationClass = env->GetObjectClass(instance);
967 | jmethodID getPackageManager = env->GetMethodID(ProxyApplicationClass, "getPackageManager", "()Landroid/content/pm/PackageManager;");
968 | if (env->ExceptionCheck())
969 | {
970 | LOGE("[-]find getPackageManager methodID failed");
971 | return;
972 | }
973 | jobject packageManager = env->CallObjectMethod(instance, getPackageManager);
974 | if (env->ExceptionCheck())
975 | {
976 | LOGE("[-]call getPackageManager method failed");
977 | return;
978 | }
979 | jmethodID pmGetApplicationInfo = env->GetMethodID(env->GetObjectClass(packageManager), "getApplicationInfo", "(Ljava/lang/String;I)Landroid/content/pm/ApplicationInfo;");
980 | jmethodID getPackageName = env->GetMethodID(ProxyApplicationClass, "getPackageName", "()Ljava/lang/String;");
981 | jobject pmAppInfo = env->CallObjectMethod(packageManager, pmGetApplicationInfo, env->CallObjectMethod(instance, getPackageName), 128);
982 |
983 | jclass PackageItemInfoClass = env->FindClass("android/content/pm/PackageItemInfo");
984 |
985 | jfieldID metaDataField = env->GetFieldID(PackageItemInfoClass, "metaData", "Landroid/os/Bundle;");
986 | jobject metaData = env->GetObjectField(pmAppInfo, metaDataField);
987 | if (metaData == NULL)
988 | {
989 | LOGE("[-]not found meta Bundle");
990 | return;
991 | }
992 |
993 | jmethodID bundleGetString = env->GetMethodID(env->GetObjectClass(metaData), "getString", "(Ljava/lang/String;)Ljava/lang/String;");
994 | //found orignal ApplicationName
995 | jstring originApplicationName = (jstring)env->CallObjectMethod(metaData, bundleGetString, env->NewStringUTF("APP_NAME"));
996 | if (originApplicationName == NULL)
997 | {
998 | LOGE("[-]not found original Application Name");
999 | return;
1000 | }
1001 | LOGD("[+]original Application Name : %s", env->GetStringUTFChars(originApplicationName, NULL));
1002 |
1003 | //将LoadedApk中的mApplication对象替换
1004 | jclass ActivityThreadClass = env->FindClass("android/app/ActivityThread");
1005 | jmethodID currentActivityThread = env->GetStaticMethodID(ActivityThreadClass, "currentActivityThread", "()Landroid/app/ActivityThread;");
1006 | jobject activityThread = env->CallStaticObjectMethod(ActivityThreadClass, currentActivityThread);
1007 | LOGE("get ActivityThreadClass");
1008 | //得到AppBindData
1009 | jfieldID mBoundApplicationField = env->GetFieldID(ActivityThreadClass, "mBoundApplication", "Landroid/app/ActivityThread$AppBindData;");
1010 | jobject mBoundApplication = env->GetObjectField(activityThread, mBoundApplicationField);
1011 | LOGE("get AppBindData");
1012 | //得到LoadedApk
1013 | jfieldID infoField = env->GetFieldID(env->GetObjectClass(mBoundApplication), "info", "Landroid/app/LoadedApk;");
1014 | jobject info = env->GetObjectField(mBoundApplication, infoField);
1015 | LOGE("get LoadedApk");
1016 | //把LoadedApk中的成员变量private Application mApplication;置空
1017 | jfieldID mApplicationField = env->GetFieldID(env->GetObjectClass(info), "mApplication", "Landroid/app/Application;");
1018 | env->SetObjectField(info, mApplicationField, NULL);
1019 | LOGE("mApplication set null");
1020 | //得到壳Application
1021 | jfieldID mInitialApplicationField = env->GetFieldID(ActivityThreadClass, "mInitialApplication", "Landroid/app/Application;");
1022 | jobject mInitialApplication = env->GetObjectField(activityThread, mInitialApplicationField);
1023 | LOGE("get packer Application");
1024 |
1025 | //将壳Application移除
1026 | jfieldID mAllApplicationsField = env->GetFieldID(ActivityThreadClass, "mAllApplications", "Ljava/util/ArrayList;");
1027 | jobject mAllApplications = env->GetObjectField(activityThread, mAllApplicationsField);
1028 | jmethodID remove = env->GetMethodID(env->GetObjectClass(mAllApplications), "remove", "(Ljava/lang/Object;)Z");
1029 | env->CallBooleanMethod(mAllApplications, remove, mInitialApplication);
1030 | LOGE("remove packer Application");
1031 | //得到AppBindData中的ApplicationInfo
1032 | jfieldID appInfoField = env->GetFieldID(env->GetObjectClass(mBoundApplication), "appInfo", "Landroid/content/pm/ApplicationInfo;");
1033 | jobject appInfo = env->GetObjectField(mBoundApplication, appInfoField);
1034 | LOGE("get AppBindData's ApplicationInfo");
1035 | //得到LoadedApk中的ApplicationInfo
1036 | jfieldID mApplicationInfoField = env->GetFieldID(env->GetObjectClass(info), "mApplicationInfo", "Landroid/content/pm/ApplicationInfo;");
1037 | jobject mApplicationInfo = env->GetObjectField(info, mApplicationInfoField);
1038 | LOGE("get LoadedApk's ApplicationInfo");
1039 | //替换掉ApplicationInfo中的className
1040 | jfieldID classNameField = env->GetFieldID(env->GetObjectClass(appInfo), "className", "Ljava/lang/String;");
1041 | env->SetObjectField(appInfo, classNameField, originApplicationName);
1042 | env->SetObjectField(mApplicationInfo, classNameField, originApplicationName);
1043 | LOGE("replace ApplicationInfo's className");
1044 | //创建新的Application
1045 | jmethodID makeApplication = env->GetMethodID(env->GetObjectClass(info), "makeApplication", "(ZLandroid/app/Instrumentation;)Landroid/app/Application;");
1046 | //这里调用原始app的attacheBaseContext
1047 | jobject originApp = env->CallObjectMethod(info, makeApplication, false, NULL);
1048 | LOGE("create new Application");
1049 | //将句柄赋值到mInitialApplicationField
1050 | env->SetObjectField(activityThread, mInitialApplicationField, originApp);
1051 | LOGE("set object mInitialApplicationField");
1052 | jfieldID mProviderMapField;
1053 | if (g_sdk_int < 19)
1054 | {
1055 | mProviderMapField = env->GetFieldID(ActivityThreadClass, "mProviderMap", "Ljava/util/HashMap;");
1056 | }
1057 | else
1058 | {
1059 | mProviderMapField = env->GetFieldID(ActivityThreadClass, "mProviderMap", "Landroid/util/ArrayMap;");
1060 | }
1061 | if (mProviderMapField == NULL)
1062 | {
1063 | LOGE("not found mProviderMapField");
1064 | return;
1065 | }
1066 | LOGE("found mProviderMapField");
1067 | jobject mProviderMap = env->GetObjectField(activityThread, mProviderMapField);
1068 | LOGE("found mProviderMap");
1069 | jmethodID values = env->GetMethodID(env->GetObjectClass(mProviderMap), "values", "()Ljava/util/Collection;");
1070 | jobject collections = env->CallObjectMethod(mProviderMap, values);
1071 | jmethodID iterator = env->GetMethodID(env->GetObjectClass(collections), "iterator", "()Ljava/util/Iterator;");
1072 | jobject mIterator = env->CallObjectMethod(collections, iterator);
1073 | jmethodID hasNext = env->GetMethodID(env->GetObjectClass(mIterator), "hasNext", "()Z");
1074 | jmethodID next = env->GetMethodID(env->GetObjectClass(mIterator), "next", "()Ljava/lang/Object;");
1075 |
1076 | //替换所有ContentProvider中的Context
1077 | LOGE("ready replace all ContentProvider's context");
1078 | while (env->CallBooleanMethod(mIterator, hasNext))
1079 | {
1080 | jobject providerClientRecord = env->CallObjectMethod(mIterator, next);
1081 | if (providerClientRecord == NULL)
1082 | {
1083 | LOGE("providerClientRecord = NULL");
1084 | continue;
1085 | }
1086 | jclass ProviderClientRecordClass = env->FindClass("android/app/ActivityThread$ProviderClientRecord");
1087 | jfieldID mLocalProviderField = env->GetFieldID(ProviderClientRecordClass, "mLocalProvider", "Landroid/content/ContentProvider;");
1088 | if (mLocalProviderField == NULL)
1089 | {
1090 | LOGE("mLocalProviderField not found");
1091 | continue;
1092 | }
1093 | jobject mLocalProvider = env->GetObjectField(providerClientRecord, mLocalProviderField);
1094 | if (mLocalProvider == NULL)
1095 | {
1096 | LOGE("mLocalProvider is NULL");
1097 | continue;
1098 | }
1099 | jfieldID mContextField = env->GetFieldID(env->GetObjectClass(mLocalProvider), "mContext", "Landroid/content/Context;");
1100 | if (mContextField == NULL)
1101 | {
1102 | LOGE("mContextField not found");
1103 | continue;
1104 | }
1105 | env->SetObjectField(mLocalProvider, mContextField, originApp);
1106 | }
1107 |
1108 | //执行originApp的onCreate
1109 | jmethodID onCreate = env->GetMethodID(env->GetObjectClass(originApp), "onCreate", "()V");
1110 | env->CallVoidMethod(originApp, onCreate);
1111 | LOGD("Packer is done");
1112 | }
1113 |
1114 | void init(JNIEnv *env)
1115 | {
1116 | jclass jclazz = env->FindClass("android/os/Build$VERSION");
1117 | jfieldID SDK_INT = env->GetStaticFieldID(jclazz, "SDK_INT", "I");
1118 |
1119 | g_sdk_int = env->GetStaticIntField(jclazz, SDK_INT);
1120 | LOGD("[+]sdk_int:%d", g_sdk_int);
1121 | if (g_sdk_int > 13)
1122 | {
1123 | jclass System = env->FindClass("java/lang/System");
1124 | jmethodID System_getProperty = env->GetStaticMethodID(System, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;");
1125 |
1126 | jstring vm_version_name = env->NewStringUTF("java.vm.version");
1127 | jstring vm_version_value = (jstring)(env->CallStaticObjectMethod(System, System_getProperty, vm_version_name));
1128 |
1129 | char *cvm_version_value = (char *)env->GetStringUTFChars(vm_version_value, NULL);
1130 | double version = atof(cvm_version_value);
1131 | g_isArt = version >= 2 ? true : false;
1132 | LOGD("[+]Android VmVersion:%f", version);
1133 |
1134 | env->ReleaseStringUTFChars(vm_version_value, cvm_version_value);
1135 | env->DeleteLocalRef(System);
1136 | env->DeleteLocalRef(vm_version_name);
1137 | env->DeleteLocalRef(vm_version_value);
1138 | }
1139 | else
1140 | {
1141 | LOGE("[-]unsupported Android version");
1142 | assert(false);
1143 | }
1144 | jniRegisterNativeMethods(env, "com/storm/fengyue/Native",
1145 | methods, sizeof(methods) / sizeof(methods[0]));
1146 | env->DeleteLocalRef(jclazz);
1147 | }
1148 |
1149 | __attribute__((visibility("default"))) JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
1150 | {
1151 | JNIEnv *env = NULL;
1152 |
1153 | if (vm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK)
1154 | {
1155 | return -1;
1156 | }
1157 | init(env);
1158 | return JNI_VERSION_1_6;
1159 | }
1160 |
--------------------------------------------------------------------------------
/jni/packer.h:
--------------------------------------------------------------------------------
1 | #ifndef PACKER_H
2 | #define PACKER_H
3 |
4 |
5 | typedef unsigned char u1;
6 | typedef unsigned short u2;
7 | typedef unsigned int u4;
8 |
9 |
10 | extern void* g_decrypt_base;
11 | extern int g_dex_size;
12 | extern int g_page_size;
13 | extern char g_fake_dex_magic[256];
14 | extern const char* g_file_dir;
15 | extern int g_sdk_int;
16 | #endif
17 |
--------------------------------------------------------------------------------
/jni/utils.cpp:
--------------------------------------------------------------------------------
1 | #include "utils.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | #include "elfGotHook/logger.h"
18 |
19 | #if 0
20 | unsigned int search_symbol_fromelf(char *lib_path, unsigned int lib_base_addr, char *target)
21 | {
22 | if (!lib_base_addr)
23 | {
24 | return 0;
25 | }
26 |
27 | int fd = open(lib_path, O_RDONLY);
28 | if (!fd)
29 | {
30 | return 0;
31 | }
32 |
33 | int size = lseek(fd, 0, SEEK_END);
34 | lseek(fd, 0, SEEK_SET);
35 | char *buffer = (char *)mmap(0, size, 1, 2, fd, 0);
36 | if (!buffer)
37 | {
38 | close(fd);
39 | return 0;
40 | }
41 | short e_phnum = *(short *)(buffer + 0x2C);
42 | LOGD("[+]%s->e_phnum:%d", lib_path, e_phnum);
43 | int program_table = buffer + 0x34;
44 | int program_table_end = program_table + 0x20 * e_phnum;
45 | unsigned int ptr = program_table;
46 | unsigned int pt_load_base = 0xfffffff;
47 | bool find_pt_load = false;
48 | unsigned int result = 0;
49 |
50 | #define PT_LOAD 1
51 | #define PT_DYNAMIC 2
52 | #define DT_STRTAB 5
53 | #define DT_SYMTAB 6
54 | #define DT_STRSZ 10
55 | do
56 | {
57 | if (*(int *)ptr != PT_LOAD)
58 | {
59 | ptr += 0x20;
60 | continue;
61 | }
62 | find_pt_load = 1;
63 | if (pt_load_base > *(unsigned int *)(ptr + 8))
64 | {
65 | pt_load_base = *(unsigned int *)(ptr + 8);
66 | }
67 | ptr += 0x20;
68 | } while (ptr != program_table_end);
69 |
70 | if (find_pt_load)
71 | {
72 | if (pt_load_base)
73 | {
74 | pt_load_base = pt_load_base & 0xfffff000;
75 | }
76 | LOGD("[+]pt_load p_vaddr:%08x", pt_load_base);
77 | }
78 | else
79 | {
80 | return 0;
81 | }
82 | ptr = program_table;
83 | unsigned int d_ptr;
84 | unsigned int strtab_addr = 0;
85 | unsigned int symtab_addr = 0;
86 | unsigned int strsz_addr = 0;
87 | do
88 | {
89 | if (*(int *)ptr == PT_DYNAMIC)
90 | {
91 | unsigned int pt_dynamic_vaddr = *(unsigned int *)(ptr + 8);
92 | unsigned int file_to_mem_offset = lib_base_addr - pt_load_base;
93 | // b3d9c000
94 | unsigned int dynamic_addr = file_to_mem_offset + pt_dynamic_vaddr; // 我的result:b4205ae4
95 | LOGD("[+]pt_dynamic_vaddr:%08x,lib_base_addr:%08x,pt_load_based:%08x,ynamic_addr:%08x", pt_dynamic_vaddr,
96 | lib_base_addr, pt_load_base, dynamic_addr);
97 | if (dynamic_addr)
98 | {
99 | int d_tag = *(int *)dynamic_addr;
100 | int *next = (int *)(dynamic_addr + 8);
101 | do
102 | {
103 | switch (d_tag)
104 | {
105 | case DT_SYMTAB:
106 | symtab_addr = file_to_mem_offset + *(next - 1);
107 | // LOGD("[+]symtab_addr offset:%08x",*(next - 1));//0xB1C0
108 | break;
109 |
110 | case DT_STRSZ:
111 | strsz_addr = *(next - 1);
112 | // LOGD("[+]strsz_addr offset:%08x",*(next - 1));//0x61797
113 | break;
114 |
115 | case DT_STRTAB:
116 | strtab_addr = file_to_mem_offset + *(next - 1); // 0x22f00
117 | // LOGD("[+]strtab_addr offset:%08x",*(next - 1));
118 | break;
119 | }
120 | d_tag = *next;
121 | next += 2;
122 | } while (d_tag);
123 | LOGD("[+]find strtab:%08x,symtab,%08x", strtab_addr, symtab_addr);
124 | int p_sym = symtab_addr;
125 | while (memcmp((char *)(strtab_addr + *(int *)(p_sym)), target, strlen(target)) != 0)
126 | {
127 | if ((unsigned int)p_sym >= strtab_addr)
128 | {
129 | LOGE("[-]Unexcepted symtab>=strtab");
130 | result = 0;
131 | goto label;
132 | }
133 | p_sym += 16;
134 | }
135 | result = file_to_mem_offset + *(unsigned int *)(p_sym + 4);
136 | LOGD("[+]get %s addr:%08x", target, result);
137 | break;
138 | }
139 | }
140 | ptr += 0x20;
141 | } while ((int)ptr != program_table_end);
142 |
143 | label:
144 | munmap((void *)buffer, (size_t)size);
145 | close(fd);
146 | return result;
147 | } // search_symbol_fromelf
148 |
149 |
150 | void *get_addr_symbol(char *module_name, char *target_symbol)
151 | {
152 | void *module_base = get_module_base(-1, module_name);
153 |
154 | if (!module_base)
155 | {
156 | LOGE("[-]get module %s base failed", module_name);
157 | return 0;
158 | }
159 | void *result = (void *)search_symbol_fromelf(module_name, (unsigned int)module_base, target_symbol);
160 | if (!result)
161 | {
162 | LOGE("[-]search symbol %s from %s failed", target_symbol, module_name);
163 | return NULL;
164 | }
165 | return result;
166 | }
167 | #endif
168 |
169 | int extract_file(JNIEnv *env, jobject ctx, const char *szDexPath, const char *fileName)
170 | {
171 | if (access(szDexPath, F_OK) == 0)
172 | {
173 | LOGD("[+]File %s have existed", szDexPath);
174 | return 0;
175 | }
176 | // jiami.dat不存在,开始提取
177 | else
178 | {
179 | AAssetManager *mgr;
180 | jclass ApplicationClass = env->GetObjectClass(ctx);
181 | jmethodID getAssets =
182 | env->GetMethodID(ApplicationClass, "getAssets", "()Landroid/content/res/AssetManager;");
183 | jobject Assets_obj = env->CallObjectMethod(ctx, getAssets);
184 | mgr = AAssetManager_fromJava(env, Assets_obj);
185 | if (mgr == NULL)
186 | {
187 | LOGE("[-]getAAssetManager failed");
188 | return 0;
189 | }
190 | AAsset *asset = AAssetManager_open(mgr, fileName, AASSET_MODE_STREAMING);
191 | FILE *file = fopen(szDexPath, "wb");
192 | int bufferSize = AAsset_getLength(asset);
193 | LOGD("[+]Asset FileName:%s,extract path:%s,size:%d\n", fileName, szDexPath, bufferSize);
194 | void *buffer = malloc(4096);
195 | while (true)
196 | {
197 | int numBytesRead = AAsset_read(asset, buffer, 4096);
198 | if (numBytesRead <= 0)
199 | {
200 | break;
201 | }
202 | fwrite(buffer, numBytesRead, 1, file);
203 | }
204 | free(buffer);
205 | fclose(file);
206 | AAsset_close(asset);
207 | chmod(szDexPath, 493);
208 | }
209 | } // extract_file
210 |
211 | void *get_module_base(pid_t pid, const char *module_name)
212 | {
213 | FILE *fp;
214 | long addr = 0;
215 | char *pch;
216 | char filename[32];
217 | char line[1024];
218 |
219 | if (pid < 0)
220 | {
221 | /* self process */
222 | snprintf(filename, sizeof(filename), "/proc/self/maps", pid);
223 | }
224 | else
225 | {
226 | snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
227 | }
228 |
229 | fp = fopen(filename, "r");
230 |
231 | if (fp != NULL)
232 | {
233 | while (fgets(line, sizeof(line), fp))
234 | {
235 | if (strstr(line, module_name))
236 | {
237 | pch = strtok(line, "-");
238 | addr = strtoull(pch, NULL, 16);
239 |
240 | if (addr == 0x8000)
241 | {
242 | addr = 0;
243 | }
244 |
245 | break;
246 | }
247 | }
248 |
249 | fclose(fp);
250 | }
251 |
252 | return (void *)addr;
253 | } // get_module_base
254 |
--------------------------------------------------------------------------------
/jni/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef _BANGCLE_UTILS_H
2 | #define _BANGCLE_UTILS_H
3 | #include
4 | #include
5 |
6 | int extract_file(JNIEnv *env, jobject ctx, const char *szDexPath, const char *fileName);
7 | void *get_module_base(pid_t pid, const char *module_name);
8 | void *get_addr_symbol(char *module_name, char *target_symbol);
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------