【移动安全】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掉,执行到返回

0 0
原创粉丝点击