Android逆向之旅—Android应用的汉化功能(修改SO中的字符串内容)

Android技术篇 尼古拉斯.赵四 12319℃ 0评论

一、前言

今天我们继续来讲述逆向的知识,今天我们来讲什么呢?我们在前一篇文章中介绍了关于SO文件的格式,今天我们继续这个话题来看看如何修改SO文件中的内容,看一下我们研究的主题:

需求:想汉化一个Apk

思路:汉化,想必大家都了解,老外开发的一个游戏,结果他不支持中文,那么我们就需要做一下汉化,那么我们知道汉化的工作其实很简单,就是替换Apk中英文的字符串位置,那么我们可以反编译Apk..得到smail文件,然后直接找到需要汉化的字符串位置,然后修改成对应的中文即可。这个倒是很简单。这里就不详细说明了,但是现在问题变得有点复杂,就是有些apk,他把字符串放到了底层,也就是so文件中,那么问题就变的伤心了,我需要去修改so中的内容了。这时候我们不能像修改smail文件那么搞了,因为底层都是指针操作字符串,而且还涉及到字符串的地址。所以我们这时候需要了解so文件的格式,才能做相应的修改。所以大家需要先来看这篇文章才能继续我们今天的课题:点击进入

二、准备工作

我们了解了SO的文件格式,也手动的写了一个工具来解析他,那么我们现在如果想修改一个字符串的内容,还需要一些准备。

需要两个工具:

1、010Editor:查看16进制的工具,比UE轻了很多,也很好用

下载地址:http://pan.baidu.com/s/1qWEbuHY

2、IDA 6.6 Pro:这个工具太出名了,在逆向领域中堪比Android中的AndroidStudio.没有他的话,逆向是难上加难,当然,这个工具也是我们日后介绍逆向领域必备的技能,网上也有相关工具的说明书,这个工具学起来不难,但是一定要学会使用

下载地址:http://pan.baidu.com/s/1pJ28eoz

3、NDK:这个工具想必大家也不陌生了,我们后面需要编译so文件,所以需要用到他,关于如何配置NDK的话,看这篇文章:

http://blog.csdn.net/jiangwei0910410003/article/details/17710243

下载地址:http://pan.baidu.com/s/1dDwMRuh

有了这两个三具我们还不够,我们还需要了解一个常识:

我们在Java中不会接触到指针的概念,但是用IDA分析so的时候,就是汇编指令,所以都是地址,我们在学习C的时候,知道一句话:地址就是指针,指针就是地址,所以我们需要了解指针的一点知识,我们在编写C程序的时候,代码中定义一个字符串:

char *str = "Hello World";

str就是一个指针,指向Hello World中的首个字符,也是这个字符串在内存中的首地址,但是这里我们需要了解的是,这个地址不是绝对地址,而是相对地址。是绝对地址减去偏移值。

三、技术原理

上面的准备工作做完了,下面我们来看看具体思路吧:

我们如果做汉化工作的话,其实原理打搅都了解,就是反编译Apk,然后将其英文改称中文即可。如果Apk的字符串都定义在string.xml中,或者是在java层代码中的话,那么就简单了,我们只需要用apktools工具修改smail文件和添加中文的string.xml就可以了。但是我今天不是重点来说这个内容,因为这个内容没难度。大家都可以实现的,今天我们要说的是有难度的,加入字符串定义在native层中,也就是在so文件中,我们该怎么办?

通过前一篇的so文件的格式详解之后,我们知道字符串都存在哪里。

下面我们就来通过一个案例来分析一下如何修改so中的字符串内容,这个案例的native层我们不准备自己手写了,我们用NDK中的一个demo就可以了:


在NDK的这个目录下,我们看一下C++的代码:

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include <string.h>
#include <jni.h>

/* This is a trivial JNI example where we use a native method
 * to return a new VM String. See the corresponding Java source
 * file located at:
 *
 *   apps/samples/hello-jni/project/src/com/example/hellojni/HelloJni.java
 */
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
{
	return (*env)->NewStringUTF(env, "Hello from JNI !");
}

上层的Java代码:

package com.example.hellojni;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class HelloJni extends Activity{
    @Override
    public void onCreate(Bundle savedInstanceState){
    	
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        final Button btn = (Button)findViewById(R.id.btn);
        btn.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View arg0) {
				String str = stringFromJNI();
				btn.setText(str);
			}});

    }
    
    public native String  stringFromJNI();

    public native String  unimplementedStringFromJNI();
    
    static {
        System.loadLibrary("hello-jnis");
    }
}

我们看到native层的字符串是:Hello from JNI !,那么我们现在来修改这个字符串内容。

四、技术实现

这时候我们就需要用到上面说到的那个强大的工具:IDA了,打开so文件,很简单的,界面如下:

 

这里有很多窗口的,所以IDA工具很强大,我们需要慢慢的学习,还有各种快捷键的使用,都是一门学问。


在Functions window窗口中我们可以看到我们的native函数,如果太多的话,我们可以用Ctrl+F搜索。然后我们双击这个函数,在IDA View窗口中就可以看到这个函数的汇编代码了:


关于汇编指令,这里也不多解释了,大学里面都学过了,但是可能都忘了,所以还得复习一下。这里我们看到了,那个字符串的地址:aHelloFromJni – 0xBF4,0xBF4是偏移地址,这个aHelloFromJni应该是一个符号,所以我们双击跳到这个字符串的绝对地址。