长春网站排名优化,免费完整视频播放器哔哩哔哩,房地产最新消息是涨还是跌,如何做自己的个人网站大概是2020年的时候#xff0c;有一次#xff0c;我们的竞争同行有另外一家公司要用我们的安卓软件app,拉了个群#xff0c;告知他用一个软件多少钱#xff0c;然后在群里发了一个我打包的apk包。结果就没有下文了。又过了一个月。我同事在那个要买我们apk的人的朋友圈有一次我们的竞争同行有另外一家公司要用我们的安卓软件app,拉了个群告知他用一个软件多少钱然后在群里发了一个我打包的apk包。结果就没有下文了。又过了一个月。我同事在那个要买我们apk的人的朋友圈发现他拍的宣传照片和我们的app界面非常相似。来问我了。我那时候觉得我apk加固的还可以。代码也都做了混淆。应该不会被破解了。排除了这可能后来公司领导还专门因为这个事开了会。讨论了下都怀疑是有内鬼把apk的解密卖了出去。然后这个事就不了了之了。 直到2024年他们的设备过保了。我们公司又中了他们之前安装的设备的维保项目然后我忽然想起来之前发生过的这个事情来。就和那边同时远程解决售后问题的时候。才发现我打包的apk被人套了个壳从新打包了。名字和图标都被改了。但是进去以后的界面和功能都没有变。很明显我的android apk包被人破解了。重新打了包。并且商用了。整个西藏所有的网点都用了这个apk。当时整个人瞬间感觉都不好了。那天心情一直很低落。证明我的加固根本就没有起大的作用。我发现这个事的时候就给老板发了消息。老板没有回我信息。我就胡思乱想是不是老板会质疑我的能力。心里也挺痛恨那个破解我apk并且商用的公司和人。这就像我的孩子换了个衣服让人给拐走了。是我做好安全防护。等上班以后。我就开始研究他是怎么给我破解的。自己把自己做的老版本给破解了。非常简单10分钟都不到就从新打包运行了。
先简单介绍下我的app。第一个界面一个激活界面。激活界面需要我们授权授权通过激活界面以后。会直接跳入设置界面就行相应的配置。激活后的设备。下次进入软件会直接进到设置界面。他反编译从新打包的我的软件版本是1.9版本。android1.9版本的app下的build.gradle配置如下
apply plugin: com.android.application
android {compileSdkVersion 26defaultConfig {applicationId minSdkVersion 17targetSdkVersion 26versionCode 1versionName 1.7testInstrumentationRunner androidx.support.test.runner.AndroidJUnitRunner//加载红外的cpp文件externalNativeBuild {cmake {cppFlags }}//abiFilter armeabindk {abiFilters armeabi}// Enabling multidex support.multiDexEnabled true}//签名配置。 配置名release{ //配置内容 }signingConfigs {release {try {storeFile file(plbs.jks)storePassword KEYSTORE_PASSWORDkeyAlias plbs-androidkeyPassword KEY_PASSWORD}catch (ex) {throw new InvalidUserDataException(You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.)}}}buildTypes {debug {//允许debugdebuggable truesigningConfig signingConfigs.release //在buildTypes中指定release时的signingConfigs对应的配置名}release {signingConfig signingConfigs.release //在buildTypes中指定release时的signingConfigs对应的配置名zipAlignEnabled true //Zipalign优化shrinkResources true // 移除无用的resource文件minifyEnabled true//是否混淆debuggable trueproguardFiles getDefaultProguardFile(proguard-android.txt), proguard-rules.pro}}externalNativeBuild {cmake {path CMakeLists.txt}}//gradle3.01 从新的打包android.applicationVariants.all { variant -variant.outputs.all {outputFileName 重庆金融数据播放${defaultConfig.versionName}_${releaseTime()}.apk}}
}
def releaseTime() {return new Date().format(yyyy-MM-dd, TimeZone.getTimeZone(UTC))
}
dependencies {implementation com.android.support.constraint:constraint-layout:1.0.2implementation fileTree(include: [*.jar], dir: libs)testImplementation junit:junit:4.12debugImplementation com.squareup.leakcanary:leakcanary-android:1.3releaseImplementation com.squareup.leakcanary:leakcanary-android-no-op:1.3implementation com.android.support:appcompat-v7:26.1.0implementation com.jiechic.library:xUtils:2.6.14implementation com.squareup.picasso:picasso:2.5.2implementation com.squareup.okhttp3:okhttp:3.7.0implementation com.google.code.gson:gson:2.8.0implementation com.squareup.okio:okio:1.13.0implementation org.greenrobot:eventbus:3.0.0implementation com.github.bumptech.glide:glide:3.7.0implementation org.java-websocket:Java-WebSocket:1.4.0// 字体fontimplementation uk.co.chrisjenx:calligraphy:2.2.0//粒子动画implementation com.plattysoft.leonids:LeonidsLib:1.3.2//加载dll 动态文件implementation files(libs/jna-3.1.0.jar)implementation files(libs/fastjson-1.2.12.jar)implementation files(libs/xstream-1.4.7.jar)implementation files(libs/zxing.jar)implementation files(libs/sun.misc.BASE64Decoder.jar)implementation com.android.support:multidex:1.0.1//webview加载网页太慢用 第三方的webview加载网页implementation ren.yale.android:cachewebviewlib:2.1.8}反编译攻先演示下是如何通过反编译从新打包1.9版本的
首先从这个网址下载apktool工具链接如下iBotPeaches / Apktool / Downloads — Bitbucket
我下载的是apktool2.4的版本的工具有需要的自己下载相应的版本。
1.9版本的第一个需要激活的界面如下图名字叫LoginActivity 通过第一个界面我们授权激活以后就跳转第二个设置界面名字叫CCBSetActivity。如下图 将我的1.9版本的apk包放到apktool工具所在的文件夹目录下如下图 在此目录下打开cmd命令。
在cmd中输入以下命令
java -jar apktool.jar d -f 1.9.apk -o out
命令的目的是将1.9.apk反编译到out目录下 如下图结束运行后可以看到在目录下多了个out文件夹。 打开out就可以看到反编译后的文件。 在清单文件里就可以修改入口了。
清单文件和android打包前的目录是完全一致的。如下
?xml version1.0 encodingutf-8 standaloneno?manifest xmlns:androidhttp://schemas.android.com/apk/res/android packagecom.meiaomei.absadplayerrotationuses-permission android:nameandroid.permission.SYSTEM_ALERT_WINDOW/uses-permission android:nameandroid.permission.READ_PHONE_STATE/uses-permission android:nameandroid.permission.READ_CONTACTS/uses-permission android:nameandroid.permission.INTERNET/uses-permission android:nameandroid.permission.WRITE_EXTERNAL_STORAGE/uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE/uses-permission android:nameandroid.permission.ACCESS_WIFI_STATE/uses-permission android:nameandroid.permission.CHANGE_WIFI_STATE/uses-permission android:nameandroid.permission.WAKE_LOCK/uses-permission android:nameandroid.permission.RECEIVE_BOOT_COMPLETED/uses-permission android:nameandroid.permission.CHANGE_NETWORK_STATE/uses-permission android:nameandroid.permission.CAMERA/uses-permission android:nameandroid.permission.GET_TASKS/uses-permission android:nameandroid.permission.DISABLE_KEYGUARD/application android:allowBackuptrue android:debuggabletrue android:iconmipmap/icon android:labelstring/app_name android:namecom.meiaomei.absadplayerrotation.AbsPlbsApplication android:supportsRtltrue android:themeandroid:style/Theme.NoTitleBar.Fullscreenactivity android:configChangeskeyboardHidden|orientation|screenSize android:launchModesingleTask android:namecom.meiaomei.absadplayerrotation.activity.CCBSetActivity android:screenOrientationunspecified android:windowSoftInputModestateHidden/activity android:configChangeskeyboardHidden|orientation|screenSize android:launchModesingleTask android:namecom.meiaomei.absadplayerrotation.activity.LoginActivityintent-filteraction android:nameandroid.intent.action.MAIN/category android:nameandroid.intent.category.LAUNCHER//intent-filter/activityreceiver /application
/manifest
可以看到入口文件是LoginActivity。将入口文件的LoginActivity修改为配置界面的CCBSetActivity。这样就可以跳过激活界面直接到配置界面。在这个反编译的文件里也可以修改xml布局文件。我们简单修改下CCBSetActivity的布局文件将系统设置4个字改为 我被狗币反编译了。如果你想修改app的图标还有app的名字在这里都可以改。改完从新打包即可。那个公司的人肯定也是这么反编译我的包的。然后换名字从新打包。 修改完清单文件AndroidManifest.xml的入口直接为系统设置界面CCBSetActivity。并且将设置界面的系统设置4个字改为 我被狗币反编译了。
然后我们从新打包这个修改过的out文件
cmd里执行以下命令
java -jar apktool.jar b -o 1.9change.apk out 将out重新打包为 1.9change.apk。 cmd执行完成后。我们可以看到已经在这个文件目录下有了一个叫1.9change.apk的包了。 这个重新打包的包拖动到模拟器里安装的时候会显示安装失败。因为这个从新打包的包没有签名。就是平常我们在as里面点击这个Generate Signed Bundle or APK按钮。然后输入app的别名账号密码等的这个按钮输入完成就打包了。 因为缺少这个签名。我们可以新建一个AS项目。然后快速的打包。会生成一个.jks文件。将这个生产的.jks文件拷贝至这个目录下。用这个.jks去替换原来这个apk的签名文件。 此时在cmd里在次执行
jarsigner -verbose -keystore aqy.jks -storepass youpassword -signedjar 1.9change_signed.apk 1.9change.apk key0
这里的youpassword就是你给新项目打包的密码替换成自己的即可。这个命令就是用aqy.jks的签名文件去给这个1.9change.apk签名生成一个1.9change_signed.apk的签名的apk包。敲完回车就会看到在重新签名。 签名成功以后。会在该目录下生成一个叫做 1.9change_signed.apk的包。 把这个包拖动到夜神模拟器安装会显示安装成功。至此完美的绕过了我设置的激活界面。打开以后看下。我在out文件里修改设置界面的布局也生效了。如下图 我能确定他就是通过这个方法反编译了我的1.9版本。
反编译防
事后我也在思考。我的失误就是我把激活界面放在首页以后在别的界面没有做校验。在首页激活软件以后。应该在每一个界面都去问下软件。是否是激活的如果不是就不让他继续使用软件。我的两个界面没有任何联系。导致他直接跳过了我的激活界面。把程序的入口修改了。
因为我们的软件是对接的第三方的接口接口是对方给的接口也没有关于安全方面的校验。没办法通过后台去做是否激活的校验。并且软件是运行在内网中的。不涉及到互联网安装后我们也没法去控制。导致别的公司破解以后就可以直接接入运行。
我后来的修改就是每个界面加了是否激活的校验如果没有激活就强制退出软件。
在修改的过程中我发现android的res目录下的valuse下的文件很不安全。被对方反编译以后。这个目录下的所有string都暴漏了。一些重要的数据最好都不要存在这里如果万不得已非要存最后采用密文存储。不要用明文。并且把名字都修改下。
之前我把激活界面的3DES对称加密的秘钥都存这里如下图真是够胆大的哈 string nameKEYnpiTUAL6InCrYPLAdbtlQfnqCNoVG5/stringstring nameIVSqHzP3eZlXE/string现在的修改是将他们都隐藏起来。把名字修改成很普通的。很容易混淆视听的名字。
然后将3DES的秘钥字符串用AES的公钥将加密一下。用的时候用私钥先进行解密。然后再去使用。如图所示涉及到非常重要的数据。从命名到数据都尽量的隐藏起来。让破解的人不知道你这个是做什么的。这样就不好去修改和破解。 string namet13C8659595676946B94D7F7C7F9A27141FC84A96049349B9116DC2E3BBCADD379E9C9063D1E7DC4013DF0BD5A135B895F3477A00E6B01C7D92D9A04BDC7D4B8623A162C69915AAFAA1CA2F5464EE7C95383174A1450AD265874B37B99812404D9947DEBB57FCA249D5F96E8ED4A5D45A25F7FB84F704D9144280C93638B96F67FB59C2AEB5DD94268613F8508E32423ACB7001E1D2994C799F9B80C8EA7BF229F2F7CA0FB2301580D31A8046F87589279E4191DAE0446B3367E06D064157E4109A2DB0CE0A9DC92422905519327525E343B07D4BBE2F81328127F39B51E067A6D612F7AD703FF75E5DECA1C50B80D79052CA7687CA491FDB288269DFC5BAAB876/stringstring namet2264578595676946B94D7F7C7F9A27141FC84A96049349B9116DC2E3BBCADD379E9C9063D1E7DC4013DF0BD5A135B895F3477A00E6B01C7D92D9A04BDC7D4B8623A162C69915AAFAA1CA2F5464EE7C95383174A1450AD265874B37B99812404D9947DEBB57FCA249D5F96E8ED4A5D45A25F7FB84F704D9144280C93638B96F67FB59C2AEB5DD94268613F8508E32423ACB7001E1D2994C799F9B80C8EA7BF229F2F7CA0FB2301580D31A8046F87589279E4191DAE0446B3367E06D064157E4109A2DB0CE0A9DC92422905519327525E343B07D4BBE2F81328127F39B51E067A6D612F7AD703FF75E5DECA1C50B80D79052CA7687CA491FDB288269DFC5BAAB876/string
加密key 和iv的时候可以用以下的RSA加密工具类 import android.os.Environment;
import java.io.File;
import java.io.IOException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import Decoder.BASE64Decoder;
import Decoder.BASE64Encoder;
/*** RSA 工具类生成/保存密钥对、加密、解密*/
public class RSAUtils {public static void main() {// 随机生成一对密钥包含公钥和私钥KeyPair keyPair null;try {keyPair RSAUtils.generateKeyPair();// 获取 公钥 和 私钥PublicKey pubKey keyPair.getPublic();PrivateKey priKey keyPair.getPrivate();// 保存 公钥 和 私钥RSAUtils.saveKeyForEncodedBase64(pubKey, new File(Environment.getExternalStorageDirectory() /pub1.txt));RSAUtils.saveKeyForEncodedBase64(priKey, new File(Environment.getExternalStorageDirectory() /pri1.txt));} catch (Exception e) {e.printStackTrace();}}/*** 算法名称*/private static final String ALGORITHM RSA;/*** 密钥长度*/private static final int KEY_SIZE 2048;/*** 加密, 返回加密后的数据*/public static byte[] clientEncrypt(byte[] plainData, File pubFile) {// 读取公钥文件, 创建公钥对象PublicKey pubKey null;byte[] cipher {};try {pubKey getPublicKey(IOUtils.readFile(pubFile));// 用公钥加密数据cipher RSAUtils.encrypt(plainData, pubKey);} catch (Exception e) {e.printStackTrace();}return cipher;}/*** 解密, 返回解密后的数据*/public static byte[] serverDecrypt(byte[] cipherData, File priFile) {// 读取私钥文件, 创建私钥对象PrivateKey priKey null;byte[] plainData {};try {priKey getPrivateKey(IOUtils.readFile(priFile));// 用私钥解密数据plainData RSAUtils.decrypt(cipherData, priKey);} catch (Exception e) {e.printStackTrace();}return plainData;}/*** 随机生成密钥对包含公钥和私钥*/public static KeyPair generateKeyPair() throws Exception {// 获取指定算法的密钥对生成器KeyPairGenerator gen KeyPairGenerator.getInstance(ALGORITHM);// 初始化密钥对生成器指定密钥长度, 使用默认的安全随机数源gen.initialize(KEY_SIZE);// 随机生成一对密钥包含公钥和私钥return gen.generateKeyPair();}/*** 将 公钥/私钥 编码后以 Base64 的格式保存到指定文件*/public static void saveKeyForEncodedBase64(Key key, File keyFile) throws IOException {// 获取密钥编码后的格式byte[] encBytes key.getEncoded();// 转换为 Base64 文本String encBase64 new BASE64Encoder().encode(encBytes);// 保存到文件IOUtils.writeFile(encBase64, keyFile);}/*** 根据公钥的 Base64 文本创建公钥对象*/public static PublicKey getPublicKey(String pubKeyBase64) throws Exception {// 把 公钥的Base64文本 转换为已编码的 公钥bytesbyte[] encPubKey new BASE64Decoder().decodeBuffer(pubKeyBase64);// 创建 已编码的公钥规格X509EncodedKeySpec encPubKeySpec new X509EncodedKeySpec(encPubKey);// 获取指定算法的密钥工厂, 根据 已编码的公钥规格, 生成公钥对象return KeyFactory.getInstance(ALGORITHM).generatePublic(encPubKeySpec);}/*** 根据私钥的 Base64 文本创建私钥对象*/public static PrivateKey getPrivateKey(String priKeyBase64) throws Exception {// 把 私钥的Base64文本 转换为已编码的 私钥bytesbyte[] encPriKey new BASE64Decoder().decodeBuffer(priKeyBase64);// 创建 已编码的私钥规格PKCS8EncodedKeySpec encPriKeySpec new PKCS8EncodedKeySpec(encPriKey);// 获取指定算法的密钥工厂, 根据 已编码的私钥规格, 生成私钥对象return KeyFactory.getInstance(ALGORITHM).generatePrivate(encPriKeySpec);}/*** 公钥加密数据*/public static byte[] encrypt(byte[] plainData, PublicKey pubKey) throws Exception {// 获取指定算法的密码器Cipher cipher Cipher.getInstance(ALGORITHM);// 初始化密码器公钥加密模型cipher.init(Cipher.ENCRYPT_MODE, pubKey);// 加密数据, 返回加密后的密文return cipher.doFinal(plainData);}/*** 私钥解密数据*/public static byte[] decrypt(byte[] cipherData, PrivateKey priKey) throws Exception {// 获取指定算法的密码器Cipher cipher Cipher.getInstance(ALGORITHM);// 初始化密码器私钥解密模型cipher.init(Cipher.DECRYPT_MODE, priKey);// 解密数据, 返回解密后的明文return cipher.doFinal(cipherData);}
}import java.io.*;
/*** IO 工具类, 读写文件*/
public class IOUtils {public static void writeFile(String data, File file) throws IOException {OutputStream out null;try {out new FileOutputStream(file);out.write(data.getBytes());out.flush();} finally {close(out);}}public static String readFile(File file) throws IOException {InputStream in null;ByteArrayOutputStream out null;try {in new FileInputStream(file);out new ByteArrayOutputStream();byte[] buf new byte[1024];int len -1;while ((len in.read(buf)) ! -1) {out.write(buf, 0, len);}out.flush();byte[] data out.toByteArray();return new String(data);} finally {close(in);close(out);}}public static void close(Closeable c) {if (c ! null) {try {c.close();} catch (IOException e) {// nothing}}}
}在任意一个activity的界面里生成公钥和私钥用公钥去加密需要保护的数据如下图
需要注意的是公钥加密完后的byte[]数组转换为string的时候不可以用new String(byte[]a)直接去转加密返回的byte[]中存在负值例如-116 。负数在Ascii码中是没有对应的值。所以直接用你new String去转byte的时候采用文件默认字符集UTF-8,处理时遇到解析不了的值会用 ‘\uFFFD’代替显示为 ‘’。解密的时候再次采用string.getbytes()将 转换回byte的话 由于找不到对应的Ascii值。会造成数据丢失。导致解密以后的数据和加密的数据对不上。所以采用HexUtils转换一下。解密的时候也用这个工具类将string转为byte。最后再去new String()。就会拿到原来加密前的字符串。然后我们将这个加密后的秘钥放在string里。这样就算破解了也不能马上就看到这个秘钥。 private void aa() {RSAUtils.main();//随机生成公钥和私钥File pubFile new File(Environment.getExternalStorageDirectory() /pub1.txt);byte keyByteEncy[]clientEncrypt(npiTUAL6InCrYPLAdbtlQfnqCNoVG5.getBytes(),pubFile);File priFile new File(Environment.getExternalStorageDirectory() /pri1.txt);String sHexUtils.bytesToHexString(keyByteEncy);Log.e(TAG, aa1: s );byte keyDecry[] serverDecrypt(HexUtils.hexStringToBytes(s),priFile);Log.e(TAG, aa2: new String(keyDecry));}//2024-12-18 15:39:16.206 4688-4688/com.hyw.safetyofficertiku E/SecureLife: aa1: 71CD5EE6506C035F749E356495E2C0847F1A38488C45569B24F74414C8EEB566DEF81B6B40F44BDBC5E3D1F5F82365FF84C931E1E34B5D77AA66062B4775D90343018F04931A3A92C401176041E2183EABABAA8DCAE0036E5028119905D44284A3E963DCB3AD4B88702C1396FC85808D5503A947F6EDB0C541BA05E8C26E28094DC56F9BE12E7856D12AC680DFC93B82BA1972CF24AE48097563334186D993508EC24F5A1C334DCF177935D825F257779487740BCDFFF2C84D81CD9C9EDC91D9E87EE25A9CE4DEDB46158E57C428C95EDE70DF372035782B3F45CA3AF962937EEA4967A0EDE6D860176DB737014DB00CCAA9DDFF5A8F902CEBA33FA49032EF70
//2024-12-18 15:39:16.214 4688-4688/com.hyw.safetyofficertiku E/SecureLife: aa2: npiTUAL6InCrYPLAdbtlQfnqCNoVG5
此处附上HeXUtils类。 public class HexUtils {private static final char[] DIGITS {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F};public static String bytesToHexString(byte[] data) {String string ;try {char[] chars new char[data.length 1];//十六进制数一个四位byte一个八位for (int i 0, j 0; i data.length; i) {chars[j] DIGITS[(data[i] 4) 0x0F];chars[j] DIGITS[data[i] 0x0F];}string new String(chars);} catch (Exception e) {e.printStackTrace();}return string;}public static byte[] hexStringToBytes(String data) {//两个四位十六进制字符合成一个八位bytebyte[] bytes new byte[data.length() / 2];char[] chars data.toCharArray();for (int i 0; i bytes.length; i) {bytes[i] (byte) ((hexCharToByte(chars[i * 2]) 4) | hexCharToByte(chars[i * 2 1]));}return bytes;}private static byte hexCharToByte(char c) {return (byte) 0123456789ABCDEF.indexOf(c);}
}以上都是我们的代码被反编译以后从新打包我们做出的一些防护措施。
如何防止反编译后从新打包 我也拿我的另外一个程序做了反编译的测试发现在用apk工具从新打包的时候会报错。这个程序的build.gradle文件是这样配置的。如图
apply plugin: com.android.application
//使用greendao
apply plugin: org.greenrobot.greendao
android {compileSdkVersion 30defaultConfig {applicationId minSdkVersion 22targetSdkVersion 30versionCode 6versionName 6.0testInstrumentationRunner android.support.test.runner.AndroidJUnitRunnermultiDexEnabled true}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}aaptOptions {noCompress pdf //表示不让aapt压缩的文件后缀 (不压缩assets下的文件)}buildTypes {release {minifyEnabled truezipAlignEnabled true //Zipalign优化shrinkResources true // 移除无用的resource文件proguardFiles getDefaultProguardFile(proguard-android-optimize.txt), proguard-rules.pro}}greendao {//版本号升级时可配置schemaVersion 1//这里可以指定编译成功后(DaoMaster、DaoSession、DAOS类)的文件目录,可以不指定daoPackage .greendaotargetGenDir src/main/java}lintOptions {checkReleaseBuilds false}//gradle3.01 从新的打包android.applicationVariants.all { variant -variant.outputs.all {outputFileName 唐朝${defaultConfig.versionName}.apk}}
}
def releaseTime() {return new Date().format(yyyy-MM-dd, TimeZone.getTimeZone(UTC))
}
dependencies {implementation fileTree(include: [*.jar], dir: libs)// 实现沉浸式状态栏implementation com.gyf.barlibrary:barlibrary:2.3.0implementationandroidx.appcompat:appcompat:1.0.0implementationandroidx.recyclerview:recyclerview:1.0.0implementationandroidx.constraintlayout:constraintlayout:1.1.2implementation com.android.support.constraint:constraint-layout:1.1.3testImplementation junit:junit:4.12androidTestImplementation com.android.support.test:runner:1.0.2androidTestImplementation com.android.support.test.espresso:espresso-core:3.0.2implementation files(libs/java_json-1.2.75.jar)implementation files(libs/zxing.jar)implementation files(libs/sun.misc.BASE64Decoder.jar)implementation com.github.barteksc:android-pdf-viewer:2.8.2implementation commons-io:commons-io:2.8.0//数据库加密类implementation net.zetetic:android-database-sqlcipher:4.2.0implementation org.greenrobot:eventbus:3.0.0//greendao依赖api org.greenrobot:greendao:3.2.2implementation com.google.code.gson:gson:2.8.0implementation androidx.multidex:multidex:2.0.0
}目标版本都是android sdk版本为30。引入了androidx的包去替换了原来的 support依赖。
继续使用前面的方法去破解先将包解压到out文件夹下。然后修改入口。从新打包。打包的时候会报错。如下代码
F:\android反编译\apktool2.4java -jar apktool.jar d -f androidx.apk -o out
I: Using Apktool 2.2.4 on androidx.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: C:\Users\hyw\AppData\Local\apktool\framework\1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...F:\android反编译\apktool2.4java -jar apktool.jar b -o androidx_change.apk out
I: Using Apktool 2.2.4
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether resources has changed...
I: Building resources...
W: F:\android反编译\apktool2.4\out\AndroidManifest.xml:1: error: No resource identifier found for attribute compileSdkVersion in package android
W:
W: F:\android反编译\apktool2.4\out\AndroidManifest.xml:1: error: No resource identifier found for attribute compileSdkVersionCodename in package android
W:
W: F:\android反编译\apktool2.4\out\AndroidManifest.xml:14: error: No resource identifier found for attribute appComponentFactory in package android
W:
Exception in thread main brut.androlib.AndrolibException: brut.androlib.AndrolibException: brut.common.BrutException: could not exec (exit code 1): [C:\Users\hyw\AppData\Local\Temp\brut_util_Jar_5866709263106215219.tmp, p, --forced-package-id, 127, --min-sdk-version, 22, --target-sdk-version, 30, --version-code, 6, --version-name, 6.0, --no-version-vectors, -F, C:\Users\hyw\AppData\Local\Temp\APKTOOL333571415111046532.tmp, -0, arsc, -0, db, -0, txt, -0, arsc, -I, C:\Users\hyw\AppData\Local\apktool\framework\1.apk, -S, F:\android反编译\apktool2.4\out\res, -M, F:\android反编译\apktool2.4\out\AndroidManifest.xml]at brut.androlib.Androlib.buildResourcesFull(Androlib.java:496)at brut.androlib.Androlib.buildResources(Androlib.java:430)at brut.androlib.Androlib.build(Androlib.java:329)at brut.androlib.Androlib.build(Androlib.java:267)at brut.apktool.Main.cmdBuild(Main.java:230)at brut.apktool.Main.main(Main.java:83)
Caused by: brut.androlib.AndrolibException: brut.common.BrutException: could not exec (exit code 1): [C:\Users\hyw\AppData\Local\Temp\brut_util_Jar_5866709263106215219.tmp, p, --forced-package-id, 127, --min-sdk-version, 22, --target-sdk-version, 30, --version-code, 6, --version-name, 6.0, --no-version-vectors, -F, C:\Users\hyw\AppData\Local\Temp\APKTOOL333571415111046532.tmp, -0, arsc, -0, db, -0, txt, -0, arsc, -I, C:\Users\hyw\AppData\Local\apktool\framework\1.apk, -S, F:\android反编译\apktool2.4\out\res, -M, F:\android反编译\apktool2.4\out\AndroidManifest.xml]at brut.androlib.res.AndrolibResources.aaptPackage(AndrolibResources.java:441)at brut.androlib.Androlib.buildResourcesFull(Androlib.java:482)... 5 more
Caused by: brut.common.BrutException: could not exec (exit code 1): [C:\Users\hyw\AppData\Local\Temp\brut_util_Jar_5866709263106215219.tmp, p, --forced-package-id, 127, --min-sdk-version, 22, --target-sdk-version, 30, --version-code, 6, --version-name, 6.0, --no-version-vectors, -F, C:\Users\hyw\AppData\Local\Temp\APKTOOL333571415111046532.tmp, -0, arsc, -0, db, -0, txt, -0, arsc, -I, C:\Users\hyw\AppData\Local\apktool\framework\1.apk, -S, F:\android反编译\apktool2.4\out\res, -M, F:\android反编译\apktool2.4\out\AndroidManifest.xml]at brut.util.OS.exec(OS.java:95)at brut.androlib.res.AndrolibResources.aaptPackage(AndrolibResources.java:435)... 6 more 反编译从新打包的时候会报错。显示android版本相关的一些信息。我怀疑是apktool工具版本太低。将apktool工具升级到最新的版本2.10。然后去打包。还是会报这个错误。我是不是可以理解为升级到androdx以后。安全性得到了提高呢。也许还是我1.9版本一样。我以为防的还可以结果被轻松绕过了入口。如果有朋友重新打包的时候解决了这个报错。
麻烦也和我分享下。不知攻焉能防。
总结重要的数据采用明文存的尽量都改为密文存储。还有google更新的时候尽量都跟着最新版本的走。不要偷懒。sdk版本越高安全性越好。
被人反编译apk的感受还是很不好的。尤其被人商用了。搞了好多钱。让人内心沮丧心情低落。幸好我去找老板的时候老板也没说我啥我义愤填膺的说要去起诉他们。至少给他们一个警告。让他们停止侵害。老板说你怎么证明他们用的咱们的。我说反编译完了对代码行数 。再说我们还有软著。奈何老板不想搞事。我只能把漏洞堵上。然后再写一篇文章记录下。