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