终于有机会来CTF摸摸鱼了
这道题是个典型的输入flag再加密比对的题,运行就不截图了。

大纲

  • 一.解题过程
    • 找到check函数地址
    • 分析check函数
      • 字符串初步比对
      • 输入16进制字符串两两一组转化成byte流
      • RC4加密
      • DES加密
      • 字符串循环移位
  • 二.解题脚本
  • 三.RegisterNatives方法
  • 四.RC4算法
  • 五.DES算法

一.解题过程

找到check函数地址

先用apkscan查壳,未加壳。那就直接上jeb,关键部分如下图所示:
加密部分为check函数,check函数在so里,该去分析下so了,这道题有2个so, arm64-v8a为64位的so,armeabi-v7a为32位的,功能差不多,我更倾向于分析32位。

打开IDA后找不到check,倒是找到了check1(队友说check1功能一样)那么check应该是动态注册的,点进JNI_ONLOAD看看。


把JNI_Onload函数的形参改一下,改完之后的为:

再修改下v3的类型

右键RegisterNatives,选择Force call type

看到有个全局变量off_18708,点进去瞧瞧。
这地址保存着3个参数,第一个是函数名check,第二个是输入参数类型Java.lang.String, 第三个则是check函数的地址。

RegisterNatives函数这里就不详细说下,放到待会再说。

分析check函数

点进刚刚找到的check函数地址。
关键代码如下(部分变量已改过名,推荐大家也这么做,更直观):
sub_74F0函数功能是取字符串长度。sub_77E8相当于substring(int start, int end)。

字符串初步比对

首先input长度是22,(22行)
第5个字符是’{’ (26行)
最后一个字符是’}’
前4个字符截取保存到head中,(根据格式猜测为’flag’)
中间16个字符截取保存到flag中

输入16进制字符串两两一组转化成byte流

sub7826代码如下:
具体分析不展开,就是将判断16个字符是不是16进制字符,并将其2个字符一组转化成8个16进制数保存到src_flag中。

RC4加密

接下来是sub_799C:
dest保存的是8个16进制数,head内容应该是’flag’
sub_78C4内容如下(变量重命名过):

这是个rc4_init函数。初始密钥是head(‘flag’),生成S。
sub_7950如下:
这就是RC4加密过程。

所以sub_799C为RC4加密函数,加密后的字符串依旧保存在dest处

DES加密

sub_7894:

大概就是把普通字符串变成16进制字符串(比如’flag’,其ascii码分别为0x66, 0x6C, 0x61, 0x67,转换后即为’666C6167’)
运行后v13为’666C6167’

下一步加密用到的密钥为v13
sub_8294:
跟之前相似的套路,先根据密钥初始化,再加密:

sub_80F0(初始化):
sub_8224(加密):

这还真没看出来是什么加密算法,室友大佬友好提示DES,密钥也知道了,就看看最后比对的字符串把

字符串循环移位

回到check函数:

des为最终加密的8个字符,v7为64位变量,刚好保存8个字符。
这个过程把字符串v0 v1 v2 v4 v4 v5 v6 v7变成 v4 v5 v6 v7 v0 v1 v2 v3
最后的这个大整数16进制为0x41316EEA99EDA1D9
所以des加密结果为0x99 0xed 0x a1 0xd9 0x41 0x31 0x6e 0xea

另外这道题分析check1函数也是可以的,安卓动态调试不熟悉静态分析简直能把人整死。

二.解题脚本

from Crypto.Cipher import DES, ARC4
from binascii import b2a_hex# b2a_hex将byte流转化成16进制字符串if __name__ == '__main__':enc = b'\x99\xed\xa1\xd9\x41\x31\x6e\xea'key_des = b'666C6167'key_rc4 = b'flag'rc4 = ARC4.new(key_rc4)des = DES.new(key_des, DES.MODE_ECB)# 输入字符串首先从16进制字符串变成byte流,然后rc4->desfinal = b2a_hex(rc4.decrypt(des.decrypt(enc))).decode('utf-8').upper()flag = 'flag{' + final + '}'print(flag)

b2a_hex是python 16进制字符串转字符串的库,比如(b2a_hex(’\xea\xb1’) = b’eab1’)

得到flag:flag{76952041E276E2BF}

三.RegisterNatives方法

该方法原型为

Jint RegisterNative(JNIEnv, jclass cls, JNINativeMethod *methods,  jint number)
  1. methods 是一个二维数组,代表着这个class里的每一个native方法所对应的实现的方法,在前面的例子中表示,一个native 方法retrieveDiretives, 返回值为AssertionStatusDirectives, 所对应的执行的本地方法是JVM_AssertionStatusDirectives

  2. 后面的number 代表要指定的native的数量

而这里的off_18708就是一个methods, 为1 * 3数组。

RegisterNatives例子如下:

#include <jni.h>jint func1(JNIEnv *env, jobject thiz, jstring str, jobject obj) {return 0;
}jint func2(JNIEnv *env, jclass cls, jstring str, jobject obj) {return 0;
}jint JNI_OnLoad(JavaVM *vm, void *reserved) {JNIEnv *env;vm->GetEnv((void**)&env,JNI_VERSION_1_4);jclass classTest = env->FindClass("com/example/hello_jni/Test");JNINativeMethod methods[]= {{"function1", "(Ljava/lang/String;Landroid/graphics/Bitmap;)I", (void*)func1},{"function1", "(Ljava/lang/String;Landroid/graphics/Bitmap;)I", (void*)func2},};env->RegisterNatives(classTest, methods, sizeof(methods)/sizeof(JNINativeMethod));return JNI_VERSION_1_4;
}

可以发现methods数组中,每个元素的第一个string表示java程序中的函数名, 第二个字符表示传入的参数类型(多个参数用;分隔),第三个参数为在c文件中定义的函数指针(实际调用的函数地址)

这里java文件中定义的方法大概为

public native void function1(String str, Bitmap bitmap);public native void function2(String str, Bitmap bitmap);

这里c文件中func1, func2的形参类型可能有错误,回头我会好好研究下这一块。

四.RC4算法

RC4是一种对称密码算法,它属于对称密码算法中的序列密码(streamcipher,也称为流密码),它是可变密钥长度,面向字节操作的流密码(一次加密一个字符)。RC4算法属于对合运算(解密和加密可以共用同一运算)

RC4首先根据密钥生成s-box,再用s-box对明文进行加密

这里贴下rc4简单的python实现

# 初始化函数
def rc4_init(key): # key是list类型length = len(key)s = []k = []for i in range(256):s[i].append(i)k[i].append(key[i % length])j = 0for i in range(256):j = (j + s[i] + k[i]) % 256s[i], s[j] = s[j], s[i]return s# 加解密函数
def rc4_encrypt(s, data):length = len(data)enc = []i = 0j = 0i = (i + 1) % 256j = (j + s[i]) % 256s[i], s[j] = s[j], s[i]t = (s[i] + s[j]) % 256enc.append(data[k] ^ s[t])return enc

五.DES算法

这里复制一下DES大致流程:

DES利用56比特串长度的密钥K来加密长度为64位的明文,得到长度为64位的
密文。加密算法分为三个阶段实现:

1.给定明文X,通过一个固定的初始置换IP排列X中的位,得到X0。 X 0 = I P ( X ) = L 0 R 0 X_0=IP(X)=L_0R_0 X0​=IP(X)=L0​R0​。其中L0由X0的前32位组成,R0由后32位组成。

2.计算函数F的16次迭代,根据下述规则计算 L i R i L_iR_i Li​Ri​: L i = R i , R i = L i − 1 ⨁ F ( R i − 1 , K i ) L_i=R_i, \ R_i=L_{i-1} \bigoplus F(R_{i-1},K_i) Li​=Ri​, Ri​=Li−1​⨁F(Ri−1​,Ki​)。其中Ki为48位子密钥。Ki可由56位密钥计算得出。

3.对 R 16 L 16 R_{16}L_{16} R16​L16​使用逆置换IP-1得到密文Y: Y = I P − 1 ( R 16 L 16 ) Y=IP^{-1}(R_{16}L_{16}) Y=IP−1(R16​L16​)。

由于DES算法具有可逆性和对合性,因此DES的加密算法与解密算法可以共用同一结构。

复制一个代码实现:

import osIP = [58, 50, 42, 34, 26, 18, 10, 2,60, 52, 44, 36, 28, 20, 12, 4,62, 54, 46, 38, 30, 22, 14, 6,64, 56, 48, 40, 32, 24, 16, 8,57, 49, 41, 33, 25, 17, 9, 1,59, 51, 43, 35, 27, 19, 11, 3,61, 53, 45, 37, 29, 21, 13, 5,63, 55, 47, 39, 31, 23, 15, 7
]IP_I = [40, 8, 48, 16, 56, 24, 64, 32,39, 7, 47, 15, 55, 23, 63, 31,38, 6, 46, 14, 54, 22, 62, 30,37, 5, 45, 13, 53, 21, 61, 29,36, 4, 44, 12, 52, 20, 60, 28,35, 3, 43, 11, 51, 19, 59, 27,34, 2, 42, 10, 50, 18, 58, 26,33, 1, 41, 9, 49, 17, 57, 25
]S_BOX = [[[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7],[0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8],[4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0],[15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]],[[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10],[3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5],[0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15],[13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9]],[[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8],[13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1],[13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7],[1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12]],[[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15],[13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9],[10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4],[3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14]],[[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9],[14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6],[4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14],[11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3]],[[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11],[10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8],[9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6],[4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13]],[[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1],[13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6],[1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2],[6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12]],[[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7],[1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2],[7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8],[2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11]]
]E_TRANS = [32, 1, 2, 3, 4, 5,4, 5, 6, 7, 8, 9,8, 9, 10, 11, 12, 13,12, 13, 14, 15, 16, 17,16, 17, 18, 19, 20, 21,20, 21, 22, 23, 24, 25,24, 25, 26, 27, 28, 29,28, 29, 30, 31, 32, 1
]P_TRANS = [16, 7, 20, 21, 29, 12, 28, 17,1, 15, 23, 26, 5, 18, 31, 10,2, 8, 24, 14, 32, 27, 3, 9,19, 13, 30, 6, 22, 11, 4, 25
]KEY_MOVE = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]KEY_TRANS_1 = [57, 49, 41, 33, 25, 17, 9,1, 58, 50, 42, 34, 26, 18,10, 2, 59, 51, 43, 35, 27,19, 11, 3, 60, 52, 44, 36,63, 55, 47, 39, 31, 23, 15,7, 62, 54, 46, 38, 30, 22,14, 6, 61, 53, 45, 37, 29,21, 13, 5, 28, 20, 12, 4,
]KEY_TRANS_2 = [14, 17, 11, 24, 1, 5, 3, 28,15, 6, 21, 10, 23, 19, 12, 4,26, 8, 16, 7, 27, 20, 13, 2,41, 52, 31, 37, 47, 55, 30, 40,51, 45, 33, 48, 44, 49, 39, 56,34, 53, 46, 42, 50, 36, 29, 32
]def DES(p, key, mode):p_IP, p_IP_I = 0, 0# e_transp_IP = IP_Trans(p)print("IP(p): " + hex(p_IP))# divide p into L and RL, R = p_IP >> 32, p_IP & (int("0xffffffff", 16))print("L0: " + hex(L))print("R0: " + hex(R))# create key_listkey_list = Key_Creater(key, mode)[:]# feistel strcturefor i in range(16):L, R = R, Function(R, key_list[i]) ^ Lprint("Round {}: L={}, R={}".format(i + 1,hex(L).replace("0x", "").zfill(8),hex(R).replace("0x", "").zfill(8)))p = (R << 32) + Lp_IP_I = IP_I_Trans(p)print("IP_I(p): ", hex(p_IP_I).zfill(16))return hex(p_IP_I).replace("0x", "").zfill(16)def Key_Creater(key, mode):key_list, key_in = [], 0key_in = PC_1(key)# divide key_in into C and DC, D = key_in >> 28, key_in & (int("0xfffffff", 16))for i in range(16):# left moveC, D = KeyMove(C, D, i)key, key_out = (C << 28) + D, 0# key_trans_2key_out = PC_2(key)key_list.append(key_out)if mode == 2:key_list.reverse()return key_listdef IP_Trans(p):p_IP = 0# e_transfor i in range(64):p_IP <<= 1if p & (1 << (64 - IP[i])) != 0:p_IP += 1return p_IPdef IP_I_Trans(p):p_IP_I = 0for i in range(64):p_IP_I <<= 1if p & (1 << (64 - IP_I[i])) != 0:p_IP_I += 1return p_IP_Idef E_Trans(R):R_E = 0# e_transfor i in range(48):R_E <<= 1if R & (1 << (32 - E_TRANS[i])) != 0:R_E += 1return R_Edef P_Trans(s_out):R_P = 0for i in range(32):R_P <<= 1if s_out & (1 << (32 - P_TRANS[i])) != 0:R_P += 1return R_Pdef S_box(s_in):extract, s_out = int("0b111111", 2), 0# s_boxfor i in range(8):s_out <<= 4# get 6 bits inputs = (s_in >> ((7 - i) * 6)) & extract# select is used to determine which list will be choseselect = ((s >> 5) << 1) + (s & 1)index = (s & int("0b011110", 2)) >> 1s_out += S_BOX[i][select][index]return s_outdef PC_1(key):key_in = 0# key_trans_1for i in range(56):key_in <<= 1if key & (1 << (64 - KEY_TRANS_1[i])) != 0:key_in += 1return key_indef PC_2(key):key_out = 0for k in range(48):key_out <<= 1if key & (1 << (56 - KEY_TRANS_2[k])) != 0:key_out += 1return key_outdef KeyMove(C, D, i):for j in range(KEY_MOVE[i]):C = ((C << 1) & int("0xfffffff", 16)) + (C >> 27)D = ((D << 1) & int("0xfffffff", 16)) + (D >> 27)return C, Ddef Function(R, key):R_E, R_P = 0, 0# e_transR_E = E_Trans(R)# s_in is a 48-bit input, extract is used to divide s_in into 8 4-bit piecess_in, extract, s_out = R_E ^ key, int("0b111111", 2), 0# s_boxs_out = S_box(s_in)# p_transR_P = P_Trans(s_out)return R_Pif __name__ == "__main__":mode = int(input("mode: [1]crypt [2]decrypt "))p = int(input("input text: "), 16)key = int(input("input key: "), 16)print("\nciphertext is: " + DES(p, key, mode))os.system("pause")

在CTF比赛中,S_BOX是判断加密算法种类的一个重要依据,要是找到了类似的S_BOX的数据并且能和AES或者DES匹配上,那就不用再分析代码了。

(祥云杯)reverse-apk1相关推荐

  1. java 中1%3c1%3c1_祥云杯2020 部分WriteUp

    祥云杯 Web ★sign 1%09||%09ls%09/ 1%09||%09ca\t%09in\dex.p\hp时有个闪 1%09||find%09/%09-name%09`echo%09ZmxhK ...

  2. 祥云杯2022 writeup

    0x01 web 1.ezjava 下载源码对jar文件进行反编译,发现POST /myTest会出现反序列化漏洞 util ,最后好像没用到 检查程序,发现apache的common−collect ...

  3. [2020首届祥云杯]带音乐家

    [2020首届祥云杯]带音乐家 题目: 下载好附件,打开,得到一个文件与一个rar包: 并且rar包是经过了加密的,我这里去010里看了下,发现并不是伪加密: 所以突破点就只有上面的decode_it ...

  4. 祥云杯-re复现 (未完待续)

    周末祥云杯没打,主要是自己想摸了..(就是这么直白)还有就是nctf举办,我出题,我到比赛那天还没出完...(太咕了..) 比赛后就想来复现这比赛,看解题人数,感觉满难的,应该很有质量,就跟着null ...

  5. 2021祥云杯PassWordBox_ProVersion

    目录 前言: 程序分析 大致思路: 利用链: _IO_wfile_overflow _IO_wfile_underflow_mmap: exp: 前言: 复现一下2021祥云杯PassWordBox_ ...

  6. 2021祥云杯部分pwn

    note 格式化字符串 本题考查了scanf的格式化字符串利用.一般我们用的都是printf的格式化字符串.这里是scanf 踩坑 一开始没有注意到sendline会多发一个换行符,导致往栈上$7的s ...

  7. 祥云杯-2020babydev

    文章目录 前言 题目 保护 分析 思路 解法一:(思路不错) 解法二:(最精简) 解法三:(最简单) 参考文章 前言 个人觉得exp要写的精简,适当注释,至少不应该留有冗余的代码,对于刚学习的pwne ...

  8. 2021祥云杯部分wp

    祥云杯2021 目前只做了两道题(没办法 tcl... MISC-鸣雏恋 下载下来是个word,打开只有一句话 不太对劲,放到010里看一看发现文件头50 4B 03 04 经典压缩包了,文件后缀改成 ...

  9. [2021祥云杯]secrets_of_admin

    [2021祥云杯]secrets_of_admin 文章目录 [2021祥云杯]secrets_of_admin 代码分析 /的POST方式 /admin的GET方式 /admin的POST方式 /a ...

  10. 深入分析祥云杯easy_yii

    深入分析祥云杯easy_yii 题目描述 yii最新的链子 前置知识 析构函数__destruct 官方解释:析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行 <?php cl ...

最新文章

  1. RabbitMQ 快速入门
  2. EOS绑定以太坊地址
  3. mysql5.7.20linux安装,linux下 mysql5.7.20安装(精华)
  4. html5通过api调数据库,使用HTML5数据库API [关闭](Using HTML5 Database API [closed])
  5. Hadoop集群日常运维
  6. SAP Marketing Cloud的双重登录认证
  7. 江苏大学计算机学院宋美如,姜震-江苏大学计算机科学与通信工程学院
  8. gradle 构建测试
  9. Python格式化输出、转义字符、结束符
  10. Xcode9使用新体验
  11. android webkit js脚本注入(js内部对象由java层构建)
  12. 51单片机下载完程序后不亮_单片机实用工具大全,超级赞,工程师必备!
  13. linux 查看md5值
  14. 使用python生成正弦光栅的代码示例,包括竖直光栅,水平光栅,圆光栅
  15. [论文写作笔记] C9 概括和结论展示科学严谨性
  16. google play以及google pay
  17. 高级编程中C语言属于,c语言高级编程
  18. MinGW-w64下载安装2024年最新教程
  19. 怎么让input输入框最右侧一直默认有百分号
  20. CStdioFile类

热门文章

  1. JAVA三大平台介绍
  2. hybris impex导入 联合主键对象
  3. 电脑经常蓝屏是什么原因 各种蓝屏代码解决方法
  4. 韩信点兵,,三人余 五人余 七人余
  5. jmeter非gui运行,jtl生成了,但是html报告没有生成
  6. Windows Mobile开发总结
  7. 数字城市三维可视化技术路线
  8. 1052: 打印图形 VII
  9. [Error]在Linux服务器:cannot connect to X server localhost:11.0
  10. shell zsh bash ash tcsh的差别和关系