安卓逆向入门-Unidbg入门 入门 Unidbg是个基于Unicorn的逆向工具,可黑盒调用Android和iOS的so文件。它不需要直接运行App或逆向so文件,通过在App中找到对应JNI接口,用Unicorn引擎直接执行该so文件。
先给Intellij IDEA配Maven环境。先下载Maven:https://maven.apache.org/download.cgi,并将\apache-maven-3.9.9\bin目录添加到环境变量,在IDEA设置中“构建、执行、部署\-\>构建工具\-\>Maven”的主路径设为\apache-maven-3.9.9,用户配置文件为\apache-maven-3.9.9\conf\settings.xml,本地仓库自己随便搞一个,取消使用\.mvn/maven\.config中的设置。再在“Maven\-\>运行程序”中虚拟机选项添加-DarchetypeCatalog=internal。
打开settings.xml,在mirrors标签内添加一个mirror块:
1 2 3 4 5 6 <mirror > <id > aliyunmaven</id > <mirrorOf > *</mirrorOf > <name > 阿里云公共仓库</name > <url > https://maven.aliyun.com/repository/public</url > </mirror >
Github上下载Unidbg,打开项目,并且加载Maven依赖。找到unidbg-android/src/test/java/com/bytedance.frameworks.core.encrypt/TTEncrypt并运行main,看到控制台输出相关调用信息,则说明导入成功。
创建一个Native程序,其中Dalvik层这样写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package com.example.myapplication;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.widget.TextView;import com.example.myapplication.databinding.ActivityMainBinding;public class MainActivity extends AppCompatActivity { static { System.loadLibrary("myapplication" ); } private ActivityMainBinding binding; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); TextView tv = binding.sampleText; tv.setText(stringFromJNI()); tv.setText(getKey(stringFromJNI())); } public native String stringFromJNI () ; public native String getKey (String keyb) ; }
布局:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="utf-8" ?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android ="http://schemas.android.com/apk/res/android" xmlns:app ="http://schemas.android.com/apk/res-auto" xmlns:tools ="http://schemas.android.com/tools" android:layout_width ="match_parent" android:layout_height ="match_parent" tools:context =".MainActivity" > <TextView android:id ="@+id/sample_text" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:text ="Hello World!" app:layout_constraintBottom_toBottomOf ="parent" app:layout_constraintEnd_toEndOf ="parent" app:layout_constraintStart_toStartOf ="parent" app:layout_constraintTop_toTopOf ="parent" /> </androidx.constraintlayout.widget.ConstraintLayout >
native-lib.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 #include <jni.h> #include <string> extern "C" JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_stringFromJNI (JNIEnv* env,jobject) { std::string hello = "Hello from C++" ; return env->NewStringUTF (hello.c_str ()); }; static const char base64_chars[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;char *base64_encode (const std::string &input) { const unsigned char *data = (const unsigned char *)input.c_str (); int input_length = input.size (); int i = 0 ; int j = 0 ; int len = 0 ; unsigned char char_array_3[3 ]; unsigned char char_array_4[4 ]; char *encoded_string = (char *)malloc (((input_length + 2 ) / 3 ) * 4 + 1 ); if (encoded_string == NULL ) return NULL ; while (input_length--) { char_array_3[i++] = *(data++); if (i == 3 ) { char_array_4[0 ] = (char_array_3[0 ] & 0xfc ) >> 2 ; char_array_4[1 ] = ((char_array_3[0 ] & 0x03 ) << 4 ) + ((char_array_3[1 ] & 0xf0 ) >> 4 ); char_array_4[2 ] = ((char_array_3[1 ] & 0x0f ) << 2 ) + ((char_array_3[2 ] & 0xc0 ) >> 6 ); char_array_4[3 ] = char_array_3[2 ] & 0x3f ; for (i = 0 ; (i < 4 ) ; i++) encoded_string[len++] = base64_chars[char_array_4[i]]; i = 0 ; }; }; if (i) { for (j = i; j < 3 ; j++) char_array_3[j] = '\0' ; char_array_4[0 ] = (char_array_3[0 ] & 0xfc ) >> 2 ; char_array_4[1 ] = ((char_array_3[0 ] & 0x03 ) << 4 ) + ((char_array_3[1 ] & 0xf0 ) >> 4 ); char_array_4[2 ] = ((char_array_3[1 ] & 0x0f ) << 2 ) + ((char_array_3[2 ] & 0xc0 ) >> 6 ); char_array_4[3 ] = char_array_3[2 ] & 0x3f ; for (j = 0 ; (j < i + 1 ); j++) encoded_string[len++] = base64_chars[char_array_4[j]]; while ((i++ < 3 )) encoded_string[len++] = '=' ; }; encoded_string[len] = '\0' ; return encoded_string; }; extern "C" JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_getKey (JNIEnv* env,jobject,jstring keyb) { std::string str="string to encode" ; char * kb=NULL ; jclass class_string=env->FindClass ("java/lang/String" ); jstring kbcode=env->NewStringUTF ("GB2312" ); jmethodID mid=env->GetMethodID (class_string,"getBytes" ,"(Ljava/lang/String;)[B" ); jbyteArray barr=(jbyteArray)env->CallObjectMethod (keyb,mid,kbcode); jsize klen=env->GetArrayLength (barr); jbyte* ba=env->GetByteArrayElements (barr,JNI_FALSE); if (klen>0 ) { kb = (char *) malloc (klen + 1 ); memcpy (kb, ba, klen); kb[klen] = 0 ; }; env->ReleaseByteArrayElements (barr,ba,0 ); std::string stemp (kb) ; free (kb); std::string newKey=str+stemp; char * encoded = base64_encode (newKey); jstring result = env->NewStringUTF (encoded); free (encoded); return result; };
随后在Unidbg工程中unidbg-master\unidbg-android\src\test\java\com下新建软件包com.unidbg_example,下有源代码EncryptUtilsJni.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 package com.unidbg_example;import com.alibaba.fastjson.util.IOUtils;import com.github.unidbg.AndroidEmulator;import com.github.unidbg.Module;import com.github.unidbg.arm.backend.Unicorn2Factory;import com.github.unidbg.linux.android.AndroidEmulatorBuilder;import com.github.unidbg.linux.android.AndroidResolver;import com.github.unidbg.linux.android.dvm.*;import com.github.unidbg.memory.Memory;import java.io.File;public class EncryptUtilsJni { private final AndroidEmulator emulator; private final VM vm; private final Module module ; private final DvmClass EncryptUtils; private final boolean logging; EncryptUtilsJni(boolean logging){ this .logging = logging; emulator = AndroidEmulatorBuilder.for64Bit().setProcessName("com.example.test" ).addBackendFactory(new Unicorn2Factory (true )).build(); final Memory memory = emulator.getMemory(); memory.setLibraryResolver(new AndroidResolver (34 )); vm = emulator.createDalvikVM(); vm.setVerbose(logging); DalvikModule dm = vm.loadLibrary(new File ("unidbg-android/src/test/resources/example_binaries/libmyapplication.so" ), false ); dm.callJNI_OnLoad(emulator); module = dm.getModule(); EncryptUtils = vm.resolveClass("com/example/myapplication/MainActivity" ); } void destroy () { IOUtils.close(emulator); if (logging) { System.out.println("destroy" ); } } private void getKey () { DvmObject<?> strRc=EncryptUtils.callStaticJniMethodObject(emulator,"stringFromJNI()Ljava/lang/String;" ); System.out.println("call stringFromJNI rc=" +strRc.getValue()); String keyb=strRc.getValue().toString(); strRc=EncryptUtils.callStaticJniMethodObject(emulator,"getKey(Ljava/lang/String;)Ljava/lang/String;" ,vm.addLocalObject(new StringObject (vm,keyb))); System.out.println("call getKey:" +strRc.getValue()); } public static void main (String[] args) { EncryptUtilsJni encryptUtilsJni=new EncryptUtilsJni (true ); encryptUtilsJni.getKey(); encryptUtilsJni.destroy(); } }
稍微有点报错,先搁着。