攻防世界Mobile5 EasyJNI 安卓逆向CTF
EasyJNI
最近正好在出写JNI,正好看到了一道JNI相关的较为简单明了的CTF,就一时兴起的写了,不得不说逆向工程和正向开发确实是可以互补互相加深的
JNI
JNI(Java Native Interface)即java本地接口,众所周知,android有四层结构(也有说五层结构,即多了一个抽象层,这里不予讨论),应用层与应用接口层是用Java写的,而C/C++核心库和linux内核层由C/C++写的,既然知道了这一点,那理解JNI就很简单了,Java和C/C++肯定是不能直接互相调用的,那么应用层肯定就不能直接调用底层的东西,比如从应用层直接用Java想调用底层C/C++开发的启动相机或NFC等肯定是不能直接实现的。
这就是JNI的作用了,它充当桥梁,向C/C++转译Java中的方法,向Java转译C/C++的函数,而NDK就是JNI开发工具。
开始解题
首先不考虑那么多的先AndroidKiller试试

既然都AK(AndroidKiller)了就索性看看JADE

实不相瞒的说在看到这两个东西之前我还想过会不会就是名字放着看的,不是调用的JNI,既然看到这里了就知道了确确实实调用了JNI,那就一步一步的分析吧,首先看OnCreate()

就这一句话是有用的,别的没啥用,这段代码中设置了一个点击事件,即创立了一个Button,并通过ID找到Button,然后设置SetOnClickListener设置监听,点击之后调用上图中的a()方法,传入的String是输入的String,通过a()方法返回一个布尔值
那就回去看a方法就好了,先放个整体图出来吧

这样就能看到这题恶心人的地方了,他的MainActivity中有a方法,但是还有一个a类,而且在a类中,还有一个静态的Byte[]也叫a,但没啥影响,降维理解一下这里吧:
初始化一个a类locala,并把输入进去的String类型的字符串穿换成Byte[]类型组传入a类locala的a方法。看着可能绕,自己做的就还行了。
那就看a类吧

不知道是不是我jade版本的问题,看这个a数组里边的东西,明明是char型的东西,没有自动转换成字符,这就很烦了,于是我换成了JEB
1 package com.a.easyjni;
2
3 public class a {
4 private static final char[] a;
5
6 static {
7 a.a = new char[]{'i', '5', 'j', 'L', 'W', '7', 'S', '0', 'G', 'X', '6', 'u', 'f', '1', 'c', 'v', '3', 'n', 'y', '4', 'q', '8', 'e', 's', '2', 'Q', '+', 'b', 'd', 'k', 'Y', 'g', 'K', 'O', 'I', 'T', '/', 't', 'A', 'x', 'U', 'r', 'F', 'l', 'V', 'P', 'z', 'h', 'm', 'o', 'w', '9', 'B', 'H', 'C', 'M', 'D', 'p', 'E', 'a', 'J', 'R', 'Z', 'N'};
8 }
9
10 public a() {
11 super();
12 }
13
14 public String a(byte[] arg10) {
15 int v8 = 3;
16 StringBuilder v4 = new StringBuilder();
17 int v0;
18 for(v0 = 0; v0 <= arg10.length - 1; v0 += 3) {
19 byte[] v5 = new byte[4];
20 int v3 = 0;
21 byte v2 = 0;
22 while(v3 <= 2) {
23 if(v0 + v3 <= arg10.length - 1) {
24 v5[v3] = ((byte)(v2 | (arg10[v0 + v3] & 0xFF) >>> v3 * 2 + 2));
25 v2 = ((byte)(((arg10[v0 + v3] & 0xFF) << (2 - v3) * 2 + 2 & 0xFF) >>> 2));
26 }
27 else {
28 v5[v3] = v2;
29 v2 = 0x40;
30 }
31
32 ++v3;
33 }
34
35 v5[v8] = v2;
36 int v2_1;
37 for(v2_1 = 0; v2_1 <= v8; ++v2_1) {
38 if(v5[v2_1] <= 0x3F) {
39 v4.append(a.a[v5[v2_1]]);
40 }
41 else {
42 v4.append('=');
43 }
44 }
45 }
46
47 return v4.toString();
48 }
49 }
实不相瞒的说,要不是我去看别人的WP我都没有意识到这是变种的Base64加密,不过这个a作为密码表还是很明显的,那再重新理一下逻辑,输入了一个字符串Str,这个字符串在a.a中被加密成立Str1,Str1被传到了布尔型的native层的ncheck中经过检测, 并由返回的布尔值判断输出。
那就简单了,看ncheck就好了,在ncheck中有判断需要逆向回去的字符串
将apk解压
so库就在lib下了
IDA大法好

Ctrl+F搜索ncheck就得到了想要的函数,分析一下这个函数吧,在v6之前说的都是废话,不用管
1 v6 = (const char *)(*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)a1 + 676))(a1, a3, 0);
2 if ( strlen(v6) == 32 )
3 {
4 v7 = 0;
5 do
6 {
7 v8 = &s1[v7];
8 s1[v7] = v6[v7 + 16];
9 v9 = v6[v7++];
10 v8[16] = v9;
11 }
12 while ( v7 != 16 );
13 (*(void (__fastcall **)(int, int, const char *))(*(_DWORD *)v4 + 680))(v4, v5, v6);
14 v10 = 0;
15 do
16 {
17 v12 = __OFSUB__(v10, 30);
18 v11 = v10 - 30 < 0;
19 v16 = s1[v10];
20 s1[v10] = s1[v10 + 1];
21 s1[v10 + 1] = v16;
22 v10 += 2;
23 }
24 while ( v11 ^ v12 );
25 v13 = memcmp(s1, "MbT3sQgX039i3g==AQOoMQFPskB1Bsc7", 0x20u);
26 result = 0;
27 if ( !v13 )
28 result = 1;
29 }
30 else
31 {
32 (*(void (__fastcall **)(int, int, const char *))(*(_DWORD *)v4 + 680))(v4, v5, v6);
33 result = 0;
34 }
35 return result;
不管别的,至少我第一眼看到的就是“MbT3sQgX039i3g==AQOoMQFPskB1Bsc7”,在这我大概就知道是Base64了,这个两个等号太明显了,而且前面的密码表很明显跟base64不一样,那就确定是base64的变种了。在这个函数中也有加密,先看一下这个加密吧,两个do...while,先看两个while,一个是v7由0变到16,一个是计算一个异或值。
先看第一个do...while,就是将前16位与后16位交换位置,没啥好多说的
看看第二个do..while,V12是一个判断溢出,__OFSUB__(int a,int b)经过查询之后的作用是判断a-b是否会产生溢出,即a+(-b)是否溢出,-30补码为11100010,如果要产生溢出,那最小的补码为00100000,十进制就是16,跟前面那个就有点意思了,也是16。并且在0到16期间也不可能减去30大于等于0,即V11永远为0。那么V11^V12的第一个跳出条件就是,当V10为16的时候。也能看出来作用就是两两交换位置。
“v13 = memcmp(s1, "MbT3sQgX039i3g==AQOoMQFPskB1Bsc7", 0x20u)”这里,memcmp(String str1,String str2,int n)作用判断为判断str1与str2的前n位,而0x20就是32。
从吾爱白嫖来的解密脚本:
#白嫖来的base64解密函数 base64_charset = "i5jLW7S0GX6uf1cv3ny4q8es2Q+bdkYgKOIT/tAxUrFlVPzhmow9BHCMDpEaJRZN" def decode(base64_str):
base64_bytes = ['{:0>6}'.format(str(bin(base64_charset.index(s))).replace('0b', '')) for s in base64_str if
s != '=']
resp = bytearray()
nums = len(base64_bytes) // 4
remain = len(base64_bytes) % 4
integral_part = base64_bytes[0:4 * nums] while integral_part:
tmp_unit = ''.join(integral_part[0:4])
tmp_unit = [int(tmp_unit[x: x + 8], 2) for x in [0, 8, 16]]
for i in tmp_unit:
resp.append(i)
integral_part = integral_part[4:] if remain:
remain_part = ''.join(base64_bytes[nums * 4:])
tmp_unit = [int(remain_part[i * 8:(i + 1) * 8], 2) for i in range(remain - 1)]
for i in tmp_unit:
resp.append(i) return resp #两两交换位置,还原so内的加密
flag = "AQOoMQFPskB1Bsc7MbT3sQgX039i3g=="
tmp=""
for i in range(len(flag)//2):
tmp += flag[i*2+1] + flag[i*2]
print(tmp)
print(decode(tmp))
攻防世界Mobile5 EasyJNI 安卓逆向CTF的更多相关文章
- CTF的一道安卓逆向
前几天打CTF时遇到的一道安卓逆向,这里简单的写一下思路 首先用jadx打开apk文件,找到simplecheck处(文件名是simplecheck),可以看到基本逻辑就是通过函数a对输入的内容进行判 ...
- 攻防世界逆向——game
攻防世界逆向:game wp 攻防世界逆向新手区的一道题目. 是一道windows的creak,动态调试打开是这样的: 题目说明是让屏幕上所有的图像都亮之后,会出现flag,看来应该是可以玩出来的. ...
- 攻防世界 WEB 高手进阶区 TokyoWesterns CTF shrine Writeup
攻防世界 WEB 高手进阶区 TokyoWesterns CTF shrine Writeup 题目介绍 题目考点 模板注入 Writeup 进入题目 import flask import os a ...
- CTF -攻防世界-crypto新手区(5~11)
easy_RSA 首先如果你没有密码学基础是得去恶补一下的 然后步骤是先算出欧拉函数 之后提交注意是cyberpeace{********}这样的 ,博主以为是flag{}耽误了很长时间 明明没算错 ...
- 攻防世界 reverse 进阶 APK-逆向2
APK-逆向2 Hack-you-2014 (看名以为是安卓逆向呢0.0,搞错了吧) 程序是.net写的,直接祭出神器dnSpy 1 using System; 2 using System.Diag ...
- 攻防世界 reverse evil
这是2017 ddctf的一道逆向题, 挑战:<恶意软件分析> 赛题背景: 员工小A收到了一封邮件,带一个文档附件,小A随手打开了附件.随后IT部门发现小A的电脑发出了异常网络访问请求,进 ...
- 攻防世界 | CAT
来自攻防世界官方WP | darkless师傅版本 题目描述 抓住那只猫 思路 打开页面,有个输入框输入域名,输入baidu.com进行测试 发现无任何回显,输入127.0.0.1进行测试. 发现已经 ...
- 记录下做攻防世界的misc题
0x00 记录一下,代表自己做过 0x01 flag_universe 看简介是来自2018年的百越杯. 将文件下载下来后,就一个flag_universe.pcapng文件,wireshark打开. ...
- 异或加密 - cr2-many-time-secrets(攻防世界) - 异性相吸(buuctf)
Crib dragging attack 在开始了解 Crib dragging attack 之前,先来理一理 异或. 异或加密 [详情请戳这里] XOR 加密简介 异或加密特性: ① 两个值相同时 ...
随机推荐
- redis维护节点常用操作
维护节点 添加主节点 hash槽重新分配 添加从节点 删除结点 1 添加主节点 集群创建成功后可以向集群中添加节点,下面是添加一个master主节点 添加7007结点作为新节点 执行命令:./redi ...
- GlobalExceptionHandler @ControllerAdvice
package org.linlinjava.litemall.core.config; import org.apache.commons.logging.Log; import org.apach ...
- Point Estimation
Point Estimation \(\bullet\)What is point estimation? Example: \(\bullet\) Bevan, Kullberg, and Rice ...
- 我是如何在四年时间里,从厨师转行为 Serverless 应用开发者
▎本文系译文,我的软件开发入行经历非常有趣 -- 我一开始其实是厨师. 作者:KieranMcCarthy 译者:Aceyclee 我在高中时就喜欢烹饪和烘焙,用不同食材的搭配去做出美味的食物,就像个 ...
- linux 上安装 java
一.源码安装 1.本地下载 java, 并上传到 linux 上 2.解压文件 tar -zxvf jdk-7u72-linux-i586.gz 3.配置环境变量 vi /etc/profile ...
- tomcat打印接口延迟时间
项目中有些页面时延不稳定,需要看每次接口调用时延,怎么看,有两种方法:一种是直接去catalina.out日志中看,一种是直接去localhost_access_log日志中看,第一种需要在代码中实现 ...
- maven-assembly-plugin 打包包含多余依赖问题一则
有同事反馈自己maven-assembly-plugin打的包里面多了很多mvn dependency:tree中没有的jar. 我当时只是试着把他的maven-assembly-plugin更新到了 ...
- OpenCV 特征描述
#include <stdio.h> #include <iostream> #include "opencv2/core/core.hpp" #inclu ...
- [LC] 231. Power of Two
Given an integer, write a function to determine if it is a power of two. Example 1: Input: 1 Output: ...
- AUTO Uninstaller 常见问题
小伙伴是不是遇到 CAD/3dmax/maya/Revit/Inventor 安装失败或者安装不了的问题了呢?AUTODESK系列软件着实令人头疼,CAD/3dmax/maya/Revit/Inven ...