热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

简单AndroidCrackMe分析

这是今年ISCC的一道AndroidCrackMe题目,相对简单的题,懂点ARM指令就差不多了,至于smali什么的,随便看看就好。大概玩一两个这样的CrackMe就对Andro

这是今年ISCC的一道Android CrackMe题目,相对简单的题,懂点ARM指令就差不多了,至于smali什么的,随便看看就好。大概玩一两个这样的CrackMe就对Android的逆向有个大概的了解了。不过后来发现这玩意是从非虫的《Android软件安全与逆向分析》上拿过来的原题,略显蛋疼。

 

这是个重启注册型APK,题目要求对其进行Patch,使得进入程序后就是企业版程序。首先,使用ApkTool GUI进行解包,发现这个App调用了一个NDK编写的so库文件,crackme6\lib\armeabi\libhack.so。把crackme6.apk重命名为crackme6.zip并进行解压处理,在解压之后的根目录可以得到classes.dex文件(crackme6Zip\classes.dex)。使用ApkTool GUI将其转换为jar文件。用JD-GUI把jar文件转换成Java代码,其中的MyApp加载了so文件,如下面的代码所示:

 


import android.app.Application;
public class MyApp extends Application {
public static int m = 0;
static {
System.loadLibrary("hack"); // 加载hack
}
public native void initSN();
public void onCreate() {
initSN();
super.onCreate();
}
public native void saveSN(String paramString);
public native void work();
}

 


除此之外,还声明了一些函数如initSN、saveSN、work等,像是so文件的导出函数。RegActivity负责注册界面,核心代码如下:

 


public class RegActivity extends Activity
{
public void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130903041);
this.btn_reg = ((Button)findViewById(2131165184));
this.edit_sn = ((EditText)findViewById(2131165185));
this.btn_reg.setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramView)
{
String str = RegActivity.this.edit_sn.getText().toString().trim();
if ((str == null) || (str.length() == 0))
{
Toast.makeText(RegActivity.this, "请输入注册码", 0).show();
return;
}
((MyApp)RegActivity.this.getApplication()).saveSN(str);
new AlertDialog.Builder(RegActivity.this).setTitle("注册").
setMessage("注册码已保存,点击确定后程序将退出,请手动重新启动本程序!").
setPositiveButton("确定", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface paramDialogInterface, int paramInt)
{
Process.killProcess(Process.myPid());
}
}).show();
}
});
}
}

 


可以看出这是一个重启注册型程序,中间调用MyApp.SaveSN保存输入的注册码,之后自动退出并需要手动重启。重启后,自然会在MainActivity中进行判断,核心代码如下:

 


public class MainActivity extends Activity
{
public void doRegister() { /*提示注册*/ }
public void onCreate(Bundle paramBundle)
{
((MyApp)getApplication());
int i = MyApp.m; // 根据这个变量判断注册类型
String str;
if (i == 0) str = "-未注册";
while (true) {
setTitle("点击执行功能去注册" + str);
this.btn1 = ((Button)findViewById(2131165184));
this.btn1.setOnClickListener(new View.OnClickListener() {
public void onClick(View paramView){
((MyApp)MainActivity.this.getApplication());
if (MyApp.m == 0) { // 提示注册
MainActivity.this.doRegister();
return;
}
((MyApp)MainActivity.this.getApplication()).work();
Toast.makeText(MainActivity.this.getApplicationContext(),
MainActivity.workString, 0).show(); // 注册成功提示语
}
});
return;
if (i == 1) { str = "-正式版"; continue;}
if (i == 2) { str = "-专业版"; continue; }
if (i == 3) { str = "-企业版"; continue; }
if (i == 4) { str = "-专供版"; continue; }
str = "-未知版";
}
}

 


可以确定work、initSN、saveSN都位于so文件内了,使用IDA对其进行逆向分析。没有看到这些导出函数,但是有三个比较可疑的函数n1,n2,n3,实际对应着这几个函数:

 

n1对应initSN,n2对应saveSN,n3对应work。n2函数负责把接收到的注册码计算小写32位MD5值,并将其保存于/sdcard/reg.dat文件之中,验证过程位于n1函数:

 


.text:000012E8 04 00 A0 E1 MOV R0, R4 ; s1
.text:000012EC 01 10 8F E0 ADD R1, PC, R1 ; 25d55ad283aa400af464c76d713c07ad
.text:000012EC ; 12345678 MD5
.text:000012F0 49 FF FF EB BL strcmp ; 字符串比较
.text:000012F4 08 00 50 E1 CMP R0, R8 ; 是否相等
.text:000012F8 17 00 00 0A BEQ loc_135C ; 相等则跳转
.text:000012FC BC 10 9F E5 LDR R1, =(a08e0750210f663 - 0x130C)
.text:00001300 04 00 A0 E1 MOV R0, R4 ; s1
.text:00001304 01 10 8F E0 ADD R1, PC, R1 ; 08e0750210f66396eb83957973705aad
.text:00001304 ; 22345678 MD5
.text:00001308 43 FF FF EB BL strcmp
.text:0000130C 00 00 50 E3 CMP R0, #0
.text:00001310 15 00 00 0A BEQ loc_136C
.text:00001314 A8 10 9F E5 LDR R1, =(aB2db1185c9e5b8 - 0x1324)
.text:00001318 04 00 A0 E1 MOV R0, R4 ; s1
.text:0000131C 01 10 8F E0 ADD R1, PC, R1 ; b2db1185c9e5b88d9b70d7b3278a4947
.text:0000131C ; 32345678 MD5
.text:00001320 3D FF FF EB BL strcmp
.text:00001324 00 00 50 E3 CMP R0, #0
.text:00001328 13 00 00 0A BEQ loc_137C
.text:0000132C 94 10 9F E5 LDR R1, =(a18e56d777d194c - 0x133C)
.text:00001330 04 00 A0 E1 MOV R0, R4 ; s1
.text:00001334 01 10 8F E0 ADD R1, PC, R1 ; 18e56d777d194c4d589046d62801501c
.text:00001334 ; 42345678 MD5
.text:00001338 37 FF FF EB BL strcmp
.text:0000133C 00 00 50 E3 CMP R0, #0
.text:00001340 04 10 A0 03 MOVEQ R1, #4
.text:00001344 07 00 A0 E1 MOV R0, R7
.text:00001348 08 10 A0 11 MOVNE R1, R8 ; R0为最开始传入的参数
.text:0000134C A9 FF FF EB BL setValue ; R1的值为0 1 2 3 4 其中0表示失败

 


上面是核心代码。initSN读取文件内容,并直接进行字符串比较,有如下几个MD5值:

 

注册码           MD5                                     意义

12345678        25d55ad283aa400af464c76d713c07ad        正式版

22345678        08e0750210f66396eb83957973705aad        专业版

32345678        b2db1185c9e5b88d9b70d7b3278a4947        企业版

42345678        18e56d777d194c4d589046d62801501c        专供版

还有其他两种状态,一种是initSN函数中打开文件失败、或者内存分配失败、或者注册码不正确,那么就提示“程序未注册,功能无法使用!”,还有一种异常状态,理论上来说不会存在“软件版本状态异常!”。

比较完成之后,通过setValue函数保存在某处内存之中。work函数通过getValue获取上述保存的值,然后进行判断:

 

.text:000014A0 10 40 2D E9                 STMFD   SP!, {R4,LR}

.text:000014A4 00 40 A0 E1                 MOV     R4, R0

.text:000014A8 6F FF FF EB                 BL      fnCheckRegSN

.text:000014AC 04 00 A0 E1                 MOV     R0, R4

.text:000014B0 35 FF FF EB                 BL      getValue        ; 读取比较结果

.text:000014B4 00 00 50 E3                 CMP     R0, #0          ; 注册失败

.text:000014B8 0C 00 00 0A                 BEQ     loc_14F0

.text:000014BC 01 00 50 E3                 CMP     R0, #1

.text:000014C0 13 00 00 0A                 BEQ     loc_1514

.text:000014C4 02 00 50 E3                 CMP     R0, #2

.text:000014C8 16 00 00 0A                 BEQ     loc_1528

.text:000014CC 03 00 50 E3                 CMP     R0, #3          ; 企业版

.text:000014D0 19 00 00 0A                 BEQ     fEnterpriseVersion

.text:000014D4 04 00 50 E3                 CMP     R0, #4

.text:000014D8 04 00 A0 E1                 MOV     R0, R4

.text:000014DC 08 00 00 0A                 BEQ     loc_1504

.text:000014E0 68 10 9F E5                 LDR     R1, =(aSPfCiicMckCabx - 0x14EC)

.text:000014E4 01 10 8F E0                 ADD     R1, PC, R1      ; 软件版本状态异常!

.text:000014E8 10 40 BD E8                 LDMFD   SP!, {R4,LR}

.text:000014EC B6 FF FF EA                 B       callWork

然后根据结果进行跳转:

 

.text:000014F0             ; ---------------------------------------------------------------------------

.text:000014F0

.text:000014F0             loc_14F0                                ; CODE XREF: fnShowRegResult+18j

.text:000014F0 5C 10 9F E5                 LDR     R1, =(aCilxPcKcIxjmqM - 0x1500)

.text:000014F4 04 00 A0 E1                 MOV     R0, R4

.text:000014F8 01 10 8F E0                 ADD     R1, PC, R1      ; 程序未注册,功能无法使用!

.text:000014FC 10 40 BD E8                 LDMFD   SP!, {R4,LR}

.text:00001500 B1 FF FF EA                 B       callWork

.text:00001504             ; ---------------------------------------------------------------------------

.text:00001504

.text:00001504             loc_1504                                ; CODE XREF: fnShowRegResult+3Cj

.text:00001504 4C 10 9F E5                 LDR     R1, =(aCdqsVcvifCfifU - 0x1510) ;

.text:00001508 01 10 8F E0                 ADD     R1, PC, R1      ; 感谢您使用专供版程序!

.text:0000150C 10 40 BD E8                 LDMFD   SP!, {R4,LR}

.text:00001510 AD FF FF EA                 B       callWork

.text:00001514             ; ---------------------------------------------------------------------------

.text:00001514

.text:00001514             loc_1514                                ; CODE XREF: fnShowRegResult+20j

.text:00001514 40 10 9F E5                 LDR     R1, =(aCdqsVcvisNfCng - 0x1524)

.text:00001518 04 00 A0 E1                 MOV     R0, R4

.text:0000151C 01 10 8F E0                 ADD     R1, PC, R1      ; 感谢您购买正式版程序!

.text:00001520 10 40 BD E8                 LDMFD   SP!, {R4,LR}

.text:00001524 A8 FF FF EA                 B       callWork

.text:00001528             ; ---------------------------------------------------------------------------

.text:00001528

.text:00001528             loc_1528                                ; CODE XREF: fnShowRegResult+28j

.text:00001528 30 10 9F E5                 LDR     R1, =(aCdqsVcvisNfFUf - 0x1538) ;

.text:0000152C 04 00 A0 E1                 MOV     R0, R4

.text:00001530 01 10 8F E0                 ADD     R1, PC, R1      ; 感谢您购买专业版程序!

.text:00001534 10 40 BD E8                 LDMFD   SP!, {R4,LR}

.text:00001538 A3 FF FF EA                 B       callWork

.text:0000153C             ; ---------------------------------------------------------------------------

.text:0000153C

.text:0000153C             fEnterpriseVersion                      ; CODE XREF: fnShowRegResult+30j

.text:0000153C 20 10 9F E5                 LDR     R1, =(asc_3A70 - 0x154C) ; 企业版注册成功

.text:00001540 04 00 A0 E1                 MOV     R0, R4

.text:00001544 01 10 8F E0                 ADD     R1, PC, R1      ; 感谢您购买企业版程序!

.text:00001548 10 40 BD E8                 LDMFD   SP!, {R4,LR}

.text:0000154C 9E FF FF EA                 B       callWork

.text:0000154C             ; End of function fnShowRegResult

.text:0000154C

当setValue设置的值为3时就是企业版。现在,我们可以修改initSN中的几个MOV语句,使得任意的比较结果、打开文件失败、分配内存失败都设置为3,那么不需要注册就提示时企业版了。

 

在IDA中回到initSN函数,以其中一个分支为例:

我们要把MOV R1, #2改为MOV R1,#3,那么通过16进制编辑器将偏移0×1370处的02改为03就行了,用同样的方法修改initSN中的分支。修改的地方如图中红色字节:

之后保存so文件并进行重新打包签名操作,安装到模拟器进行测试,点击按钮提示“感谢您购买企业版程序”,不再出现注册过程,结果如图:

 


成功破解这个Android CrackMe

文章中所提到的APK以及idb文件已经打包上传到了百度云,下载地址为:Android CrackMe

 

 

Copyed From 程序人生 

Home Page:http://www.programlife.net 




推荐阅读
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 第四章高阶函数(参数传递、高阶函数、lambda表达式)(python进阶)的讲解和应用
    本文主要讲解了第四章高阶函数(参数传递、高阶函数、lambda表达式)的相关知识,包括函数参数传递机制和赋值机制、引用传递的概念和应用、默认参数的定义和使用等内容。同时介绍了高阶函数和lambda表达式的概念,并给出了一些实例代码进行演示。对于想要进一步提升python编程能力的读者来说,本文将是一个不错的学习资料。 ... [详细]
  • iOS Swift中如何实现自动登录?
    本文介绍了在iOS Swift中如何实现自动登录的方法,包括使用故事板、SWRevealViewController等技术,以及解决用户注销后重新登录自动跳转到主页的问题。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
author-avatar
guitar402
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有