逆向so的刨析速成

发布于:2023-01-04 ⋅ 阅读:(204) ⋅ 点赞:(0)

准备工作

  1. IDA 工具
  2. jadx-gui

先刨析java 层逻辑

在这里插入图片描述
读写app,native做了加密

package com.qxc.testnative3;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    Button btnRead;
    Button btnWrite;
    EditText etData;

    public native String read(String str); //在native 实现

    public native void write(String str, String str2); //在native 实现

    static {
        System.loadLibrary("native-lib");
    }

    /* access modifiers changed from: protected */
    @Override // androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, androidx.appcompat.app.AppCompatActivity, androidx.fragment.app.FragmentActivity
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.etData = (EditText) findViewById(R.id.et_data);
        this.btnWrite = (Button) findViewById(R.id.btn_write);
        this.btnRead = (Button) findViewById(R.id.btn_read);
        final String filePath = getFilesDir().getPath() + "/test";
        this.btnWrite.setOnClickListener(new View.OnClickListener() {
            /* class com.qxc.testnative3.MainActivity.AnonymousClass1 */

            public void onClick(View v) {
                MainActivity.this.write(filePath, MainActivity.this.etData.getText().toString());
            }
        });
        this.btnRead.setOnClickListener(new View.OnClickListener() {
            /* class com.qxc.testnative3.MainActivity.AnonymousClass2 */

            public void onClick(View v) {
                Toast.makeText(MainActivity.this, MainActivity.this.read(filePath), 1).show();
            }
        });
    }
}

在这里插入图片描述
在这里插入图片描述

不是静态注册,这边肯定就是动态注册。
动态注册调用JNI_OnLoad这个函数进行动态注册

jint JNI_OnLoad(JavaVM *vm, void *reserved);

加载本机库时VM 调用JNI_OnLoad(例如,通过System.loadLibrary)。 JNI_OnLoad必须返回本机库所需的 JNI 版本。
为了使用任何新的 JNI 函数,本机库必须导出一个JNI_OnLoad返回 JNI_VERSION_1_2. 如果原生库不导出JNI_OnLoad函数,VM 会假定该库只需要 JNI 版本JNI_VERSION_1_1。如果 VM 无法识别返回的版本号 JNI_OnLoad,则无法加载本机库。

我们直接双击更过去,JNI_OnLoad函数,然后f5转成伪c代码

signed int __fastcall JNI_OnLoad(_JavaVM *a1)
{
  int v1; // r0
  signed int result; // r0
  signed int v3; // [sp+20h] [bp-30h]
  _JNIEnv *v4; // [sp+24h] [bp-2Ch]
  __int64 v5; // [sp+28h] [bp-28h]
  __int64 v6; // [sp+30h] [bp-20h]
  __int64 v7; // [sp+38h] [bp-18h]
  int v8; // [sp+44h] [bp-Ch]

  v4 = 0;
  if ( _JavaVM::GetEnv(a1, (void **)&v4, 65542) )
  {
    v3 = -1;
  }
  else
  {
    v5 = *(_QWORD *)off_176C8;
    v6 = *(_QWORD *)&off_176D0;
    v7 = *(_QWORD *)&off_176D8;
    v1 = _JNIEnv::FindClass(v4, "com/qxc/testnative3/MainActivity");
    if ( _JNIEnv::RegisterNatives(v4, v1, &v5, 2) )
      v3 = -1;
    else
      v3 = 65542;
  }
  result = v3;
  if ( _stack_chk_guard == v8 )
    result = v3;
  return result;
}

在这里插入图片描述

/**
 * 动态注册
 * @param vm 虚拟机对象
 * @return
 */
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*){
    jint result = -1;
    JNIEnv *env = NULL;

    //通过虚拟机对象获得环境对象
    if(vm->GetEnv((void**)&env,JNI_VERSION_1_6)!=JNI_OK){
        return result;
    }

    //定义java native函数与c native实现函数的映射关系
    const JNINativeMethod method[] = {
            {"write","(Ljava/lang/String;Ljava/lang/String;)V",(void *)TestWrite},
            {"read","(Ljava/lang/String;)Ljava/lang/String;",(void *)TestRead}
    };

    //找到java类
    jclass jclassName = env->FindClass("com/qxc/testnative3/MainActivity");
    //执行动态注册
    jint ret = env->RegisterNatives(jclassName,method,2);

    if(ret != JNI_OK){
        return result;
    }
    return JNI_VERSION_1_6;

汇编和jni 对应关系!
在这里插入图片描述
①为 :写方法
②为:读取方法

双击任何一个方法都可以跳转到对应的函数,然后f5

FILE *__fastcall TestWrite(int a1, int a2, int a3, int a4)
{
  char *filename; // ST3C_4
  int v5; // ST28_4
  FILE *result; // r0
  int v7; // ST34_4
  char *s; // ST58_4
  size_t size; // ST64_4
  int v10; // r3
  FILE *stream; // [sp+38h] [bp-40h]
  int v12; // [sp+40h] [bp-38h]
  int v13; // [sp+4Ch] [bp-2Ch]

  v13 = a1;
  v12 = a4;
  filename = (char *)_JNIEnv::GetStringUTFChars(a1, a3);
  v5 = _JNIEnv::GetStringUTFChars(v13, v12);
  _android_log_print(4, "JNIDemo", &unk_14121, v5);
  result = fopen(filename, (const char *)&unk_14145);
  stream = result;
  if ( result )
  {
    _android_log_print(4, "JNIDemo", &unk_14147, "JNIDemo");
    v7 = encrypt(v13, v12);
    s = (char *)_JNIEnv::GetStringUTFChars(v13, v7);
    _android_log_print(4, "JNIDemo", &unk_1415D, s);
    size = strlen(s);
    fwrite(s, size, 1u, stream);
    fclose(stream);
    result = (FILE *)_android_log_print(4, "JNIDemo", &unk_14175, v10);
  }
  return result;
}

我这边是写的这个方法

extern "C" void
TestWrite(JNIEnv *env, jobject, jstring filePath, jstring fileContent){
    const char *jPath = env->GetStringUTFChars(filePath,NULL);

    LOGI("准备写入文件...,数据:%s",env->GetStringUTFChars(fileContent,NULL));

    //打开文件
    FILE *pFile = fopen(jPath,"w");
    if(pFile == NULL){
        return;
    }
    LOGI("文件打开成功...");

    //数据加密
    jstring enFileContent = encrypt(env,fileContent);
    const char *jFileContent = env->GetStringUTFChars(enFileContent,NULL);
    LOGI("加密后的数据:%s",jFileContent);

    //数据写入
    fwrite(jFileContent,strlen(jFileContent),1,pFile);

    //关闭文件
    fclose(pFile);

    LOGI("文件写入成功,关闭文件");
}

伪代码和jni 对比 区别不大把!

在这里插入图片描述

static char* key = "1234567887654321";

/**
 * AES加密功能
 * @param env 环境对象
 * @param fileContent 待加密的文件内容
 * @return 加密后的密文数据
 */
jstring encrypt(JNIEnv *env, jstring fileContent){
    //获得java端class
    jclass cls = env->FindClass("com/qxc/testnative3/AES");
    if(cls == NULL){
        return NULL;
    }

    //通过class获取方法id
    jmethodID  methodidEncrypt = env->GetStaticMethodID(cls,"encrypt","(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
    if(methodidEncrypt == NULL){
        return NULL;
    }

    //char* 转jstring
    jstring keyAes = env->NewStringUTF(key);

    //调用AES加密方法
    return  (jstring)env->CallStaticObjectMethod(cls,methodidEncrypt,fileContent,keyAes);
}

在这里插入图片描述

encrypt这个方法就找到了!我们在学习so算法逆向,多学习ndk开发!
我是任雪飘。一个技术渣渣,请关注,不定期更新


网站公告

今日签到

点亮在社区的每一天
去签到

热门文章