├── .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 | --------------------------------------------------------------------------------