1. apk 安装到手机,只有一个输入框,随便输入点什么,提示error

2. apk拖入到jadx中

public class MainActivity extends AppCompatActivity {
static int n = 0;
public static byte[] su; public native String stringFromJNI(); static {
System.loadLibrary("native-lib");
su = new byte[]{-66, -81, 25, -66, 122, -8, 42, -10, 78, -117, 104, -17, 118, -27, 40, -80, -20, 40, -60, -80, -11, -5, 75, 5, 100, 47, -48, 42, -119, -60, -66, 113};
} /* JADX INFO: Access modifiers changed from: protected */
@Override // androidx.appcompat.app.AppCompatActivity, androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
Button aa = (Button) findViewById(R.id.button);
aa.setOnClickListener(new View.OnClickListener() { // from class: com.r0ysue.test.MainActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View v) {
TextView ss = (TextView) MainActivity.this.findViewById(R.id.editTextTextPassword);
String mingwen = MainActivity.string2hex(ss.getText().toString());
if (mingwen.length() != 26) {
tv.setText("error");
return;
}
String ming1 = mingwen.substring(0, 8);
String ming2 = mingwen.substring(8, 16);
String ming3 = mingwen.substring(16, 24);
String ming4 = mingwen.substring(24, 26);
int a1 = Integer.parseInt(ming1, 16);
int a2 = Integer.parseInt(ming2, 16);
int a3 = Integer.parseInt(ming3, 16);
int a4 = Integer.parseInt(ming4, 16);
if (MainActivity.this.encrypt(a1, a2, a3, a4) == 1) {
tv.setText("success");
} else {
tv.setText("error");
}
}
});
} public int encrypt(int a, int b, int c, int d) {
try {
String content = Integer.toString(a, 16) + Integer.toString(b, 16) + Integer.toString(c, 16) + Integer.toString(d, 16);
String password = "r0ysue-yyds";
while (password.length() < 16) {
password = password + "0";
}
SecretKeySpec secretKeySpec = new SecretKeySpec(password.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
byte[] byteContent = content.getBytes("utf-8");
cipher.init(1, secretKeySpec);
byte[] result = cipher.doFinal(byteContent);
int n2 = 0;
while (true) {
byte[] bArr = su;
if (n2 >= bArr.length) {
return 1;
}
if (result[n2] != bArr[n2]) {
return 0;
}
n2++;
}
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} public static String string2hex(String string) {
StringBuffer unicode = new StringBuffer();
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
unicode.append(Integer.toHexString(c));
}
return unicode.toString();
}
}

看起来很简单,java写个解密过程,填入密码,还是不对。

看来so里有问题

2. so拖入IDA中,发现了一个函数.init_proc 查了下,是最早运行的一个函数

unsigned __int64 init_proc()
{
...... v10 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
strcpy(v9, "com/r0ysue/test/MainActivity");
for ( i = 0; i < (unsigned __int64)__strlen_chk(v9, 0x1Du); ++i )
byte_54A0[i] = v9[i] ^ 0x3C;
strcpy((char *)&v8, "encrypt");
for ( j = 0; j < (unsigned __int64)__strlen_chk((const char *)&v8, 8u); ++j )
byte_54D2[j] = v9[j - 8] ^ 0x3D;
strcpy((char *)&v7, "(IIII)I");
for ( k = 0; k < (unsigned __int64)__strlen_chk((const char *)&v7, 8u); ++k )
byte_5504[k] = *((_BYTE *)&v7 + k) ^ 0x3F;
for ( m = 0; m <= (unsigned __int64)__strlen_chk(v9, 0x1Du); ++m )
{
byte_54A0[m] ^= 0x3Cu;
if ( m == (unsigned __int64)__strlen_chk(v9, 0x1Du) )
byte_54A0[m] = 0;
}
for ( n = 0; n < (unsigned __int64)__strlen_chk((const char *)&v8, 8u); ++n )
{
byte_54D2[n] ^= 0x3Du;
if ( n == (unsigned __int64)__strlen_chk(v9, 0x1Du) )
byte_54D2[n] = 0;
}
for ( ii = 0; ; ++ii )
{
result = __strlen_chk((const char *)&v7, 8u);
if ( ii >= result )
break;
byte_5504[ii] ^= 0x3Fu;
if ( ii == (unsigned __int64)__strlen_chk(v9, 0x1Du) )
byte_5504[ii] = 0;
}
_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
return result;
}

可以看到貌似在搜集java层 encrypt 方法的信息

byte_54A0 v9  MainActivity
byte_54D2 v8 encrypt
byte_5504 v7 (IIII)I

点进Java_com_r0ysue_test_MainActivity_stringFromJNI看看

__int64 __fastcall Java_com_r0ysue_test_MainActivity_stringFromJNI(JNIEnv *env)
{
...... v11 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
pthread_create_sym = find_sym_sub_1604((__int64)"/system/lib64/libc.so", (__int64)"pthread_create");
v6 = 1;
__android_log_print(6, "r0ysue", "%x", pthread_create_sym);
v5 = fopen("/proc/self/maps", "r");
while ( __fgets_chk(v10, 1024LL, v5, 1024LL) )
{
if ( strstr(v10, "libc.so") )
{
if ( v6 == 2 )
{
v1 = strtok(v10, "-");
v7 = strtoul(v1, 0LL, 16);
}
else
{
strtok(v10, "-");
}
v2 = strtok(0LL, " ");
strtoul(v2, 0LL, 16);
++v6;
}
}
ret_chars = sub_20C0(pthread_create_sym, v7);
sub_1D40((__int64)env, (__int64)sub_272C, (__int64)byte_54A0, (__int64)byte_54D2, (__int64)byte_5504, 0);
result = sub_3104((__int64)env, (__int64)ret_chars);
_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
return result;
}

这一行 sub_1D40((__int64)env, (__int64)sub_272C, (__int64)byte_54A0, (__int64)byte_54D2, (__int64)byte_5504, 0);把上面的encrypt的三个信息全取出来了,还传入了一个函数sub_272C,点进去看看是在干啥

_QWORD *__fastcall sub_1D40(
JNIEnv *env,
__int64 t_func,
const char *class_name,
const char *method_name,
const char *sig_name,
int arg_num)
{
....... v23 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
v20 = method_name;
v21 = sig_name;
v22 = t_func;
if ( !dword_5350 )
{
v12 = 1;
v11 = fopen("/proc/self/maps", "r");
while ( __fgets_chk(v19, 1024LL, v11, 1024LL) )
{
if ( strstr(v19, "libart.so") )
{
__android_log_print(6, "r0ysue", "%s", v19);
if ( v12 == 1 )
{
v6 = strtok(v19, "-");
libart_startp_qword_53F8 = strtoul(v6, 0LL, 16);
}
else
{
strtok(v19, "-");
}
v7 = strtok(0LL, " ");
strtoul(v7, 0LL, 16);
++v12;
}
}
++dword_5350;
}
v10 = find_sym_sub_1604((__int64)"/system/lib64/libart.so", (__int64)"art_quick_generic_jni_trampoline");
jclass_mainActivity = (__int64)find_class_sub_2040(env, class_name);
jmethodId = (_QWORD *)getMethodId_sub_2078(env, (void *)jclass_mainActivity, method_name, sig_name);
qword_5358[arg_num] = *(_QWORD *)((char *)jmethodId + 4);
qword_53A8[arg_num] = jmethodId[5];
*(_QWORD *)((char *)jmethodId + 4) ^= 0x80100uLL;// *(_DWORD *) (a1 + 4) & 0x80000 == 0为是否为native的标志
jmethodId[5] = libart_startp_qword_53F8 + v10 - 0x25000;// //需要-0x25000是因为libart.so的程序头在偏移为0x25000 , 这里没遍历偷懒了
jmethodId[4] = t_func;
_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
return jmethodId;
}

看到了一个关键的字符串art_quick_generic_jni_trampoline 和下面修改jmethod 成员的操作,和 开源项目sandhook 十分相似,应该就是使用native方法去替换java层方法的行为

参考: https://github.com/asLody/SandHook

那么可以推测 t_func 即 sub_272C 就是替换用的native函数

bool __fastcall sub_272C(JNIEnv *env, jobject jobject, int a, int b, int c, int d)
{
if ( sub_2128(a, qword_5000, 101) == 0x384B099F681D8BA5LL )
{
if ( sub_2128(b, qword_5000, 101) == 0xCA6AFBB12E68AFF0LL )
return sub_2128(c, qword_5000, 101) == 0x910E2DB62AE48A6ELL
&& sub_2128(d, qword_5000, 101) == 0x1664C6F89BFD8183LL;
else
return 0;
}
else
{
return 0;
}
}
.data:0000000000005000 79 2D 65 75 73 79 30 72       qword_5000 DCQ 'r0ysue-y'               ; DATA XREF: sub_272C+C↑o
.data:0000000000005000 ; sub_272C+4C↑r
.data:0000000000005008

从这里可以推测出sub_2128是某种加密算法, 密钥为 r0ysue-y,开始寻找算法特征

DES 算法 参考 https://www.cnblogs.com/zhangzixu/p/14471822.html

.data:0000000000005008 3A 32 2A 22 1A 12 0A 02 3C 34+ip_byte_5008 DCB 0x3A, 0x32, 0x2A, 0x22, 0x1A, 0x12, 0xA, 2, 0x3C, 0x34, 0x2C, 0x24, 0x1C, 0x14, 0xC, 4, 0x3E, 0x36
.data:0000000000005008 2C 24 1C 14 0C 04 3E 36 2E 26+ ; DATA XREF: sub_2128+B4↑o
.data:0000000000005008 1E 16 0E 06 40 38 30 28 20 18+DCB 0x2E, 0x26, 0x1E, 0x16, 0xE, 6, 0x40, 0x38, 0x30, 0x28, 0x20, 0x18, 0x10, 8, 0x39, 0x31, 0x29, 0x21
.data:0000000000005008 10 08 39 31 29 21 19 11 09 01+DCB 0x19, 0x11, 9, 1, 0x3B, 0x33, 0x2B, 0x23, 0x1B, 0x13, 0xB, 3, 0x3D, 0x35, 0x2D, 0x25, 0x1D, 0x15
.data:0000000000005008 3B 33 2B 23 1B 13 0B 03 3D 35+DCB 0xD, 5, 0x3F, 0x37, 0x2F, 0x27, 0x1F, 0x17, 0xF, 7 .data:0000000000005080 01 01 02 02 02 02 02 02 01 02+left_move_byte_5080 DCB 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
.data:0000000000005080 02 02 02 02 02 01

从算法中使用到的数组来看,这明显是一个DES加密算法

那么只要对 0x384B099F681D8BA5LL 0xCA6AFBB12E68AFF0LL 0x910E2DB62AE48A6ELL 0x1664C6F89BFD8183LL 进行解密即可得出

使用 https://gchq.github.io/CyberChef 进行解密操作得到....i-lo....ve-r....0ysu.......e

flag即为i-love-r0ysue

【Android 逆向】看雪题目:找出flag 如果输入正确则屏幕上的 hello会变成success的更多相关文章

  1. 《第一行代码 android》 读书笔记:找出当前界面对应的Activity

    在android开发中找出当前界面对应的Activity,步骤如下: 新建一个BaseActivity继承自Activity,然后在BaseActivity中重写onCreate()方法,通过getC ...

  2. sar 找出系统瓶颈的利器 目前Linux上最为全面的系统性能分析工具之一 直接 sar -dur 1 30 即可看内存 CPU和IO占用

    12. sar 找出系统瓶颈的利器 sar是System Activity Reporter(系统活动情况报告)的缩写.sar工具将对系统当前的状态进行取样,然后通过计算数据和比例来表达系统的当前运行 ...

  3. 2019看雪CTF 晋级赛Q2第四题wp

    上次参加2019看雪CTF 晋级赛Q2卡在了这道题上,虽然逆出算法,但是方程不会解,哈哈哈哈,果然数学知识很重要呀,现在记录一下. 首先根据关键信息,根据错误提示字符串定位到这里: 1 int __t ...

  4. 如何在 Linux 中找出最近或今天被修改的文件

    1. 使用 ls 命令,只列出你的 home 文件夹中今天的文件. ls -al --time-style=+%D | grep `date +%D` 其中: -a- 列出所有文件,包括隐藏文件 -l ...

  5. python经典算法题目:找出这两个有序数组的中位数

    题目:找出这两个有序数组的中位数 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2. 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n)). 你可以 ...

  6. 一起来刷《剑指Offer》-- 题目一:找出数组中重复的数字(Python多种方法实现)

    数组中重复的数字 最近在复习算法和数据结构(基于Python实现),然后看了Python的各种"序列"--比如列表List.元组Tuple和字符串String,后期会写一篇博客介绍 ...

  7. python基础练习题(题目 两个乒乓球队进行比赛,各出三人。甲队为a,b,c三人,乙队为x,y,z三人。已抽签决定比赛名单。有人向队员打听比赛的名单。a说他不和x比,c说他不和x,z比,请编程序找出三队赛手的名单)

    day14 --------------------------------------------------------------- 实例022:比赛对手 题目 两个乒乓球队进行比赛,各出三人. ...

  8. Android系统,动态找出一个包下所有的类

    最近在写一个android应用,由于针对不同机型功能很不同,为了隔离变化,希望将各项功能插件化,通过编译开关来控制不同版本的功能,而不是在代码中通过逻辑来判断. 我想了一个办法,用表驱动的方法,结合插 ...

  9. c语言题目:找出一个二维数组的“鞍点”,即该位置上的元素在该行上最大,在该列上最小。也可能没有鞍点

    //题目:找出一个二维数组的“鞍点”,即该位置上的元素在该行上最大,在该列上最小.也可能没有鞍点. // #include "stdio.h" #include <stdli ...

  10. 面试- 阿里-. 大数据题目- 给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?

    假如每个url大小为10bytes,那么可以估计每个文件的大小为50G×64=320G,远远大于内存限制的4G,所以不可能将其完全加载到内存中处理,可以采用分治的思想来解决. Step1:遍历文件a, ...

随机推荐

  1. [转帖]如何使用 minio 进行 BR 备份

    https://tidb.net/blog/ada69456#5.%20%E4%BD%BF%E7%94%A8%20minio%20%E8%BF%9B%E8%A1%8C%20BR%20%E5%A4%87 ...

  2. [转帖]Jmeter学习笔记(二十一)——Concurrency Thread Group阶梯式加压测试

    https://www.cnblogs.com/pachongshangdexuebi/p/11739064.html 一.先安装jmeter的插件管理工具 1.下载地址:jmeter-plugins ...

  3. [转帖]MegaCli命令

    MegaCli命令 设置jbod模式 1.3 LSI 9260/9261 raid卡配置 LSI 9260/9261 raid卡支持0.1.10.5.6.50.60 常用命令: 清除raid卡原有的配 ...

  4. [转帖]Java 认证与授权(JAAS)介绍

    https://www.cnblogs.com/wuyongyin/p/16981469.html JAAS(Java Authentication Authorization Service),即 ...

  5. [转帖]CentOS 7 下用 firewall-cmd / iptables 实现 NAT 转发供内网服务器联网

    https://www.cnblogs.com/hope250/p/8033818.html 自从用 HAProxy 对服务器做了负载均衡以后,感觉后端服务器真的没必要再配置并占用公网IP资源.而且由 ...

  6. 编译打包rabbitmq然后一键部署的简单方法

    摘要 之前总结过一版,但是感觉不太全面 想着本次能够将使用中遇到的问题总结一下. 所以本次是第二版 介质下载 rabbitmq 不区分介质的打包文件 rabbitmq-server-generic-u ...

  7. CS231N Assignment1 SVM 笔记

    svm.ipynb 为SVM实现一个完全矢量化的损失函数 为其解析梯度实现完全矢量化表达式 使用数值梯度检查实现结果 使用验证集调整学习率和正则化 使用 SGD 优化损失函数 可视化最终学习权重 第一 ...

  8. windows10卸载小娜

    适用于2004版本往后的 win+x如图 输入如下代码 Get-AppxPackage-allusersMicrosoft.549981C3F5F10|Remove-AppxPackage 运行结束后 ...

  9. 开源IM项目OpenIM单聊及万人群压测报告

    单聊压测结论: 华为云主机s3一台:8核16G内存,网络带宽10Mb,普通磁盘(非SSD) 同时在线及压测客户端数量:1万 每秒钟发送消息量:2300条: 从发送到对方接收平均消息延时:5秒 群聊压测 ...

  10. 人工智能创新挑战赛:助力精准气象和海洋预测Baseline[3]:TCNN+RNN模型、SA-ConvLSTM模型

    "AI Earth"人工智能创新挑战赛:助力精准气象和海洋预测Baseline[3]:TCNN+RNN模型.SA-ConvLSTM模型 1.气象海洋预测-模型建立之TCNN+RNN ...