【移动安全】so动态调试对抗反编译及反调试
来源:互联网 发布:淘宝设置第二件半价 编辑:程序博客网 时间:2024/06/05 00:58
环境配置
1、设置JDK环境变量后需要修改JEB的配置脚本jeb_wincon.bat
rem Prefer a JDK over a JRE, which allows support for JEB native Java plugins
if defined JAVA_HOME (set base=”d:\Program Files\Java\jdk1.8.0_65\bin”) else (set base=”%SystemRoot%\System32”)
set JAVA=%base%\java.exe
2、ApkIDE环境中工具-》配置中设置JDK的安装路径
去除反编译
1、下面是判断签名信息的函数,修改反编译后的smali代码,使其最后判断签名处始终为真,这时可以跳过签名,此时可以重新打包。
public static boolean a(Context arg4, String arg5) { PackageInfo v1_1; boolean v0 = false; try { v1_1 = arg4.getPackageManager().getPackageInfo(arg4.getPackageName(), 64); } catch(PackageManager$NameNotFoundException v1) { v1.printStackTrace(); return v0; } byte[] v1_2 = v1_1.signatures[0].toByteArray(); try { v1_2 = CertificateFactory.getInstance("X509").generateCertificate(new ByteArrayInputStream( v1_2)).getEncoded(); } catch(CertificateException v1_3) { v1_3.printStackTrace(); return v0; } try { String v2 = new String(Base64.encode(MessageDigest.getInstance("md5").digest(v1_2), 19)); } catch(NoSuchAlgorithmException v1_4) { v1_4.printStackTrace(); return v0; } if("WJmkxxkkGnYbExi3dqzeaA".equals(v2)) { v0 = Ch.ch(arg5); } return v0;}
.method public static a(Landroid/content/Context;Ljava/lang/String;)Z .locals 6 const/4 v0, 0x0 :try_start_0 invoke-virtual {p0}, Landroid/content/Context;->getPackageManager()Landroid/content/pm/PackageManager; move-result-object v1 invoke-virtual {p0}, Landroid/content/Context;->getPackageName()Ljava/lang/String; move-result-object v2 const/16 v3, 0x40 invoke-virtual {v1, v2, v3}, Landroid/content/pm/PackageManager;->getPackageInfo(Ljava/lang/String;I)Landroid/content/pm/PackageInfo; :try_end_0 .catch Landroid/content/pm/PackageManager$NameNotFoundException; {:try_start_0 .. :try_end_0} :catch_0 move-result-object v1 iget-object v1, v1, Landroid/content/pm/PackageInfo;->signatures:[Landroid/content/pm/Signature; aget-object v1, v1, v0 invoke-virtual {v1}, Landroid/content/pm/Signature;->toByteArray()[B move-result-object v1 :try_start_1 const-string v2, "X509" invoke-static {v2}, Ljava/security/cert/CertificateFactory;->getInstance(Ljava/lang/String;)Ljava/security/cert/CertificateFactory; move-result-object v2 new-instance v3, Ljava/io/ByteArrayInputStream; invoke-direct {v3, v1}, Ljava/io/ByteArrayInputStream;-><init>([B)V invoke-virtual {v2, v3}, Ljava/security/cert/CertificateFactory;->generateCertificate(Ljava/io/InputStream;)Ljava/security/cert/Certificate; move-result-object v1 invoke-virtual {v1}, Ljava/security/cert/Certificate;->getEncoded()[B :try_end_1 .catch Ljava/security/cert/CertificateException; {:try_start_1 .. :try_end_1} :catch_1 move-result-object v1 :try_start_2 new-instance v2, Ljava/lang/String; const-string v3, "md5" invoke-static {v3}, Ljava/security/MessageDigest;->getInstance(Ljava/lang/String;)Ljava/security/MessageDigest; move-result-object v3 invoke-virtual {v3, v1}, Ljava/security/MessageDigest;->digest([B)[B move-result-object v1 const/16 v3, 0x13 invoke-static {v1, v3}, Landroid/util/Base64;->encode([BI)[B move-result-object v1 invoke-direct {v2, v1}, Ljava/lang/String;-><init>([B)V :try_end_2 .catch Ljava/security/NoSuchAlgorithmException; {:try_start_2 .. :try_end_2} :catch_2 const-string v1, "WJmkxxkkGnYbExi3dqzeaA" invoke-virtual {v1, v2}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v1 #add by jyh 跳过反编译打包签名的判断 const/4 v1, 0x1 if-nez v1, :cond_0 :goto_0 return v0 :catch_0 move-exception v1 invoke-virtual {v1}, Landroid/content/pm/PackageManager$NameNotFoundException;->printStackTrace()V goto :goto_0 :catch_1 move-exception v1 invoke-virtual {v1}, Ljava/security/cert/CertificateException;->printStackTrace()V goto :goto_0 :catch_2 move-exception v1 invoke-virtual {v1}, Ljava/security/NoSuchAlgorithmException;->printStackTrace()V goto :goto_0 :cond_0 invoke-static {p1}, Lk2015/a2/Ch;->ch(Ljava/lang/String;)Z move-result v0 const-string v4, "outout" invoke-static {v4,v4}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I const/4 v1, 0x1 invoke-static {v1}, Ljava/lang/String;->valueOf(I)Ljava/lang/String; move-result-object v1 invoke-static {v4, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I goto :goto_0.end method
2、添加调试开关,如下红色部分,如果不添加则无法进行调试跟踪,在DDMS中看不到进程端口等信息。同时如果使用am等待调试时需要如下信息即package和name
am start -D -n k2015.a2/k2015.a2.Main
<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="k2015.a2" platformBuildVersionCode="10" platformBuildVersionName="2.3.3"> <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true"> <activity android:label="@string/app_name" android:name="Main"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application></manifest>
去除反调试
通过ptrace方式判断
1、 如果进程被附加处于调试状态,则/etc/$(procID)/status中进行procid的判断,如果进程id不为零则直接杀死本进程退出。
2、 如果进程被附加处于调试状态,则/etc/self/status中对TracerPid后面的进程ID进行判断,如果进程id不为零则直接杀死本进程退出。
char *__fastcall sub_1284(){ FILE *v0; // r9@1 char *result; // r0@3 __pid_t pid; // [sp+4h] [bp-30Ch]@1 int v3; // [sp+8h] [bp-308h]@5 char v4; // [sp+Ch] [bp-304h]@5 char s; // [sp+8Ch] [bp-284h]@1 char v6; // [sp+28Ch] [bp-84h]@1 _aeabi_memset(&v6, 100, 0); pid = getpid(); sprintf(&v6, "/proc/%d/status"); v0 = fopen(&v6, "r"); _aeabi_memset(&s, 512, 0); pthread_mutex_lock((pthread_mutex_t *)&unk_5E40); if ( unk_5E48 ) pthread_cond_signal((pthread_cond_t *)&unk_5E44); pthread_mutex_unlock((pthread_mutex_t *)&unk_5E40); result = fgets(&s, 512, v0); if ( result ) { while ( 1 ) { if ( strstr(&s, "TracerPid") ) { _aeabi_memset(&v4, 128, 0); v3 = 0; sscanf(&s, "%s %d", &v4, &v3); if ( v3 >= 1 ) break; } result = fgets(&s, 512, v0); if ( !result ) return result; } result = (char *)kill(pid, 9); } return result;}
函数恢复
mprotect函数将某一块内存区域设置为可写,然后解密,再将此内存区域改为可执行,执行后再加密回原内存区域,设置为只读。
举例:
mprotect((void *)((unsigned int)&loc_24C8 & -unk_5E9C & 0xFFFFFFFE), v20, 7); v22 = 0u; do { *(_BYTE *)(((unsigned int)&loc_24C8 & 0xFFFFFFFE) + v22) ^= byte_5140[v22 % 0x6C]; ++v22; } while ( v22 != 2280 ); cacheflush(); mprotect(v21, v20, 5); v3 = ((int (__fastcall *)(char *))loc_24C8)(&v43);
经验总结
1、 在加载so之前调试,如果反调试在so中的init_array段中则需要利用am方式启动应用等待调试,之后利用ida附加,设置debugger,进程启动和库加载时暂停,然后运行等待,利用jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700触发执行。Ida继续跟踪。
Ctrl+S查看段和so信息,利用so文件偏移在ida中找到内存中so的code的基址+偏移,找到内存中的函数下断点,按P后F5即可查看函数信息。
2、 加载so后调试
直接附加跟踪
3、 按Y输入JNIEnv*
a) v3 = a1;
b) v4 = a3;
c) v5 = (const char )((int (*)(void))((_DWORD *)a1 + 676))();
d) v6 = sub_1DE0(v5);
e) ((void (__fastcall *)(int, int, const char ))((_DWORD *)v3 + 680))(v3, v4, v5);
f) return v6;
g) v3 = a1;
h) v4 = a3;
i) v5 = (const char )((int ()(void))(*a1)->GetStringUTFChars)();
j) v6 = sub_1DE0(v5);
k) ((void (__fastcall )(JNIEnv , int, const char *))(*v3)->ReleaseStringUTFChars)(v3, v4, v5);
l) return v6;
4、 ARM中的NOP指令
00 00 A0 E1 (MOV R1,R1) NOP
5、 0A代表BEQ,1A代表BNE
text代码段偏移00001BCC,标号:loc_1C28 指令:1500000A
(0x15+2)*4 + 0x1BCC = 0x1C28
6、 init_array中pthread_create 和 clone需要被NOP掉,执行到返回
- 【移动安全】so动态调试对抗反编译及反调试
- 迷你播放器--第一阶段(7)--安全攻防第一战--对抗反编译,代码混淆和对抗动态调试
- ida动态调试之so层反调试入门篇
- IDA so 反调试
- 简单对抗某个驱动的反调试
- 静态反调试与动态反调试
- IDA 动态调试SO
- IDA动态调试so
- Android应用安全与校验之反动态调试
- 【移动安全】Android App Smail代码动态跟踪调试方法
- android 反编译 反调试入门资料
- android 反编译、反调试方法总结
- android 反编译、反调试方法总结
- 动态调试反编译的apk
- IDA动态调试so库
- so动态调试(阿里脱壳)
- IDA动态调试so文件
- IDA动态调试Android SO
- android shape的使用
- 数据库优化,开发高效的数据库系统
- hadoop安装之-hadoop
- Schedule用法实例
- swift UITextFiled边框设置
- 【移动安全】so动态调试对抗反编译及反调试
- 日期与时间的转换,计算两个日期间的天数,月数
- 大数据就业方向
- java基础学习笔记(6)
- SQOOP导入hive表报错
- 两个手机靠近,唤起应用如微信(需打开NFC)
- 游戏打击感
- 连接真机没反应
- swift UIViewController生命周期