概述
本文使用IDA对android调用so进行静态分析,以此实验掌握so层的一些分析技巧。
前置条件
ARM 汇编 (虚拟机为armebi-v7a)
IDA的基本使用
JNI开发基础
Android中调用so
# direct methods
# 加载so库
.method static constructor <clinit>()V
.locals 1
.prologue
.line 26
const-string v0, "verify"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
.line 27
return-void
.end method
#定义native 方法
.method public native verify([B)Ljava/lang/String;
#调用so层方法
invoke-virtual {v1, v2}, Lcom/example/cctf/MainActivity;->verify([B)Ljava/lang/String;
当我们反编译java代码为smali代码,看到以上类似的代码,就应该能猜得其关键逻辑是在so层进行处理的,这个时候我们就需要对so进行调试分析。
静态分析
so文件一般在apk中的lib文件夹中,将其解压出来,丢到IDA进行静态分析。
image.png image.png image.png
进入Exports
可以看到有一个JNI_OnLoad且没有以java开头的导出函数,所以这里基本可以断定是动态注册。
进入后代码如下:
我们先使用IDA 导入C/C++头文件,添加头文件中的结构体,使用此结构体中的函数替换反汇编中的偏移,使文件可读性更好
点击IDA Pro 主界面上的“Structures”选项卡 然后按下Insert键打开“Create structure/union”对话框,点击界面上的"Add standard structure"按钮,在打开的结构体选择对话框中选择JNINativeInterface并点击OK返回,同理JNIInvokeInterface结构体_JNIEnv和_JavaVm也导入进来;
image.png
image.png
如果没有结构体请导入jni.h头文件,可参考以下教程:
报错的h文件都注释掉就好了。
https://blog.csdn.net/u010382106/article/details/44960243
这时候回到汇编窗口,右键相关函数就可以转成对应的方法了:
image.png
按F5进入,c/c++窗口:
将函数的参数转化为正确的参数,鼠标点击参数,然后右键选中 Convert to Struct *
这里当然转成JavaVM
image.png
#其中代码如下,我们可以猜测到v6为JNIEnv
!a1->functions->GetEnv((JavaVM *)a1, (void **)&v6, 65540)
将v6转成JNIEnv
#这句可以知道v3也是JNIEnv
v3 = v6
最终分析代码如下:
int __fastcall JNI_OnLoad(_JavaVM *a1, int a2, int a3)
{
_JNIEnv *v3; // r5@2
int v4; // r1@3
int result; // r0@4
_JNIEnv *v6; // [sp+4h] [bp-14h]@1
int v7; // [sp+8h] [bp-10h]@1
v7 = a3;
v6 = 0;
if ( !a1->functions->GetEnv((JavaVM *)a1, (void **)&v6, 65540)
&& (v3 = v6) != 0
&& (v4 = ((int (*)(void))v6->functions->FindClass)()) != 0 )
{
//这里RegisterNatives原型为functions->RegisterNatives(this, clazz, methods, nMethods);
//由此可以知道
//v4是类名称
//off_4014是注册native数组的地址
//1 是数组的个数
result = (((int (__fastcall *)(_JNIEnv *, int, char **, signed int))v3->functions->RegisterNatives)(
v3,
v4,
off_4014,
1) >> 31) | 0x10004;
}
else
{
result = -1;
}
return result;
}
我们现在知道了off_4014是注册native数组的地址,我们就进去看看它组成的函数地址在哪
可以看出这个就是Android代码中调用的函数
刚好都是4个字节,直接进入byte_CA5中,这个就是我们的verify函数地址: image.png
这里大家应该都看不懂了,我也看不懂了0.0。
这是因为ida把它识别为了数据,我们先设置一下16进制代码显示。
在Option->General中,设置为4bytes:
image.png
效果如下:
image.png
现在我们在函数开始地址按快捷键C将代码翻译为,ARM汇编。
image.png
结果是这样的,这汇编代码一看就不对劲啊!
这是因为这一段代码是thumb指令,而ida识别为arm指令集了
修改:按alt+G,然后让value=1 为thumb指令,= 0为arm指令。
image.png
修改后如下:
image.png
在代码入口,右键creat fun
按F5进入c和c++代码
这个其实依然不是真正的代码,所以要结合下一章动态调试分析
网友评论