BUUCTF逆向工程-2
相册
打开后可以找到发送邮件的函数原型:
根据交叉引用找到调用它的地方:
可以知道C2.MAILSERVER应当为邮箱,根据交叉引用可以找到:
这个函数加载了一个core文件,然后调用里面的NativeMethod.m()函数,查看它的Library:
有一个libcore.so文件,将它用IDA打开,在java_com_net_cn_NativeMethod_m()函数中可以看见:
查看base64方法中的shared可以拿到加密表:
解密得到flag:18218465125@163.com
[MRCTF2020]hello_world_go
代码写得根本看不懂在干什么,但是瞎点一通发现unk_4D3C58里就是flag:hello_world_gogogo
从结果来看应该是一个go语言,无语。。。
[WUSTCTF2020]level3
打开看见它想让我破译一个base64:
点进加密函数可以跟踪到密码表:
用这个密码表解码发现解出来是乱码…想到密码表可能被修改过,查看它的交叉引用:
写个简单的脚本得到flag:Base64_is_the_start_of_reverse
[GWCTF 2019]xxor
打开看见:
前面一段对输入进行TEA,之后判断结果,解码脚本在此:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <stdio.h> #include <stdint.h> void decrypt (int *v, int *k) { unsigned int v0 = v[0 ], v1 = v[1 ], i; int delta = 1166789954 ; int sum = 0 ; for (i = 0 ; i < 64 ; i++) { sum += delta; } for (i = 0 ; i < 64 ; i++) { v1 -= (v0 + sum + 20 ) ^ ((v0 << 6 ) + k[2 ]) ^ ((v0 >> 9 ) + k[3 ]) ^ 0x10 ; v0 -= (v1 + sum + 11 ) ^ ((v1 << 6 ) + k[0 ]) ^ ((v1 >> 9 ) + k[1 ]) ^ 0x20 ; sum -= delta; } v[0 ] = v0; v[1 ] = v1; return ; } int main () { int v[2 ] = {}, k[4 ] = {2 ,2 ,3 ,4 }; unsigned int a1[6 ] = {-548868226 , 550153460 , 3774025685 , 1548802262 , 2652626477 , -2064448480 }; int i, j; for (i = 0 ; i <= 2 ; i++) { v[0 ] = a1[i*2 ]; v[1 ] = a1[i*2 +1 ]; decrypt (v, k); a1[i*2 ] = v[0 ]; a1[i*2 +1 ] = v[1 ]; } for (i = 0 ; i <= 5 ; i++) { for (j = 2 ; j >= 0 ; j--) { printf ("%c" , *((char *)&a1[i] + j)); } } return 0 ; }
得到flag:re_is_great!
说实话,写完这题我仍然不是很理解HIDWORD、LODWORD和ELF的逆序存储,全靠IDA动调测算出数据的存储方式,然后进行逆推,再根据输出调整顺序。。。
虽说篇幅不长,但是这个b干了我将近4个小时
[FlareOn4]IgniteMe
打开IDA,果然,C++写出来的程序最恶心了(虽然我喜欢用C++):
sub_4010F0是输入函数,sub_401050是加密函数:
其中sub401000函数里面是一个__ROL4__函数,百度了半天我也没看明白,但是IDA动调之后可以看见最后v4=4,所以也可以写出脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <iostream> using namespace std;int main () { int ans[99 ] = {13 , 38 , 73 , 69 , 42 , 23 , 120 , 68 , 43 , 108 , 93 , 94 , 69 , 18 , 47 , 23 , 43 , 68 , 111 , 110 , 86 , 9 , 95 , 69 , 71 , 115 , 38 , 10 , 13 , 19 , 23 , 72 , 66 , 1 , 64 , 77 , 12 , 2 , 105 }; int flag[99 ]; int i; int v4 = 4 ; for (i = 38 ; i >= 0 ; i--) { flag[i] = v4 ^ ans[i]; v4 = flag[i]; } for (i = 0 ; i <= 38 ; i++) { cout << char (flag[i]); } return 0 ; }
得出flag:R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com
[WUSTCTF2020]Cr0ssfun
没啥技术含量
flag:cpp_@nd_r3verse_@re_fun
[FlareOn6]Overlong
IDA中代码很短,理论上运行一遍就有答案:
其中unk_402008是给定的175空间的数组,但是sub_401160中对于次数组的调用最多只有28*4=112空间,因此推测所传参数28太小,所以拖入x32dbg修改对应二进制值1C为AE:
之后运行起来,即可得到结果:
得到flag:I_a_M_t_h_e_e_n_C_o_D_i_n_g@flare-on.com
[UTCTF2020]basic-re
shift+F12:
得到flag:str1ngs_1s_y0ur_fr13nd
[FlareOn3]Challenge1
简单的变表base64,得到flag:sh00ting_phish_in_a_barrel@flare-on.com
[ACTF新生赛2020]Oruga
这是一道比较抽象的迷宫题:
由这个可以推出地图是一个16*16的空间,长这个样子:
看一看它的校验部分:
它的v2在校验中就进行了更改,而下一次循环又不会对v2进行回溯,因此它走迷宫的路线会变成直来直去的样子。一直向某个方向走到底直到遇见非空的格子,同时还不能越界,因此路线为:
得到flag:MEWEMEWJMEWJM
[BJDCTF2020]BJD hamburger competition
下载之后非常懵逼,是一个Unity的游戏,打开Visual Studio发现Unity的游戏使用C#写的,所以我们要在它给的一大坨东西里面找一个C#写的dll文件。发现在BJD hamburger competition_Data\Managed下有一个Assembly-CSharp.dll,使用dnSpy打开它,找到加密部分:
跟踪Md5(),发现它截取了答案的前20位:
写出脚本:
1 2 3 4 5 6 7 import hashlibstr = "DD01903921EA24941C26A48F2CEC24E0BB0E8CC7" for i in range (10000000000000 ): if hashlib.sha1(i.__str__().encode()).hexdigest().upper() == str : break print ('flag{' + hashlib.md5(i.__str__().encode()).hexdigest().upper()[0 :20 ] + '}' )
得到flag:B8C37E33DEFDE51CF91E
特殊的 BASE64
简单的变表base64,不得不说,C++的逆向代码看起来确实恶心
得到flag:Special_Base64_By_Lich
[Zer0pts2020]easy strcmp
主函数内只有这些,提交发现这不是正确答案:
返回去看看init函数有没有进行一些什么操作:
发现它其实调用了一些函数,只不过是通过直接访问地址的形式调用的,双击funcs_889可以看到:
它调用了两个函数sub_6E0和函数sub_795,其中第一个没什么卵用,跟进第二个:
发现这个函数很神奇,将strcmp函数的地址传给了qword_201090,将sub_6EA函数的地址传给了off_201028,双击sub_6EA查看:
发现sub_6EA对参数做了一通操作,然后返回地址在qword_201090的函数的值,而这个函数恰好就是刚赋完值的strcmp函数。在sub_795函数里将sub_6EA函数的地址传给了off_201028,双击off_201028查看:
发现off_201028地址上的函数恰好又是strcmp函数。所以主函数里执行strcmp时其实先执行了sub_6EA函数,再执行strcmp函数,可以写出脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <iostream> using namespace std;int main () { char p[99 ] = "zer0pts{********CENSORED********}" ; long long k[4 ] = {0 , 0x410A4335494A0942 , 0x0B0EF2F50BE619F0 , 0x4F0A3A064A35282B }; for (int i = 0 ; i < 4 ; i++) { *(long long *)&(p[i * 8 ]) += k[i]; } cout << p; }
得到flag:l3ts_m4k3_4_DETOUR_t0d4y
[ACTF新生赛2020]Universe_final_answer
是个简单的z3,此题大多数时间用在了z3的安装和调查使用教程,算出key的值之后用IDA动调一下即可:
得到flag:F0uRTy_7w@_42
[WUSTCTF2020]level4
这是个算法题,给出二叉树的中序遍历和后序遍历,求先序遍历。有一点神奇的是在IDA里静态或者动调的时候都没有找到它存放这些数据的地方…
得到flag:This_IS_A_7reE
crackMe
代码逻辑非常清晰,但是代码很长,很恶心:
先后输入用户名和密码,根据用户名在sub_401090()中创建byte_416050[],在loc_4011A0()中创建Format[]和v4[],跟进loc_4011A0()会有一个花指令,nop掉之后可以得知Format是正确提示且v3恒等于1,因此需要sub_401830()返回true,跟进sub_401830():
第一部分将password当成16进制数两两一组分割,存入v14[]。第二部分用v14[]和byte_416050[]创建v16[],最后再用v16创建v13,进行判断。根据v5<8可以得知v14[]长度为8。在sub_410470()中可以得知v16的值是“dbappsec”。跟进sub_401710():
虽然它判断了一堆情况,但是v4是用户名“welcomebeijing”的长度,v3最大为8,因此它只会执行else if的内容。将sub_401830()中第二部分内的两次反动调在汇编码中将jz改为jmp绕过,动调得到创建v16时的byte_416050[]的值。要注意在汇编码中,程序将byte_416050[v12+v7]的值传给了v12,再用v12进行异或,所以如果只看伪代码手动生成是不对的。写出脚本:、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <iostream> using namespace std;int main () { char ans[99 ] = "dbappsec" ; char name[99 ] = "welcomebeijing" ; int XOR[99 ] = {0x2A , 0xD7 , 0x92 , 0xE9 , 0x53 , 0xE2 , 0xC4 , 0xCD }; int i, j; for (i = 0 ; i < 8 ; i++) { ans[i] ^= name[i]; } for (i = 0 ; i < 8 ; i++) { ans[i] ^= XOR[i]; } for (i = 0 ; i < 8 ; i++) { printf ("%x" , ans[i] & 255 ); } return 0 ; }
得到密码:39d09ffa4cfcc4cc,将程序中所有反动调全部patch掉然后动调检验,或者直接运行程序会看见程序退出证明成功(因为失败会让你继续输入):
将其md5之后提交显示不正确。百度搜索得知“正确”的解答中并没有分析sub_401710(),得到密码4eb5f3992391a1ae,很明显它不正确:
得到
可以通过提交的flag:d2be2981b84f2a905669995873d6a36c
可以通过程序的flag:84ab2835640e510eb81f86e0ced4d91c
[网鼎杯 2020 青龙组]signal
这个东西滴加密比较复杂,有一张加密流程表,根据表单内容对输入进行各种赋值、异或、加减乘除。逆过来的话有一定的难度,所以,我决定请出angr:
1 2 3 4 5 6 7 8 import angrp = angr.Project('signal.exe' , auto_load_libs = False ) init_state = p.factory.entry_state() s = p.factory.simgr(init_state) s.explore(find = 0x0040179E , avoid = 0x00401539 ) print (s.found[0 ].posix.dumps(0 ))
得到flag:757515121f3d478
超!这angr真nm好用!
[GUET-CTF2019]number_game
很奇妙的一道题:
不是很能理解为什么sub_400758()返回值明明是个指针,但在其内部却可以把指针变量赋值给整型变量。在sub_400917()内查看矩阵的样子:
得到flag:1134240024
findKey
又一个非常恶心的C++,主函数东西很少,shift+F12找到关键词“flag{}”,双击跟进发现花指令,nop掉:
之后进入真正恶心的地方,关注函数sub_40101E:
和sub_401005
sub_40101E进去发现:
0x8003u是MD5加密的特征值,因此判定整个函数用于MD5。
对于第一个sub_401005,就是将那一长串绿色的东西每一位异或‘S’,得到的东西应该为MD5之后的输入,在线解密得到123321。而第二个sub_401005并没有找到v5-492对应的值,猜测就是输入,结果证明我猜对了。附上解密脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <iostream> using namespace std;int main () { int key[99 ] = {87 , 94 , 82 , 84 , 73 , 95 , 1 , 109 , 105 , 70 , 2 , 110 , 95 , 2 , 108 , 87 , 91 , 84 , 76 }; char ans[99 ] = "0kk`d1a`55k222k2a776jbfgd`06cjjb" ; int i; for (i = 0 ; i <= 31 ; i++) { ans[i] ^= 'S' ; cout << char (ans[i]); } cout << endl; char k[9 ] = "123321" ; for (i = 0 ; i <= 18 ; i++) { key[i] ^= k[i % 6 ]; cout << char (key[i]); } return 0 ; }
得到flag:n0_Zu0_n0_die
确实,no zuo no die,没事别碰逆向,这个b又干了我4个小时。
[羊城杯 2020]easyre
这个没啥,就是繁,encodeone进行base64,encodetwo乾坤大挪移,encodethree凯撒,逆过来就行
得到flag:672cc4778a38e80cb362987341133ea2
[网鼎杯 2020 青龙组]jocker
打开看见SMC,所以它前面的东西一定是假的,看都不用看。修改完之后得到两个被隐藏的函数encrypt()和Finally()。
encrypt()函数逻辑很清晰,用输入去异或Buffer得到unk_403040。
但是这个Finally()函数中以time(0)作为种子取随机数,也就是说,你是极大概率得不到出题人当时的情况的。经百度,这里需要你去猜,同样也是异或加密,而且是跟v2异或。
根据猜到的结果写出脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <stdio.h> #include <iostream> using namespace std;int main () { int ans[999 ] = {14 , 0 , 0 , 0 , 13 , 0 , 0 , 0 , 9 , 0 , 0 , 0 , 6 , 0 , 0 , 0 , 19 , 0 , 0 , 0 , 5 , 0 , 0 , 0 , 88 , 0 , 0 , 0 , 86 , 0 , 0 , 0 , 62 , 0 , 0 , 0 , 6 , 0 , 0 , 0 , 12 , 0 , 0 , 0 , 60 , 0 , 0 , 0 , 31 , 0 , 0 , 0 , 87 , 0 , 0 , 0 , 20 , 0 , 0 , 0 , 107 , 0 , 0 , 0 , 87 , 0 , 0 , 0 , 89 , 0 , 0 , 0 , 13 }; char XOR1[99 ] = "hahahaha_do_you_find_me?" ; char XOR2[99 ] = "%tp&:" ; int flag[99 ], temp; int i; for (i = 0 ; i < 19 ; i++) { flag[i] = ans[i*4 ] ^ XOR1[i]; } temp = '}' ^ ':' ; for (i = 0 ; i < 5 ; i++) { flag[i+19 ] = temp ^ XOR2[i]; } for (i = 0 ; i < 24 ; i++) { printf ("%c" , flag[i]); } return 0 ; }
得到flag:d07abccf8a410cb37a
不是很认可这种本地打不通的题。。。
[FlareOn5]Minesweeper Championship Registration
是个java的程序,没逆过,但是拖进IDA就能得到flag:GoldenTicket2018@flare-on.com
firmware
固件逆向,不想学,看这里 吧。
得到flag:33a422c45d551ac6e4756f59812a954b
[ACTF新生赛2020]SoulLike
一起来感受3000行屎山代码的美,没有含金量,flag:b0Nf|Re_LiT!
[GWCTF 2019]re3
第一次见,代码自修改问题:
在file/Script command中编写idc脚本:
转成代码并构造函数,得到被隐藏的内容:
使用findcrypt插件可以得知sub_400A71()和sub_40196E()和AES加密有关。unk_603170为秘钥。找到生成它的地方:
插件提示sub_401CF9()为md5加密。从伪代码来看秘钥只与第一和第五个md5有关,然而手动生成与动调结果并不一致。写出解密脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from Crypto.Cipher import AESfrom Crypto.Util.number import *a = [0xBC , 0x0A , 0xAD , 0xC0 , 0x14 , 0x7C , 0x5E , 0xCC , 0xE0 , 0xB1 , 0x40 , 0xBC , 0x9C , 0x51 , 0xD5 , 0x2B , 0x46 , 0xB2 , 0xB9 , 0x43 , 0x4D , 0xE5 , 0x32 , 0x4B , 0xAD , 0x7F , 0xB4 , 0xB3 , 0x9C , 0xDB , 0x4B , 0x5B ] k = [0xCB , 0x8D , 0x49 , 0x35 , 0x21 , 0xB4 , 0x7A , 0x4C , 0xC1 , 0xAE , 0x7E , 0x62 , 0x22 , 0x92 , 0x66 , 0xCE ] ans = "" key = "" for i in range (len (a)): ans += "{:02x}" .format (a[i]) for i in range (len (k)): key += "{:02x}" .format (k[i]) ans = int (ans, 16 ) key = int (key, 16 ) aes = AES.new(long_to_bytes(key), mode = AES.MODE_ECB) flag = aes.decrypt(long_to_bytes(ans)) print (flag)
得到flag:924a9ab2163d390410d0a1f670
[GXYCTF2019]simple CPP
今天也是讨厌C++逆向的一天呢~
异或的东西可以通过动调得到
然后是
接着是
最后那一大坨考虑使用z3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from z3 import *s = Solver() x = BitVec('x' , 64 ) y = BitVec('y' , 64 ) z = BitVec('z' , 64 ) w = BitVec('w' , 64 ) s.add(z & (~x) == 0x11204161012 ) s.add(0x3E3A4717373E7F1F ^ w == 0x3E3A4717050F791F ) s.add(0x11204161012 | (x & y) | (z & (~y)) | (x & (~y)) == 0x3E3A4717373E7F1F ) s.add((z & (~y)) & x | z & ((x & y) | y & ~x | ~(y | x)) == 0x8020717153E3013 ) s.add(0x11204161012 | (x & y) | y & z == ~x & z | 0xC00020130082C0C ) if s.check(): r = s.model() for i in r: print (i, hex (r[i].as_long()))
将得到的答案在异或回去:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <stdio.h> int main () { long long ans[99 ]; char XOR[] = "i_will_check_is_debug_or_not" ; long long i, j, flag[99 ]; ans[1 ] = 865872043546520588 ; ans[0 ] = 4483973367147818765 ; ans[3 ] = 842073600 ; ans[2 ] = 577031497978884115 ; for (i = 0 ; i < 4 ; i++) { if (i == 3 ) { for (j = 0 ; j < 4 ; j++) { flag[i*8 +j] = (ans[i] & 0xFF000000 ) >> 24 ; ans[i] = ans[i] << 8 ; } } else { for (j = 0 ; j < 8 ; j++) { flag[i*8 +j] = (ans[i] & 0xFF00000000000000 ) >> 56 ; ans[i] = ans[i] << 8 ; } } } for (i = 0 ; i < 27 ; i++) { flag[i] ^= XOR[i]; printf ("%c" , flag[i]); } return 0 ; }
然后就可以得到乱码We1l_D0ndaQbg�_Slgebra_am_i
经百度,是题错了,z3解出来不止一组解。挺神奇的,5个条件约束不住4个数。
得到flag:We1l_D0ne!P0or_algebra_am_i
[FlareOn5]Ultimate Minesweeper
get了一个dnSpy的新玩法。拖进去容易找到加密函数:
但是仔细看一看发现它用revealedCells作为种子生成了一个随机数数组array,之后在加密输出。因此想法是动调,查看一下会让我们失败的函数:
根据英文提示,第一个if就是失败判定,把它右键、编辑方法,给它注释掉:
右下角编译之后Ctrl+shift+s保存为新程序,运行新程序,找到三个非雷地块:
之后再在正常的程序里点击这三个地块,得到flag:Ch3aters_Alw4ys_W1n@flare-on.com
[MRCTF2020]PixelShooter
附件是一个apk,但是里面有很多unity的关键字,所以去找Assembly-CSharp.dll:
导出后拖进dnSpy,在UIControler方法中找到:
得到flag:Unity_1S_Fun_233
[FlareOn1]Bob Doge
又是一个C#的程序,拖入dnSpy,容易找到加密函数:
发现需要寻找dat_secret,可惜找不到(话说,这玩意儿是怎么藏起来的?),所以准备动调:
在数据栏中得到flag:3rmahg3rd.b0b.d0ge@flare-on.com
[2019红帽杯]xx
红帽杯的题总能让我眼前一黑
首先判断输入位数为19位,然后判断输入的值是不是在特定字符串里。
然后构造key,发现key保留了输入的前4个,其余的赋0,再将其转为4个32位数用于XXTEA。然后你需要坚定不移地猜输入的前4个就是"flag"。XXTEA的代码是真心没看懂,但好在他是标准的。通过动调可以知道如果输入为1234,在XXTEA中input会变成34333231,解密时要注意大小端序。
对加密结果进行打乱,并且进行了一个离谱的异或。解异或需要从后往前解。
最后进行对比,这种赋值方式也会产生大小端序的问题,算不过来的话…动调吧!骚年!
写出脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 #include <stdio.h> #define DELTA 0x9e3779b9 #define MX (((z>>5^y<<2) + (y> >3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z))) void XXTEA (unsigned int *v, int n, unsigned int key[4 ]) { unsigned int y, z, sum; unsigned p, rounds, e; rounds = 6 + 52 / n; sum = rounds * DELTA; y = v[0 ]; do { e = (sum >> 2 ) & 3 ; for (p = n - 1 ; p > 0 ; p--) { z = v[p - 1 ]; y = v[p] -= MX; } z = v[n - 1 ]; y = v[0 ] -= MX; sum -= DELTA; } while (--rounds); } int main () { int ans[99 ] = {206 , 188 , 64 , 107 , 124 , 58 , 149 , 192 , 239 , 155 , 32 , 32 , 145 , 247 , 2 , 53 , 35 , 24 , 2 , 200 , 231 , 86 , 86 , 250 }, enc[99 ]; int v21 = 23 , v22 = 23 , i, j; for (; v21 >= 1 ; v22--) { int v23 = 0 ; if (v21 / 3 > 0 ) { do { ans[v22] ^= ans[v23]; v23++; } while (v23 < v21 / 3 ); } v21--; } enc[2 ] = ans[0 ]; enc[0 ] = ans[1 ]; enc[3 ] = ans[2 ]; enc[1 ] = ans[3 ]; enc[6 ] = ans[4 ]; enc[4 ] = ans[5 ]; enc[7 ] = ans[6 ]; enc[5 ] = ans[7 ]; enc[10 ] = ans[8 ]; enc[8 ] = ans[9 ]; enc[11 ] = ans[10 ]; enc[9 ] = ans[11 ]; enc[14 ] = ans[12 ]; enc[12 ] = ans[13 ]; enc[15 ] = ans[14 ]; enc[13 ] = ans[15 ]; enc[18 ] = ans[16 ]; enc[16 ] = ans[17 ]; enc[19 ] = ans[18 ]; enc[17 ] = ans[19 ]; enc[22 ] = ans[20 ]; enc[20 ] = ans[21 ]; enc[23 ] = ans[22 ]; enc[21 ] = ans[23 ]; unsigned int flag[99 ]; for (i = 0 ; i < 6 ; i++) { for (j = 3 ; j >= 0 ; j--) { flag[i] = (flag[i] << 8 ) + enc[i*4 +j]; } } unsigned int key[4 ] = {0x67616c66 , 0 , 0 , 0 }; XXTEA (flag, 6 , key); for (i = 0 ; i < 6 ; i++) { for (j = 0 ; j < 4 ; j++) { printf ("%c" , flag[i] & 0xFF ); flag[i] >>= 8 ; } } return 0 ; }
得到flag:CXX_and_++tea
[CFI-CTF 2018]IntroToPE
这道题就比较水了,打开找到判断函数:
可以看出,应当使validatePassword.verifyPassword()返回真值,双击跟踪:
看见是一个base64,理论上应该接着去找加密使用的对应表,可惜没找到,就用默认的吧。
得到flag:.NetC#_1s_@w3s0m3
equation
非常sb的一道题,先jsfuck,再z3。
得到flag:A_l0ng_10NG_eqU4Ti0n_1s_E4Sy_W1Th_z3