这一题不easy,不知为何叫这个名字。。。。

1. apk 安装到手机,不知所云,各种亮瞎眼闪光

2. jadx 打开apk,一行java代码都没有,打开AndroidManifest看看

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.a.sample.findmydex" platformBuildVersionCode="24" platformBuildVersionName="7">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="24"/>
<application android:theme="@style/AppTheme" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:hasCode="false" android:allowBackup="false" android:fullBackupContent="false">
<activity android:label="@string/app_name" android:name="android.app.NativeActivity" android:configChanges="orientation|keyboardHidden">
<meta-data android:name="android.app.lib_name" android:value="native"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.a.sample.findmydex.MainActivity">
<intent-filter>
<action android:name="com.a.sample.findmydex.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>

注意这一行<meta-data android:name="android.app.lib_name" android:value="native"/>

还有android:hasCode="false"

说明代码在native层

2. so拖入到IDA中进行分析

符号表中看到一个叫android_main的函数,打开看看

,函数比较大,看留下的日志可以得出,需要我们摇晃手机100次的样子;先摇了再说

2023-03-22 15:21:29.741 6951-6976/? I/FindMyDex: Oh yeah~ You Got it~ 17 times to go~
2023-03-22 15:21:29.891 6951-6976/? I/FindMyDex: Oh yeah~ You Got it~ 15 times to go~
2023-03-22 15:21:30.041 6951-6976/? I/FindMyDex: Oh yeah~ You Got it~ 13 times to go~
2023-03-22 15:21:30.192 6951-6976/? I/FindMyDex: Oh yeah~ You Got it~ 11 times to go~
2023-03-22 15:21:30.207 6951-6976/? I/FindMyDex: Oh yeah~ You Got it~ 9 times to go~
2023-03-22 15:21:30.342 6951-6976/? I/FindMyDex: Oh yeah~ You Got it~ 7 times to go~
2023-03-22 15:21:30.491 6951-6976/? I/FindMyDex: Oh yeah~ You Got it~ 5 times to go~
2023-03-22 15:21:30.658 6951-6976/? I/FindMyDex: Oh yeah~ You Got it~ 3 times to go~
2023-03-22 15:21:30.790 6951-6976/? I/FindMyDex: Oh yeah~ You Got it~ 1 times to go~

看来实在监听我们摇晃的次数,达到次数后就打开界面

达到100次后,这里有一串代码

if ( v14 == 100 )
{
if ( time(0) - v6 > 9 )
{
_android_log_print(4, "FindMyDex", "OH~ You are too slow. Please try again");
qmemcpy(v3, &unk_7004, (size_t)off_43A18);
v10 = 0;
}
else
{
v20 = v6;
if ( uncompress(dest, &destLen, (const Bytef *)v3, (uLong)off_43A18) )
_android_log_print(5, "FindMyDex", "Dangerous operation detected.");
v21 = open(filename, 577, 511);
if ( !v21 )
_android_log_print(5, "FindMyDex", "Something wrong with the permission.");
write(v21, dest, destLen);
close(v21);
free(dest);
free(v3);
if ( access(name, 0) && mkdir(name, 0x1FFu) )
_android_log_print(5, "FindMyDex", "Something wrong with the permission..");
sub_2368(a1);
remove(filename);
_android_log_print(4, "FindMyDex", "Congratulations!! You made it!");
sub_2250(a1);
v10 = 0x80000000;
v6 = v20;
}
}

感觉实在写文件,然后又删了,看看删之前的sub_2368函数

  if ( (*(int (__fastcall **)(_DWORD, JNIEnv **, _DWORD))(**(_DWORD **)(*(_DWORD *)(a1 + 12) + 4) + 16))(
*(_DWORD *)(*(_DWORD *)(a1 + 12) + 4),
&v21,
0) != -1 )
{
v4 = (*v21)->FindClass(v21, "android/app/Activity");
v5 = (*v21)->GetMethodID(v21, v4, "getClassLoader", "()Ljava/lang/ClassLoader;");
v6 = (*v21)->CallObjectMethod(v21, *(jobject *)(*(_DWORD *)(a1 + 12) + 12), v5);
v7 = (*v21)->NewStringUTF(v21, v25);
v8 = (*v21)->NewStringUTF(v21, v22);
v9 = (*v21)->FindClass(v21, "dalvik/system/DexClassLoader");
v10 = (*v21)->GetMethodID(
v21,
v9,
"<init>",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");
v11 = (*v21)->NewObject(v21, v9, v10, v7, v8, 0, v6);
v12 = (*v21)->FindClass(v21, "android/content/ContextWrapper");
v13 = (*v21)->GetFieldID(v21, v12, "mBase", "Landroid/content/Context;");
v14 = (*v21)->GetObjectField(v21, *(_DWORD *)(*(_DWORD *)(a1 + 12) + 12), v13);
v15 = (*v21)->GetObjectClass(v21, v14);
v16 = (*v21)->GetFieldID(v21, v15, "mPackageInfo", "Landroid/app/LoadedApk;");
v17 = (*v21)->GetObjectField(v21, v14, v16);
v18 = (*v21)->GetObjectClass(v21, v17);
v19 = (*v21)->GetFieldID(v21, v18, "mClassLoader", "Ljava/lang/ClassLoader;");
(*v21)->GetObjectField(v21, v17, v19);
(*v21)->SetObjectField(v21, v17, v19, v11);
}
return _stack_chk_guard - v27;
}

这一看就是在动态加载dex,那么可以怀疑时so中动态释放出来了dex,然后加载

4. hook 以下remove 看一下文件写在哪了

    var lib_handler = Process.findModuleByName("libnative.so")
var dst_addr = new NativePointer(lib_handler.base.add(0x00002762 + 1))
console.log("==== " + dst_addr)
Interceptor.attach(dst_addr, {
onEnter:function(args) {
console.log("==== args: " + ptr(args[0]).readCString())
console.log("==== r0: " + print_dump(this.context.r0 ))
}
})

得出:/data/data/com.a.sample.findmydex/files/classes.dex

5. nop remove 不能让他删了,好取出文件


var lib_handler = Process.findModuleByName("libnative.so")
var dst_addr = new NativePointer(lib_handler.base.add(0x00002762))
Memory.patchCode(dst_addr, 4, function (code) {
var cw = new ArmWriter(code, { pc: dst_addr });
cw.putNop()
cw.flush();
});

成功得到classes.dex

6. 将classes.dex 和 之前反编译出来的resources.arsc 一起拖入jadx中就可以看到代码了

public class MainActivity extends u {
private static byte[] m = {-120, 77, -14, -38, 17, 5, -42, 44, -32, 109, 85, 31, 24, -91, -112, -83, 64, -83, Byte.MIN_VALUE, 84, 5, -94, -98, -30, 18, 70, -26, 71, 5, -99, -62, -58, 117, 29, -44, 6, 112, -4, 81, 84, 9, 22, -51, 95, -34, 12, 47, 77}; /* JADX INFO: Access modifiers changed from: private */
public static byte[] b(String str, String str2) {
try {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new ByteArrayInputStream(str.getBytes()));
ArrayList arrayList = new ArrayList();
Object a = b.a(str2.getBytes());
for (byte[] bArr = new byte[16]; bufferedInputStream.read(bArr, 0, 16) != -1; bArr = new byte[16]) {
arrayList.add(b.a(bArr, 0, a));
}
ByteBuffer allocate = ByteBuffer.allocate(arrayList.size() * 16);
for (Object obj : arrayList.toArray()) {
allocate.put((byte[]) obj);
}
return allocate.array();
} catch (Exception e) {
return new byte[1];
}
} /* JADX INFO: Access modifiers changed from: protected */
@Override // android.support.v7.a.u, android.support.v4.a.v, android.support.v4.a.p, android.app.Activity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
((Button) findViewById(R.id.button)).setOnClickListener(new a(this, (EditText) findViewById(R.id.edit_text), this));
}
}

通过分析(查看其他大佬的分析)可知,这是用了twofish算法实现的加密,twofish 首先时对称加密输出byte数组,然后通过base64生成字符串输出,推测m就是没有被base64编码过的byte数组,处理成base64后,

import base64
a = [-120, 77, -14, -38, 17, 5, -42, 44, -32, 109, 85, 31, 24, -91, -112, -83, 64, -83, -128, 84, 5, -94, -98, -30, 18, 70, -26, 71, 5, -99, -62, -58, 117, 29, -44, 6, 112, -4, 81, 84, 9, 22, -51, 95, -34, 12, 47, 77]
a = [i&255 for i in a]
b = base64.b64encode(bytes(a))
print(b) 日志
iE3y2hEF1izgbVUfGKWQrUCtgFQFop7iEkbmRwWdwsZ1HdQGcPxRVAkWzV/eDC9N

用在线的twofish算法解密可得出结果qwb{TH3y_Io<e_EACh_OTh3r_FOrEUER}

【Android 逆向】【攻防世界】easy-dex的更多相关文章

  1. 【Android 逆向】手动构造dex文件

    public class Hello { public static void main(String[] args) { System.out.println("hello android ...

  2. 逆向-攻防世界-crackme

    查壳,nSpack壳,直接用软件脱壳,IDA载入程序. 很明显,就是将402130的数据和输入的数据进行异或,判断是否等于402150处的数据.dwrd占4字节. 这道题主要记录一下刚学到的,直接在I ...

  3. 逆向-攻防世界-maze

    题目提示是走迷宫. IDA载入程序分析. 输入字符长度必须是24,开头必须是nctf{,结尾必须是}.在125处按R就可以变成字符. sub_400650和sub_400660是关键函数,分析sub_ ...

  4. 逆向-攻防世界-CSAW2013Reversing2

    运行程序乱码,OD载入搜索字符串,断电到弹窗Flag附近. 发现跳过00B61000函数,弹窗乱码,我们试试调用00B61000函数.将00B61094的指令修改为JE SHORT 00B6109b. ...

  5. 逆向-攻防世界-logmein

    iDA载入程序,shift+F12查看关键字符串,找到双击来到所在地址,进入函数 然后进入主函数, 经过分析,可以得出:输入的字符要等于  经过处理的v7和v8的异或.v8很明显,但是v7是怎么回事呢 ...

  6. 逆向-攻防世界-no-strings-attached

    看题目就知道查找不到关键字符串,为防止踩坑,strings命令查看,没有找到有用的字符串.IDA载入程序查找入口函数, main函数中有4个函数,经过分析判断authenticate()为关键函数,跟 ...

  7. 攻防世界逆向——game

    攻防世界逆向:game wp 攻防世界逆向新手区的一道题目. 是一道windows的creak,动态调试打开是这样的: 题目说明是让屏幕上所有的图像都亮之后,会出现flag,看来应该是可以玩出来的. ...

  8. [转]Android逆向之动态调试总结

    一.在SO中关键函数上下断点 刚学逆向调试时.大多都满足于在SO中某关键函数上下断点.然后通过操作应用程序,去触发这个断点,然后进行调试 详细的步骤可以参见非虫大大的<Android软件安全与逆 ...

  9. Android trap攻防思路整理

    Android trap攻防                                                                      图/文 h_one 0x01 反 ...

  10. android逆向学习小结--CrackMe_1

    断断续续的总算的把android开发和逆向的这两本书看完了,虽然没有java,和android开发的基础,但总体感觉起来还是比较能接收的,毕竟都是触类旁通的.当然要深入的话还需要对这门语言的细节特性和 ...

随机推荐

  1. [转帖]TiDB 统计数据库占用大小的N种方法

    TiDB之路2022-03-06 3896 前言 TiDB 如何统计数据库占用空间大小 四种方法 方法一 TiDB 统计数据库占用大小的第一种方法是监控.通过查看 {cluster-name} - O ...

  2. [转帖]【KingbaseES】sys_dump逻辑备份工具详解

    KingbaseES逻辑备份还原工具提供了数据库对象一级的联机备份还原功能,备份对象包括: 数据库 模式 表 视图 约束 权限 触发器 函数 序列 逻辑备份的输出格式包括: 二进制 SQL脚本 此外, ...

  3. [转帖]数据库系列之TiDB存储引擎TiKV实现机制

    TiDB存储引擎TiKV是基于RocksDB存储引擎,通过Raft分布式算法保证数据一致性.本文详细介绍了TiKV存储引擎的实现机制和原理,加深对TiDB底层存储架构的理解. 1.TiDB存储引擎Ti ...

  4. 【转帖】Windows Server 2016与旧版本系统比较

    一.性能和可扩性 特征描述 Windows Server 2012/2012 R2 标准版和数据中心 Windows Server 2016 标准版和数据中心 物理内存(主机)支持 每个物理服务器至多 ...

  5. 正则表达式match方法和search方法

    正则表达式, //match() 方法可在字符串内检索指定的值 找到返回相关数据,找不到返回null var part = /Box/ig; var str = "this is box,i ...

  6. 私密离线聊天新体验!llama-gpt聊天机器人:极速、安全、搭载Llama 2

    "私密离线聊天新体验!llama-gpt聊天机器人:极速.安全.搭载Llama 2,尽享Code Llama支持!" 一个自托管的.离线的.类似chatgpt的聊天机器人.由美洲驼 ...

  7. C++ CryptoPP使用AES加解密

    Crypto++ (CryptoPP) 是一个用于密码学和加密的 C++ 库.它是一个开源项目,提供了大量的密码学算法和功能,包括对称加密.非对称加密.哈希函数.消息认证码 (MAC).数字签名等.C ...

  8. Flask 之SocketIO库实现绘图表

    Flask 默认提供了针对WebSocket的支持插件from flask_socketio import SocketIO 直接通过pip命令安装即可导入使用,前端也需要引入socketIO库文件, ...

  9. 群联预告满血PCIe 5.0 SSD主控:飙上14.7GB/s

    群联电子将在CES 2024上展示两款新的PCIe 5.0 SSD主控方案,一个定位旗舰,一个面向主流. PCIe 5.0 SSD诞生已经差不多一年了,但是受限于群联E26主控的先天不足,以及闪存技术 ...

  10. 小结_第一个Java程序

    总结: 1. Java程序的编写与执行: 步骤1: 编写. 在后缀名为.java的文件中编写Java代码,该文件称为源文件 步骤2: 编译. 针对后缀名为.java源文件进行编译,生成字节码文件. 格 ...