├── .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
├── hook_instance.cpp
├── hook_instance.h
├── log.h
├── log.txt
├── packe_bak.cpp
├── packer.cpp
├── packer.h
├── solist.h
├── util.c
├── util.h
├── utils.cpp
├── utils.h
└── xhook
├── queue.h
├── tree.h
├── xh_core.c
├── xh_core.h
├── xh_elf.c
├── xh_elf.h
├── xh_errno.h
├── xh_jni.c
├── xh_log.c
├── xh_log.h
├── xh_util.c
├── xh_util.h
├── xh_version.c
├── xh_version.h
├── xhook.c
└── xhook.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/lpcdma/Bangcle/d3e3dd3fd0d058cbb8d2c12249082110c6a96817/bangcle_tool/Bangcle.jar
--------------------------------------------------------------------------------
/bangcle_tool/libs/dom4j-2.0.0-RC1-sources.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lpcdma/Bangcle/d3e3dd3fd0d058cbb8d2c12249082110c6a96817/bangcle_tool/libs/dom4j-2.0.0-RC1-sources.jar
--------------------------------------------------------------------------------
/bangcle_tool/libs/dom4j-2.0.0-RC1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lpcdma/Bangcle/d3e3dd3fd0d058cbb8d2c12249082110c6a96817/bangcle_tool/libs/dom4j-2.0.0-RC1.jar
--------------------------------------------------------------------------------
/bangcle_tool/libs/zip4j_1.3.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lpcdma/Bangcle/d3e3dd3fd0d058cbb8d2c12249082110c6a96817/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/lpcdma/Bangcle/d3e3dd3fd0d058cbb8d2c12249082110c6a96817/bangcle_tool/tools/apktool.jar
--------------------------------------------------------------------------------
/bangcle_tool/tools/libdexload_a64.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lpcdma/Bangcle/d3e3dd3fd0d058cbb8d2c12249082110c6a96817/bangcle_tool/tools/libdexload_a64.so
--------------------------------------------------------------------------------
/bangcle_tool/tools/libdexload_arm.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lpcdma/Bangcle/d3e3dd3fd0d058cbb8d2c12249082110c6a96817/bangcle_tool/tools/libdexload_arm.so
--------------------------------------------------------------------------------
/bangcle_tool/tools/signapk.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lpcdma/Bangcle/d3e3dd3fd0d058cbb8d2c12249082110c6a96817/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 | .registers 1
9 |
10 | .line 5
11 | invoke-direct {p0}, Ljava/lang/Object;->()V
12 |
13 | return-void
14 | .end method
15 |
16 | .method public static native attachBaseContext(Landroid/content/Context;)V
17 | .end method
18 |
19 | .method public static native onCreate(Landroid/content/Context;)V
20 | .end method
21 |
--------------------------------------------------------------------------------
/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 | .registers 1
15 |
16 | .line 16
17 | const-string v0, "fengyue"
18 |
19 | sput-object v0, Lcom/storm/fengyue/StubApplication;->TAG:Ljava/lang/String;
20 |
21 | .line 17
22 | const-string v0, "libdexload"
23 |
24 | sput-object v0, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
25 |
26 | return-void
27 | .end method
28 |
29 | .method public constructor ()V
30 | .registers 1
31 |
32 | .line 15
33 | invoke-direct {p0}, Landroid/app/Application;->()V
34 |
35 | return-void
36 | .end method
37 |
38 | .method public static copy(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
39 | .registers 13
40 | .param p0, "context" # Landroid/content/Context;
41 | .param p1, "asset_soname" # Ljava/lang/String;
42 | .param p2, "str2" # Ljava/lang/String;
43 | .param p3, "str3" # Ljava/lang/String;
44 |
45 | .line 46
46 | new-instance v0, Ljava/lang/StringBuilder;
47 |
48 | invoke-static {p2}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
49 |
50 | move-result-object v1
51 |
52 | invoke-direct {v0, v1}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
53 |
54 | sget-object v1, Ljava/io/File;->separator:Ljava/lang/String;
55 |
56 | invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
57 |
58 | invoke-virtual {v0, p3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
59 |
60 | invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
61 |
62 | move-result-object v0
63 |
64 | .line 47
65 | .local v0, "so_dest":Ljava/lang/String;
66 | new-instance v1, Ljava/io/File;
67 |
68 | invoke-direct {v1, p2}, Ljava/io/File;->(Ljava/lang/String;)V
69 |
70 | .line 48
71 | .local v1, "file":Ljava/io/File;
72 | invoke-virtual {v1}, Ljava/io/File;->exists()Z
73 |
74 | move-result v2
75 |
76 | if-nez v2, :cond_23
77 |
78 | .line 49
79 | invoke-virtual {v1}, Ljava/io/File;->mkdir()Z
80 |
81 | .line 51
82 | :cond_23
83 | new-instance v2, Ljava/io/File;
84 |
85 | invoke-direct {v2, v0}, Ljava/io/File;->(Ljava/lang/String;)V
86 |
87 | move-object v1, v2
88 |
89 | .line 53
90 | const/4 v2, 0x0
91 |
92 | :try_start_2a
93 | invoke-virtual {v1}, Ljava/io/File;->exists()Z
94 |
95 | move-result v3
96 |
97 | if-eqz v3, :cond_6a
98 |
99 | .line 55
100 | invoke-virtual {p0}, Landroid/content/Context;->getResources()Landroid/content/res/Resources;
101 |
102 | move-result-object v3
103 |
104 | invoke-virtual {v3}, Landroid/content/res/Resources;->getAssets()Landroid/content/res/AssetManager;
105 |
106 | move-result-object v3
107 |
108 | invoke-virtual {v3, p1}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream;
109 |
110 | move-result-object v3
111 |
112 | .line 56
113 | .local v3, "open":Ljava/io/InputStream;
114 | new-instance v4, Ljava/io/FileInputStream;
115 |
116 | invoke-direct {v4, v1}, Ljava/io/FileInputStream;->(Ljava/io/File;)V
117 |
118 | .line 57
119 | .local v4, "fileInputStream":Ljava/io/InputStream;
120 | new-instance v5, Ljava/io/BufferedInputStream;
121 |
122 | invoke-direct {v5, v3}, Ljava/io/BufferedInputStream;->(Ljava/io/InputStream;)V
123 |
124 | .line 58
125 | .local v5, "bufferedInputStream":Ljava/io/BufferedInputStream;
126 | new-instance v6, Ljava/io/BufferedInputStream;
127 |
128 | invoke-direct {v6, v4}, Ljava/io/BufferedInputStream;->(Ljava/io/InputStream;)V
129 |
130 | .line 59
131 | .local v6, "bufferedInputStream2":Ljava/io/BufferedInputStream;
132 | sget-object v7, Lcom/storm/fengyue/StubApplication;->TAG:Ljava/lang/String;
133 |
134 | const-string v8, "check is same file"
135 |
136 | invoke-static {v7, v8}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
137 |
138 | .line 60
139 | invoke-static {v5, v6}, Lcom/storm/fengyue/StubApplication;->isSameFile(Ljava/io/BufferedInputStream;Ljava/io/BufferedInputStream;)Z
140 |
141 | move-result v7
142 |
143 | if-eqz v7, :cond_5a
144 |
145 | .line 61
146 | const/4 v7, 0x1
147 |
148 | .line 61
149 | .local v7, "result":Z
150 | goto :goto_5b
151 |
152 | .line 63
153 | .end local v7 # "result":Z
154 | :cond_5a
155 | const/4 v7, 0x0
156 |
157 | .line 65
158 | .restart local v7 # "result":Z
159 | :goto_5b
160 | invoke-virtual {v3}, Ljava/io/InputStream;->close()V
161 |
162 | .line 66
163 | invoke-virtual {v4}, Ljava/io/InputStream;->close()V
164 |
165 | .line 67
166 | invoke-virtual {v5}, Ljava/io/BufferedInputStream;->close()V
167 |
168 | .line 68
169 | invoke-virtual {v6}, Ljava/io/BufferedInputStream;->close()V
170 |
171 | .line 69
172 | if-eqz v7, :cond_6a
173 |
174 | .line 70
175 | return v7
176 |
177 | .line 73
178 | .end local v3 # "open":Ljava/io/InputStream;
179 | .end local v4 # "fileInputStream":Ljava/io/InputStream;
180 | .end local v5 # "bufferedInputStream":Ljava/io/BufferedInputStream;
181 | .end local v6 # "bufferedInputStream2":Ljava/io/BufferedInputStream;
182 | .end local v7 # "result":Z
183 | :cond_6a
184 | invoke-virtual {p0}, Landroid/content/Context;->getResources()Landroid/content/res/Resources;
185 |
186 | move-result-object v3
187 |
188 | invoke-virtual {v3}, Landroid/content/res/Resources;->getAssets()Landroid/content/res/AssetManager;
189 |
190 | move-result-object v3
191 |
192 | invoke-virtual {v3, p1}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream;
193 |
194 | move-result-object v3
195 |
196 | .line 74
197 | .local v3, "open2":Ljava/io/InputStream;
198 | new-instance v4, Ljava/io/FileOutputStream;
199 |
200 | invoke-direct {v4, v0}, Ljava/io/FileOutputStream;->(Ljava/lang/String;)V
201 |
202 | .line 75
203 | .local v4, "fileOutputStream":Ljava/io/FileOutputStream;
204 | const/16 v5, 0x1c00
205 |
206 | new-array v5, v5, [B
207 |
208 | .line 77
209 | .local v5, "bArr":[B
210 | :goto_7f
211 | invoke-virtual {v3, v5}, Ljava/io/InputStream;->read([B)I
212 |
213 | move-result v6
214 |
215 | .line 78
216 | .local v6, "read":I
217 | if-gtz v6, :cond_a8
218 |
219 | .line 79
220 | nop
221 |
222 | .line 83
223 | .end local v6 # "read":I
224 | invoke-virtual {v4}, Ljava/io/FileOutputStream;->close()V
225 |
226 | .line 84
227 | invoke-virtual {v3}, Ljava/io/InputStream;->close()V
228 | :try_end_8c
229 | .catch Ljava/io/FileNotFoundException; {:try_start_2a .. :try_end_8c} :catch_b1
230 | .catch Ljava/io/IOException; {:try_start_2a .. :try_end_8c} :catch_ac
231 |
232 | .line 86
233 | :try_start_8c
234 | invoke-static {}, Ljava/lang/Runtime;->getRuntime()Ljava/lang/Runtime;
235 |
236 | move-result-object v6
237 |
238 | new-instance v7, Ljava/lang/StringBuilder;
239 |
240 | invoke-direct {v7}, Ljava/lang/StringBuilder;->()V
241 |
242 | const-string v8, "chmod 755 "
243 |
244 | invoke-virtual {v7, v8}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
245 |
246 | invoke-virtual {v7, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
247 |
248 | invoke-virtual {v7}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
249 |
250 | move-result-object v7
251 |
252 | invoke-virtual {v6, v7}, Ljava/lang/Runtime;->exec(Ljava/lang/String;)Ljava/lang/Process;
253 | :try_end_a4
254 | .catch Ljava/lang/Exception; {:try_start_8c .. :try_end_a4} :catch_a5
255 | .catch Ljava/io/FileNotFoundException; {:try_start_8c .. :try_end_a4} :catch_b1
256 | .catch Ljava/io/IOException; {:try_start_8c .. :try_end_a4} :catch_ac
257 |
258 | .line 88
259 | goto :goto_a6
260 |
261 | .line 87
262 | :catch_a5
263 | move-exception v2
264 |
265 | .line 89
266 | :goto_a6
267 | const/4 v2, 0x1
268 |
269 | return v2
270 |
271 | .line 81
272 | .restart local v6 # "read":I
273 | :cond_a8
274 | :try_start_a8
275 | invoke-virtual {v4, v5, v2, v6}, Ljava/io/FileOutputStream;->write([BII)V
276 | :try_end_ab
277 | .catch Ljava/io/FileNotFoundException; {:try_start_a8 .. :try_end_ab} :catch_b1
278 | .catch Ljava/io/IOException; {:try_start_a8 .. :try_end_ab} :catch_ac
279 |
280 | .line 82
281 | .end local v6 # "read":I
282 | goto :goto_7f
283 |
284 | .line 92
285 | .end local v3 # "open2":Ljava/io/InputStream;
286 | .end local v4 # "fileOutputStream":Ljava/io/FileOutputStream;
287 | .end local v5 # "bArr":[B
288 | :catch_ac
289 | move-exception v3
290 |
291 | .line 93
292 | .local v3, "e3":Ljava/io/IOException;
293 | invoke-virtual {v3}, Ljava/io/IOException;->printStackTrace()V
294 |
295 | .line 93
296 | .end local v3 # "e3":Ljava/io/IOException;
297 | goto :goto_b6
298 |
299 | .line 90
300 | :catch_b1
301 | move-exception v3
302 |
303 | .line 91
304 | .local v3, "e2":Ljava/io/FileNotFoundException;
305 | invoke-virtual {v3}, Ljava/io/FileNotFoundException;->printStackTrace()V
306 |
307 | .line 94
308 | .end local v3 # "e2":Ljava/io/FileNotFoundException;
309 | nop
310 |
311 | .line 95
312 | :goto_b6
313 | return v2
314 | .end method
315 |
316 | .method public static isSameFile(Ljava/io/BufferedInputStream;Ljava/io/BufferedInputStream;)Z
317 | .registers 9
318 | .param p0, "bufferedInputStream" # Ljava/io/BufferedInputStream;
319 | .param p1, "bufferedInputStream2" # Ljava/io/BufferedInputStream;
320 |
321 | .line 21
322 | const/4 v0, 0x0
323 |
324 | :try_start_1
325 | invoke-virtual {p0}, Ljava/io/BufferedInputStream;->available()I
326 |
327 | move-result v1
328 |
329 | .line 22
330 | .local v1, "available":I
331 | invoke-virtual {p1}, Ljava/io/BufferedInputStream;->available()I
332 |
333 | move-result v2
334 |
335 | .line 23
336 | .local v2, "available2":I
337 | if-eq v1, v2, :cond_c
338 |
339 | .line 24
340 | return v0
341 |
342 | .line 26
343 | :cond_c
344 | new-array v3, v1, [B
345 |
346 | .line 27
347 | .local v3, "bArr":[B
348 | new-array v4, v2, [B
349 |
350 | .line 28
351 | .local v4, "bArr2":[B
352 | invoke-virtual {p0, v3}, Ljava/io/BufferedInputStream;->read([B)I
353 |
354 | .line 29
355 | invoke-virtual {p1, v4}, Ljava/io/BufferedInputStream;->read([B)I
356 |
357 | .line 30
358 | const/4 v2, 0x0
359 |
360 | :goto_17
361 | if-ge v2, v1, :cond_23
362 |
363 | .line 31
364 | aget-byte v5, v3, v2
365 |
366 | aget-byte v6, v4, v2
367 | :try_end_1d
368 | .catch Ljava/io/FileNotFoundException; {:try_start_1 .. :try_end_1d} :catch_2a
369 | .catch Ljava/io/IOException; {:try_start_1 .. :try_end_1d} :catch_25
370 |
371 | if-eq v5, v6, :cond_20
372 |
373 | .line 32
374 | return v0
375 |
376 | .line 30
377 | :cond_20
378 | add-int/lit8 v2, v2, 0x1
379 |
380 | goto :goto_17
381 |
382 | .line 35
383 | :cond_23
384 | const/4 v0, 0x1
385 |
386 | return v0
387 |
388 | .line 39
389 | .end local v1 # "available":I
390 | .end local v2 # "available2":I
391 | .end local v3 # "bArr":[B
392 | .end local v4 # "bArr2":[B
393 | :catch_25
394 | move-exception v1
395 |
396 | .line 40
397 | .local v1, "e2":Ljava/io/IOException;
398 | invoke-virtual {v1}, Ljava/io/IOException;->printStackTrace()V
399 |
400 | .line 41
401 | return v0
402 |
403 | .line 36
404 | .end local v1 # "e2":Ljava/io/IOException;
405 | :catch_2a
406 | move-exception v1
407 |
408 | .line 37
409 | .local v1, "e":Ljava/io/FileNotFoundException;
410 | invoke-virtual {v1}, Ljava/io/FileNotFoundException;->printStackTrace()V
411 |
412 | .line 38
413 | return v0
414 | .end method
415 |
416 |
417 | # virtual methods
418 | .method protected attachBaseContext(Landroid/content/Context;)V
419 | .registers 7
420 | .param p1, "context" # Landroid/content/Context;
421 |
422 | .line 99
423 | invoke-super {p0, p1}, Landroid/app/Application;->attachBaseContext(Landroid/content/Context;)V
424 |
425 | .line 100
426 | sget-object v0, Lcom/storm/fengyue/StubApplication;->TAG:Ljava/lang/String;
427 |
428 | const-string v1, "StubApplication.attachBaseContext"
429 |
430 | invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
431 |
432 | .line 101
433 | new-instance v0, Ljava/lang/StringBuilder;
434 |
435 | invoke-virtual {p1}, Landroid/content/Context;->getFilesDir()Ljava/io/File;
436 |
437 | move-result-object v1
438 |
439 | invoke-virtual {v1}, Ljava/io/File;->getAbsolutePath()Ljava/lang/String;
440 |
441 | move-result-object v1
442 |
443 | invoke-static {v1}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
444 |
445 | move-result-object v1
446 |
447 | invoke-direct {v0, v1}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
448 |
449 | const-string v1, "/.jiagu"
450 |
451 | invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
452 |
453 | invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
454 |
455 | move-result-object v0
456 |
457 | .line 102
458 | .local v0, "str":Ljava/lang/String;
459 | sget-object v1, Landroid/os/Build;->CPU_ABI:Ljava/lang/String;
460 |
461 | .line 103
462 | .local v1, "abi":Ljava/lang/String;
463 | sget v2, Landroid/os/Build$VERSION;->SDK_INT:I
464 |
465 | const/16 v3, 0x15
466 |
467 | if-lt v2, v3, :cond_35
468 |
469 | .line 104
470 | sget-object v2, Landroid/os/Build;->SUPPORTED_ABIS:[Ljava/lang/String;
471 |
472 | .line 105
473 | .local v2, "CPU_ABIS":[Ljava/lang/String;
474 | array-length v3, v2
475 |
476 | if-lez v3, :cond_34
477 |
478 | .line 106
479 | const/4 v3, 0x0
480 |
481 | aget-object v1, v2, v3
482 |
483 | .line 108
484 | .end local v2 # "CPU_ABIS":[Ljava/lang/String;
485 | :cond_34
486 | goto :goto_37
487 |
488 | .line 109
489 | :cond_35
490 | sget-object v1, Landroid/os/Build;->CPU_ABI:Ljava/lang/String;
491 |
492 | .line 111
493 | :goto_37
494 | sget-object v2, Lcom/storm/fengyue/StubApplication;->TAG:Ljava/lang/String;
495 |
496 | new-instance v3, Ljava/lang/StringBuilder;
497 |
498 | invoke-direct {v3}, Ljava/lang/StringBuilder;->()V
499 |
500 | const-string v4, "Build.CPU_ABI:"
501 |
502 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
503 |
504 | invoke-virtual {v3, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
505 |
506 | invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
507 |
508 | move-result-object v3
509 |
510 | invoke-static {v2, v3}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
511 |
512 | .line 112
513 | const-string v2, "armeabi"
514 |
515 | invoke-virtual {v1, v2}, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z
516 |
517 | move-result v2
518 |
519 | if-eqz v2, :cond_a2
520 |
521 | .line 113
522 | new-instance v2, Ljava/lang/StringBuilder;
523 |
524 | invoke-direct {v2}, Ljava/lang/StringBuilder;->()V
525 |
526 | sget-object v3, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
527 |
528 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
529 |
530 | const-string v3, "_arm.so"
531 |
532 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
533 |
534 | invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
535 |
536 | move-result-object v2
537 |
538 | new-instance v3, Ljava/lang/StringBuilder;
539 |
540 | invoke-direct {v3}, Ljava/lang/StringBuilder;->()V
541 |
542 | sget-object v4, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
543 |
544 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
545 |
546 | const-string v4, ".so"
547 |
548 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
549 |
550 | invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
551 |
552 | move-result-object v3
553 |
554 | invoke-static {p1, v2, v0, v3}, Lcom/storm/fengyue/StubApplication;->copy(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
555 |
556 | .line 114
557 | new-instance v2, Ljava/lang/StringBuilder;
558 |
559 | invoke-static {v0}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
560 |
561 | move-result-object v3
562 |
563 | invoke-direct {v2, v3}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
564 |
565 | sget-object v3, Ljava/io/File;->separator:Ljava/lang/String;
566 |
567 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
568 |
569 | sget-object v3, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
570 |
571 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
572 |
573 | const-string v3, ".so"
574 |
575 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
576 |
577 | invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
578 |
579 | move-result-object v2
580 |
581 | invoke-static {v2}, Ljava/lang/System;->load(Ljava/lang/String;)V
582 |
583 | .line 115
584 | invoke-static {p1}, Lcom/storm/fengyue/Native;->attachBaseContext(Landroid/content/Context;)V
585 |
586 | goto/16 :goto_160
587 |
588 | .line 116
589 | :cond_a2
590 | const-string v2, "arm64"
591 |
592 | invoke-virtual {v1, v2}, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z
593 |
594 | move-result v2
595 |
596 | if-eqz v2, :cond_f6
597 |
598 | .line 117
599 | new-instance v2, Ljava/lang/StringBuilder;
600 |
601 | invoke-direct {v2}, Ljava/lang/StringBuilder;->()V
602 |
603 | sget-object v3, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
604 |
605 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
606 |
607 | const-string v3, "_a64.so"
608 |
609 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
610 |
611 | invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
612 |
613 | move-result-object v2
614 |
615 | new-instance v3, Ljava/lang/StringBuilder;
616 |
617 | invoke-direct {v3}, Ljava/lang/StringBuilder;->()V
618 |
619 | sget-object v4, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
620 |
621 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
622 |
623 | const-string v4, ".so"
624 |
625 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
626 |
627 | invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
628 |
629 | move-result-object v3
630 |
631 | invoke-static {p1, v2, v0, v3}, Lcom/storm/fengyue/StubApplication;->copy(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
632 |
633 | .line 118
634 | new-instance v2, Ljava/lang/StringBuilder;
635 |
636 | invoke-static {v0}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
637 |
638 | move-result-object v3
639 |
640 | invoke-direct {v2, v3}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
641 |
642 | sget-object v3, Ljava/io/File;->separator:Ljava/lang/String;
643 |
644 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
645 |
646 | sget-object v3, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
647 |
648 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
649 |
650 | const-string v3, ".so"
651 |
652 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
653 |
654 | invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
655 |
656 | move-result-object v2
657 |
658 | invoke-static {v2}, Ljava/lang/System;->load(Ljava/lang/String;)V
659 |
660 | .line 119
661 | invoke-static {p1}, Lcom/storm/fengyue/Native;->attachBaseContext(Landroid/content/Context;)V
662 |
663 | goto :goto_160
664 |
665 | .line 120
666 | :cond_f6
667 | const-string v2, "x86"
668 |
669 | invoke-virtual {v1, v2}, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z
670 |
671 | move-result v2
672 |
673 | if-eqz v2, :cond_14a
674 |
675 | .line 121
676 | new-instance v2, Ljava/lang/StringBuilder;
677 |
678 | invoke-direct {v2}, Ljava/lang/StringBuilder;->()V
679 |
680 | sget-object v3, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
681 |
682 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
683 |
684 | const-string v3, "_x86.so"
685 |
686 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
687 |
688 | invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
689 |
690 | move-result-object v2
691 |
692 | new-instance v3, Ljava/lang/StringBuilder;
693 |
694 | invoke-direct {v3}, Ljava/lang/StringBuilder;->()V
695 |
696 | sget-object v4, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
697 |
698 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
699 |
700 | const-string v4, ".so"
701 |
702 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
703 |
704 | invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
705 |
706 | move-result-object v3
707 |
708 | invoke-static {p1, v2, v0, v3}, Lcom/storm/fengyue/StubApplication;->copy(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
709 |
710 | .line 122
711 | new-instance v2, Ljava/lang/StringBuilder;
712 |
713 | invoke-static {v0}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
714 |
715 | move-result-object v3
716 |
717 | invoke-direct {v2, v3}, Ljava/lang/StringBuilder;->(Ljava/lang/String;)V
718 |
719 | sget-object v3, Ljava/io/File;->separator:Ljava/lang/String;
720 |
721 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
722 |
723 | sget-object v3, Lcom/storm/fengyue/StubApplication;->soName:Ljava/lang/String;
724 |
725 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
726 |
727 | const-string v3, ".so"
728 |
729 | invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
730 |
731 | invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
732 |
733 | move-result-object v2
734 |
735 | invoke-static {v2}, Ljava/lang/System;->load(Ljava/lang/String;)V
736 |
737 | .line 123
738 | invoke-static {p1}, Lcom/storm/fengyue/Native;->attachBaseContext(Landroid/content/Context;)V
739 |
740 | goto :goto_160
741 |
742 | .line 125
743 | :cond_14a
744 | sget-object v2, Lcom/storm/fengyue/StubApplication;->TAG:Ljava/lang/String;
745 |
746 | new-instance v3, Ljava/lang/StringBuilder;
747 |
748 | invoke-direct {v3}, Ljava/lang/StringBuilder;->()V
749 |
750 | const-string v4, "Bangcle is not supported abi:"
751 |
752 | invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
753 |
754 | invoke-virtual {v3, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
755 |
756 | invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
757 |
758 | move-result-object v3
759 |
760 | invoke-static {v2, v3}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
761 |
762 | .line 127
763 | :goto_160
764 | return-void
765 | .end method
766 |
767 | .method public onCreate()V
768 | .registers 3
769 |
770 | .line 130
771 | invoke-super {p0}, Landroid/app/Application;->onCreate()V
772 |
773 | .line 131
774 | sget-object v0, Lcom/storm/fengyue/StubApplication;->TAG:Ljava/lang/String;
775 |
776 | const-string v1, "StubApplication.onCreate"
777 |
778 | invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
779 |
780 | .line 132
781 | invoke-static {p0}, Lcom/storm/fengyue/Native;->onCreate(Landroid/content/Context;)V
782 |
783 | .line 133
784 | return-void
785 | .end method
786 |
--------------------------------------------------------------------------------
/bangcle_tool/tools/testkey.pk8:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lpcdma/Bangcle/d3e3dd3fd0d058cbb8d2c12249082110c6a96817/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 |
3 | # include $(CLEAR_VARS)
4 | # LOCAL_MODULE := xhook
5 | # LOCAL_SRC_FILES := $(LOCAL_PATH)/libxhook/libs/$(TARGET_ARCH_ABI)/libxhook.so
6 | # LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/libxhook/jni
7 | # include $(PREBUILT_SHARED_LIBRARY)
8 |
9 | include $(CLEAR_VARS)
10 | LOCAL_MODULE := dexload
11 | ifeq ($(TARGET_ARCH),x86)
12 | LOCAL_MODULE := dexload_x86
13 | endif
14 | ifeq ($(TARGET_ARCH),armeabi-v7a)
15 | LOCAL_MODULE := dexload_arm
16 | endif
17 | ifeq ($(TARGET_ARCH),arm64-v8a)
18 | LOCAL_MODULE := dexload_a64
19 | endif
20 |
21 | LOCAL_C_INCLUDES +=$(LOCAL_PATH)/xhook/
22 | # LOCAL_STATIC_LIBRARIES := static_openssl_crypto
23 | # LOCAL_STATIC_LIBRARIES := static_openssl_ssl
24 | LOCAL_SRC_FILES := packer.cpp \
25 | hook_instance.cpp \
26 | byte_load.cpp \
27 | utils.cpp \
28 | util.c
29 | LOCAL_SRC_FILES +=aes.c
30 | LOCAL_SRC_FILES += xhook/xhook.c \
31 | xhook/xh_core.c \
32 | xhook/xh_elf.c \
33 | xhook/xh_jni.c \
34 | xhook/xh_log.c \
35 | xhook/xh_util.c \
36 | xhook/xh_version.c
37 |
38 | LOCAL_CFLAGS := -Wall
39 | # LOCAL_CFLAGS +=-fpermissive
40 | LOCAL_CPPFLAGS += -Os
41 | LOCAL_CFLAGS += -Os -DNO_WINDOWS_BRAINDEATH #-Werror-pointer-arith #-fvisibility=hidden
42 | LOCAL_LDLIBS :=-llog -landroid
43 | # LOCAL_LDLIBS +=$(LOCAL_PATH)/openssl/libcrypto.a
44 | # LOCAL_LDLIBS +=$(LOCAL_PATH)/openssl/libssl.a
45 | include $(BUILD_SHARED_LIBRARY)
46 |
--------------------------------------------------------------------------------
/jni/Application.mk:
--------------------------------------------------------------------------------
1 | APP_ABI := x86 armeabi-v7a arm64-v8a
2 | APP_STL := c++_static
3 | APP_CPPFLAGS := -std=c++11 -fexceptions -frtti
4 | APP_PLATFORM := android-16
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 "log.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 = new std::string("");
132 | std::string *err_msg = new std::string("");
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 | delete location;
156 | delete err_msg;
157 |
158 | void *a = retcookie;
159 |
160 | // 返回的value等于retcookie ,*(int*)retcookie存储了加载dex的cookie
161 | LOGD("[+]openmemory value:%p,*retcookie:%x,jlong* retcookie:%llx", value, *(int *)retcookie, *(jlong *)a);
162 | // (*(jlong*)retcookie和*(int*)retcookie相等
163 | return (void *)(*(jlong *)retcookie);
164 | }
165 |
166 | void *mem_loadDex_byte24(void *artHandle, const char *base, size_t size)
167 | {
168 | std::string location = "";
169 | std::string err_msg;
170 | void *retcookie = malloc(0x78);
171 | memset(retcookie, 0, 0x78);
172 |
173 | // #define SEARCH_SYMBOL_Nougat _ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_
174 | org_artDexFileOpenMemory23 func = (org_artDexFileOpenMemory23)dlsym(artHandle,
175 | "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_");
176 |
177 | if (!func)
178 | {
179 | LOGE("[-]sdk_int:%d dlsym openMemory failed:%s", g_sdk_int, dlerror());
180 | #ifndef SEARCH_SYMBOL_Nougat
181 | return NULL;
182 | #else // ifndef SEARCH_SYMBOL_Nougat
183 | LOGD("[+]try search symbol from elf file");
184 | func = (org_artDexFileOpenMemory23)get_addr_symbol("/system/lib/libart.so",
185 | "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_");
186 |
187 | if (!func)
188 | {
189 | LOGE("[-]search symbol openMemory uniptr failed");
190 | return NULL;
191 | }
192 | #endif // ifndef SEARCH_SYMBOL_Nougat
193 | }
194 | const Header *dex_header = reinterpret_cast(base);
195 | void *value = func(retcookie,
196 | (const unsigned char *)base,
197 | size,
198 | location,
199 | dex_header->checksum_,
200 | NULL,
201 | NULL,
202 | &err_msg);
203 | void *a = retcookie;
204 |
205 | // LOGD改变了retcookie?? 所以先用a备份
206 | LOGD("[+]openMemory value:%p,*(int*)retcookie:%x,*(jlong*)retcookie:%llx",
207 | value,
208 | *(int *)retcookie,
209 | *(jlong *)a);
210 |
211 | return (void *)(*(jlong *)retcookie);
212 | } // mem_loadDex_byte24
213 |
214 | // For Andoird oreo 8.0 and 8.1
215 | // Reserved
216 |
217 | /*
218 | * void* mem_loadDex_byte26(void* artHandle, const char* base, size_t size)
219 | * {
220 | *
221 | * std::string location="";
222 | * std::string err_msg;
223 | * void* retcookie = malloc(0x78);
224 | * memset(retcookie, 0, 0x78);
225 | *
226 | #define OREO_TARGET_STRING "_ZN3art7DexFile10OpenCommonEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileEbbPS9_PNS0_12VerifyResultE"
227 | * orig_OpenCommon func = (orig_OpenCommon)dlsym(artHandle,OREO_TARGET_STRING );
228 | * if (!func) {
229 | * LOGE("[-]sdk_int:%d dlsym openCommon failed:%s",g_sdk_int,dlerror());
230 | * return NULL;
231 | *
232 | * // LOGD("[+]try search symbol %s from elf
233 | * file",(char*)OREO_TARGET_STRING);
234 | * //
235 | * func=(org_artDexFileOpenMemory23)get_addr_symbol("/system/lib/libart.so",OREO_TARGET_STRING);
236 | * // if (!func) {
237 | * // LOGE("[-]search symbol %s addr failed",OREO_TARGET_STRING);
238 | * // return NULL;
239 | * // }
240 | * }
241 | * else {
242 | * LOGD("[+]sdk_int:%d,dlsym openCommon :%p",g_sdk_int,func);
243 | * return NULL;
244 | * }
245 | * const Header* dex_header = reinterpret_cast(base);
246 | * void* value=func(retcookie,(const unsigned char *)base, size, location,
247 | * dex_header->checksum_, NULL,false,false, &err_msg,NULL);
248 | * void* a=retcookie;
249 | * //LOGD改变了retcookie?? 所以先用a备份
250 | * LOGD("[+]openCommon
251 | * value:%p,*(int*)retcookie:%x,*(jlong*)retcookie:%llx",value,*(int*)retcookie,*(jlong*)a);
252 | *
253 | * return (void*)(*(jlong*)retcookie);
254 | *
255 | * }
256 | */
257 |
--------------------------------------------------------------------------------
/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 | u8 contents[1];
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/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 "log.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 | LOGD("[+]my open pathname:%s", pathname);
35 | if (strlen(g_fake_dex_magic) > 1)
36 | {
37 | LOGD("[+]my open g_fake_dex_magic:%s", g_fake_dex_magic);
38 | }
39 |
40 | if (strstr(pathname, g_fake_dex_magic))
41 | {
42 | LOGD("[+]my open pathname:%s,result:%d", pathname, result);
43 | if (result == -1)
44 | {
45 | LOGE("[-]my open failed error:%s", strerror(errno));
46 | }
47 | }
48 | return result;
49 | }
50 |
51 | int new_fstat(int fd, struct stat *buf)
52 | {
53 | int result = old_fstat(fd, buf);
54 | LOGD("[+]my fstat");
55 |
56 | char fdlinkstr[128] = {0};
57 | char linkPath[256] = {0};
58 |
59 | memset(fdlinkstr, 0, 128);
60 | memset(linkPath, 0, 256);
61 |
62 | int pid = getpid();
63 | snprintf(fdlinkstr, 128, "/proc/%d/fd/%d", pid, fd);
64 |
65 | if (readlink(fdlinkstr, linkPath, 256) >= 0)
66 | {
67 | // LOGD("[+]new fstat file:%s",linkPath);
68 | if (strstr(linkPath,(char*)g_fake_dex_magic))
69 | {
70 | buf->st_size = g_dex_size;
71 | LOGD("[+]fstat linkPath:%s,buf.size:%d", linkPath, buf->st_size);
72 | }
73 | }
74 | else
75 | {
76 | LOGD("[-]fun my fstat readlink error");
77 | }
78 | return result;
79 | }
80 |
81 | ssize_t new_read(int fd, void *buf, size_t count)
82 | {
83 | char fdlinkstr[128] = {0};
84 | char linkPath[256] = {0};
85 |
86 | memset(fdlinkstr, 0, 128);
87 | memset(linkPath, 0, 256);
88 | int pid = getpid();
89 | snprintf(fdlinkstr, 128, "/proc/%d/fd/%d", pid, fd);
90 | if (readlink(fdlinkstr, linkPath, 256) >= 0)
91 | {
92 | // LOGD("[+]my read file:%s,count:%d",linkPath,count);
93 | if (strstr(linkPath,(char*)g_fake_dex_magic))
94 | {
95 | LOGD("[+]my read memcpy dex magic");
96 | memcpy(buf, kDexMagic, 4);
97 | return 4;
98 | }
99 | }
100 | else
101 | {
102 | LOGD("[-]my read readlink error");
103 | }
104 | LOGD("[+]my read");
105 | return old_read(fd, buf, count);
106 | }
107 |
108 | ssize_t new_read_chk(int fd, void *buf, size_t nbytes, size_t buflen)
109 | {
110 | char fdlinkstr[128] = {0};
111 | char linkPath[256] = {0};
112 |
113 | memset(fdlinkstr, 0, 128);
114 | memset(linkPath, 0, 256);
115 | int pid = getpid();
116 | snprintf(fdlinkstr, 128, "/proc/%d/fd/%d", pid, fd);
117 | if (readlink(fdlinkstr, linkPath, 256) >= 0)
118 | {
119 | // LOGD("[+]my read_chk file:%s,nbytes:%d,buflen:%d",linkPath,nbytes,buflen);
120 |
121 | // [+]my read_chk file:/data/data/com.ai
122 | // speech.weiyu/files/.jiagu/mini.dex,nbytes:4,buflen:-1
123 | // [+]my read_chk g_faked_dex_path:/data
124 | // /user/0/com.aispeech.weiyu/files/.jiagu/mini.dex
125 |
126 | // 这里不能使用strcmp比较 如果使用mini.dex作为fake_dex,mini_dex的位置为
127 | // /data/user/0/pkg_name/files/.jiagu/mini.dex
128 | // 但是使用readlink获取到的mini.dex路径为
129 | // /data/data/pkg_name/files/.jiagu/mini.dex
130 | if (strstr(linkPath,(char*)g_fake_dex_magic))
131 | {
132 | LOGD("[+]fun my read_chk memcpy dex magic");
133 | memcpy(buf, kDexMagic, 4);
134 | return 4;
135 | }
136 | }
137 | else
138 | {
139 | LOGD("[-]fun my read_chk readlink error");
140 | }
141 | LOGD("[+]my read_chk");
142 | return old_read_chk(fd, buf, nbytes, buflen);
143 | }
144 |
145 | void *new_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
146 | {
147 | char fdlinkstr[128] = {0};
148 | char linkPath[256] = {0};
149 |
150 | memset(fdlinkstr, 0, 128);
151 | memset(linkPath, 0, 256);
152 | int pid = (int)getpid();
153 | snprintf(fdlinkstr, 128, "/proc/%d/fd/%d", pid, fd);
154 |
155 | if (readlink(fdlinkstr, linkPath, 256) < 0)
156 | {
157 | LOGD("[-]my mmap readlink error");
158 | return old_mmap(start, length, prot, flags, fd, offset);
159 | }
160 |
161 | if (strstr(linkPath,(char*)g_fake_dex_magic))
162 | {
163 | LOGD("[+]mmap linkpath:%s,size:%zu", linkPath, length);
164 | return g_decrypt_base;
165 | }
166 | LOGD("[+]my mmap");
167 | return old_mmap(start, length, prot, flags, fd, offset);
168 | }
169 |
170 | int new_munmap(void *start, size_t length)
171 | {
172 | if ((start == g_decrypt_base) || (length == g_page_size))
173 | {
174 | LOGD("[+]munmap start:%p,length:%zu", start, length);
175 | return 0;
176 | }
177 | LOGD("[+]my munmap");
178 | return old_munmap(start, length);
179 | }
180 |
181 | pid_t new_fork(void)
182 | {
183 | LOGD("[+]fun my fork called");
184 | return -1;
185 | }
186 |
--------------------------------------------------------------------------------
/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.h:
--------------------------------------------------------------------------------
1 | #ifndef LOG_H
2 | #define LOG_H 1
3 |
4 | #include
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 |
10 | extern android_LogPriority xh_log_priority;
11 |
12 | #define LOG_TAG "LOGXX"
13 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
14 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
15 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
16 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
17 |
18 | #ifdef __cplusplus
19 | }
20 | #endif
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/jni/log.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lpcdma/Bangcle/d3e3dd3fd0d058cbb8d2c12249082110c6a96817/jni/log.txt
--------------------------------------------------------------------------------
/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/solist.h:
--------------------------------------------------------------------------------
1 | #ifndef _SOLIST_H
2 | #define _SOLIST_H
3 |
4 | #include
5 |
6 | #define SOINFO_NAME_LEN 128
7 |
8 | #define SHT_ARM_EXIDEX 0x70000001
9 | #define SHF_LINKORDER 0x80
10 | #define SHT_FINI_ARRAY 15
11 | #define SHT_INIT_ARRAY 14
12 | #define PT_ARM_EXIDEX 0x70000001
13 |
14 | #define ANDROID_ARM_LINKER
15 |
16 | #ifndef DT_INIT_ARRAY
17 | #define DT_INIT_ARRAY 25
18 | #endif
19 |
20 | #ifndef DT_FINI_ARRAY
21 | #define DT_FINI_ARRAY 26
22 | #endif
23 |
24 | #ifndef DT_INIT_ARRAYSZ
25 | #define DT_INIT_ARRAYSZ 27
26 | #endif
27 |
28 | #ifndef DT_FINI_ARRAYSZ
29 | #define DT_FINI_ARRAYSZ 28
30 | #endif
31 |
32 | #ifndef DT_PREINIT_ARRAY
33 | #define DT_PREINIT_ARRAY 32
34 | #endif
35 |
36 | #ifndef DT_PREINIT_ARRAYSZ
37 | #define DT_PREINIT_ARRAYSZ 33
38 | #endif
39 |
40 | struct link_map
41 | {
42 | uintptr_t l_addr;
43 | char * l_name;
44 | uintptr_t l_ld;
45 | struct link_map * l_next;
46 | struct link_map * l_prev;
47 | };
48 |
49 | typedef struct soinfo soinfo;
50 |
51 | struct soinfo
52 | {
53 | const char name[SOINFO_NAME_LEN];
54 | Elf32_Phdr *phdr;
55 | int phnum;
56 | unsigned entry;
57 | unsigned base;
58 | unsigned size;
59 |
60 | Elf32_Dyn *dynamic;
61 |
62 | unsigned wrprotect_start;
63 | unsigned wrprotect_end;
64 |
65 | soinfo *next;
66 | unsigned flags;
67 |
68 | const char *strtab;
69 | Elf32_Sym *symtab;
70 | unsigned strsz; //添加strsz字段,便于操作
71 |
72 | unsigned nbucket;
73 | unsigned nchain;
74 | unsigned *bucket;
75 | unsigned *chain;
76 |
77 | unsigned *plt_got;
78 |
79 | Elf32_Rel *plt_rel;
80 | unsigned plt_rel_count;
81 |
82 | Elf32_Rel *rel;
83 | unsigned rel_count;
84 |
85 | unsigned *preinit_array;
86 | unsigned preinit_array_count;
87 |
88 | unsigned *init_array;
89 | unsigned init_array_count;
90 | unsigned *fini_array;
91 | unsigned fini_array_count;
92 |
93 | void (*init_func)(void);
94 | void (*fini_func)(void);
95 |
96 | #ifdef ANDROID_ARM_LINKER
97 | unsigned *ARM_exidx;
98 | unsigned ARM_exidx_count;
99 | #endif
100 | unsigned refcount;
101 | struct link_map linkmap;
102 | };
103 |
104 | #endif
105 |
--------------------------------------------------------------------------------
/jni/util.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Elf parsing code taken from: hijack.c (for x86)
3 | * by Victor Zandy
4 | *
5 | * Elf parsing code slightly modified for this project
6 | * (c) Collin Mulliner
7 | *
8 | * License: LGPL v2.1
9 | *
10 | * Termios code taken from glibc with slight modifications for this project
11 | *
12 | */
13 | #define _XOPEN_SOURCE 500
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | #include
33 | // #include
34 |
35 | #define MODULE_NAME "LOGXX"
36 | #define log(...) {__android_log_print(ANDROID_LOG_ERROR, MODULE_NAME, __VA_ARGS__);}
37 |
38 | /* memory map for libraries */
39 | #define MAX_NAME_LEN 256
40 | #define MEMORY_ONLY "[memory]"
41 | struct mm {
42 | char name[MAX_NAME_LEN];
43 | unsigned long start, end;
44 | };
45 |
46 | typedef struct symtab *symtab_t;
47 | struct symlist {
48 | Elf32_Sym *sym; /* symbols */
49 | char *str; /* symbol strings */
50 | unsigned num; /* number of symbols */
51 | };
52 | struct symtab {
53 | struct symlist *st; /* "static" symbols */
54 | struct symlist *dyn; /* dynamic symbols */
55 | };
56 |
57 | static void *xmalloc(size_t size) {
58 | void *p;
59 | p = malloc(size);
60 | if (!p) {
61 | printf("Out of memory\n");
62 | exit(1);
63 | }
64 | return p;
65 | }
66 |
67 | static int my_pread(int fd, void *buf, size_t count, off_t offset) {
68 | lseek(fd, offset, SEEK_SET);
69 | return read(fd, buf, count);
70 | }
71 |
72 | static struct symlist *
73 | get_syms(int fd, Elf32_Shdr *symh, Elf32_Shdr *strh) {
74 | struct symlist *sl, *ret;
75 | int rv;
76 |
77 | ret = NULL;
78 | sl = (struct symlist *) xmalloc(sizeof(struct symlist));
79 | sl->str = NULL;
80 | sl->sym = NULL;
81 |
82 | /* sanity */
83 | if (symh->sh_size % sizeof(Elf32_Sym)) {
84 | //printf("elf_error\n");
85 | goto out;
86 | }
87 |
88 | /* symbol table */
89 | sl->num = symh->sh_size / sizeof(Elf32_Sym);
90 | sl->sym = (Elf32_Sym *) xmalloc(symh->sh_size);
91 | rv = my_pread(fd, sl->sym, symh->sh_size, symh->sh_offset);
92 | if (0 > rv) {
93 | //perror("read");
94 | goto out;
95 | }
96 | if (rv != symh->sh_size) {
97 | //printf("elf error\n");
98 | goto out;
99 | }
100 |
101 | /* string table */
102 | sl->str = (char *) xmalloc(strh->sh_size);
103 | rv = my_pread(fd, sl->str, strh->sh_size, strh->sh_offset);
104 | if (0 > rv) {
105 | //perror("read");
106 | goto out;
107 | }
108 | if (rv != strh->sh_size) {
109 | //printf("elf error");
110 | goto out;
111 | }
112 |
113 | ret = sl;
114 | out:
115 | return ret;
116 | }
117 |
118 | static int do_load(int fd, symtab_t symtab) {
119 | int rv;
120 | size_t size;
121 | Elf32_Ehdr ehdr;
122 | Elf32_Shdr *shdr = NULL, *p;
123 | Elf32_Shdr *dynsymh, *dynstrh;
124 | Elf32_Shdr *symh, *strh;
125 | char *shstrtab = NULL;
126 | int i;
127 | int ret = -1;
128 |
129 | /* elf header */
130 | rv = read(fd, &ehdr, sizeof(ehdr));
131 | if (0 > rv) {
132 | log("read\n")
133 | goto out;
134 | }
135 | if (rv != sizeof(ehdr)) {
136 | log("elf error 1\n")
137 | goto out;
138 | }
139 | if (strncmp(ELFMAG, ehdr.e_ident, SELFMAG)) { /* sanity */
140 | log("not an elf\n")
141 | goto out;
142 | }
143 | if (sizeof(Elf32_Shdr) != ehdr.e_shentsize) { /* sanity */
144 | log("elf error 2\n")
145 | goto out;
146 | }
147 |
148 | /* section header table */
149 | size = ehdr.e_shentsize * ehdr.e_shnum;
150 | shdr = (Elf32_Shdr *) xmalloc(size);
151 | rv = my_pread(fd, shdr, size, ehdr.e_shoff);
152 | if (0 > rv) {
153 | log("read\n")
154 | goto out;
155 | }
156 | if (rv != size) {
157 | log("elf error 3 %d %d\n", rv, size)
158 | goto out;
159 | }
160 |
161 | /* section header string table */
162 | size = shdr[ehdr.e_shstrndx].sh_size;
163 | shstrtab = (char *) xmalloc(size);
164 | rv = my_pread(fd, shstrtab, size, shdr[ehdr.e_shstrndx].sh_offset);
165 | if (0 > rv) {
166 | log("read\n")
167 | goto out;
168 | }
169 | if (rv != size) {
170 | log("elf error 4 %d %d\n", rv, size)
171 | goto out;
172 | }
173 |
174 | /* symbol table headers */
175 | symh = dynsymh = NULL;
176 | strh = dynstrh = NULL;
177 | for (i = 0, p = shdr; i < ehdr.e_shnum; i++, p++)
178 | if (SHT_SYMTAB == p->sh_type) {
179 | if (symh) {
180 | log("too many symbol tables\n")
181 | goto out;
182 | }
183 | symh = p;
184 | } else if (SHT_DYNSYM == p->sh_type) {
185 | if (dynsymh) {
186 | log("too many symbol tables\n")
187 | goto out;
188 | }
189 | dynsymh = p;
190 | } else if (SHT_STRTAB == p->sh_type
191 | && !strncmp(shstrtab + p->sh_name, ".strtab", 7)) {
192 | if (strh) {
193 | log("too many string tables\n")
194 | goto out;
195 | }
196 | strh = p;
197 | } else if (SHT_STRTAB == p->sh_type
198 | && !strncmp(shstrtab + p->sh_name, ".dynstr", 7)) {
199 | if (dynstrh) {
200 | log("too many string tables\n")
201 | goto out;
202 | }
203 | dynstrh = p;
204 | }
205 | /* sanity checks */
206 | if ((!dynsymh && dynstrh) || (dynsymh && !dynstrh)) {
207 | log("bad dynamic symbol table\n")
208 | goto out;
209 | }
210 | if ((!symh && strh) || (symh && !strh)) {
211 | log("bad symbol table\n")
212 | goto out;
213 | }
214 | if (!dynsymh && !symh) {
215 | log("no symbol table\n")
216 | goto out;
217 | }
218 |
219 | /* symbol tables */
220 | if (dynsymh)
221 | symtab->dyn = get_syms(fd, dynsymh, dynstrh);
222 | if (symh)
223 | symtab->st = get_syms(fd, symh, strh);
224 | ret = 0;
225 | out:
226 | free(shstrtab);
227 | free(shdr);
228 | return ret;
229 | }
230 |
231 | static symtab_t load_symtab(char *filename) {
232 | int fd;
233 | symtab_t symtab;
234 |
235 | symtab = (symtab_t) xmalloc(sizeof(*symtab));
236 | memset(symtab, 0, sizeof(*symtab));
237 |
238 | fd = open(filename, O_RDONLY);
239 | if (0 > fd) {
240 | log("%s open\n", __func__);
241 | return NULL;
242 | }
243 | if (0 > do_load(fd, symtab)) {
244 | log("Error ELF parsing %s\n", filename)
245 | free(symtab);
246 | symtab = NULL;
247 | }
248 | close(fd);
249 | return symtab;
250 | }
251 |
252 | static int load_memmap(pid_t pid, struct mm *mm, int *nmmp) {
253 | char raw[1024 * 1024]; // increase this if needed for larger "maps"
254 | char name[MAX_NAME_LEN];
255 | char *p;
256 | unsigned long start, end;
257 | struct mm *m;
258 | int nmm = 0;
259 | int fd, rv;
260 | int i;
261 |
262 | sprintf(raw, "/proc/%d/maps", pid);
263 | fd = open(raw, O_RDONLY);
264 | if (0 > fd) {
265 | log("Can't open %s for reading\n", raw)
266 | return -1;
267 | }
268 |
269 | /* Zero to ensure data is null terminated */
270 | memset(raw, 0, sizeof(raw));
271 |
272 | p = raw;
273 | while (1) {
274 | rv = read(fd, p, sizeof(raw) - (p - raw));
275 | if (0 > rv) {
276 | log("read")
277 | return -1;
278 | }
279 | if (0 == rv)
280 | break;
281 | p += rv;
282 | if (p - raw >= sizeof(raw)) {
283 | log("Too many memory mapping\n")
284 | return -1;
285 | }
286 | }
287 | close(fd);
288 |
289 | p = strtok(raw, "\n");
290 | m = mm;
291 | while (p) {
292 | /* parse current map line */
293 | rv = sscanf(p, "%08lx-%08lx %*s %*s %*s %*s %s\n",
294 | &start, &end, name);
295 |
296 | p = strtok(NULL, "\n");
297 |
298 | if (rv == 2) {
299 | m = &mm[nmm++];
300 | m->start = start;
301 | m->end = end;
302 | strcpy(m->name, MEMORY_ONLY);
303 | continue;
304 | }
305 |
306 | /* search backward for other mapping with same name */
307 | for (i = nmm - 1; i >= 0; i--) {
308 | m = &mm[i];
309 | if (!strcmp(m->name, name))
310 | break;
311 | }
312 |
313 | if (i >= 0) {
314 | if (start < m->start)
315 | m->start = start;
316 | if (end > m->end)
317 | m->end = end;
318 | } else {
319 | /* new entry */
320 | m = &mm[nmm++];
321 | m->start = start;
322 | m->end = end;
323 | strcpy(m->name, name);
324 | }
325 | }
326 |
327 | *nmmp = nmm;
328 | return 0;
329 | }
330 |
331 | /* Find libc in MM, storing no more than LEN-1 chars of
332 | its name in NAME and set START to its starting
333 | address. If libc cannot be found return -1 and
334 | leave NAME and START untouched. Otherwise return 0
335 | and null-terminated NAME. */
336 | static int find_libname(char *libn, char *name, int len, unsigned long *start, struct mm *mm,
337 | int nmm) {
338 | int i;
339 | struct mm *m;
340 | char *p;
341 | for (i = 0, m = mm; i < nmm; i++, m++) {
342 | if (!strcmp(m->name, MEMORY_ONLY))
343 | continue;
344 | p = strrchr(m->name, '/');
345 | if (!p)
346 | continue;
347 | p++;
348 | if (strncmp(libn, p, strlen(libn)))
349 | continue;
350 | p += strlen(libn);
351 |
352 | /* here comes our crude test -> 'libc.so' or 'libc-[0-9]' */
353 | if (!strncmp("so", p, 2) || 1) // || (p[0] == '-' && isdigit(p[1])))
354 | break;
355 | }
356 | if (i >= nmm)
357 | /* not found */
358 | return -1;
359 |
360 | *start = m->start;
361 | strncpy(name, m->name, len);
362 | if (strlen(m->name) >= len)
363 | name[len - 1] = '\0';
364 |
365 | mprotect((void *) m->start, m->end - m->start, PROT_READ | PROT_WRITE | PROT_EXEC);
366 | return 0;
367 | }
368 |
369 | static int lookup2(struct symlist *sl, unsigned char type,
370 | char *name, unsigned long *val) {
371 | Elf32_Sym *p;
372 | int len;
373 | int i;
374 |
375 | len = strlen(name);
376 | for (i = 0, p = sl->sym; i < sl->num; i++, p++) {
377 | //log("name: %s %x\n", sl->str+p->st_name, p->st_value)
378 | if (!strncmp(sl->str + p->st_name, name, len) && *(sl->str + p->st_name + len) == 0
379 | && ELF32_ST_TYPE(p->st_info) == type) {
380 | //if (p->st_value != 0) {
381 | *val = p->st_value;
382 | return 0;
383 | //}
384 | }
385 | }
386 | return -1;
387 | }
388 |
389 | static int lookup_sym(symtab_t s, unsigned char type,
390 | char *name,
391 | unsigned long *val) {
392 | if (s->dyn && !lookup2(s->dyn, type, name, val))
393 | return 0;
394 | if (s->st && !lookup2(s->st, type, name, val))
395 | return 0;
396 | return -1;
397 | }
398 |
399 | static int lookup_func_sym(symtab_t s, char *name, unsigned long *val) {
400 | return lookup_sym(s, STT_FUNC, name, val);
401 | }
402 |
403 | int find_name(pid_t pid, char *name, char *libn, unsigned long *addr) {
404 | struct mm mm[1000];
405 | unsigned long libcaddr;
406 | int nmm;
407 | char libc[1024];
408 | symtab_t s;
409 |
410 | if (0 > load_memmap(pid, mm, &nmm)) {
411 | log("cannot read memory map\n")
412 | return -1;
413 | }
414 | if (0 > find_libname(libn, libc, sizeof(libc), &libcaddr, mm, nmm)) {
415 | log("cannot find lib: %s\n", libn)
416 | return -1;
417 | }
418 | log("lib: >%s<\n", libc)
419 | s = load_symtab(libc);
420 | if (!s) {
421 | log("cannot read symbol table\n");
422 | return -1;
423 | }
424 | if (0 > lookup_func_sym(s, name, addr)) {
425 | log("cannot find function: %s\n", name);
426 | return -1;
427 | }
428 | *addr += libcaddr;
429 | log("libcaddr ==> %x", libcaddr);
430 | log("addr == > 0x%x", *addr);
431 | Elf32_Ehdr *ehdr = (Elf32_Ehdr *) libcaddr;
432 | log("ehdr->e_phoff: 0x%x\n", ehdr->e_phoff);
433 | log("ehdr->e_phnum: 0x%x\n", ehdr->e_phnum);
434 | Elf32_Phdr *phdr = NULL;
435 | for (int i = 0; i < ehdr->e_phnum; ++i) {
436 | log("in for");
437 | Elf32_Phdr *phdr_tmp = (Elf32_Phdr *) (libcaddr + ehdr->e_phoff + (sizeof(Elf32_Phdr) * i));
438 | log("phdr_tmp->p_vaddr ==> 0x%x\n", phdr_tmp->p_vaddr);
439 | if (phdr_tmp->p_type == 0x01) {
440 | phdr = phdr_tmp;
441 | break;
442 | }
443 | }
444 | log("phdr->p_vaddr ==> 0x%x\n", phdr->p_vaddr);
445 | if (phdr != NULL && phdr->p_vaddr != 0) {
446 | *addr -= phdr->p_vaddr;
447 | }
448 | return 0;
449 | }
450 |
451 | int find_libbase(pid_t pid, char *libn, unsigned long *addr) {
452 | struct mm mm[1000];
453 | unsigned long libcaddr;
454 | int nmm;
455 | char libc[1024];
456 | symtab_t s;
457 |
458 | if (0 > load_memmap(pid, mm, &nmm)) {
459 | log("cannot read memory map\n")
460 | return -1;
461 | }
462 | if (0 > find_libname(libn, libc, sizeof(libc), &libcaddr, mm, nmm)) {
463 | log("cannot find lib\n");
464 | return -1;
465 | }
466 | *addr = libcaddr;
467 | log("libcaddr ==> %x", libcaddr);
468 | Elf32_Ehdr *ehdr = (Elf32_Ehdr *) libcaddr;
469 | log("ehdr->e_phoff: 0x%x\n", ehdr->e_phoff);
470 | log("ehdr->e_phnum: 0x%x\n", ehdr->e_phnum);
471 | Elf32_Phdr *phdr = NULL;
472 | for (int i = 0; i < ehdr->e_phnum; ++i) {
473 | log("in for");
474 | Elf32_Phdr *phdr_tmp = (Elf32_Phdr *) (libcaddr + ehdr->e_phoff + (sizeof(Elf32_Phdr) * i));
475 | log("phdr_tmp->p_vaddr ==> 0x%x\n", phdr_tmp->p_vaddr);
476 | if (phdr_tmp->p_type == 0x01) {
477 | phdr = phdr_tmp;
478 | break;
479 | }
480 | }
481 | log("phdr->p_vaddr ==> 0x%x\n", phdr->p_vaddr);
482 | if (phdr != NULL && phdr->p_vaddr != 0) {
483 | *addr -= phdr->p_vaddr;
484 | }
485 | return 0;
486 | }
487 |
488 | //尝试处理加密的so,
489 | //内存中未加密但是只能拿到.dynsym
490 | //.symtab目前只能通过soinfo拿到
491 | //7.0以上比较麻烦
492 | int find_name_dyn(pid_t pid, char *name, char *libn, unsigned long *addr) __attribute__((optnone)) {
493 | struct mm mm[1000];
494 | unsigned long libcaddr;
495 | int nmm;
496 | char libc[1024];
497 | symtab_t s;
498 |
499 | if (0 > load_memmap(pid, mm, &nmm)) {
500 | log("cannot read memory map\n")
501 | return -1;
502 | }
503 | if (0 > find_libname(libn, libc, sizeof(libc), &libcaddr, mm, nmm)) {
504 | log("cannot find lib\n");
505 | return -1;
506 | }
507 | *addr = libcaddr;
508 | log("libcaddr ==> %x", libcaddr);
509 | Elf32_Ehdr *ehdr = (Elf32_Ehdr *) libcaddr;
510 | log("ehdr->e_phoff: 0x%x\n", ehdr->e_phoff);
511 | log("ehdr->e_phnum: 0x%x\n", ehdr->e_phnum);
512 |
513 | Elf32_Phdr *phdr = NULL;
514 | for (int i = 0; i < ehdr->e_phnum; ++i) {
515 | log("in for");
516 | Elf32_Phdr *phdr_tmp = (Elf32_Phdr *) (libcaddr + ehdr->e_phoff + (sizeof(Elf32_Phdr) * i));
517 | log("phdr_tmp->p_vaddr ==> 0x%x\n", phdr_tmp->p_vaddr);
518 | if (phdr_tmp->p_type == 0x01) {
519 | phdr = phdr_tmp;
520 | break;
521 | }
522 | }
523 | log("phdr->p_vaddr ==> 0x%x\n", phdr->p_vaddr);
524 | Elf32_Addr va_fa_gap = phdr->p_vaddr;
525 |
526 | Elf32_Phdr *phdr_dyn = NULL;
527 | for (int i = 0; i < ehdr->e_phnum; ++i) {
528 | log("in for");
529 | Elf32_Phdr *phdr_tmp = (Elf32_Phdr *) (libcaddr + ehdr->e_phoff + (sizeof(Elf32_Phdr) * i));
530 | log("phdr_tmp->p_vaddr ==> 0x%x\n", phdr_tmp->p_vaddr);
531 | log("phdr_tmp->p_offset ==> 0x%x\n", phdr_tmp->p_offset);
532 | if (phdr_tmp->p_type == PT_DYNAMIC) {
533 | phdr_dyn = phdr_tmp;
534 | break;
535 | }
536 | }
537 | void* dyn_section = (void*)(libcaddr + phdr_dyn->p_offset + 0x1000);
538 | log("dyn_section ==> %p", dyn_section);
539 | Elf32_Sym *sym = NULL;
540 | Elf32_Addr str = NULL;
541 | Elf32_Sword dyn_str_size = NULL;
542 | for (Elf32_Dyn *dyn = (Elf32_Dyn *)dyn_section; dyn->d_tag != DT_NULL; dyn++){
543 | log("read dyn item flag=%x, value=0x%x", dyn->d_tag, dyn->d_un.d_val);
544 | if (dyn->d_tag == DT_STRTAB) {
545 | log("DT_STRTAB========================read dyn item flag=%d, value=0x%x", dyn->d_tag, dyn->d_un.d_ptr);
546 | str = (Elf32_Addr)(libcaddr + dyn->d_un.d_val - va_fa_gap);
547 | }
548 | if (dyn->d_tag == DT_SYMTAB) {
549 | log("DT_SYMTAB========================read dyn item flag=%d, value=0x%x", dyn->d_tag, dyn->d_un.d_ptr);
550 | sym = (Elf32_Sym*)(libcaddr + dyn->d_un.d_val - va_fa_gap);
551 | }
552 | if (dyn->d_tag == DT_STRSZ) {
553 | log("DT_STRSZ========================read dyn item flag=%d, value=0x%x", dyn->d_tag, dyn->d_un.d_val);
554 | dyn_str_size = (Elf32_Sword)(dyn->d_un.d_val);
555 | }
556 | }
557 | if (sym != NULL && str != NULL && dyn_str_size != NULL) {
558 | int count = 0;
559 | do {
560 | log("sym->st_name ==> %s", (char*)(str + sym->st_name));
561 | log("counte ==> %d", count++);
562 | } while (++sym != NULL && sym->st_name >=0 && sym->st_name < dyn_str_size);
563 | }
564 | if (phdr != NULL && phdr->p_vaddr != 0) {
565 | *addr -= va_fa_gap;
566 | }
567 | return 0;
568 | }
569 |
570 | // --------------------------------------------------------------
571 | #if 0
572 |
573 | # define IBAUD0 0
574 |
575 | /* Set *T to indicate raw mode. */
576 | void cfmakeraw (struct termios *t)
577 | {
578 | t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
579 | t->c_oflag &= ~OPOST;
580 | t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
581 | t->c_cflag &= ~(CSIZE|PARENB);
582 | t->c_cflag |= CS8;
583 | t->c_cc[VMIN] = 1; /* read returns when one char is available. */
584 | t->c_cc[VTIME] = 0;
585 | }
586 | #define __KERNEL_NCCS 19
587 | struct __kernel_termios
588 | {
589 | tcflag_t c_iflag; /* input mode flags */
590 | tcflag_t c_oflag; /* output mode flags */
591 | tcflag_t c_cflag; /* control mode flags */
592 | tcflag_t c_lflag; /* local mode flags */
593 | cc_t c_line; /* line discipline */
594 | cc_t c_cc[__KERNEL_NCCS]; /* control characters */
595 | };
596 |
597 |
598 | /* Set the state of FD to *TERMIOS_P. */
599 | int tcsetattr (int fd, int optional_actions, const struct termios *termios_p)
600 | {
601 | struct __kernel_termios k_termios;
602 | unsigned long int cmd;
603 | int retval;
604 |
605 | switch (optional_actions)
606 | {
607 | case TCSANOW:
608 | cmd = TCSETS;
609 | break;
610 | case TCSADRAIN:
611 | cmd = TCSETSW;
612 | break;
613 | case TCSAFLUSH:
614 | cmd = TCSETSF;
615 | break;
616 | default:
617 | //__set_errno (EINVAL);
618 | return -1;
619 | }
620 |
621 | k_termios.c_iflag = termios_p->c_iflag & ~IBAUD0;
622 | k_termios.c_oflag = termios_p->c_oflag;
623 | k_termios.c_cflag = termios_p->c_cflag;
624 | k_termios.c_lflag = termios_p->c_lflag;
625 | k_termios.c_line = termios_p->c_line;
626 | #ifdef _HAVE_C_ISPEED
627 | k_termios.c_ispeed = termios_p->c_ispeed;
628 | #endif
629 | #ifdef _HAVE_C_OSPEED
630 | k_termios.c_ospeed = termios_p->c_ospeed;
631 | #endif
632 | memcpy (&k_termios.c_cc[0], &termios_p->c_cc[0],
633 | __KERNEL_NCCS * sizeof (cc_t));
634 |
635 | retval = ioctl (fd, cmd, &k_termios);
636 |
637 | if (retval == 0 && cmd == TCSETS)
638 | {
639 | /* The Linux kernel has a bug which silently ignore the invalid
640 | c_cflag on pty. We have to check it here. */
641 | int save = 0; //errno;
642 | retval = ioctl (fd, TCGETS, &k_termios);
643 | if (retval)
644 | {
645 | /* We cannot verify if the setting is ok. We don't return
646 | an error (?). */
647 | //__set_errno (save);
648 | retval = 0;
649 | }
650 | else if ((termios_p->c_cflag & (PARENB | CREAD))
651 | != (k_termios.c_cflag & (PARENB | CREAD))
652 | || ((termios_p->c_cflag & CSIZE)
653 | && ((termios_p->c_cflag & CSIZE)
654 | != (k_termios.c_cflag & CSIZE))))
655 | {
656 | /* It looks like the Linux kernel silently changed the
657 | PARENB/CREAD/CSIZE bits in c_cflag. Report it as an
658 | error. */
659 | //__set_errno (EINVAL);
660 | retval = -1;
661 | }
662 | }
663 |
664 | return retval;
665 | }
666 |
667 | int tcgetattr (int fd, struct termios *termios_p)
668 | {
669 | struct __kernel_termios k_termios;
670 | int retval;
671 |
672 | retval = ioctl (fd, TCGETS, &k_termios);
673 | if(retval == 0) {
674 | termios_p->c_iflag = k_termios.c_iflag;
675 | termios_p->c_oflag = k_termios.c_oflag;
676 | termios_p->c_cflag = k_termios.c_cflag;
677 | termios_p->c_lflag = k_termios.c_lflag;
678 | termios_p->c_line = k_termios.c_line;
679 | #ifdef _HAVE_C_ISPEED
680 | termios_p->c_ispeed = k_termios.c_ispeed;
681 | #endif
682 | #ifdef _HAVE_C_OSPEED
683 | termios_p->c_ospeed = k_termios.c_ospeed;
684 | #endif
685 |
686 |
687 | if (sizeof (cc_t) == 1 || _POSIX_VDISABLE == 0
688 | || (unsigned char) _POSIX_VDISABLE == (unsigned char) -1)
689 | {
690 | #if 0
691 | memset (mempcpy (&termios_p->c_cc[0], &k_termios.c_cc[0],
692 | __KERNEL_NCCS * sizeof (cc_t)),
693 | _POSIX_VDISABLE, (NCCS - __KERNEL_NCCS) * sizeof (cc_t));
694 | #endif
695 | memset ( (memcpy (&termios_p->c_cc[0], &k_termios.c_cc[0],
696 | __KERNEL_NCCS * sizeof (cc_t)) + (__KERNEL_NCCS * sizeof (cc_t))) ,
697 | _POSIX_VDISABLE, (NCCS - __KERNEL_NCCS) * sizeof (cc_t));
698 |
699 | } else {
700 | size_t cnt;
701 |
702 | memcpy (&termios_p->c_cc[0], &k_termios.c_cc[0],
703 | __KERNEL_NCCS * sizeof (cc_t));
704 |
705 | for (cnt = __KERNEL_NCCS; cnt < NCCS; ++cnt)
706 | termios_p->c_cc[cnt] = _POSIX_VDISABLE;
707 | }
708 | }
709 |
710 | return retval;
711 | }
712 | #endif
713 |
--------------------------------------------------------------------------------
/jni/util.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Collin's Binary Instrumentation Tool/Framework for Android
3 | * Collin Mulliner
4 | * http://www.mulliner.org/android/
5 | *
6 | * (c) 2012,2013
7 | *
8 | * License: LGPL v2.1
9 | *
10 | */
11 |
12 | #include
13 | #ifdef __cplusplus
14 | extern "C" {
15 | #endif
16 | int find_name(pid_t pid, char *name, char *libn, unsigned long *addr);
17 | int find_libbase(pid_t pid, char *libn, unsigned long *addr);
18 |
19 | #ifdef __cplusplus
20 | }
21 | #endif
22 |
23 |
--------------------------------------------------------------------------------
/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 "log.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 |
--------------------------------------------------------------------------------
/jni/xhook/queue.h:
--------------------------------------------------------------------------------
1 | /*-
2 | * Copyright (c) 1991, 1993
3 | * The Regents of the University of California. All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of the University nor the names of its contributors
14 | * may be used to endorse or promote products derived from this software
15 | * without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 | * SUCH DAMAGE.
28 | *
29 | * @(#)queue.h 8.5 (Berkeley) 8/20/94
30 | * $FreeBSD: stable/9/sys/sys/queue.h 252365 2013-06-29 04:25:40Z lstewart $
31 | */
32 |
33 | #ifndef QUEUE_H
34 | #define QUEUE_H
35 |
36 | /* #include */
37 | #define __containerof(ptr, type, field) ((type *)((char *)(ptr) - ((char *)&((type *)0)->field)))
38 |
39 | /*
40 | * This file defines four types of data structures: singly-linked lists,
41 | * singly-linked tail queues, lists and tail queues.
42 | *
43 | * A singly-linked list is headed by a single forward pointer. The elements
44 | * are singly linked for minimum space and pointer manipulation overhead at
45 | * the expense of O(n) removal for arbitrary elements. New elements can be
46 | * added to the list after an existing element or at the head of the list.
47 | * Elements being removed from the head of the list should use the explicit
48 | * macro for this purpose for optimum efficiency. A singly-linked list may
49 | * only be traversed in the forward direction. Singly-linked lists are ideal
50 | * for applications with large datasets and few or no removals or for
51 | * implementing a LIFO queue.
52 | *
53 | * A singly-linked tail queue is headed by a pair of pointers, one to the
54 | * head of the list and the other to the tail of the list. The elements are
55 | * singly linked for minimum space and pointer manipulation overhead at the
56 | * expense of O(n) removal for arbitrary elements. New elements can be added
57 | * to the list after an existing element, at the head of the list, or at the
58 | * end of the list. Elements being removed from the head of the tail queue
59 | * should use the explicit macro for this purpose for optimum efficiency.
60 | * A singly-linked tail queue may only be traversed in the forward direction.
61 | * Singly-linked tail queues are ideal for applications with large datasets
62 | * and few or no removals or for implementing a FIFO queue.
63 | *
64 | * A list is headed by a single forward pointer (or an array of forward
65 | * pointers for a hash table header). The elements are doubly linked
66 | * so that an arbitrary element can be removed without a need to
67 | * traverse the list. New elements can be added to the list before
68 | * or after an existing element or at the head of the list. A list
69 | * may be traversed in either direction.
70 | *
71 | * A tail queue is headed by a pair of pointers, one to the head of the
72 | * list and the other to the tail of the list. The elements are doubly
73 | * linked so that an arbitrary element can be removed without a need to
74 | * traverse the list. New elements can be added to the list before or
75 | * after an existing element, at the head of the list, or at the end of
76 | * the list. A tail queue may be traversed in either direction.
77 | *
78 | * For details on the use of these macros, see the queue(3) manual page.
79 | *
80 | * SLIST LIST STAILQ TAILQ
81 | * _HEAD + + + +
82 | * _HEAD_INITIALIZER + + + +
83 | * _ENTRY + + + +
84 | * _INIT + + + +
85 | * _EMPTY + + + +
86 | * _FIRST + + + +
87 | * _NEXT + + + +
88 | * _PREV - + - +
89 | * _LAST - - + +
90 | * _FOREACH + + + +
91 | * _FOREACH_FROM + + + +
92 | * _FOREACH_SAFE + + + +
93 | * _FOREACH_FROM_SAFE + + + +
94 | * _FOREACH_REVERSE - - - +
95 | * _FOREACH_REVERSE_FROM - - - +
96 | * _FOREACH_REVERSE_SAFE - - - +
97 | * _FOREACH_REVERSE_FROM_SAFE - - - +
98 | * _INSERT_HEAD + + + +
99 | * _INSERT_BEFORE - + - +
100 | * _INSERT_AFTER + + + +
101 | * _INSERT_TAIL - - + +
102 | * _CONCAT - - + +
103 | * _REMOVE_AFTER + - + -
104 | * _REMOVE_HEAD + - + -
105 | * _REMOVE + + + +
106 | * _SWAP + + + +
107 | *
108 | */
109 |
110 | /*
111 | * Singly-linked List declarations.
112 | */
113 | #define SLIST_HEAD(name, type, qual) \
114 | struct name { \
115 | struct type *qual slh_first; /* first element */ \
116 | }
117 |
118 | #define SLIST_HEAD_INITIALIZER(head) \
119 | { NULL }
120 |
121 | #define SLIST_ENTRY(type, qual) \
122 | struct { \
123 | struct type *qual sle_next; /* next element */ \
124 | }
125 |
126 | /*
127 | * Singly-linked List functions.
128 | */
129 | #define SLIST_INIT(head) do { \
130 | SLIST_FIRST((head)) = NULL; \
131 | } while (0)
132 |
133 | #define SLIST_EMPTY(head) ((head)->slh_first == NULL)
134 |
135 | #define SLIST_FIRST(head) ((head)->slh_first)
136 |
137 | #define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
138 |
139 | #define SLIST_FOREACH(var, head, field) \
140 | for ((var) = SLIST_FIRST((head)); \
141 | (var); \
142 | (var) = SLIST_NEXT((var), field))
143 |
144 | #define SLIST_FOREACH_FROM(var, head, field) \
145 | for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
146 | (var); \
147 | (var) = SLIST_NEXT((var), field))
148 |
149 | #define SLIST_FOREACH_SAFE(var, head, field, tvar) \
150 | for ((var) = SLIST_FIRST((head)); \
151 | (var) && ((tvar) = SLIST_NEXT((var), field), 1); \
152 | (var) = (tvar))
153 |
154 | #define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
155 | for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
156 | (var) && ((tvar) = SLIST_NEXT((var), field), 1); \
157 | (var) = (tvar))
158 |
159 | #define SLIST_INSERT_HEAD(head, elm, field) do { \
160 | SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
161 | SLIST_FIRST((head)) = (elm); \
162 | } while (0)
163 |
164 | #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
165 | SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
166 | SLIST_NEXT((slistelm), field) = (elm); \
167 | } while (0)
168 |
169 | #define SLIST_REMOVE_AFTER(elm, field) do { \
170 | SLIST_NEXT(elm, field) = \
171 | SLIST_NEXT(SLIST_NEXT(elm, field), field); \
172 | } while (0)
173 |
174 | #define SLIST_REMOVE_HEAD(head, field) do { \
175 | SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
176 | } while (0)
177 |
178 | #define SLIST_REMOVE(head, elm, type, field) do { \
179 | if (SLIST_FIRST((head)) == (elm)) { \
180 | SLIST_REMOVE_HEAD((head), field); \
181 | } \
182 | else { \
183 | struct type *curelm = SLIST_FIRST((head)); \
184 | while (SLIST_NEXT(curelm, field) != (elm)) \
185 | curelm = SLIST_NEXT(curelm, field); \
186 | SLIST_REMOVE_AFTER(curelm, field); \
187 | } \
188 | } while (0)
189 |
190 | #define SLIST_SWAP(head1, head2, type) do { \
191 | struct type *swap_first = SLIST_FIRST(head1); \
192 | SLIST_FIRST(head1) = SLIST_FIRST(head2); \
193 | SLIST_FIRST(head2) = swap_first; \
194 | } while (0)
195 |
196 | /*
197 | * List declarations.
198 | */
199 | #define LIST_HEAD(name, type, qual) \
200 | struct name { \
201 | struct type *qual lh_first; /* first element */ \
202 | }
203 |
204 | #define LIST_HEAD_INITIALIZER(head) \
205 | { NULL }
206 |
207 | #define LIST_ENTRY(type, qual) \
208 | struct { \
209 | struct type *qual le_next; /* next element */ \
210 | struct type *qual *le_prev; /* address of previous next element */ \
211 | }
212 |
213 | /*
214 | * List functions.
215 | */
216 | #define LIST_INIT(head) do { \
217 | LIST_FIRST((head)) = NULL; \
218 | } while (0)
219 |
220 | #define LIST_EMPTY(head) ((head)->lh_first == NULL)
221 |
222 | #define LIST_FIRST(head) ((head)->lh_first)
223 |
224 | #define LIST_NEXT(elm, field) ((elm)->field.le_next)
225 |
226 | #define LIST_PREV(elm, head, type, field) \
227 | ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \
228 | __containerof((elm)->field.le_prev, struct type, field.le_next))
229 |
230 | #define LIST_FOREACH(var, head, field) \
231 | for ((var) = LIST_FIRST((head)); \
232 | (var); \
233 | (var) = LIST_NEXT((var), field))
234 |
235 | #define LIST_FOREACH_FROM(var, head, field) \
236 | for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
237 | (var); \
238 | (var) = LIST_NEXT((var), field))
239 |
240 | #define LIST_FOREACH_SAFE(var, head, field, tvar) \
241 | for ((var) = LIST_FIRST((head)); \
242 | (var) && ((tvar) = LIST_NEXT((var), field), 1); \
243 | (var) = (tvar))
244 |
245 | #define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
246 | for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
247 | (var) && ((tvar) = LIST_NEXT((var), field), 1); \
248 | (var) = (tvar))
249 |
250 | #define LIST_INSERT_HEAD(head, elm, field) do { \
251 | if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
252 | LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field); \
253 | LIST_FIRST((head)) = (elm); \
254 | (elm)->field.le_prev = &LIST_FIRST((head)); \
255 | } while (0)
256 |
257 | #define LIST_INSERT_BEFORE(listelm, elm, field) do { \
258 | (elm)->field.le_prev = (listelm)->field.le_prev; \
259 | LIST_NEXT((elm), field) = (listelm); \
260 | *(listelm)->field.le_prev = (elm); \
261 | (listelm)->field.le_prev = &LIST_NEXT((elm), field); \
262 | } while (0)
263 |
264 | #define LIST_INSERT_AFTER(listelm, elm, field) do { \
265 | if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL) \
266 | LIST_NEXT((listelm), field)->field.le_prev = \
267 | &LIST_NEXT((elm), field); \
268 | LIST_NEXT((listelm), field) = (elm); \
269 | (elm)->field.le_prev = &LIST_NEXT((listelm), field); \
270 | } while (0)
271 |
272 | #define LIST_REMOVE(elm, field) do { \
273 | if (LIST_NEXT((elm), field) != NULL) \
274 | LIST_NEXT((elm), field)->field.le_prev = \
275 | (elm)->field.le_prev; \
276 | *(elm)->field.le_prev = LIST_NEXT((elm), field); \
277 | } while (0)
278 |
279 | #define LIST_SWAP(head1, head2, type, field) do { \
280 | struct type *swap_tmp = LIST_FIRST((head1)); \
281 | LIST_FIRST((head1)) = LIST_FIRST((head2)); \
282 | LIST_FIRST((head2)) = swap_tmp; \
283 | if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
284 | swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
285 | if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
286 | swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
287 | } while (0)
288 |
289 | /*
290 | * Singly-linked Tail queue declarations.
291 | */
292 | #define STAILQ_HEAD(name, type, qual) \
293 | struct name { \
294 | struct type *qual stqh_first;/* first element */ \
295 | struct type *qual *stqh_last;/* addr of last next element */ \
296 | }
297 |
298 | #define STAILQ_HEAD_INITIALIZER(head) \
299 | { NULL, &(head).stqh_first }
300 |
301 | #define STAILQ_ENTRY(type, qual) \
302 | struct { \
303 | struct type *qual stqe_next; /* next element */ \
304 | }
305 |
306 | /*
307 | * Singly-linked Tail queue functions.
308 | */
309 | #define STAILQ_INIT(head) do { \
310 | STAILQ_FIRST((head)) = NULL; \
311 | (head)->stqh_last = &STAILQ_FIRST((head)); \
312 | } while (0)
313 |
314 | #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
315 |
316 | #define STAILQ_FIRST(head) ((head)->stqh_first)
317 |
318 | #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
319 |
320 | #define STAILQ_LAST(head, type, field) \
321 | (STAILQ_EMPTY((head)) ? NULL : \
322 | __containerof((head)->stqh_last, struct type, field.stqe_next))
323 |
324 | #define STAILQ_FOREACH(var, head, field) \
325 | for((var) = STAILQ_FIRST((head)); \
326 | (var); \
327 | (var) = STAILQ_NEXT((var), field))
328 |
329 | #define STAILQ_FOREACH_FROM(var, head, field) \
330 | for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
331 | (var); \
332 | (var) = STAILQ_NEXT((var), field))
333 |
334 | #define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
335 | for ((var) = STAILQ_FIRST((head)); \
336 | (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
337 | (var) = (tvar))
338 |
339 | #define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
340 | for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
341 | (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
342 | (var) = (tvar))
343 |
344 | #define STAILQ_INSERT_HEAD(head, elm, field) do { \
345 | if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
346 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \
347 | STAILQ_FIRST((head)) = (elm); \
348 | } while (0)
349 |
350 | #define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
351 | if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL) \
352 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \
353 | STAILQ_NEXT((tqelm), field) = (elm); \
354 | } while (0)
355 |
356 | #define STAILQ_INSERT_TAIL(head, elm, field) do { \
357 | STAILQ_NEXT((elm), field) = NULL; \
358 | *(head)->stqh_last = (elm); \
359 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \
360 | } while (0)
361 |
362 | #define STAILQ_CONCAT(head1, head2) do { \
363 | if (!STAILQ_EMPTY((head2))) { \
364 | *(head1)->stqh_last = (head2)->stqh_first; \
365 | (head1)->stqh_last = (head2)->stqh_last; \
366 | STAILQ_INIT((head2)); \
367 | } \
368 | } while (0)
369 |
370 | #define STAILQ_REMOVE_AFTER(head, elm, field) do { \
371 | if ((STAILQ_NEXT(elm, field) = \
372 | STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
373 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \
374 | } while (0)
375 |
376 | #define STAILQ_REMOVE_HEAD(head, field) do { \
377 | if ((STAILQ_FIRST((head)) = \
378 | STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
379 | (head)->stqh_last = &STAILQ_FIRST((head)); \
380 | } while (0)
381 |
382 | #define STAILQ_REMOVE(head, elm, type, field) do { \
383 | if (STAILQ_FIRST((head)) == (elm)) { \
384 | STAILQ_REMOVE_HEAD((head), field); \
385 | } \
386 | else { \
387 | struct type *curelm = STAILQ_FIRST((head)); \
388 | while (STAILQ_NEXT(curelm, field) != (elm)) \
389 | curelm = STAILQ_NEXT(curelm, field); \
390 | STAILQ_REMOVE_AFTER(head, curelm, field); \
391 | } \
392 | } while (0)
393 |
394 | #define STAILQ_SWAP(head1, head2, type) do { \
395 | struct type *swap_first = STAILQ_FIRST(head1); \
396 | struct type **swap_last = (head1)->stqh_last; \
397 | STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
398 | (head1)->stqh_last = (head2)->stqh_last; \
399 | STAILQ_FIRST(head2) = swap_first; \
400 | (head2)->stqh_last = swap_last; \
401 | if (STAILQ_EMPTY(head1)) \
402 | (head1)->stqh_last = &STAILQ_FIRST(head1); \
403 | if (STAILQ_EMPTY(head2)) \
404 | (head2)->stqh_last = &STAILQ_FIRST(head2); \
405 | } while (0)
406 |
407 | /*
408 | * Tail queue declarations.
409 | */
410 | #define TAILQ_HEAD(name, type, qual) \
411 | struct name { \
412 | struct type *qual tqh_first; /* first element */ \
413 | struct type *qual *tqh_last; /* addr of last next element */ \
414 | }
415 |
416 | #define TAILQ_HEAD_INITIALIZER(head) \
417 | { NULL, &(head).tqh_first }
418 |
419 | #define TAILQ_ENTRY(type, qual) \
420 | struct { \
421 | struct type *qual tqe_next; /* next element */ \
422 | struct type *qual *tqe_prev; /* address of previous next element */ \
423 | }
424 |
425 | /*
426 | * Tail queue functions.
427 | */
428 | #define TAILQ_INIT(head) do { \
429 | TAILQ_FIRST((head)) = NULL; \
430 | (head)->tqh_last = &TAILQ_FIRST((head)); \
431 | } while (0)
432 |
433 | #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
434 |
435 | #define TAILQ_FIRST(head) ((head)->tqh_first)
436 |
437 | #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
438 |
439 | #define TAILQ_PREV(elm, headname, field) \
440 | (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
441 |
442 | #define TAILQ_LAST(head, headname) \
443 | (*(((struct headname *)((head)->tqh_last))->tqh_last))
444 |
445 | #define TAILQ_FOREACH(var, head, field) \
446 | for ((var) = TAILQ_FIRST((head)); \
447 | (var); \
448 | (var) = TAILQ_NEXT((var), field))
449 |
450 | #define TAILQ_FOREACH_FROM(var, head, field) \
451 | for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
452 | (var); \
453 | (var) = TAILQ_NEXT((var), field))
454 |
455 | #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
456 | for ((var) = TAILQ_FIRST((head)); \
457 | (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
458 | (var) = (tvar))
459 |
460 | #define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
461 | for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
462 | (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
463 | (var) = (tvar))
464 |
465 | #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
466 | for ((var) = TAILQ_LAST((head), headname); \
467 | (var); \
468 | (var) = TAILQ_PREV((var), headname, field))
469 |
470 | #define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \
471 | for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
472 | (var); \
473 | (var) = TAILQ_PREV((var), headname, field))
474 |
475 | #define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
476 | for ((var) = TAILQ_LAST((head), headname); \
477 | (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
478 | (var) = (tvar))
479 |
480 | #define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \
481 | for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
482 | (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
483 | (var) = (tvar))
484 |
485 | #define TAILQ_INSERT_HEAD(head, elm, field) do { \
486 | if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
487 | TAILQ_FIRST((head))->field.tqe_prev = \
488 | &TAILQ_NEXT((elm), field); \
489 | else \
490 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \
491 | TAILQ_FIRST((head)) = (elm); \
492 | (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
493 | } while (0)
494 |
495 | #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
496 | (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
497 | TAILQ_NEXT((elm), field) = (listelm); \
498 | *(listelm)->field.tqe_prev = (elm); \
499 | (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
500 | } while (0)
501 |
502 | #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
503 | if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL) \
504 | TAILQ_NEXT((elm), field)->field.tqe_prev = \
505 | &TAILQ_NEXT((elm), field); \
506 | else \
507 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \
508 | TAILQ_NEXT((listelm), field) = (elm); \
509 | (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
510 | } while (0)
511 |
512 | #define TAILQ_INSERT_TAIL(head, elm, field) do { \
513 | TAILQ_NEXT((elm), field) = NULL; \
514 | (elm)->field.tqe_prev = (head)->tqh_last; \
515 | *(head)->tqh_last = (elm); \
516 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \
517 | } while (0)
518 |
519 | #define TAILQ_CONCAT(head1, head2, field) do { \
520 | if (!TAILQ_EMPTY(head2)) { \
521 | *(head1)->tqh_last = (head2)->tqh_first; \
522 | (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
523 | (head1)->tqh_last = (head2)->tqh_last; \
524 | TAILQ_INIT((head2)); \
525 | } \
526 | } while (0)
527 |
528 | #define TAILQ_REMOVE(head, elm, field) do { \
529 | if ((TAILQ_NEXT((elm), field)) != NULL) \
530 | TAILQ_NEXT((elm), field)->field.tqe_prev = \
531 | (elm)->field.tqe_prev; \
532 | else \
533 | (head)->tqh_last = (elm)->field.tqe_prev; \
534 | *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
535 | } while (0)
536 |
537 | #define TAILQ_SWAP(head1, head2, type, field) do { \
538 | struct type *swap_first = (head1)->tqh_first; \
539 | struct type **swap_last = (head1)->tqh_last; \
540 | (head1)->tqh_first = (head2)->tqh_first; \
541 | (head1)->tqh_last = (head2)->tqh_last; \
542 | (head2)->tqh_first = swap_first; \
543 | (head2)->tqh_last = swap_last; \
544 | if ((swap_first = (head1)->tqh_first) != NULL) \
545 | swap_first->field.tqe_prev = &(head1)->tqh_first; \
546 | else \
547 | (head1)->tqh_last = &(head1)->tqh_first; \
548 | if ((swap_first = (head2)->tqh_first) != NULL) \
549 | swap_first->field.tqe_prev = &(head2)->tqh_first; \
550 | else \
551 | (head2)->tqh_last = &(head2)->tqh_first; \
552 | } while (0)
553 |
554 | #endif
555 |
--------------------------------------------------------------------------------
/jni/xhook/xh_core.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2018-04-11.
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include "queue.h"
35 | #include "tree.h"
36 | #include "xh_errno.h"
37 | #include "xh_log.h"
38 | #include "xh_elf.h"
39 | #include "xh_version.h"
40 | #include "xh_core.h"
41 |
42 | #define XH_CORE_DEBUG 0
43 |
44 | //registered hook info collection
45 | typedef struct xh_core_hook_info
46 | {
47 | #if XH_CORE_DEBUG
48 | char *pathname_regex_str;
49 | #endif
50 | regex_t pathname_regex;
51 | char *symbol;
52 | void *new_func;
53 | void **old_func;
54 | TAILQ_ENTRY(xh_core_hook_info,) link;
55 | } xh_core_hook_info_t;
56 | typedef TAILQ_HEAD(xh_core_hook_info_queue, xh_core_hook_info,) xh_core_hook_info_queue_t;
57 |
58 | //ignored hook info collection
59 | typedef struct xh_core_ignore_info
60 | {
61 | #if XH_CORE_DEBUG
62 | char *pathname_regex_str;
63 | #endif
64 | regex_t pathname_regex;
65 | char *symbol; //NULL meaning for all symbols
66 | TAILQ_ENTRY(xh_core_ignore_info,) link;
67 | } xh_core_ignore_info_t;
68 | typedef TAILQ_HEAD(xh_core_ignore_info_queue, xh_core_ignore_info,) xh_core_ignore_info_queue_t;
69 |
70 | //required info from /proc/self/maps
71 | typedef struct xh_core_map_info
72 | {
73 | char *pathname;
74 | uintptr_t base_addr;
75 | xh_elf_t elf;
76 | RB_ENTRY(xh_core_map_info) link;
77 | } xh_core_map_info_t;
78 | static __inline__ int xh_core_map_info_cmp(xh_core_map_info_t *a, xh_core_map_info_t *b)
79 | {
80 | return strcmp(a->pathname, b->pathname);
81 | }
82 | typedef RB_HEAD(xh_core_map_info_tree, xh_core_map_info) xh_core_map_info_tree_t;
83 | RB_GENERATE_STATIC(xh_core_map_info_tree, xh_core_map_info, link, xh_core_map_info_cmp)
84 |
85 | //signal handler for SIGSEGV
86 | //for xh_elf_init(), xh_elf_hook(), xh_elf_check_elfheader()
87 | static int xh_core_sigsegv_enable = 1; //enable by default
88 | static struct sigaction xh_core_sigsegv_act_old;
89 | static volatile int xh_core_sigsegv_flag = 0;
90 | static sigjmp_buf xh_core_sigsegv_env;
91 | static void xh_core_sigsegv_handler(int sig)
92 | {
93 | (void)sig;
94 |
95 | if(xh_core_sigsegv_flag)
96 | siglongjmp(xh_core_sigsegv_env, 1);
97 | else
98 | sigaction(SIGSEGV, &xh_core_sigsegv_act_old, NULL);
99 | }
100 | static int xh_core_add_sigsegv_handler()
101 | {
102 | struct sigaction act;
103 |
104 | if(!xh_core_sigsegv_enable) return 0;
105 |
106 | if(0 != sigemptyset(&act.sa_mask)) return (0 == errno ? XH_ERRNO_UNKNOWN : errno);
107 | act.sa_handler = xh_core_sigsegv_handler;
108 |
109 | if(0 != sigaction(SIGSEGV, &act, &xh_core_sigsegv_act_old))
110 | return (0 == errno ? XH_ERRNO_UNKNOWN : errno);
111 |
112 | return 0;
113 | }
114 | static void xh_core_del_sigsegv_handler()
115 | {
116 | if(!xh_core_sigsegv_enable) return;
117 |
118 | sigaction(SIGSEGV, &xh_core_sigsegv_act_old, NULL);
119 | }
120 |
121 |
122 | static xh_core_hook_info_queue_t xh_core_hook_info = TAILQ_HEAD_INITIALIZER(xh_core_hook_info);
123 | static xh_core_ignore_info_queue_t xh_core_ignore_info = TAILQ_HEAD_INITIALIZER(xh_core_ignore_info);
124 | static xh_core_map_info_tree_t xh_core_map_info = RB_INITIALIZER(&xh_core_map_info);
125 | static pthread_mutex_t xh_core_mutex = PTHREAD_MUTEX_INITIALIZER;
126 | static pthread_cond_t xh_core_cond = PTHREAD_COND_INITIALIZER;
127 | static volatile int xh_core_inited = 0;
128 | static volatile int xh_core_init_ok = 0;
129 | static volatile int xh_core_async_inited = 0;
130 | static volatile int xh_core_async_init_ok = 0;
131 | static pthread_mutex_t xh_core_refresh_mutex = PTHREAD_MUTEX_INITIALIZER;
132 | static pthread_t xh_core_refresh_thread_tid;
133 | static volatile int xh_core_refresh_thread_running = 0;
134 | static volatile int xh_core_refresh_thread_do = 0;
135 |
136 |
137 | int xh_core_register(const char *pathname_regex_str, const char *symbol,
138 | void *new_func, void **old_func)
139 | {
140 | xh_core_hook_info_t *hi;
141 | regex_t regex;
142 |
143 | if(NULL == pathname_regex_str || NULL == symbol || NULL == new_func) return XH_ERRNO_INVAL;
144 |
145 | if(xh_core_inited)
146 | {
147 | XH_LOG_ERROR("do not register hook after refresh(): %s, %s", pathname_regex_str, symbol);
148 | return XH_ERRNO_INVAL;
149 | }
150 |
151 | if(0 != regcomp(®ex, pathname_regex_str, REG_NOSUB)) return XH_ERRNO_INVAL;
152 |
153 | if(NULL == (hi = malloc(sizeof(xh_core_hook_info_t)))) return XH_ERRNO_NOMEM;
154 | if(NULL == (hi->symbol = strdup(symbol)))
155 | {
156 | free(hi);
157 | return XH_ERRNO_NOMEM;
158 | }
159 | #if XH_CORE_DEBUG
160 | if(NULL == (hi->pathname_regex_str = strdup(pathname_regex_str)))
161 | {
162 | free(hi->symbol);
163 | free(hi);
164 | return XH_ERRNO_NOMEM;
165 | }
166 | #endif
167 | hi->pathname_regex = regex;
168 | hi->new_func = new_func;
169 | hi->old_func = old_func;
170 |
171 | pthread_mutex_lock(&xh_core_mutex);
172 | TAILQ_INSERT_TAIL(&xh_core_hook_info, hi, link);
173 | pthread_mutex_unlock(&xh_core_mutex);
174 |
175 | return 0;
176 | }
177 |
178 | int xh_core_ignore(const char *pathname_regex_str, const char *symbol)
179 | {
180 | xh_core_ignore_info_t *ii;
181 | regex_t regex;
182 |
183 | if(NULL == pathname_regex_str) return XH_ERRNO_INVAL;
184 |
185 | if(xh_core_inited)
186 | {
187 | XH_LOG_ERROR("do not ignore hook after refresh(): %s, %s", pathname_regex_str, symbol ? symbol : "ALL");
188 | return XH_ERRNO_INVAL;
189 | }
190 |
191 | if(0 != regcomp(®ex, pathname_regex_str, REG_NOSUB)) return XH_ERRNO_INVAL;
192 |
193 | if(NULL == (ii = malloc(sizeof(xh_core_ignore_info_t)))) return XH_ERRNO_NOMEM;
194 | if(NULL != symbol)
195 | {
196 | if(NULL == (ii->symbol = strdup(symbol)))
197 | {
198 | free(ii);
199 | return XH_ERRNO_NOMEM;
200 | }
201 | }
202 | else
203 | {
204 | ii->symbol = NULL; //ignore all symbols
205 | }
206 | #if XH_CORE_DEBUG
207 | if(NULL == (ii->pathname_regex_str = strdup(pathname_regex_str)))
208 | {
209 | free(ii->symbol);
210 | free(ii);
211 | return XH_ERRNO_NOMEM;
212 | }
213 | #endif
214 | ii->pathname_regex = regex;
215 |
216 | pthread_mutex_lock(&xh_core_mutex);
217 | TAILQ_INSERT_TAIL(&xh_core_ignore_info, ii, link);
218 | pthread_mutex_unlock(&xh_core_mutex);
219 |
220 | return 0;
221 | }
222 |
223 | static int xh_core_check_elf_header(uintptr_t base_addr, const char *pathname)
224 | {
225 | if(!xh_core_sigsegv_enable)
226 | {
227 | return xh_elf_check_elfheader(base_addr);
228 | }
229 | else
230 | {
231 | int ret = XH_ERRNO_UNKNOWN;
232 |
233 | xh_core_sigsegv_flag = 1;
234 | if(0 == sigsetjmp(xh_core_sigsegv_env, 1))
235 | {
236 | ret = xh_elf_check_elfheader(base_addr);
237 | }
238 | else
239 | {
240 | ret = XH_ERRNO_SEGVERR;
241 | XH_LOG_WARN("catch SIGSEGV when check_elfheader: %s", pathname);
242 | }
243 | xh_core_sigsegv_flag = 0;
244 | return ret;
245 | }
246 | }
247 |
248 | static void xh_core_hook_impl(xh_core_map_info_t *mi)
249 | {
250 | //init
251 | if(0 != xh_elf_init(&(mi->elf), mi->base_addr, mi->pathname)) return;
252 |
253 | //hook
254 | xh_core_hook_info_t *hi;
255 | xh_core_ignore_info_t *ii;
256 | int ignore;
257 | TAILQ_FOREACH(hi, &xh_core_hook_info, link) //find hook info
258 | {
259 | if(0 == regexec(&(hi->pathname_regex), mi->pathname, 0, NULL, 0))
260 | {
261 | ignore = 0;
262 | TAILQ_FOREACH(ii, &xh_core_ignore_info, link) //find ignore info
263 | {
264 | if(0 == regexec(&(ii->pathname_regex), mi->pathname, 0, NULL, 0))
265 | {
266 | if(NULL == ii->symbol) //ignore all symbols
267 | return;
268 |
269 | if(0 == strcmp(ii->symbol, hi->symbol)) //ignore the current symbol
270 | {
271 | ignore = 1;
272 | break;
273 | }
274 | }
275 | }
276 |
277 | if(0 == ignore)
278 | xh_elf_hook(&(mi->elf), hi->symbol, hi->new_func, hi->old_func);
279 | }
280 | }
281 | }
282 |
283 | static void xh_core_hook(xh_core_map_info_t *mi)
284 | {
285 | if(!xh_core_sigsegv_enable)
286 | {
287 | xh_core_hook_impl(mi);
288 | }
289 | else
290 | {
291 | xh_core_sigsegv_flag = 1;
292 | if(0 == sigsetjmp(xh_core_sigsegv_env, 1))
293 | {
294 | xh_core_hook_impl(mi);
295 | }
296 | else
297 | {
298 | XH_LOG_WARN("catch SIGSEGV when init or hook: %s", mi->pathname);
299 | }
300 | xh_core_sigsegv_flag = 0;
301 | }
302 | }
303 |
304 | static void xh_core_refresh_impl()
305 | {
306 | char line[512];
307 | FILE *fp;
308 | uintptr_t base_addr;
309 | char perm[5];
310 | unsigned long offset;
311 | int pathname_pos;
312 | char *pathname;
313 | size_t pathname_len;
314 | xh_core_map_info_t *mi, *mi_tmp;
315 | xh_core_map_info_t mi_key;
316 | xh_core_hook_info_t *hi;
317 | xh_core_ignore_info_t *ii;
318 | int match;
319 | xh_core_map_info_tree_t map_info_refreshed = RB_INITIALIZER(&map_info_refreshed);
320 |
321 | if(NULL == (fp = fopen("/proc/self/maps", "r")))
322 | {
323 | XH_LOG_ERROR("fopen /proc/self/maps failed");
324 | return;
325 | }
326 |
327 | while(fgets(line, sizeof(line), fp))
328 | {
329 | if(sscanf(line, "%"PRIxPTR"-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue;
330 |
331 | //check permission
332 | if(perm[0] != 'r') continue;
333 | if(perm[3] != 'p') continue; //do not touch the shared memory
334 |
335 | //check offset
336 | //
337 | //We are trying to find ELF header in memory.
338 | //It can only be found at the beginning of a mapped memory regions
339 | //whose offset is 0.
340 | if(0 != offset) continue;
341 |
342 | //get pathname
343 | while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1))
344 | pathname_pos += 1;
345 | if(pathname_pos >= (int)(sizeof(line) - 1)) continue;
346 | pathname = line + pathname_pos;
347 | pathname_len = strlen(pathname);
348 | if(0 == pathname_len) continue;
349 | if(pathname[pathname_len - 1] == '\n')
350 | {
351 | pathname[pathname_len - 1] = '\0';
352 | pathname_len -= 1;
353 | }
354 | if(0 == pathname_len) continue;
355 | if('[' == pathname[0]) continue;
356 |
357 | //check pathname
358 | //if we need to hook this elf?
359 | match = 0;
360 | TAILQ_FOREACH(hi, &xh_core_hook_info, link) //find hook info
361 | {
362 | if(0 == regexec(&(hi->pathname_regex), pathname, 0, NULL, 0))
363 | {
364 | TAILQ_FOREACH(ii, &xh_core_ignore_info, link) //find ignore info
365 | {
366 | if(0 == regexec(&(ii->pathname_regex), pathname, 0, NULL, 0))
367 | {
368 | if(NULL == ii->symbol)
369 | goto check_finished;
370 |
371 | if(0 == strcmp(ii->symbol, hi->symbol))
372 | goto check_continue;
373 | }
374 | }
375 |
376 | match = 1;
377 | check_continue:
378 | break;
379 | }
380 | }
381 | check_finished:
382 | if(0 == match) continue;
383 |
384 | //check elf header format
385 | //We are trying to do ELF header checking as late as possible.
386 | if(0 != xh_core_check_elf_header(base_addr, pathname)) continue;
387 |
388 | //check existed map item
389 | mi_key.pathname = pathname;
390 | if(NULL != (mi = RB_FIND(xh_core_map_info_tree, &xh_core_map_info, &mi_key)))
391 | {
392 | //exist
393 | RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi);
394 |
395 | //repeated?
396 | //We only keep the first one, that is the real base address
397 | if(NULL != RB_INSERT(xh_core_map_info_tree, &map_info_refreshed, mi))
398 | {
399 | #if XH_CORE_DEBUG
400 | XH_LOG_DEBUG("repeated map info when update: %s", line);
401 | #endif
402 | free(mi->pathname);
403 | free(mi);
404 | continue;
405 | }
406 |
407 | //re-hook if base_addr changed
408 | if(mi->base_addr != base_addr)
409 | {
410 | mi->base_addr = base_addr;
411 | xh_core_hook(mi);
412 | }
413 | }
414 | else
415 | {
416 | //not exist, create a new map info
417 | if(NULL == (mi = (xh_core_map_info_t *)malloc(sizeof(xh_core_map_info_t)))) continue;
418 | if(NULL == (mi->pathname = strdup(pathname)))
419 | {
420 | free(mi);
421 | continue;
422 | }
423 | mi->base_addr = base_addr;
424 |
425 | //repeated?
426 | //We only keep the first one, that is the real base address
427 | if(NULL != RB_INSERT(xh_core_map_info_tree, &map_info_refreshed, mi))
428 | {
429 | #if XH_CORE_DEBUG
430 | XH_LOG_DEBUG("repeated map info when create: %s", line);
431 | #endif
432 | free(mi->pathname);
433 | free(mi);
434 | continue;
435 | }
436 |
437 | //hook
438 | xh_core_hook(mi); //hook
439 | }
440 | }
441 | fclose(fp);
442 |
443 | //free all missing map item, maybe dlclosed?
444 | RB_FOREACH_SAFE(mi, xh_core_map_info_tree, &xh_core_map_info, mi_tmp)
445 | {
446 | #if XH_CORE_DEBUG
447 | XH_LOG_DEBUG("remove missing map info: %s", mi->pathname);
448 | #endif
449 | RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi);
450 | if(mi->pathname) free(mi->pathname);
451 | free(mi);
452 | }
453 |
454 | //save the new refreshed map info tree
455 | xh_core_map_info = map_info_refreshed;
456 |
457 | XH_LOG_INFO("map refreshed");
458 |
459 | #if XH_CORE_DEBUG
460 | RB_FOREACH(mi, xh_core_map_info_tree, &xh_core_map_info)
461 | XH_LOG_DEBUG(" %"PRIxPTR" %s\n", mi->base_addr, mi->pathname);
462 | #endif
463 | }
464 |
465 | static void *xh_core_refresh_thread_func(void *arg)
466 | {
467 | (void)arg;
468 |
469 | pthread_setname_np(pthread_self(), "xh_refresh_loop");
470 |
471 | while(xh_core_refresh_thread_running)
472 | {
473 | //waiting for a refresh task or exit
474 | pthread_mutex_lock(&xh_core_mutex);
475 | while(!xh_core_refresh_thread_do && xh_core_refresh_thread_running)
476 | {
477 | pthread_cond_wait(&xh_core_cond, &xh_core_mutex);
478 | }
479 | if(!xh_core_refresh_thread_running)
480 | {
481 | pthread_mutex_unlock(&xh_core_mutex);
482 | break;
483 | }
484 | xh_core_refresh_thread_do = 0;
485 | pthread_mutex_unlock(&xh_core_mutex);
486 |
487 | //refresh
488 | pthread_mutex_lock(&xh_core_refresh_mutex);
489 | xh_core_refresh_impl();
490 | pthread_mutex_unlock(&xh_core_refresh_mutex);
491 | }
492 |
493 | return NULL;
494 | }
495 |
496 | static void xh_core_init_once()
497 | {
498 | if(xh_core_inited) return;
499 |
500 | pthread_mutex_lock(&xh_core_mutex);
501 |
502 | if(xh_core_inited) goto end;
503 |
504 | xh_core_inited = 1;
505 |
506 | //dump debug info
507 | XH_LOG_INFO("%s\n", xh_version_str_full());
508 | #if XH_CORE_DEBUG
509 | xh_core_hook_info_t *hi;
510 | TAILQ_FOREACH(hi, &xh_core_hook_info, link)
511 | XH_LOG_INFO(" hook: %s @ %s, (%p, %p)\n", hi->symbol, hi->pathname_regex_str,
512 | hi->new_func, hi->old_func);
513 | xh_core_ignore_info_t *ii;
514 | TAILQ_FOREACH(ii, &xh_core_ignore_info, link)
515 | XH_LOG_INFO(" ignore: %s @ %s\n", ii->symbol ? ii->symbol : "ALL ",
516 | ii->pathname_regex_str);
517 | #endif
518 |
519 | //register signal handler
520 | if(0 != xh_core_add_sigsegv_handler()) goto end;
521 |
522 | //OK
523 | xh_core_init_ok = 1;
524 |
525 | end:
526 | pthread_mutex_unlock(&xh_core_mutex);
527 | }
528 |
529 | static void xh_core_init_async_once()
530 | {
531 | if(xh_core_async_inited) return;
532 |
533 | pthread_mutex_lock(&xh_core_mutex);
534 |
535 | if(xh_core_async_inited) goto end;
536 |
537 | xh_core_async_inited = 1;
538 |
539 | //create async refresh thread
540 | xh_core_refresh_thread_running = 1;
541 | if(0 != pthread_create(&xh_core_refresh_thread_tid, NULL, &xh_core_refresh_thread_func, NULL))
542 | {
543 | xh_core_refresh_thread_running = 0;
544 | goto end;
545 | }
546 |
547 | //OK
548 | xh_core_async_init_ok = 1;
549 |
550 | end:
551 | pthread_mutex_unlock(&xh_core_mutex);
552 | }
553 |
554 | int xh_core_refresh(int async)
555 | {
556 | //init
557 | xh_core_init_once();
558 | if(!xh_core_init_ok) return XH_ERRNO_UNKNOWN;
559 |
560 | if(async)
561 | {
562 | //init for async
563 | xh_core_init_async_once();
564 | if(!xh_core_async_init_ok) return XH_ERRNO_UNKNOWN;
565 |
566 | //refresh async
567 | pthread_mutex_lock(&xh_core_mutex);
568 | xh_core_refresh_thread_do = 1;
569 | pthread_cond_signal(&xh_core_cond);
570 | pthread_mutex_unlock(&xh_core_mutex);
571 | }
572 | else
573 | {
574 | //refresh sync
575 | pthread_mutex_lock(&xh_core_refresh_mutex);
576 | xh_core_refresh_impl();
577 | pthread_mutex_unlock(&xh_core_refresh_mutex);
578 | }
579 |
580 | return 0;
581 | }
582 |
583 | void xh_core_clear()
584 | {
585 | //stop the async refresh thread
586 | if(xh_core_async_init_ok)
587 | {
588 | pthread_mutex_lock(&xh_core_mutex);
589 | xh_core_refresh_thread_running = 0;
590 | pthread_cond_signal(&xh_core_cond);
591 | pthread_mutex_unlock(&xh_core_mutex);
592 |
593 | pthread_join(xh_core_refresh_thread_tid, NULL);
594 | xh_core_async_init_ok = 0;
595 | }
596 | xh_core_async_inited = 0;
597 |
598 | //unregister the sig handler
599 | if(xh_core_init_ok)
600 | {
601 | xh_core_del_sigsegv_handler();
602 | xh_core_init_ok = 0;
603 | }
604 | xh_core_inited = 0;
605 |
606 | pthread_mutex_lock(&xh_core_mutex);
607 | pthread_mutex_lock(&xh_core_refresh_mutex);
608 |
609 | //free all map info
610 | xh_core_map_info_t *mi, *mi_tmp;
611 | RB_FOREACH_SAFE(mi, xh_core_map_info_tree, &xh_core_map_info, mi_tmp)
612 | {
613 | RB_REMOVE(xh_core_map_info_tree, &xh_core_map_info, mi);
614 | if(mi->pathname) free(mi->pathname);
615 | free(mi);
616 | }
617 |
618 | //free all hook info
619 | xh_core_hook_info_t *hi, *hi_tmp;
620 | TAILQ_FOREACH_SAFE(hi, &xh_core_hook_info, link, hi_tmp)
621 | {
622 | TAILQ_REMOVE(&xh_core_hook_info, hi, link);
623 | #if XH_CORE_DEBUG
624 | free(hi->pathname_regex_str);
625 | #endif
626 | regfree(&(hi->pathname_regex));
627 | free(hi->symbol);
628 | free(hi);
629 | }
630 |
631 | //free all ignore info
632 | xh_core_ignore_info_t *ii, *ii_tmp;
633 | TAILQ_FOREACH_SAFE(ii, &xh_core_ignore_info, link, ii_tmp)
634 | {
635 | TAILQ_REMOVE(&xh_core_ignore_info, ii, link);
636 | #if XH_CORE_DEBUG
637 | free(ii->pathname_regex_str);
638 | #endif
639 | regfree(&(ii->pathname_regex));
640 | free(ii->symbol);
641 | free(ii);
642 | }
643 |
644 | pthread_mutex_unlock(&xh_core_refresh_mutex);
645 | pthread_mutex_unlock(&xh_core_mutex);
646 | }
647 |
648 | void xh_core_enable_debug(int flag)
649 | {
650 | xh_log_priority = (flag ? ANDROID_LOG_DEBUG : ANDROID_LOG_WARN);
651 | }
652 |
653 | void xh_core_enable_sigsegv_protection(int flag)
654 | {
655 | xh_core_sigsegv_enable = (flag ? 1 : 0);
656 | }
657 |
--------------------------------------------------------------------------------
/jni/xhook/xh_core.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2018-04-11.
23 |
24 | #ifndef XH_CORE_H
25 | #define XH_CORE_H 1
26 |
27 | #ifdef __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | int xh_core_register(const char *pathname_regex_str, const char *symbol,
32 | void *new_func, void **old_func);
33 |
34 | int xh_core_ignore(const char *pathname_regex_str, const char *symbol);
35 |
36 | int xh_core_refresh(int async);
37 |
38 | void xh_core_clear();
39 |
40 | void xh_core_enable_debug(int flag);
41 |
42 | void xh_core_enable_sigsegv_protection(int flag);
43 |
44 | #ifdef __cplusplus
45 | }
46 | #endif
47 |
48 | #endif
49 |
--------------------------------------------------------------------------------
/jni/xhook/xh_elf.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2018-04-11.
23 |
24 | #ifndef XH_ELF_H
25 | #define XH_ELF_H 1
26 |
27 | #include
28 | #include
29 | #include
30 |
31 | #ifdef __cplusplus
32 | extern "C" {
33 | #endif
34 |
35 | typedef struct
36 | {
37 | const char *pathname;
38 |
39 | ElfW(Addr) base_addr;
40 | ElfW(Addr) bias_addr;
41 |
42 | ElfW(Ehdr) *ehdr;
43 | ElfW(Phdr) *phdr;
44 |
45 | ElfW(Dyn) *dyn; //.dynamic
46 | ElfW(Word) dyn_sz;
47 |
48 | const char *strtab; //.dynstr (string-table)
49 | ElfW(Sym) *symtab; //.dynsym (symbol-index to string-table's offset)
50 |
51 | ElfW(Addr) relplt; //.rel.plt or .rela.plt
52 | ElfW(Word) relplt_sz;
53 |
54 | ElfW(Addr) reldyn; //.rel.dyn or .rela.dyn
55 | ElfW(Word) reldyn_sz;
56 |
57 | ElfW(Addr) relandroid; //android compressed rel or rela
58 | ElfW(Word) relandroid_sz;
59 |
60 | //for ELF hash
61 | uint32_t *bucket;
62 | uint32_t bucket_cnt;
63 | uint32_t *chain;
64 | uint32_t chain_cnt; //invalid for GNU hash
65 |
66 | //append for GNU hash
67 | uint32_t symoffset;
68 | ElfW(Addr) *bloom;
69 | uint32_t bloom_sz;
70 | uint32_t bloom_shift;
71 |
72 | int is_use_rela;
73 | int is_use_gnu_hash;
74 | } xh_elf_t;
75 |
76 | int xh_elf_init(xh_elf_t *self, uintptr_t base_addr, const char *pathname);
77 | int xh_elf_hook(xh_elf_t *self, const char *symbol, void *new_func, void **old_func);
78 |
79 | int xh_elf_check_elfheader(uintptr_t base_addr);
80 |
81 | #ifdef __cplusplus
82 | }
83 | #endif
84 |
85 | #endif
86 |
--------------------------------------------------------------------------------
/jni/xhook/xh_errno.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2018-04-11.
23 |
24 | #ifndef XH_ERRNO_H
25 | #define XH_ERRNO_H 1
26 |
27 | #define XH_ERRNO_UNKNOWN 1001
28 | #define XH_ERRNO_INVAL 1002
29 | #define XH_ERRNO_NOMEM 1003
30 | #define XH_ERRNO_REPEAT 1004
31 | #define XH_ERRNO_NOTFND 1005
32 | #define XH_ERRNO_BADMAPS 1006
33 | #define XH_ERRNO_FORMAT 1007
34 | #define XH_ERRNO_ELFINIT 1008
35 | #define XH_ERRNO_SEGVERR 1009
36 |
37 | #endif
38 |
--------------------------------------------------------------------------------
/jni/xhook/xh_jni.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2018-04-11.
23 |
24 | #include
25 | #include "xhook.h"
26 |
27 | #define JNI_API_DEF(f) Java_com_qiyi_xhook_NativeHandler_##f
28 |
29 | JNIEXPORT jint JNI_API_DEF(refresh)(JNIEnv *env, jobject obj, jboolean async)
30 | {
31 | (void)env;
32 | (void)obj;
33 |
34 | return xhook_refresh(async ? 1 : 0);
35 | }
36 |
37 | JNIEXPORT void JNI_API_DEF(clear)(JNIEnv *env, jobject obj)
38 | {
39 | (void)env;
40 | (void)obj;
41 |
42 | xhook_clear();
43 | }
44 |
45 | JNIEXPORT void JNI_API_DEF(enableDebug)(JNIEnv *env, jobject obj, jboolean flag)
46 | {
47 | (void)env;
48 | (void)obj;
49 |
50 | xhook_enable_debug(flag ? 1 : 0);
51 | }
52 |
53 | JNIEXPORT void JNI_API_DEF(enableSigSegvProtection)(JNIEnv *env, jobject obj, jboolean flag)
54 | {
55 | (void)env;
56 | (void)obj;
57 |
58 | xhook_enable_sigsegv_protection(flag ? 1 : 0);
59 | }
60 |
--------------------------------------------------------------------------------
/jni/xhook/xh_log.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2018-04-11.
23 |
24 | #include
25 | #include "xh_log.h"
26 |
27 | android_LogPriority xh_log_priority = ANDROID_LOG_WARN;
28 |
--------------------------------------------------------------------------------
/jni/xhook/xh_log.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2018-04-11.
23 |
24 | #ifndef XH_LOG_H
25 | #define XH_LOG_H 1
26 |
27 | #include
28 |
29 | #ifdef __cplusplus
30 | extern "C" {
31 | #endif
32 |
33 | extern android_LogPriority xh_log_priority;
34 |
35 | #define XH_LOG_TAG "xhook"
36 | #define XH_LOG_DEBUG(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_DEBUG) __android_log_print(ANDROID_LOG_DEBUG, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0)
37 | #define XH_LOG_INFO(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_INFO) __android_log_print(ANDROID_LOG_INFO, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0)
38 | #define XH_LOG_WARN(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_WARN) __android_log_print(ANDROID_LOG_WARN, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0)
39 | #define XH_LOG_ERROR(fmt, ...) do{if(xh_log_priority <= ANDROID_LOG_ERROR) __android_log_print(ANDROID_LOG_ERROR, XH_LOG_TAG, fmt, ##__VA_ARGS__);}while(0)
40 |
41 | #ifdef __cplusplus
42 | }
43 | #endif
44 |
45 | #endif
46 |
--------------------------------------------------------------------------------
/jni/xhook/xh_util.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2018-04-11.
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include "xh_util.h"
37 | #include "xh_errno.h"
38 | #include "xh_log.h"
39 |
40 | #define PAGE_START(addr) ((addr) & PAGE_MASK)
41 | #define PAGE_END(addr) (PAGE_START(addr + sizeof(uintptr_t) - 1) + PAGE_SIZE)
42 | #define PAGE_COVER(addr) (PAGE_END(addr) - PAGE_START(addr))
43 |
44 | int xh_util_get_mem_protect(uintptr_t addr, size_t len, const char *pathname, unsigned int *prot)
45 | {
46 | uintptr_t start_addr = addr;
47 | uintptr_t end_addr = addr + len;
48 | FILE *fp;
49 | char line[512];
50 | uintptr_t start, end;
51 | char perm[5];
52 | int load0 = 1;
53 | int found_all = 0;
54 |
55 | *prot = 0;
56 |
57 | if(NULL == (fp = fopen("/proc/self/maps", "r"))) return XH_ERRNO_BADMAPS;
58 |
59 | while(fgets(line, sizeof(line), fp))
60 | {
61 | if(NULL != pathname)
62 | if(NULL == strstr(line, pathname)) continue;
63 |
64 | if(sscanf(line, "%"PRIxPTR"-%"PRIxPTR" %4s ", &start, &end, perm) != 3) continue;
65 |
66 | if(perm[3] != 'p') continue;
67 |
68 | if(start_addr >= start && start_addr < end)
69 | {
70 | if(load0)
71 | {
72 | //first load segment
73 | if(perm[0] == 'r') *prot |= PROT_READ;
74 | if(perm[1] == 'w') *prot |= PROT_WRITE;
75 | if(perm[2] == 'x') *prot |= PROT_EXEC;
76 | load0 = 0;
77 | }
78 | else
79 | {
80 | //others
81 | if(perm[0] != 'r') *prot &= ~PROT_READ;
82 | if(perm[1] != 'w') *prot &= ~PROT_WRITE;
83 | if(perm[2] != 'x') *prot &= ~PROT_EXEC;
84 | }
85 |
86 | if(end_addr <= end)
87 | {
88 | found_all = 1;
89 | break; //finished
90 | }
91 | else
92 | {
93 | start_addr = end; //try to find the next load segment
94 | }
95 | }
96 | }
97 |
98 | fclose(fp);
99 |
100 | if(!found_all) return XH_ERRNO_SEGVERR;
101 |
102 | return 0;
103 | }
104 |
105 | int xh_util_get_addr_protect(uintptr_t addr, const char *pathname, unsigned int *prot)
106 | {
107 | return xh_util_get_mem_protect(addr, sizeof(addr), pathname, prot);
108 | }
109 |
110 | int xh_util_set_addr_protect(uintptr_t addr, unsigned int prot)
111 | {
112 | if(0 != mprotect((void *)PAGE_START(addr), PAGE_COVER(addr), (int)prot))
113 | return 0 == errno ? XH_ERRNO_UNKNOWN : errno;
114 |
115 | return 0;
116 | }
117 |
118 | void xh_util_flush_instruction_cache(uintptr_t addr)
119 | {
120 | __builtin___clear_cache((void *)PAGE_START(addr), (void *)PAGE_END(addr));
121 | }
122 |
--------------------------------------------------------------------------------
/jni/xhook/xh_util.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2018-04-11.
23 |
24 | #ifndef XH_UTILS_H
25 | #define XH_UTILS_H 1
26 |
27 | #ifdef __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | #if defined(__LP64__)
32 | #define XH_UTIL_FMT_LEN "16"
33 | #define XH_UTIL_FMT_X "llx"
34 | #else
35 | #define XH_UTIL_FMT_LEN "8"
36 | #define XH_UTIL_FMT_X "x"
37 | #endif
38 |
39 | #define XH_UTIL_FMT_FIXED_X XH_UTIL_FMT_LEN XH_UTIL_FMT_X
40 | #define XH_UTIL_FMT_FIXED_S XH_UTIL_FMT_LEN "s"
41 |
42 | int xh_util_get_mem_protect(uintptr_t addr, size_t len, const char *pathname, unsigned int *prot);
43 | int xh_util_get_addr_protect(uintptr_t addr, const char *pathname, unsigned int *prot);
44 | int xh_util_set_addr_protect(uintptr_t addr, unsigned int prot);
45 | void xh_util_flush_instruction_cache(uintptr_t addr);
46 |
47 | #ifdef __cplusplus
48 | }
49 | #endif
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/jni/xhook/xh_version.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2018-04-11.
23 |
24 | #include "xh_version.h"
25 |
26 | #define XH_VERSION_MAJOR 1
27 | #define XH_VERSION_MINOR 1
28 | #define XH_VERSION_EXTRA 9
29 |
30 | #define XH_VERSION ((XH_VERSION_MAJOR << 16) | (XH_VERSION_MINOR << 8) | (XH_VERSION_EXTRA))
31 |
32 | #define XH_VERSION_TO_STR_HELPER(x) #x
33 | #define XH_VERSION_TO_STR(x) XH_VERSION_TO_STR_HELPER(x)
34 |
35 | #define XH_VERSION_STR XH_VERSION_TO_STR(XH_VERSION_MAJOR) "." \
36 | XH_VERSION_TO_STR(XH_VERSION_MINOR) "." \
37 | XH_VERSION_TO_STR(XH_VERSION_EXTRA)
38 |
39 | #if defined(__arm__)
40 | #define XH_VERSION_ARCH "arm"
41 | #elif defined(__aarch64__)
42 | #define XH_VERSION_ARCH "aarch64"
43 | #elif defined(__i386__)
44 | #define XH_VERSION_ARCH "x86"
45 | #elif defined(__x86_64__)
46 | #define XH_VERSION_ARCH "x86_64"
47 | #else
48 | #define XH_VERSION_ARCH "unknown"
49 | #endif
50 |
51 | #define XH_VERSION_STR_FULL "libxhook "XH_VERSION_STR" ("XH_VERSION_ARCH")"
52 |
53 | unsigned int xh_version()
54 | {
55 | return XH_VERSION;
56 | }
57 |
58 | const char *xh_version_str()
59 | {
60 | return XH_VERSION_STR;
61 | }
62 |
63 | const char *xh_version_str_full()
64 | {
65 | return XH_VERSION_STR_FULL;
66 | }
67 |
--------------------------------------------------------------------------------
/jni/xhook/xh_version.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2018-04-11.
23 |
24 | #ifndef XH_VERSION_H
25 | #define XH_VERSION_H 1
26 |
27 | #ifdef __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | unsigned int xh_version();
32 |
33 | const char *xh_version_str();
34 |
35 | const char *xh_version_str_full();
36 |
37 | #ifdef __cplusplus
38 | }
39 | #endif
40 |
41 | #endif
42 |
--------------------------------------------------------------------------------
/jni/xhook/xhook.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2018-04-11.
23 |
24 | #include "xh_core.h"
25 | #include "xhook.h"
26 |
27 | int xhook_register(const char *pathname_regex_str, const char *symbol,
28 | void *new_func, void **old_func)
29 | {
30 | return xh_core_register(pathname_regex_str, symbol, new_func, old_func);
31 | }
32 |
33 | int xhook_ignore(const char *pathname_regex_str, const char *symbol)
34 | {
35 | return xh_core_ignore(pathname_regex_str, symbol);
36 | }
37 |
38 | int xhook_refresh(int async)
39 | {
40 | return xh_core_refresh(async);
41 | }
42 |
43 | void xhook_clear()
44 | {
45 | return xh_core_clear();
46 | }
47 |
48 | void xhook_enable_debug(int flag)
49 | {
50 | return xh_core_enable_debug(flag);
51 | }
52 |
53 | void xhook_enable_sigsegv_protection(int flag)
54 | {
55 | return xh_core_enable_sigsegv_protection(flag);
56 | }
57 |
--------------------------------------------------------------------------------
/jni/xhook/xhook.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2018-present, iQIYI, Inc. All rights reserved.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2018-04-11.
23 |
24 | #ifndef XHOOK_H
25 | #define XHOOK_H 1
26 |
27 | #ifdef __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | #define XHOOK_EXPORT __attribute__((visibility("default")))
32 |
33 | int xhook_register(const char *pathname_regex_str, const char *symbol,
34 | void *new_func, void **old_func) XHOOK_EXPORT;
35 |
36 | int xhook_ignore(const char *pathname_regex_str, const char *symbol) XHOOK_EXPORT;
37 |
38 | int xhook_refresh(int async) XHOOK_EXPORT;
39 |
40 | void xhook_clear() XHOOK_EXPORT;
41 |
42 | void xhook_enable_debug(int flag) XHOOK_EXPORT;
43 |
44 | void xhook_enable_sigsegv_protection(int flag) XHOOK_EXPORT;
45 |
46 | #ifdef __cplusplus
47 | }
48 | #endif
49 |
50 | #endif
51 |
--------------------------------------------------------------------------------