NSSCTF Round#18 RE WP 完整复现

1. GenshinWishSimulator

恶搞原神抽卡模拟器

看到软件的界面,大致有三种思路:

  1. 修改石头数量一直抽,如果概率正常肯定能抽到(但是估计设置的概率是0)
  2. 在源码里找flag的数据
  3. 把抽卡概率改成100%直接抽出来

Unity逆向,根据经验应该dnspy查看Assembly-CSharp.dll

上来看到SM4,但是别急

Gacha是抽卡的意思,这里应该是抽卡的主逻辑

Gift内可以看到主要逻辑,以array作为key"NSSCTF_2024_R#18" 为偏移(IV),用SM4/CBC/PKCS7Padding模式加密input数组,最后保存字符串到flag对象里

也就是说如果静态分析直接求flag就是一个SM4_CBC的解密过程,检查一下发现SM4没有经过魔改,应该容易解出

a. 静态分析解密

只要得到SM4解密需要的几个重要参数,再结合在线工具就能得出答案

  • 密文就是input数组

  • 密钥key是array数组,其计算方法很明显

然后找bucket数组,在Check()函数里发现了一堆方程,用于验证bucket数组的值

z3算一下,SM4的密钥长度只有16字节,设置变量类型时用Int,BitVec会因为位数多导致解出结果过大

from z3 import *
from Crypto.Util.number import *
bucket = [Int("bucket[%d]" % i) for i in range(16)]
s = Solver()
s.add(bucket[0] * 40 + bucket[1] * 65 + bucket[2] * -53 + bucket[3] * 70 + bucket[4] * -84 + bucket[5] * -38 + bucket[6] * 94 + bucket[7] * -39 + bucket[8] * -91 + bucket[9] * -35 + bucket[10] * 54 + bucket[11] * 17 + bucket[12] * 45 + bucket[13] * 92 + bucket[14] * -29 + bucket[15] * 61 == 3004)
s.add(bucket[0] * -15 + bucket[1] * 74 + bucket[2] * -89 + bucket[3] * -82 + bucket[4] * -92 + bucket[5] * 27 + bucket[6] * 21 + bucket[7] * -24 + bucket[8] * -82 + bucket[9] * -58 + bucket[10] * -36 + bucket[11] * 64 + bucket[12] * -49 + bucket[13] * -22 + bucket[14] * 59 + bucket[15] * -47 == -674)
s.add(bucket[0] * 67 + bucket[1] * -23 + bucket[2] * 63 + bucket[3] * -38 + bucket[4] * -32 + bucket[5] * 61 + bucket[6] * -71 + bucket[7] * 49 + bucket[8] * 83 + bucket[9] * -92 + bucket[10] * -16 + bucket[11] * 65 + bucket[12] * -22 + bucket[13] * 12 + bucket[14] * -85 + bucket[15] * 74 == 945 )
s.add(bucket[0] * -49 + bucket[1] * 48 + bucket[2] * -11 + bucket[3] * 20 + bucket[4] * -14 + bucket[5] * 92 + bucket[6] * -19 + bucket[7] * 32 + bucket[8] * 64 + bucket[9] * -77 + bucket[10] * 49 + bucket[11] * -19 + bucket[12] * 72 + bucket[13] * -64 + bucket[14] * 85 + bucket[15] * 54 == 1721)
s.add(bucket[0] * 36 + bucket[1] * -21 + bucket[2] * -59 + bucket[3] * -54 + bucket[4] * -96 + bucket[5] * -81 + bucket[6] * -33 + bucket[7] * 31 + bucket[8] * -41 + bucket[9] * -70 + bucket[10] * -27 + bucket[11] * 24 + bucket[12] * 95 + bucket[13] * -61 + bucket[14] * -17 + bucket[15] * -52 == -2198)
s.add(bucket[0] * 78 + bucket[1] * -62 + bucket[2] * 70 + bucket[3] * -69 + bucket[4] * 38 + bucket[5] * 90 + bucket[6] * -52 + bucket[7] * 41 + bucket[8] * 63 + bucket[9] * -65 + bucket[10] * -15 + bucket[11] * 59 + bucket[12] * -31 + bucket[13] * 54 + bucket[14] * 33 + bucket[15] * -57 == -1833)
s.add(bucket[0] * 56 + bucket[1] * 75 + bucket[2] * 71 + bucket[3] * 78 + bucket[4] * -39 + bucket[5] * -84 + bucket[6] * 55 + bucket[7] * 54 + bucket[8] * -12 + bucket[9] * -57 + bucket[10] * 32 + bucket[11] * -19 + bucket[12] * 13 + bucket[13] * -83 + bucket[14] * 11 + bucket[15] * -67 == 829)
s.add(bucket[0] * 10 + bucket[1] * -97 + bucket[2] * 56 + bucket[3] * -61 + bucket[4] * 45 + bucket[5] * -22 + bucket[6] * 33 + bucket[7] * 81 + bucket[8] * 32 + bucket[9] * 49 + bucket[10] * -19 + bucket[11] * -18 + bucket[12] * 80 + bucket[13] * -98 + bucket[14] * 79 + bucket[15] * -36 == -2551)
s.add(bucket[0] * 24 + bucket[1] * -61 + bucket[2] * 91 + bucket[3] * 93 + bucket[4] * 76 + bucket[5] * 54 + bucket[6] * -33 + bucket[7] * -29 + bucket[8] * -72 + bucket[9] * 20 + bucket[10] * 48 + bucket[11] * 79 + bucket[12] * 76 + bucket[13] * 68 + bucket[14] * 51 + bucket[15] * 25 == 2996)
s.add(bucket[0] * -83 + bucket[1] * -77 + bucket[2] * -64 + bucket[3] * -38 + bucket[4] * -13 + bucket[5] * -85 + bucket[6] * 33 + bucket[7] * -76 + bucket[8] * 27 + bucket[9] * 14 + bucket[10] * -79 + bucket[11] * -63 + bucket[12] * -78 + bucket[13] * 53 + bucket[14] * -73 + bucket[15] * 61 == -2315)
s.add(bucket[0] * 84 + bucket[1] * -67 + bucket[2] * 57 + bucket[3] * 26 + bucket[4] * 94 + bucket[5] * 20 + bucket[6] * -71 + bucket[7] * -88 + bucket[8] * -28 + bucket[9] * -13 + bucket[10] * -40 + bucket[11] * 76 + bucket[12] * -14 + bucket[13] * 33 + bucket[14] * 76 + bucket[15] * -75 == -150)
s.add(bucket[0] * -60 + bucket[1] * 88 + bucket[2] * -66 + bucket[3] * -72 + bucket[4] * 41 + bucket[5] * 49 + bucket[6] * 48 + bucket[7] * -77 + bucket[8] * -42 + bucket[9] * 25 + bucket[10] * -50 + bucket[11] * -84 + bucket[12] * 40 + bucket[13] * 50 + bucket[14] * -83 + bucket[15] * -27 == -1919)
s.add(bucket[0] * -16 + bucket[1] * -53 + bucket[2] * -21 + bucket[3] * -44 + bucket[4] * 26 + bucket[5] * -56 + bucket[6] * -90 + bucket[7] * -93 + bucket[8] * -73 + bucket[9] * 48 + bucket[10] * 15 + bucket[11] * -43 + bucket[12] * -61 + bucket[13] * -24 + bucket[14] * 71 + bucket[15] * 67 == -1199)
s.add(bucket[0] * 55 + bucket[1] * -34 + bucket[2] * -22 + bucket[3] * 60 + bucket[4] * 93 + bucket[5] * -95 + bucket[6] * 50 + bucket[7] * 36 + bucket[8] * -48 + bucket[9] * -26 + bucket[10] * -94 + bucket[11] * -35 + bucket[12] * 21 + bucket[13] * -27 + bucket[14] * 91 + bucket[15] * -76 == -1163)
s.add(bucket[0] * 64 + bucket[1] * -50 + bucket[2] * -23 + bucket[3] * -70 + bucket[4] * -78 + bucket[5] * 34 + bucket[6] * 26 + bucket[7] * 64 + bucket[8] * -72 + bucket[9] * 10 + bucket[10] * -96 + bucket[11] * 61 + bucket[12] * -15 + bucket[13] * 31 + bucket[14] * 36 + bucket[15] * 50 == -266)
s.add(bucket[0] * -27 + bucket[1] * 86 + bucket[2] * -61 + bucket[3] * 89 + bucket[4] * -53 + bucket[5] * 10 + bucket[6] * -42 + bucket[7] * 92 + bucket[8] * -48 + bucket[9] * 13 + bucket[10] * 84 + bucket[11] * -71 + bucket[12] * 93 + bucket[13] * 54 + bucket[14] * -69 + bucket[15] * -30 == 892)
if s.check() == sat:
    s = s.model()
print(s)
'''
[bucket[15] = 16,
 bucket[13] = 0,
 bucket[10] = 1,
 bucket[11] = 17,
 bucket[14] = 2,
 bucket[4] = 2,
 bucket[2] = 1,
 bucket[1] = 14,
 bucket[5] = 1,
 bucket[7] = 0,
 bucket[12] = 2,
 bucket[6] = 1,
 bucket[3] = 17,
 bucket[8] = 2,
 bucket[9] = 4,
 bucket[0] = 1]
 '''

然后每个+53就可以得到array也就是key了

  • IV很显然是"NSSCTF_2024_R#18"

用脚本转化一下形式使得数据容易套进在线工具里


#genshin wp
enc = [145,
		118,
		31,
		48,
		103,
		110,
		52,
		82,
		113,
		19,
		83,
		44,
		176,
		130,
		138,
		129,
		115,
		110,
		38,
		10,
		42,
		100,
		193,
		105,
		125,
		61,
		7,
		229,
		230,
		180,
		68,
		133,
		11,
		177,
		210,
		122,
		161,
		60,
		129,
		140,
		16,
		45,
		224,
		83,
		238,
		0,
		213,
		157,
		121,
		193,
		135,
		197,
		87,
		118,
		155,
		110,
		90,
		91,
		30,
		158,
		248,
		44,
		95,
		215,
		166,
		247,
		239,
		43,
		228,
		114,
		227,
		146,
		164,
		137,
		111,
		79,
		143,
		17,
		132,
		14]
print("enc: ")
for i in enc:  
    print(hex(i), end=' ')
print("\n")
from z3 import *
from Crypto.Util.number import *
bucket = [Int("bucket[%d]" % i) for i in range(16)]
s = Solver()
s.add(bucket[0] * 40 + bucket[1] * 65 + bucket[2] * -53 + bucket[3] * 70 + bucket[4] * -84 + bucket[5] * -38 + bucket[6] * 94 + bucket[7] * -39 + bucket[8] * -91 + bucket[9] * -35 + bucket[10] * 54 + bucket[11] * 17 + bucket[12] * 45 + bucket[13] * 92 + bucket[14] * -29 + bucket[15] * 61 == 3004)
s.add(bucket[0] * -15 + bucket[1] * 74 + bucket[2] * -89 + bucket[3] * -82 + bucket[4] * -92 + bucket[5] * 27 + bucket[6] * 21 + bucket[7] * -24 + bucket[8] * -82 + bucket[9] * -58 + bucket[10] * -36 + bucket[11] * 64 + bucket[12] * -49 + bucket[13] * -22 + bucket[14] * 59 + bucket[15] * -47 == -674)
s.add(bucket[0] * 67 + bucket[1] * -23 + bucket[2] * 63 + bucket[3] * -38 + bucket[4] * -32 + bucket[5] * 61 + bucket[6] * -71 + bucket[7] * 49 + bucket[8] * 83 + bucket[9] * -92 + bucket[10] * -16 + bucket[11] * 65 + bucket[12] * -22 + bucket[13] * 12 + bucket[14] * -85 + bucket[15] * 74 == 945 )
s.add(bucket[0] * -49 + bucket[1] * 48 + bucket[2] * -11 + bucket[3] * 20 + bucket[4] * -14 + bucket[5] * 92 + bucket[6] * -19 + bucket[7] * 32 + bucket[8] * 64 + bucket[9] * -77 + bucket[10] * 49 + bucket[11] * -19 + bucket[12] * 72 + bucket[13] * -64 + bucket[14] * 85 + bucket[15] * 54 == 1721)
s.add(bucket[0] * 36 + bucket[1] * -21 + bucket[2] * -59 + bucket[3] * -54 + bucket[4] * -96 + bucket[5] * -81 + bucket[6] * -33 + bucket[7] * 31 + bucket[8] * -41 + bucket[9] * -70 + bucket[10] * -27 + bucket[11] * 24 + bucket[12] * 95 + bucket[13] * -61 + bucket[14] * -17 + bucket[15] * -52 == -2198)
s.add(bucket[0] * 78 + bucket[1] * -62 + bucket[2] * 70 + bucket[3] * -69 + bucket[4] * 38 + bucket[5] * 90 + bucket[6] * -52 + bucket[7] * 41 + bucket[8] * 63 + bucket[9] * -65 + bucket[10] * -15 + bucket[11] * 59 + bucket[12] * -31 + bucket[13] * 54 + bucket[14] * 33 + bucket[15] * -57 == -1833)
s.add(bucket[0] * 56 + bucket[1] * 75 + bucket[2] * 71 + bucket[3] * 78 + bucket[4] * -39 + bucket[5] * -84 + bucket[6] * 55 + bucket[7] * 54 + bucket[8] * -12 + bucket[9] * -57 + bucket[10] * 32 + bucket[11] * -19 + bucket[12] * 13 + bucket[13] * -83 + bucket[14] * 11 + bucket[15] * -67 == 829)
s.add(bucket[0] * 10 + bucket[1] * -97 + bucket[2] * 56 + bucket[3] * -61 + bucket[4] * 45 + bucket[5] * -22 + bucket[6] * 33 + bucket[7] * 81 + bucket[8] * 32 + bucket[9] * 49 + bucket[10] * -19 + bucket[11] * -18 + bucket[12] * 80 + bucket[13] * -98 + bucket[14] * 79 + bucket[15] * -36 == -2551)
s.add(bucket[0] * 24 + bucket[1] * -61 + bucket[2] * 91 + bucket[3] * 93 + bucket[4] * 76 + bucket[5] * 54 + bucket[6] * -33 + bucket[7] * -29 + bucket[8] * -72 + bucket[9] * 20 + bucket[10] * 48 + bucket[11] * 79 + bucket[12] * 76 + bucket[13] * 68 + bucket[14] * 51 + bucket[15] * 25 == 2996)
s.add(bucket[0] * -83 + bucket[1] * -77 + bucket[2] * -64 + bucket[3] * -38 + bucket[4] * -13 + bucket[5] * -85 + bucket[6] * 33 + bucket[7] * -76 + bucket[8] * 27 + bucket[9] * 14 + bucket[10] * -79 + bucket[11] * -63 + bucket[12] * -78 + bucket[13] * 53 + bucket[14] * -73 + bucket[15] * 61 == -2315)
s.add(bucket[0] * 84 + bucket[1] * -67 + bucket[2] * 57 + bucket[3] * 26 + bucket[4] * 94 + bucket[5] * 20 + bucket[6] * -71 + bucket[7] * -88 + bucket[8] * -28 + bucket[9] * -13 + bucket[10] * -40 + bucket[11] * 76 + bucket[12] * -14 + bucket[13] * 33 + bucket[14] * 76 + bucket[15] * -75 == -150)
s.add(bucket[0] * -60 + bucket[1] * 88 + bucket[2] * -66 + bucket[3] * -72 + bucket[4] * 41 + bucket[5] * 49 + bucket[6] * 48 + bucket[7] * -77 + bucket[8] * -42 + bucket[9] * 25 + bucket[10] * -50 + bucket[11] * -84 + bucket[12] * 40 + bucket[13] * 50 + bucket[14] * -83 + bucket[15] * -27 == -1919)
s.add(bucket[0] * -16 + bucket[1] * -53 + bucket[2] * -21 + bucket[3] * -44 + bucket[4] * 26 + bucket[5] * -56 + bucket[6] * -90 + bucket[7] * -93 + bucket[8] * -73 + bucket[9] * 48 + bucket[10] * 15 + bucket[11] * -43 + bucket[12] * -61 + bucket[13] * -24 + bucket[14] * 71 + bucket[15] * 67 == -1199)
s.add(bucket[0] * 55 + bucket[1] * -34 + bucket[2] * -22 + bucket[3] * 60 + bucket[4] * 93 + bucket[5] * -95 + bucket[6] * 50 + bucket[7] * 36 + bucket[8] * -48 + bucket[9] * -26 + bucket[10] * -94 + bucket[11] * -35 + bucket[12] * 21 + bucket[13] * -27 + bucket[14] * 91 + bucket[15] * -76 == -1163)
s.add(bucket[0] * 64 + bucket[1] * -50 + bucket[2] * -23 + bucket[3] * -70 + bucket[4] * -78 + bucket[5] * 34 + bucket[6] * 26 + bucket[7] * 64 + bucket[8] * -72 + bucket[9] * 10 + bucket[10] * -96 + bucket[11] * 61 + bucket[12] * -15 + bucket[13] * 31 + bucket[14] * 36 + bucket[15] * 50 == -266)
s.add(bucket[0] * -27 + bucket[1] * 86 + bucket[2] * -61 + bucket[3] * 89 + bucket[4] * -53 + bucket[5] * 10 + bucket[6] * -42 + bucket[7] * 92 + bucket[8] * -48 + bucket[9] * 13 + bucket[10] * 84 + bucket[11] * -71 + bucket[12] * 93 + bucket[13] * 54 + bucket[14] * -69 + bucket[15] * -30 == 892)
if s.check() == sat:
    s = s.model()
print(s)
bucket[15] = 16
bucket[13] = 0
bucket[10] = 1
bucket[11] = 17
bucket[14] = 2
bucket[4] = 2
bucket[2] = 1
bucket[1] = 14
bucket[5] = 1
bucket[7] = 0
bucket[12] = 2
bucket[6] = 1
bucket[3] = 17
bucket[8] = 2
bucket[9] = 4
bucket[0] = 1
array = [0]*16
print(bucket)
for i in range(len(bucket)):
    array[i] = bucket[i] + 53
key = ''
for i in array:
	key += chr(i)
print("key:",key)
#iv = "NSSCTF_2024_R#18"  
'''
enc: 
0x91 0x76 0x1f 0x30 0x67 0x6e 0x34 0x52 0x71 0x13 0x53 0x2c 0xb0 0x82 0x8a 0x81 0x73 0x6e 0x26 0xa 0x2a 0x64 0xc1 0x69 0x7d 0x3d 0x7 0xe5 0xe6 0xb4 0x44 0x85 0xb 0xb1 0xd2 0x7a 0xa1 0x3c 0x81 0x8c 0x10 0x2d 0xe0 0x53 0xee 0x0 0xd5 0x9d 0x79 0xc1 0x87 0xc5 0x57 0x76 0x9b 0x6e 0x5a 0x5b 0x1e 0x9e 0xf8 0x2c 0x5f 0xd7 0xa6 0xf7 0xef 0x2b 0xe4 0x72 0xe3 0x92 0xa4 0x89 0x6f 0x4f 0x8f 0x11 0x84 0xe

[bucket[15] = 16,
 bucket[13] = 0,
 bucket[10] = 1,
 bucket[11] = 17,
 bucket[14] = 2,
 bucket[4] = 2,
 bucket[2] = 1,
 bucket[1] = 14,
 bucket[5] = 1,
 bucket[7] = 0,
 bucket[12] = 2,
 bucket[6] = 1,
 bucket[3] = 17,
 bucket[8] = 2,
 bucket[9] = 4,
 bucket[0] = 1]
[1, 14, 1, 17, 2, 1, 1, 0, 2, 4, 1, 17, 2, 0, 2, 16]
key: 6C6F7665796F757E
'''

几个参数注意一下就可以了

b. 修改逻辑(动态分析)

但考虑修改抽卡概率的方法可能更方便

尝试在这里下断点但是直接抽卡不运行这一段代码,无法在这里断下来

只能修改代码逻辑

我们找到这个GetRandomItem函数,发现要经过Check才可以出发生成flag的Gift函数

即bucket必须满足上面我们z3解出来的那个值,我们直接把bucket赋值

在GachaHistoryBucket中,修改GetBucket()或者直接修改bucket初始值都可以

修改初始值的话记得选择编辑类,不然编译不通过

抽取的部分也要改一下

我们要的flag在这里,修改一下使得它必然被执行

保存一下运行

OCR提取一下文字,少数几个错字自己改一下

2. NewYearGift

IDA打开来没什么头绪,不过似乎和dll有关

尝试从程序中提取dll文件

这里用静态提取即可

用010Editor打开,搜索PE文件头,开头有一个中间有一个,应该是打包在exe里的dll

复制MZ到结尾的部分

后面可以看到一些相关的字段

新建一个十六进制文件粘贴进去

然后就可以在dnspy分析,主逻辑很清晰

比较简便的方法就是把Program的代码都抠出来,去掉if判断的部分直接编译

3. SenpaiCalc

IDA反编译非常难看,dnspy、ILspy都不行,因为使用了NativeAOT编译

NativeAOT 是 dotnet 新增加的运行模式,自.NET7之后便开始支持。其中,AOT是 Ahead-Of-Time 的缩写,和 JIT 边运行边编译不同,NativeAOT 直接将 IL 代码编译为目标平台的机器码发布,它的文件大小、启动时间和内存占用均比 JIT 低。但与之相对的是,逆向难度也要比以前更加高,以往使用DnSpy、ILSpy等工具在这里通通失效。因此,在没有更好的针对性逆向工具诞生之前,IDA仍然是优选。

不过题目提供了pdb文件,可以恢复符号表

尽管如此,符号表依然是依托答辩

搜一下Main,看一下相邻地址的函数

就可疑的函数名查看,最终锁定SenpaiCalc_Program__Senpai函数

还是一坨,不过只关注if判断部分,只是将高低四位交换

密文在SenpaiCalc__PrivateImplementationDetails____278942435594DEEBEFE7E3ACD891A0F13784E54403702D22BEF1387DEB336845

脚本就很简单了

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
    char enc[] = { 0xE4, 0x35, 0x35, 0x34, 0x45, 0x64, 0xB7, 0x63, 0x37, 0xE6,
                  0x76, 0x93, 0x56, 0x96, 0x93, 0xB6, 0x93, 0x93, 0x03, 0x93,
                  0xE6, 0x33, 0x36, 0x17, 0x53, 0xE6, 0x23, 0x27, 0x37, 0xC6,
                  0x76, 0x97, 0x23, 0x33, 0x86, 0x87, 0xB6, 0x63, 0xC6, 0xF6,
                  0x33, 0x86, 0x56, 0xC6, 0x23, 0x03, 0xD6, 0x86, 0xC6, 0x96,
                  0x67, 0x33, 0xE6, 0x07, 0x96, 0x47, 0x23, 0x57, 0x83, 0x97,
                  0x26, 0xB6, 0x43, 0xD7 };
    char flag[65];
    int i;
    for (i = 0; i < 64; i++)
    {
        flag[i] = (((enc[i] & 0b1111) << 4) | ((enc[i] & 0b11110000) >> 4));
    }
    printf("%s", flag);
}
//NSSCTF{6sng9ei9k9909n3cq5n2rslgy23hxk6lo3hel20mhliv3npit2u8ybk4}

4. 炒鸡常见的编码哇

主逻辑如图,类似魔改base64

类似rc4初始化的函数,实际上只是打乱了bin内容

然后用爆破逆向

#swbase wp
enc = [0xE2, 0xF7, 0xD3, 0xE2, 0xC8, 0xB4, 0xD8, 0xC5, 0xCF, 0xB4, 
       0xE7, 0xEE, 0xE1, 0xD9, 0xF1, 0xEF, 0xCB, 0xEB, 0xD9, 0xC9, 
       0xCE, 0xC5, 0xD9, 0xE5, 0xCC, 0xB7, 0xD1, 0xED, 0xE0, 0xB4, 
       0xF1, 0xEE, 0xE0, 0xE7, 0xD2, 0xF6, 0xCB, 0xF3, 0xC9, 0xF3, 
       0xD3, 0xD5, 0xEF]
map = [0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 
       0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 
       0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xE0, 0xE1, 0xE2, 0xE3, 
       0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 
       0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 
       0xF8, 0xF9, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 
       0xB7, 0xB8, 0xAA, 0xAE]

v1 = []
for i in enc:
    v1.append(map.index(i)) #计算索引
print("v1:",v1)

bins = []
for i in v1:
    bins.append(bin(i)[2:].zfill(6)) #十进制转二进制,去掉开头的0b,补齐到6位
print("bins:",bins)

res = ""
for i in bins:
    for j in range(0b111111):
        tem = list(bin(j)[2:].zfill(6))
        v3 = 0
        v4 = 0
        for k in range(0,256,2):
            v3 = (k + 1)%256
            v4 = (v3 + v4 + 1) % 256
            tem[v3 % 6],tem[v4 % 6] = tem[v4 % 6],tem[v3 % 6]
        d = "".join(tem)
        if d == i:
            res += bin(j)[2:].zfill(6)
            break
print("res:",res)
#爆破求打乱前的二进制数组

binflag = [res[i:i+8] for i in range(0, len(res), 8)]
print("binflag:",binflag)
flag = ''
for i in binflag:
    flag += chr(int(i,2))
print("flag:",flag)
'''
v1: [28, 49, 19, 28, 8, 57, 24, 5, 15, 57, 33, 40, 27, 25, 43, 41, 11, 37, 25, 9, 14, 5, 25, 31, 12, 60, 17, 39, 26, 57, 43, 40, 26, 33, 18, 48, 11, 45, 9, 45, 19, 21, 41]
bins: ['011100', '110001', '010011', '011100', '001000', '111001', '011000', '000101', '001111', '111001', '100001', '101000', '011011', '011001', '101011', '101001', '001011', '100101', '011001', '001001', '001110', '000101', '011001', '011111', '001100', '111100', '010001', '100111', '011010', '111001', '101011', '101000', '011010', '100001', '010010', '110000', '001011', '101101', '001001', '101101', '010011', '010101', '101001']
res: 010011100101001101010011010000110101010001000110011110110101100100110000011101010101111100110100011100100110010101010100011010000110010101011111010010110011000101101110011001110101111100110000011001100100001001100001011100110110010100110110001101000111110100
binflag: ['01001110', '01010011', '01010011', '01000011', '01010100', '01000110', '01111011', '01011001', '00110000', '01110101', '01011111', '00110100', '01110010', '01100101', '01010100', '01101000', '01100101', '01011111', '01001011', '00110001', '01101110', '01100111', '01011111', '00110000', '01100110', '01000010', '01100001', '01110011', '01100101', '00110110', '00110100', '01111101', '00']
flag: NSSCTF{Y0u_4reThe_K1ng_0fBase64}
'''

5. EzADVM

主逻辑在libezadvm.so里,需要解压apk

用IDA分析,是vm,但是并没有模拟到汇编层面

提出opcode打印指令,大部分是循环

opcode = [0x01, 0x01, 0x21, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x53, 
  0x57, 0x44, 0x61, 0x44, 0x64, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 
  0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 
  0xE5, 0xD4, 0xA1, 0x53, 0x57, 0x44, 0x61, 0x44, 0x64, 0xF1, 
  0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 
  0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 
  0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x53, 
  0x57, 0x44, 0x61, 0x44, 0x64, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 
  0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 
  0xE5, 0xD4, 0xA1, 0x53, 0x57, 0x44, 0x61, 0x44, 0x64, 0xF1, 
  0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 
  0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x66, 0x6C, 0x61, 
  0x67, 0x7B, 0x59, 0x75, 0x69, 0x73, 0x61, 0x62, 0x65, 0x61, 
  0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x67, 0x69, 0x72, 0x6C, 
  0x7D, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 
  0xE5, 0xD4, 0xA1, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x59, 0x75, 
  0x69, 0x73, 0x61, 0x62, 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 
  0x75, 0x6C, 0x67, 0x69, 0x72, 0x6C, 0x7D, 0xF1, 0xC3, 0xB2, 
  0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x66, 
  0x6C, 0x61, 0x67, 0x7B, 0x59, 0x75, 0x69, 0x73, 0x61, 0x62, 
  0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x67, 0x69, 
  0x72, 0x6C, 0x7D, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 
  0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x53, 0x57, 0x44, 0x61, 0x44, 
  0x64, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x59, 0x75, 0x69, 0x73, 
  0x61, 0x62, 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 
  0x67, 0x69, 0x72, 0x6C, 0x7D, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 
  0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 
  0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x53, 
  0x57, 0x44, 0x61, 0x44, 0x64, 0x66, 0x6C, 0x61, 0x67, 0x7B, 
  0x59, 0x75, 0x69, 0x73, 0x61, 0x62, 0x65, 0x61, 0x75, 0x74, 
  0x69, 0x66, 0x75, 0x6C, 0x67, 0x69, 0x72, 0x6C, 0x7D, 0xF1, 
  0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x66, 0x6C, 0x61, 0x67, 0x7B, 
  0x59, 0x75, 0x69, 0x73, 0x61, 0x62, 0x65, 0x61, 0x75, 0x74, 
  0x69, 0x66, 0x75, 0x6C, 0x67, 0x69, 0x72, 0x6C, 0x7D, 0xF1, 
  0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 
  0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 
  0xE5, 0xD4, 0xA1, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 0xA1, 0x53, 
  0x57, 0x44, 0x61, 0x44, 0x64, 0xF1, 0xC3, 0xB2, 0xE5, 0xD4, 
  0xA1, 0x99, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 
  0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 
  0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 
  0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 
  0xBF, 0xBB, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x59, 0x75, 0x69, 
  0x73, 0x61, 0x62, 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 
  0x6C, 0x67, 0x69, 0x72, 0x6C, 0x7D, 0xBF, 0xBB, 0xBF, 0xBB, 
  0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 
  0xBF, 0xBB, 0xBF, 0xBB, 0xBF, 0xBB, 0x53, 0x57, 0x44, 0x44, 
  0xBF, 0xBB, 0xBF, 0xBB, 0x99, 0x53, 0x57, 0x44, 0x44, 0x53, 
  0x57, 0x44, 0x44, 0x88, 0xFF, 0x53, 0x57, 0x44, 0x44]

for i in opcode:
    match i:
        case 0xA1:
            print("enc[i - 1] = v25 & v22")
        case 0xC3:
            print("v22 = v17 | v18")
        case 0xB2:
            print("v23 = ~v17")
        case 0xE5:
            print("v24 = ~v18")
        case 0xF1:
            print("v17 = input[i]")
            print("v18 = input[++i]")
        case 0xD4:
            print("v25 = v24 | v23")
        case 0xBF:
            print("v6 = i++")
            print("v21[0] = enc[v6]")
        case 0x99:
            print("i = 0")
        case 0xBB:
            print("enc[i - 1] = i + v21[0] - 1")
'''
v17 = input[i]
v18 = input[++i]
v22 = v17 | v18
v23 = ~v17
v24 = ~v18
v25 = v24 | v23
enc[i - 1] = v25 & v22    
#((~input[i])|(~input[i+1]))&((input[i])|(input[i+1])) 相当于input[i]^input[i+1]
…………
i = 0
v6 = i++
v21[0] = enc[v6]
enc[i - 1] = i + v21[0] - 1       #enc[i - 1] = i + enc[i] - 1
…………
i = 0
'''

主要逻辑就是一个 ((~input[i])|(~input[i+1]))&((input[i])|(input[i+1])) 相当于input[i]^input[i+1]以及 +i的操作

enc = [  0x1D, 0x01, 0x12, 0x1A, 0x16, 0x42, 0x39, 0x0F, 0x38, 0x09, 
  0x13, 0x31, 0x28, 0x38, 0x67, 0x6E, 0x1B, 0x61, 0x7C, 0x24, 
  0x1F, 0x47, 0x44, 0x81, 0x6A, 0x2C, 0x6D, 0x2B, 0x2C, 0x2D, 
  0x6A, 0x9C]
for i in range(32):
    enc[i] -= i
print(enc)
for i in range(30,-1,-1):
    enc[i] ^= enc[i + 1]
print(enc)
flag = ''
for i in enc:
    flag += chr(i)
print(flag)
#NSSCTF{H@ppy_Ch1ne5_NEwY3ar!1!1}

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-16 15:58:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-16 15:58:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-02-16 15:58:01       87 阅读
  4. Python语言-面向对象

    2024-02-16 15:58:01       96 阅读

热门阅读

  1. 算法训练营day27(补),贪心算法1

    2024-02-16 15:58:01       48 阅读
  2. 记录 | ubuntu pyqt5 pycharm配置

    2024-02-16 15:58:01       66 阅读
  3. makefile使用

    2024-02-16 15:58:01       46 阅读