比赛信息
题目详解
拿到题目之后,从题目名字中的”asm”可以看出,这是一道考察
![图片[1],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第1页-1-1.png)
那么接下来就是 找到右上方的(x)用小手点击一下鼠标左键 哐哐一顿分析啦,详细的分解步骤就不多说了,这里涉及到汇编语言的知识,我简单解释一下它的逻辑:
这段汇编代码的功能是对一个字符串(flag)进行加密处理,然后输出加密后的结果。具体的操作步骤如下:
- 首先,定义一个变量var_4,用来存储字符串的索引,初始值为0。
- 然后,进入一个循环,对字符串的每个字符进行两次异或和减法操作,具体如下:
- 将var_4作为偏移量,从flag中取出一个字符,与16进制数0x1E异或,得到新的字符。
- 将新的字符存回flag中覆盖原来的字符。
- 再次从flag中取出同一个字符,减去16进制数0x0A,得到最终的加密字符。
- 将最终的加密字符存回flag中覆盖原来的字符。
- 将var_4加一,准备处理下一个字符。
- 循环结束的条件是var_4等于16进制数0x27,也就是字符串的长度。
- 最后,调用printf函数,输出加密后的字符串。
下面是我们对这段ASM加密算法翻译后的代码:
#include<string>#include<iostream>using namespace std;string encrypt(string s) {string result = "";for (char c : s) {unsigned int x = (unsigned int)c;x ^= 0x1E;x -= 0x0A;result += (char)x;}return result;}int main() {string flag = "";string crypt_str = encrypt(flag);cout << crypt_str << endl;return 0;}#include<string> #include<iostream> using namespace std; string encrypt(string s) { string result = ""; for (char c : s) { unsigned int x = (unsigned int)c; x ^= 0x1E; x -= 0x0A; result += (char)x; } return result; } int main() { string flag = ""; string crypt_str = encrypt(flag); cout << crypt_str << endl; return 0; }#include<string> #include<iostream> using namespace std; string encrypt(string s) { string result = ""; for (char c : s) { unsigned int x = (unsigned int)c; x ^= 0x1E; x -= 0x0A; result += (char)x; } return result; } int main() { string flag = ""; string crypt_str = encrypt(flag); cout << crypt_str << endl; return 0; }
那么知道了加密的原理,下面就是解密啦,我们只需要把这段加密过程逆过来运算即可:
- 逐一遍历flag的每一个字符,对每一个字符进行逆运算操作。
- 将每一个字符都加上16进制数0x0A
- 再将每一个字符都与16进制数0x1E进行异或操作
- 最后逐一储存在result中并返回原始字符串
代码如下:
#include<string>#include<iostream>using namespace std;string decrypt(string s) {string result = "";for (char c : s) {unsigned int x = (unsigned int)c;x += 0x0A;x ^= 0x1E;result += (char)x;}return result;}int main() {string flag = "";string crypt_str = decrypt(flag);cout << crypt_str << endl;return 0;}#include<string> #include<iostream> using namespace std; string decrypt(string s) { string result = ""; for (char c : s) { unsigned int x = (unsigned int)c; x += 0x0A; x ^= 0x1E; result += (char)x; } return result; } int main() { string flag = ""; string crypt_str = decrypt(flag); cout << crypt_str << endl; return 0; }#include<string> #include<iostream> using namespace std; string decrypt(string s) { string result = ""; for (char c : s) { unsigned int x = (unsigned int)c; x += 0x0A; x ^= 0x1E; result += (char)x; } return result; } int main() { string flag = ""; string crypt_str = decrypt(flag); cout << crypt_str << endl; return 0; }
我们将题目提供的加密后的字符串:nhuo[M
将题目下载下来,发现这是一个可执行程序,那么我们要做的第一步就是查壳,确定程序的PE类型:(查壳图片略),查壳过后我们发现这是一个x64可执行程序,打开之后我们会发现他是直接让我们输入flag的:
![图片[2],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第2页-6-2.png)
那根据我们的直觉或者经验,可以看出,他肯定有一套验证flag是否正确的算法,我们直接拖进IDA看看之后发现,所有的验证代码全都在Main函数里,而且没有任何混淆:
![图片[3],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第2页-5-2.png)
从伪代码的这一部分分析可以知道,处理过后的字符串通过与
![图片[4],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第2页-8-2.png)
我们直接从HEX进制窗口中复制这一段字节:
66 C6 16 76 B7 45 27 97 F5 47 03 F5 37 03 C6 67 33 F5 47 86 56 F5 26 96 E6 16 27 97 F5 07 27 03 26 C6 33 D6 D7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
代码段Str[i] = (Str[i] >> 4) | (16 * Str[i]);其实是位操作中的典型算法:位交换,即把每一个字节的高低位互换位置,那么如果我们想要得到原始数据,就需要把des的高低位互换回去,我们只需要重新调用一次这个算法即可,代码以及运行结果如下:
#include<string>#include<iostream>#include<stdio.h>#include<windows.h>using namespace std;int main() {BYTE des[64] = {0x66, 0xC6 ,0x16 ,0x76 ,0xB7 ,0x45 ,0x27 ,0x97 ,0xF5 ,0x47 ,0x03 ,0xF5 ,0x37 ,0x03 ,0xC6 ,0x67 ,0x33 ,0xF5 ,0x47 ,0x86 ,0x56 ,0xF5 ,0x26 ,0x96 ,0xE6 ,0x16 ,0x27 ,0x97 ,0xF5 ,0x07 ,0x27 ,0x03 ,0x26 ,0xC6 ,0x33 ,0xD6 ,0xD7 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00};for (auto i = 0; i < 64; ++i) {des[i] = (des[i] >> 4) | (16 * des[i]);printf("%X ", des[i]);}return 0;}#include<string> #include<iostream> #include<stdio.h> #include<windows.h> using namespace std; int main() { BYTE des[64] = { 0x66, 0xC6 ,0x16 ,0x76 ,0xB7 ,0x45 ,0x27 ,0x97 , 0xF5 ,0x47 ,0x03 ,0xF5 ,0x37 ,0x03 ,0xC6 ,0x67 , 0x33 ,0xF5 ,0x47 ,0x86 ,0x56 ,0xF5 ,0x26 ,0x96 , 0xE6 ,0x16 ,0x27 ,0x97 ,0xF5 ,0x07 ,0x27 ,0x03 , 0x26 ,0xC6 ,0x33 ,0xD6 ,0xD7 ,0x00 ,0x00 ,0x00 , 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 , 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 , 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 }; for (auto i = 0; i < 64; ++i) { des[i] = (des[i] >> 4) | (16 * des[i]); printf("%X ", des[i]); } return 0; }#include<string> #include<iostream> #include<stdio.h> #include<windows.h> using namespace std; int main() { BYTE des[64] = { 0x66, 0xC6 ,0x16 ,0x76 ,0xB7 ,0x45 ,0x27 ,0x97 , 0xF5 ,0x47 ,0x03 ,0xF5 ,0x37 ,0x03 ,0xC6 ,0x67 , 0x33 ,0xF5 ,0x47 ,0x86 ,0x56 ,0xF5 ,0x26 ,0x96 , 0xE6 ,0x16 ,0x27 ,0x97 ,0xF5 ,0x07 ,0x27 ,0x03 , 0x26 ,0xC6 ,0x33 ,0xD6 ,0xD7 ,0x00 ,0x00 ,0x00 , 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 , 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 , 0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 }; for (auto i = 0; i < 64; ++i) { des[i] = (des[i] >> 4) | (16 * des[i]); printf("%X ", des[i]); } return 0; }
![图片[5],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第3页-14-2.png)
将右图字节集转换为字符串即为flag:
下载题目,发现是一个可执行程序,查壳发现是一个64位的可执行程序,运行,啥玩意都没有,我们直接拖进IDA查看Main函数,好了,flag就在眼前:flag{flag1sinarray}
![图片[6],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第4页-18-2.png)
下载题目,发现是一个可执行程序,查壳发现是一个64位的可执行程序,运行,直接让我们输入falg,我们直接拖进IDA查看Main函数,可以看到这里与[WEEK1]easy_re是大同小异的,都是异或操作之后与内存中的一串字节des对比,我们直接逆运算即可得出来原本的输入数据,要注意这里是与取随机数之后的v5数组进行异或,我们要先模拟v5,再进行异或。
![图片[7],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第4页-19-2.png)
解密代码以及运行结果如下:
#include<string>#include<iostream>#include<stdio.h>#include<windows.h>using namespace std;int main() {DWORD des[48] = {0x00000040 ,0x00000029 ,0x00000028 ,0x000000E9 ,0x000000C2 ,0x00000004 ,0x000000A4 ,0x000000ED ,0x0000009F ,0x00000053 ,0x0000005F ,0x00000075 ,0x0000003C ,0x000000D1 ,0x000000CD ,0x0000002B ,0x000000A8 ,0x000000C4 ,0x00000089 ,0x00000069 ,0x00000015 ,0x00000021 ,0x00000016 ,0x000000EF ,0x000000D7 ,0x00000027 ,0x00000092 ,0x000000DF ,0x000000CA ,0x00000053 ,0x0000005F ,0x0000002A ,0x0000003C ,0x000000D1 ,0x000000CE ,0x00000003 ,0x000000A3 ,0x000000EF ,0x000000A5 ,0x00000078 ,0x00000016 ,0x0000001A ,0x0000002D ,0x000000E1 ,0x000000C4 ,0x00000000 ,0x00000000 ,0x00000000};BYTE v5[10];srand(0);for (auto i = 0; i <= 9; ++i){v5[i] = rand() % 255;}for (size_t i = 0; i <= 44; i++){auto v1 = des[i] ^ v5[i % 10];printf("%X ", v1);}return 0;}#include<string> #include<iostream> #include<stdio.h> #include<windows.h> using namespace std; int main() { DWORD des[48] = { 0x00000040 ,0x00000029 ,0x00000028 ,0x000000E9 ,0x000000C2 ,0x00000004 ,0x000000A4 ,0x000000ED , 0x0000009F ,0x00000053 ,0x0000005F ,0x00000075 ,0x0000003C ,0x000000D1 ,0x000000CD ,0x0000002B , 0x000000A8 ,0x000000C4 ,0x00000089 ,0x00000069 ,0x00000015 ,0x00000021 ,0x00000016 ,0x000000EF , 0x000000D7 ,0x00000027 ,0x00000092 ,0x000000DF ,0x000000CA ,0x00000053 ,0x0000005F ,0x0000002A , 0x0000003C ,0x000000D1 ,0x000000CE ,0x00000003 ,0x000000A3 ,0x000000EF ,0x000000A5 ,0x00000078 , 0x00000016 ,0x0000001A ,0x0000002D ,0x000000E1 ,0x000000C4 ,0x00000000 ,0x00000000 ,0x00000000 }; BYTE v5[10]; srand(0); for (auto i = 0; i <= 9; ++i) { v5[i] = rand() % 255; } for (size_t i = 0; i <= 44; i++) { auto v1 = des[i] ^ v5[i % 10]; printf("%X ", v1); } return 0; }#include<string> #include<iostream> #include<stdio.h> #include<windows.h> using namespace std; int main() { DWORD des[48] = { 0x00000040 ,0x00000029 ,0x00000028 ,0x000000E9 ,0x000000C2 ,0x00000004 ,0x000000A4 ,0x000000ED , 0x0000009F ,0x00000053 ,0x0000005F ,0x00000075 ,0x0000003C ,0x000000D1 ,0x000000CD ,0x0000002B , 0x000000A8 ,0x000000C4 ,0x00000089 ,0x00000069 ,0x00000015 ,0x00000021 ,0x00000016 ,0x000000EF , 0x000000D7 ,0x00000027 ,0x00000092 ,0x000000DF ,0x000000CA ,0x00000053 ,0x0000005F ,0x0000002A , 0x0000003C ,0x000000D1 ,0x000000CE ,0x00000003 ,0x000000A3 ,0x000000EF ,0x000000A5 ,0x00000078 , 0x00000016 ,0x0000001A ,0x0000002D ,0x000000E1 ,0x000000C4 ,0x00000000 ,0x00000000 ,0x00000000 }; BYTE v5[10]; srand(0); for (auto i = 0; i <= 9; ++i) { v5[i] = rand() % 255; } for (size_t i = 0; i <= 44; i++) { auto v1 = des[i] ^ v5[i % 10]; printf("%X ", v1); } return 0; }
![图片[8],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第4页-17-1.png)
执行代码,并输出数据即可得到flag的字节集,转换为字符串即可得到flag:
下载题目,发现是一个py文件,里面是关于对flag进行加密的算法,分析一下算法可知:
- 要求输入flag,并且程序会检查输入的字符串是否是42个字符长。如果不是,程序将打印出”Check your length!”并且退出程序。
- 如果输入的字符串长度符合要求,程序将进入一个循环。在这个循环中,输入的字符串被分成6个部分,每个部分包含7个字符。然后将每个部分中的字符转换成对应的ASCII码,再转换成16进制的形式。这些16进制数值会被存储在列表l中。
- 接下来的部分是一系列的条件判断。程序会检查列表l中的值是否满足一组复杂的方程式,其中每个方程式的右边都是一个十六进制数。如果所有的条件都满足,程序会打印”Good job!”,否则打印”Wrong\nTry again!!!”并退出程序。
题目源代码如下:
print("Please input flag:")flag = input()if len(flag)!=42:print("Check your length!")exit()l=[]for i in range(6):s=""for j in flag[i*7:i*7+7]:s+=hex(ord(j))[2:]l.append(int(s,16))if ((593*l[0] + 997*l[1] + 811*l[2] + 258*l[3] + 829*l[4] + 532*l[5])== 0x5b8e0aef71d34ff43 and \(605*l[0] + 686*l[1] + 328*l[2] + 602*l[3] + 695*l[4] + 576*l[5])== 0x551a262360964ef7f and \(373*l[0] + 512*l[1] + 449*l[2] + 756*l[3] + 448*l[4] + 580*l[5])== 0x49d158a5657d6931c and \(560*l[0] + 635*l[1] + 422*l[2] + 971*l[3] + 855*l[4] + 597*l[5])== 0x625568d5abbabf4f3 and \(717*l[0] + 507*l[1] + 388*l[2] + 925*l[3] + 324*l[4] + 524*l[5])== 0x50ee0c025e70e3c23 and \(312*l[0] + 368*l[1] + 884*l[2] + 518*l[3] + 495*l[4] + 414*l[5])== 0x40e735f8aa2815f65):print("Good job!")else:print("Wrong\nTry again!!!")exit()print("Please input flag:") flag = input() if len(flag)!=42: print("Check your length!") exit() l=[] for i in range(6): s="" for j in flag[i*7:i*7+7]: s+=hex(ord(j))[2:] l.append(int(s,16)) if ( (593*l[0] + 997*l[1] + 811*l[2] + 258*l[3] + 829*l[4] + 532*l[5])== 0x5b8e0aef71d34ff43 and \ (605*l[0] + 686*l[1] + 328*l[2] + 602*l[3] + 695*l[4] + 576*l[5])== 0x551a262360964ef7f and \ (373*l[0] + 512*l[1] + 449*l[2] + 756*l[3] + 448*l[4] + 580*l[5])== 0x49d158a5657d6931c and \ (560*l[0] + 635*l[1] + 422*l[2] + 971*l[3] + 855*l[4] + 597*l[5])== 0x625568d5abbabf4f3 and \ (717*l[0] + 507*l[1] + 388*l[2] + 925*l[3] + 324*l[4] + 524*l[5])== 0x50ee0c025e70e3c23 and \ (312*l[0] + 368*l[1] + 884*l[2] + 518*l[3] + 495*l[4] + 414*l[5])== 0x40e735f8aa2815f65): print("Good job!") else: print("Wrong\nTry again!!!") exit()print("Please input flag:") flag = input() if len(flag)!=42: print("Check your length!") exit() l=[] for i in range(6): s="" for j in flag[i*7:i*7+7]: s+=hex(ord(j))[2:] l.append(int(s,16)) if ( (593*l[0] + 997*l[1] + 811*l[2] + 258*l[3] + 829*l[4] + 532*l[5])== 0x5b8e0aef71d34ff43 and \ (605*l[0] + 686*l[1] + 328*l[2] + 602*l[3] + 695*l[4] + 576*l[5])== 0x551a262360964ef7f and \ (373*l[0] + 512*l[1] + 449*l[2] + 756*l[3] + 448*l[4] + 580*l[5])== 0x49d158a5657d6931c and \ (560*l[0] + 635*l[1] + 422*l[2] + 971*l[3] + 855*l[4] + 597*l[5])== 0x625568d5abbabf4f3 and \ (717*l[0] + 507*l[1] + 388*l[2] + 925*l[3] + 324*l[4] + 524*l[5])== 0x50ee0c025e70e3c23 and \ (312*l[0] + 368*l[1] + 884*l[2] + 518*l[3] + 495*l[4] + 414*l[5])== 0x40e735f8aa2815f65): print("Good job!") else: print("Wrong\nTry again!!!") exit()
其实到了这一步,看到了解方程这里,这道题目就很简单了,我们直接调用python的sympy库对方程进行求解,即可得到原始flag的数据,下面是简单的python代码:
![图片[9],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第5页-22-1.png)
运行后即可得到原始的flag字符串,即为:
![图片[10],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第5页-21.png)
下载题目,发现是一个可执行程序,查壳发现是一个32位的可执行程序,运行,随便输入一个密钥,会输出给我们一份加密后的字符串,我们直接拖进IDA查看Main函数:
![图片[11],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第3页-13-2.png)
进入IDA后,我们发现,程序开始对ArgList已经赋值了,紧接着又对其部分位置的字符进行了修改,此处的代码编译器进行了优化,我们很难看出来他的执行逻辑,那么我们可以另辟蹊径,通过动态调试来拿到修改后的ArgList的数值,此处动态调试的过程不再展示。
紧接着他又利用我们输入的那个密钥对ArgList进行了进一步的加密,然后输出了加密后的字符串。此处出题人其实是在迷惑我们,其实第一次处理后的ArgList就是用Base64编码后的字符串,我们直接动态调试出第一次处理后ArgList的字节集,然后用伪代码中出题人给的异或算法输出Base64编码后的字节集,将输出的字节集转换为字符串,并将字符串用Base64解码即可得到flag:
下面是解密代码以及运行结果:
![图片[12],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第3页-12-1.png)
![图片[13],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第3页-11-1.png)
拿到题目我们可以发现是.bc文件,经过搜索我们可以知道,bc文件为LLVM IR bitcode文件,所谓LLVM IR bitcode文件 ,就是代码到可执行文件的中间码。我们可以使用命令将其继续编译下去 ,生成可执行文件。
在linux下 ,我们使用命令clang not_gcc.bc -o not_gcc(这里文件需要改名 ,题目文件有空格 ,将其改为_)
![图片[14],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第1页-1-2.png)
生成可执行文件,我们放入ida中进行分析:
![图片[15],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第2页-5-3.png)
各种跳转 ,有点花 ,不好厘清逻辑,动态调试 ,厘清一下思路:
先判断字符长度 ,81位:
![图片[16],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第2页-4.png)
判断第一个输入的字符是否为0:
![图片[17],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第3页-8.png)
判断输入 ,输入字符的都必须满足1~9:
![图片[18],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第3页-7.png)
进入关键逻辑,进入函数内部 ,分析逻辑可以知道 ,是生成了9*9的数独盘 ,以0为标志 ,作为未填充:
![图片[19],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第3页-6.png)
![图片[20],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第4页-9-1.png)
因此需要我们写脚本将数独解出:
![图片[21],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/QQ截图20231030004711.png)
![图片[22],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/QQ截图20231030004750.png)
我们可以解出数独为:497513268538426917612987354759164823261839475843275196986351742125748639374692581
这个就是我们的解出来的数独,但是由于程序有第⼀位检测,所以我们需要将第⼀位的4改为0
因此:097513268538426917612987354759164823261839475843275196986351742125748639374692581
就是我们最终的数独,我们将其输入到脚本中可得到:
![图片[23],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第5页-10.png)
将flag按照出题人要求的,将数独取MD5哈希值,即为flag。
但此处解出来flag之后,出题人并未指明flag的具体格式,在比赛中途我没有再去尝试这一题。
下载题目,发现是一个可执行文件,打开之后需要我们输入Key,Key的范围是0-100,我直接用爆破的方式了,解出来key是23,输入之后,下面让我们输入flag,我们将其拖入DIE查看,会发现他的Packer是PyInstaller,从这里可以判断这个是用Py打包的方式生成的可执行文件:
![图片[24],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第6页-26.png)
那么我们直接调用
![图片[25],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第6页-25.png)
![图片[26],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第6页-24-1.png)
反汇编出来python源代码之后,我们要注意的是:我们需要配置与他的源代码一致的python环境,从反汇编的信息上来看,这个脚本是python3.8的版本,我们配置完环境之后直接调试这段代码即可,我们在图中指向的地方下断点,这里的主要目的是为了拿到他处理后的执行代码,flag的字节就在里面。
![图片[27],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第7页-30-1.png)
断下来之后,我们查看输出窗口,找到
![图片[28],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第7页-29.png)
![图片[29],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第7页-28.png)
运行以上代码,即可得到flag:
![图片[30],[SHCTF]新生赛 – 部分Reverse题目解析,网络安全爱好者中心-神域博客网](https://godyu.com/wp-content/uploads/2023/10/第7页-27.png)
尾言
以上解析部分代码不能提供文本,主要原因在于我自己,因为写每一题的时候,都直接把上一题的代码覆盖掉了,然后昨天手贱把这次CTF的所有代码都删了,真无语。
暂无评论内容