android 加壳与破解--静态修改so,常用破解方法

2023-11-06 09:30

本文主要是介绍android 加壳与破解--静态修改so,常用破解方法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.工具介绍

IDA6.5,静态分析so文件用

010 Editor,修改so文件16进制码

Android Killer Android反编译工具

2.修改SO

项目是Android jni的关键代码 可以用AndroidKiller  打开app,找出相应的so库,获取当前程序的包名

例:cn.com.location.hshelldemo

源码:

Java_cn_com_location_hshelldemo_MainActivity_stringFromJNI(JNIEnv *env,jobject /* this */) {std::string hello = "Hello from C++";int ret = getAuthInfo(10000);if(ret == RET_OK){LOGE(" !!!Check successfully\n");} else{LOGE(" !!!Check failed\n");}if(ret != RET_OK){LOGE(" =====Check successfully\n");}else{LOGE(" =====Check failed\n");}return env->NewStringUTF(hello.c_str());
}

so 使用 IDA 打开,然后进入options | General;

随便点击左侧的函数,按Ctrl+F  输入 java 这里是找 jni接口;

例:

找到接口单击,双击可以看到汇编源码,按F5可以找到C代码(C很重要,现在懂汇编的不多,C大家基本还是学的):

jstring __fastcall Java_cn_com_location_hshelldemo_MainActivity_stringFromJNI(JNIEnv *env, jobject a2)
{unsigned __int8 *bytes; // ST0C_4jstring result; // r0_jstring *v4; // [sp+8h] [bp-78h]int v5; // [sp+58h] [bp-28h]_JNIEnv *v6; // [sp+68h] [bp-18h]std::allocator<char> v7; // [sp+6Ch] [bp-14h]std::basic_string<char,std::char_traits<char>,std::allocator<char> > v8; // [sp+70h] [bp-10h]int v9; // [sp+74h] [bp-Ch]v6 = env;std::allocator<char>::allocator(&v7);std::string::string(&v8, "Hello from C++", &v7);std::allocator<char>::~allocator(&v7);v5 = getAuthInfo(10000);if ( v5 == 10000 )_android_log_print(6, "native-lib-jni", " !!!Check successfully\n");else_android_log_print(6, "native-lib-jni", " !!!Check failed\n");if ( v5 != 10000 )_android_log_print(6, "native-lib-jni", " =====Check failed\n");else_android_log_print(6, "native-lib-jni", " =====Check successfully\n");bytes = (unsigned __int8 *)std::string::c_str(&v8);v4 = _JNIEnv::NewStringUTF(v6, bytes);std::string::~string(&v8);result = (jstring)_stack_chk_guard;if ( _stack_chk_guard == v9 )result = v4;return result;
}

可以看到和上面源码基本一样,所以现在很多算法库都要加壳,否则很容易被破解;

我们想做的其实就是把   if ( v5 == 10000 ) 取反,这样就可以成功;


 

这里直接说关键代码:

            loc_4346
11 98       LDR             R0, [SP,#0x80+var_3C]
16 90       STR             R0, [SP,#0x80+var_28]
16 99       LDR             R1, [SP,#0x80+var_28]
42 F2 10 72 MOVW            R2, #0x2710
91 42       CMP             R1, R2
1C D1       BNE             loc_438E

 

如果是IDA 7.0

直接在 BNE 上右键,Kaypatch->patcher 直接修改指令,保存就可以,最简单;

最后点击Edit > Patch program > Apply pathes to input file > OK

 

 

BNE意思是上一行的CMP比较指令如果R1,R2不相等 就跳转到loc_438E处,会输出失败。当然如果正常运行后值不相等。
 

点击

点击View->open subviews->hex dump可以看到相应地址

可以看出跳转指令B对应的16进制机器码为E7,我们现在要做的就是把4350 处的指令改成B loc_4356,意思就是不用判断上一行的CMP指令直接跳转到正常的地方。

使用 010 Editor修改so

(1) 修改跳转地址

BNE 跳转指令对应的HEX机器码是D1,B 对应的16进制机器码为E7  ,B 无条件跳转指令

将D1 改为E7

保存,然后重新运行项目,  successfully了。

其实也可以把修改后的so重新拖入IDA可以看到,直接转到我们想到的地方;

(2) 修改指令

关于,指令:

 BNE,BEQ;

BNE指令,是个条件跳转,即:是“不相等(或不为0)跳转指令”。如果不为0就跳转到后面指定的地址。

BEQ功能与BNE刚好相反。

我们也可以 修改BNE,为BEQ,这里可能就需要一个转机器码的软件;ARM_ASM Converter

类似 CBZ ,CBNZ;

(3) 改比较的值

第三种方式,我们也可以修改比较的值如:

#0x2710

42 F2 10 72 MOVW            R2, #0x2710

这和8086汇编有类似之处,就是十六进制和汇编代码是大体颠倒的。我们做一个正确的颠倒:27 10。 我们可以改成

42 F2 10 72  -》 42 F2 11 72 

指令变为:

MOVW            R2, #0x2711 

即可以变它变成我们想要的值,这里是 16进制;

最近使用 Android killer 将 so文件重新打包;

当然修改字符串类似,这里不在详细说,下面转一个看过的https://www.52pojie.cn/thread-399062-1-1.html:

===============================================================

1.我们要达到什么目地?
我们逆向APK时,如今对于so一般来说是肯定要做修改的,然而IDA修改汇编代码,不像OD可以直接修改汇编指令,必须通过WINHEX等修改十六进制。我们仅仅知道00表示代码清除,90表示NOP指令,即空指令。但仅仅删除一行代码这样的修改肯定是满足不了需要的。我们需要深入修改一点。


2.Intel8086与ARM基础知识
Intel8086是英特尔公司的16位处理器,ARM是ARM公司的32位处理器。每个处理器都对应自己的一套汇编语言,所以两个处理器分别对应于8086汇编和ARM汇编。由于处理器的位数,所以8086汇编指令的机器码是16位,而ARM汇编指令的机器码就是32位。机器码可以看作是二进制指令,其实所谓的HEX即称为十六进制操作码或十六进制机器码,也是二进制指令,只是把二进制的数值用十六进制去展示。


3.ARM汇编非常重要
ARM汇编可以做的事情在我看来比8086汇编多得多,如果你会了ARM,就会了主流的嵌入式开发,然后就是硬件编程,然后就是机器人或机械制造。所以,ARM真的非常重要,希望可以去认真学习,不仅是ARM指令集,还有ARM的机器码的原理,以及ELF文件在linux下的objdump反编译。下面只能简单讲解。


4.ARM的机器码简单讲解
ARM机器码为32位,我们以跳转指令BL和BEQ为例讲解。其实我们只需要关注最高的8位,也就是24-31位。首先来看,28-31这四位,不同条件这四位有什么不同。然后在27-24这四位里,BL和BEQ都是1010.所以BL指令的二进制是11101010,即十六进制的EA;相同BEQ的十六进制就是0A。


5.SO里面的情况
当我们把SO里的汇编语言放到工具中去转换为HEX时,会发现和IDA中的HEX有时是完全不同的,这是因为IDA中有时反编译SO使用的不是ARM,而是16位的ARM,也就是Thumb指令,但有时却是ARM的32位指令。


6.修改汇编跳转指令
这种情况一般是Thumb指令,一般而言一行代码对应是2个HEX码。
例子:bne指令修改为beq指令
通过工具,我们发现bne跳转指令对应的HEX机器码是D1,beq对应的HEX机器码是D0,然后用WINHEX修改,再用IDA检测。


7.修改数据
这种情况一般是ARM指令,一般而言一行代码对应是4个HEX码。
例子:修改小黄人快跑中初始化金币量
so里面原来ARM代码:mov R1,#0x49C8
最大可改为0XFFFF,也就是65535,修改后的代码应为:mov R1,#0xFFFF
原本的代码对应的HEX:C8 19 04 E3,为什么是这个样子,这和8086汇编有类似之处,就是十六进制和汇编代码是大体颠倒的。最后的E3是MOV这个汇编指令。我们做一个正确的颠倒:E3 01 49 C8。这下就懂了吧!所以,我们改为FF 1F 0F E3。
当然,为了方便,可以直接使用工具,不过这样的分析能够极大增强大家ARM分析的能力。不过不要寄太多希望于工具,因为很多时候,工具会发生错误或者和IDA中的HEX-VIEW情况不一致,也不利于我们学习的。所以工具只是辅助,主要还是动脑子。


8.修改字符串
这种情况比较简单,字符串就是字符串,修改字符串的HEX码就是利用ASCII转HEX的工具就可以,我们可以对比两个so来看看。当然最简单修改办法,是用WINHEX直接在右边修改字符串。其实,这和修改文本是一样的,记事本,notepad都可以。手机端的MT,HEXEDITOR,十六进制编辑器等等也都可以修改SO的字符串,推荐使用默小坑兄弟的ADK编辑器。

 

 

 

 

 

 

这篇关于android 加壳与破解--静态修改so,常用破解方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/355792

相关文章

Python判断for循环最后一次的6种方法

《Python判断for循环最后一次的6种方法》在Python中,通常我们不会直接判断for循环是否正在执行最后一次迭代,因为Python的for循环是基于可迭代对象的,它不知道也不关心迭代的内部状态... 目录1.使用enuhttp://www.chinasem.cnmerate()和len()来判断for

Java循环创建对象内存溢出的解决方法

《Java循环创建对象内存溢出的解决方法》在Java中,如果在循环中不当地创建大量对象而不及时释放内存,很容易导致内存溢出(OutOfMemoryError),所以本文给大家介绍了Java循环创建对象... 目录问题1. 解决方案2. 示例代码2.1 原始版本(可能导致内存溢出)2.2 修改后的版本问题在

四种Flutter子页面向父组件传递数据的方法介绍

《四种Flutter子页面向父组件传递数据的方法介绍》在Flutter中,如果父组件需要调用子组件的方法,可以通过常用的四种方式实现,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录方法 1:使用 GlobalKey 和 State 调用子组件方法方法 2:通过回调函数(Callb

一文详解Python中数据清洗与处理的常用方法

《一文详解Python中数据清洗与处理的常用方法》在数据处理与分析过程中,缺失值、重复值、异常值等问题是常见的挑战,本文总结了多种数据清洗与处理方法,文中的示例代码简洁易懂,有需要的小伙伴可以参考下... 目录缺失值处理重复值处理异常值处理数据类型转换文本清洗数据分组统计数据分箱数据标准化在数据处理与分析过

Java中Object类的常用方法小结

《Java中Object类的常用方法小结》JavaObject类是所有类的父类,位于java.lang包中,本文为大家整理了一些Object类的常用方法,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. public boolean equals(Object obj)2. public int ha

golang1.23版本之前 Timer Reset方法无法正确使用

《golang1.23版本之前TimerReset方法无法正确使用》在Go1.23之前,使用`time.Reset`函数时需要先调用`Stop`并明确从timer的channel中抽取出东西,以避... 目录golang1.23 之前 Reset ​到底有什么问题golang1.23 之前到底应该如何正确的

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element

Python调用另一个py文件并传递参数常见的方法及其应用场景

《Python调用另一个py文件并传递参数常见的方法及其应用场景》:本文主要介绍在Python中调用另一个py文件并传递参数的几种常见方法,包括使用import语句、exec函数、subproce... 目录前言1. 使用import语句1.1 基本用法1.2 导入特定函数1.3 处理文件路径2. 使用ex

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

Git中恢复已删除分支的几种方法

《Git中恢复已删除分支的几种方法》:本文主要介绍在Git中恢复已删除分支的几种方法,包括查找提交记录、恢复分支、推送恢复的分支等步骤,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录1. 恢复本地删除的分支场景方法2. 恢复远程删除的分支场景方法3. 恢复未推送的本地删除分支场景方法4. 恢复