app安卓逆向之native层代码静态分析基础

本文详细介绍了安卓应用逆向过程中针对Native层的静态分析,包括ARM指令、IDA工具的使用、Java层调用Native层的方法原理、Native层代码修改以及SO文件的替换。通过实例展示了如何找到并修改Native代码,以及如何在App中替换修改后的SO文件。
摘要由CSDN通过智能技术生成

Native层代码静态分析

1.背景分析

在安卓逆向的过程当中会遇到以下场景

  1. 经过上一阶段的Java层代码静态分析以及动态调试,发现加密参数的生成方法调用了Native层方法
  2. 经过对Native层代码分析后修改对应代码,替换原so文件发现app运行异常

针对以上的情景,我们需要使用IDA直接对Native层方法进行静态分析,找出关键代码并且完成相应的代码修改及复现,最终的目的是完成加密算法的还原或是本地调用对应的so文件。


2.概述

本文主要介绍以下安卓Native层逆向的基础知识,主要包括以下部分

  1. ARM指令
  2. IDA的基本使用方法
  3. Java层调用Native层方法原理
  4. Native层代码的修改
  5. so文件的替换

相关软件下载

本教程中用到的所有软件都保存在该网盘中,其中包括jadx、ida7.0

https://pan.baidu.com/s/1XsMANMxzdxlrQAnEjIedxQ

密码:zzkk


3.开始

3.1 ARM指令

首先,为什么要掌握基本的ARM指令?

在安卓的Native层逆向中,使用IDA工具对so文件进行反编译,得到的是原始的ARM汇编指令,类比之前的Java层逆向需要懂Smali代码一样,因此需要掌握基本的ARM指令知识。

常见的寻址方式

1、立即数寻址

MOV R0,#64 (将立即数64传给寄存器R0)

2、寄存器寻址

ADD R0,R1,R2 (将寄存器R1与寄存器R2的值相加,得到的和传给R0)

3、寄存器间接寻址

LDR R0,[R1] (将寄存器R1中的值作为地址,对这个地址进行寻址获取操作数,取得的操作数传给寄存器R0)

4、寄存器基址变址寻址

LDR R0,[R1,#4] (将寄存器R1的值+4作为地址,对这个地址进行寻址获取操作数,取得的操作数传给寄存器R0)

5、多寄存器寻址

LDMIA R0,{R1,R2,R3,R4} (将R0寄存器的值寻址获得操作数给R1,然后将R0寄存器的值+4寻址获得操作数给R2,后面R0+8,R0+12如此类推)

LDMIB R0,{R1,R2,R3,R4} (将R0寄存器的值+4寻址获得操作数给R1,后面R0+8,R0+12如此类推)

6、堆栈寻址

STMFD sp!,{R1-R7,LR} (将R1~R7,LR寄存器的值压入堆栈,满递减堆栈)

LDMED sp!,{R1-R7,LR} (将堆栈中的数据取回R1~R7,LR寄存器,空递减堆栈)

LD : load 加载,出栈操作 ST : store 存储,入栈操作 M : multi 多次 F: full 满栈,SP指向最后一个数据 E: empty 空栈,SP指向与最后一个数据相邻的下一个可写入存储单元 D: descending 递减,代表栈的增长方向 A: ascending 递增,代表栈的增长方向

E\F详解

D\A详解

常用寄存器

R0-R3:用于参数返回值的传递

R4-R6,R8,R10-R11:普通的常用寄存器

R7:栈帧指针,指向前一个保存的栈帧,以及链接寄存器在栈上的地址

R9:操作系统保留

R12:又叫IP,指令指针寄存器,CS:IP用于指定指令的起始地址

R13:又叫SP,栈顶指针

R14:又叫LR,存放函数的返回地址

R15:又叫PC,指向下一条指令的地址,也即将将要执行的指令代码

常用指令

ADD:加指令

SUB:减指令

STR:寄存器内容入栈

LDR:寄存器内容出栈

.W:表示指令宽度,确保生成32位长度指令

BL\BLX:函数调用,对应ARM与Thumb指令集

CMP:操作数比较

示例代码

#include <stdio.h>
int func(int a,int b,int c,int d,int e,int f){
    int g = a + b + c + d + e + f;
    return g;
}

add r0,r1; 将参数a+b求和赋给r0
ldr.w r12,[SP]; 将栈顶f的值赋给r12
add r0,r2; 将c的值和r0求和赋给r0
ldr.w r9,[sp,#4]; 将栈顶+4地址的值赋予给r9,即将e赋给r9
add r0,r3; 将d与r0求和赋给r0
add r0,r12; 将r12与r0求和赋给r0
add r0,r9; 将r9与r0求和赋给r0

3.2 IDA基本使用方法

首先,IDA工具是什么,能帮助我们做什么?

IDA是一款交互式的,可编程的,可扩展的,多处理器的,交叉WindowsLinux WinCE MacOS平台主机来分析程序, 被公认为最好的花钱可以买到的逆向工程利器。IDA已经成为事实上的分析敌意代码的标准,让其自身迅速成为攻击研究领域的重要工具。它支持数十种CPU指令集。

使用IDA能帮助我们在逆向工作中完成以下工作:

1、分析so文件,查看该so为文件的汇编代码及C、C++代码

2、通过静态分析可以通过修改十六进制代码来完成源代码的修改

3、支持App程序在so层的动态调试

打开so文件

1、双击打开IDA Pro (32-bit),并且一路选择OK,最后点GO进入IDA主界面

2、直接拖拽SO文件进入IDA界面,选择ARM格式,便能直接打开SO文件

主窗口介绍

1、函数窗口:列出该so文件里每一个函数,常用对函数进行搜索

2、消息窗口:IDA工具的输出控制台,从中可以读到IDA的运行情况

3、工具栏区域:其主要包括六个逆向工作中的常用窗口

  • IDA View:操作和分析二进制文件的主要工具,其主要包括两种形式:文本视图(汇编代码)和图形视图(某个函数的调用执行情况)

红色箭头:表示跨函数调用

粗箭头:表示循环

实线箭头:表示无条件分支

点线箭头:表示条件分支

  • Hex View:显示程序内容的标准十六进制代码,每行显示十六个字节,以及对应的ascii字符,假如在文本视图中选中某一地址,则切换至十六进制窗口中该地址代码将会显示高亮

  • 结构体窗口:用于显示IDA决定决定在一个二进制文件中使用的复杂数据结构,双击结构体名称可以展开内部结构

  • 枚举窗口:类似于结构体窗口,当IDA识别到枚举类型,则在该窗口展现

  • 导出窗口:列出文件的入口点,其包含该so文件导出函数的名称及虚拟地址

  • 导入窗口:和导出窗口相反,表示该so文件导入的所有函数名及虚拟地址

4、概况导航栏:表示不同类型的文件内容

  • 蓝色:.text section

      深蓝:用户自己写的函数编译后的代码区
        
      浅蓝:编译器自己添加的函数,像启动函数,异常函数等(我自己猜的,不一定百分百正确)
    
  • 粉红色:.idata section

      有关输入表的一些数据信息
    
  • 军绿色:.rdata section

     纯数据,只读
    
  • 灰色:为了段对齐而留下的空隙

  • 黑色:禁区,不存在任何数据

常用快捷键及设置

1、F5:文本视图指向函数时,按F5能查看该函数段C代码

2、y JNIEnv *:还原C代码后部分方法调用需要还原JNI函数方法名,选中对应指针按y然后输入JNIEnv *还原JNI函数名

3、SPACE:用于在IDA VIEW视图中切换文本视图及图形视图

4、Shift+F12:展示所有字符串内容窗口,能够查看字符串存储地址及调用地址

5、Ctrl+S:查看段地址的快捷键,得到段的起始地址和结束地址

6、G:跳转到指定地址的代码位置


3.3 Java层调用Native层方法原理

背景概述

在安卓逆向的工作当中,我们在对Java层代码进行分析后,通过System.load()以及System.loadLibrary()方法能够让我们准确的知道相应的Native方法在哪个so文件中实现,但是我们该如何在so文件中找到找到对应的实现方法的位置呢,这时就需要去了解安卓开发中Java层调用Native层方法原理。

Native层方法注册方式

在安卓开发中Native层方法的注册分为静态注册以及动态注册两种形式,对于安卓开发而言,静态注册与动态注册在Java层实现逻辑时一模一样的,区别仅在于如何建立Java层函数与Native层函数的映射关系。

静态注册

静态注册流程:

静态注册优点:

  • 注册方式比较简单,有规范的注册流程

静态注册的缺点:

  • 不利于方法的更新

  • 多次调用效率低

动态注册

动态注册流程:

动态注册优点:

  • 注册效率高

  • 利于方法更新

  • 调用效率高

动态注册缺点:

  • 需要理解动态注册原理以及关注注册信息规范

对于逆向工作而言,静态注册方法最终在Native层中生成的函数名格式为Java_包名_类名_Native方法名,如拼多多中:

因此我们能很快速找到Native层中函数实现的位置,对于动态注册方法,我们则需要进入JNI_Onload()方法中查找对应的函数注册数组,然后找到Native层中的对应实现位置,如京东到家:


3.4 Native层代码的修改

背景概述

在对Native层代码进行逆向时,有时候我们需要通过修改Native层代码来屏蔽某些代码或是插入我们的代码,而Native层代码的修改是基于ARM汇编来完成的,因此我们通过修改其十六进制代码便能完成Native层代码的修改。

修改案例

通过阅读此处代码,可以看出用于调用安卓日志类输出指针v27之前共33个字符

此时我们想修改这个v22参数,将其变大,使其输出80个字符,我们首先需要去到IDA VIEW中查看该命令地址以及在IDA HEX中该地址对应的十六进制代码

此时进入https://armconverter.com/中将我们想要替换的汇编代码生成十六进制代码

得到十六进制代码后回到IDA HEX窗口按F2修改对应的十六进制代码,修改完毕后按F12保存

保存完毕后查看查看代码是否修改成功


3.5 So文件替换

概述

经过上一步对Native代码进行修改,我们需要对so文件进行重新打包,并且完成替换原so文件操作

重打包

点击hedaer工具栏Edit-》Path program-》Apply pathces to input file-》ok

替换so

进入安卓模拟器路径/data/app/{对应app文件夹}/lib/替换原有so文件


4.总结

至此简要的介绍了以下在APP逆向工作中Native层静态分析的基础知识,让我们对安卓逆向有了基本的认识。逆向是一门实践学科,基础知识的掌握只是根基,只有通过大量的app逆向经验,逆向技术才能不断进步。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值