BUUCTF Reverse 11-32 [toc]
11. Java逆向解密 附件是一个class文件,用jadx打开
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 public class Reverse { public static void main (String[] args) { Scanner s = new Scanner (System.in); System.out.println("Please input the flag :" ); String str = s.next(); System.out.println("Your input is :" ); System.out.println(str); char [] stringArr = str.toCharArray(); Encrypt(stringArr); } public static void Encrypt (char [] arr) { ArrayList<Integer> Resultlist = new ArrayList <>(); for (char c : arr) { int result = (c + '@' ) ^ 32 ; Resultlist.add(Integer.valueOf(result)); } int [] KEY = {180 , 136 , 137 , 147 , 191 , 137 , 147 , 191 , 148 , 136 , 133 , 191 , 134 , 140 , 129 , 135 , 191 , 65 }; ArrayList<Integer> KEYList = new ArrayList <>(); for (int i : KEY) { KEYList.add(Integer.valueOf(i)); } System.out.println("Result:" ); if (Resultlist.equals(KEYList)) { System.out.println("Congratulations!" ); } else { System.err.println("Error!" ); } } }
exp
1 2 3 4 5 6 7 8 9 key = [180 , 136 , 137 , 147 , 191 , 137 , 147 , 191 , 148 , 136 , 133 , 191 , 134 , 140 , 129 , 135 , 191 , 65 ] flag = '' for j in key: for i in range (31 ,128 ): if ((i+ord ('@' ))^32 ) == j: print (i) flag += chr (i) break print (flag)
12. [GXYCTF2019]luck_guy 从main函数跟进到patch_me(4)
跟进get_flag()
在case 4
中对f2进行赋值,在case 5
中对f2进行修改,在case 1
中拼接f1和f2,然后输出
exp
1 2 3 4 5 6 7 8 9 10 11 flag='GXY{do_not_' f2=[0x69 ,0x63 ,0x75 ,0x67 ,0x60 ,0x6f ,0x66 ,0x7f ] v1=[] a = '' for i in range (8 ): if i%2 ==1 : a = f2[i]-2 else : a = f2[i]-1 flag+=chr (a) print (flag)
13. [BJDCTF2020]JustRE 32位
32位
shift+f12查看字符串
替换%d
flag{1999902069a45792d233ac}
14. 刮开有奖 32位
shift+f12查看字符串,跟进
在函数DialogFunc中被引用
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 INT_PTR __stdcall DialogFunc (HWND hDlg, UINT a2, WPARAM a3, LPARAM a4) { const char *v4; const char *v5; int v7[2 ]; int v8; int v9; int v10; int v11; int v12; int v13; int v14; int v15; int v16; CHAR String[65536 ]; char v18[65536 ]; if ( a2 == 272 ) return 1 ; if ( a2 != 273 ) return 0 ; if ( (_WORD)a3 == 1001 ) { memset (String, 0 , 0xFFFF u); GetDlgItemTextA(hDlg, 1000 , String, 0xFFFF ); if ( strlen (String) == 8 ) { v7[0 ] = 90 ; v7[1 ] = 74 ; v8 = 83 ; v9 = 69 ; v10 = 67 ; v11 = 97 ; v12 = 78 ; v13 = 72 ; v14 = 51 ; v15 = 110 ; v16 = 103 ; sub_4010F0((int )v7, 0 , 10 ); memset (v18, 0 , 0xFFFF u); v18[0 ] = String[5 ]; v18[2 ] = String[7 ]; v18[1 ] = String[6 ]; v4 = (const char *)sub_401000(v18, strlen (v18)); memset (v18, 0 , 0xFFFF u); v18[1 ] = String[3 ]; v18[0 ] = String[2 ]; v18[2 ] = String[4 ]; v5 = (const char *)sub_401000(v18, strlen (v18)); if ( String[0 ] == v7[0 ] + 34 && String[1 ] == v10 && 4 * String[2 ] - 141 == 3 * v8 && String[3 ] / 4 == 2 * (v13 / 9 ) && !strcmp (v4, "ak1w" ) && !strcmp (v5, "V1Ax" ) ) { MessageBoxA(hDlg, "U g3t 1T!" , "@_@" , 0 ); } } return 0 ; } if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 ) return 0 ; EndDialog(hDlg, (unsigned __int16)a3); return 1 ; }
x查看引用,main函数中调用了该函数
主要逻辑,其中sub_4010F0为
所以根据if判断反推String
,exp瞎写的
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 import base64v7 = [0 ,1 ] v7[0 ] = 90 v7[1 ] = 74 v8 = 83 v9 = 69 v10 = 67 v11 = 97 v12 = 78 v13 = 72 v14 = 51 v15 = 110 v16 = 103 flag = [0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ] flag[0 ] = chr (51 + 34 ) flag[1 ] = chr (74 ) print (flag)a = base64.b64decode('V1Ax' ) print (a) a = 'jMp' flag[2 ] = 'W' flag[3 ] = 'P' flag[4 ] = '1' flag[5 ] = 'j' flag[6 ] = 'M' flag[7 ] = 'p' print (flag)x = '' for i in flag: x += str (i) print (x)
15. 简单注册器 apk包丢入jadx,直接看flag生成部分代码
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class test { public static void main (String[] args) { char [] x = "dd2940c04462b4dd7c450528835cca15" .toCharArray(); x[2 ] = (char ) ((x[2 ] + x[3 ]) - 50 ); x[4 ] = (char ) ((x[2 ] + x[5 ]) - 48 ); x[30 ] = (char ) ((x[31 ] + x[9 ]) - 48 ); x[14 ] = (char ) ((x[27 ] + x[28 ]) - 97 ); for (int i = 0 ; i < 16 ; i++) { char a = x[31 - i]; x[31 - i] = x[i]; x[i] = a; } String bbb = String.valueOf(x); System.out.println("flag{" + bbb + "}" ); } }
16. [GWCTF 2019]pyre python反编译
借助于python反编译在线网站:python反编译 - 在线工具 (tool.lu)
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 print 'Welcome to Re World!' print 'Your input1 is your flag~' l = len (input1) for i in range (l): num = ((input1[i] + i) % 128 + 128 ) % 128 code += num for i in range (l - 1 ): code[i] = code[i] ^ code[i + 1 ] print codecode = [ '%1f' , '%12' , '%1d' , '(' , '0' , '4' , '%01' , '%06' , '%14' , '4' , ',' , '%1b' , 'U' , '?' , 'o' , '6' , '*' , ':' , '%01' , 'D' , ';' , '%' , '%13' ]
exp
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 code = [ '\x1f' , '\x12' , '\x1d' , '(' , '0' , '4' , '\x01' , '\x06' , '\x14' , '4' , ',' , '\x1b' , 'U' , '?' , 'o' , '6' , '*' , ':' , '\x01' , 'D' , ';' , '%' , '\x13' ] for i in range (len (code)-2 ,-1 ,-1 ): code[i]=chr (ord (code[i])^ord (code[i+1 ])) flag = '' for i in range (len (code)): print (ord (code[i])-i) code[i] = chr ((ord (code[i])-i)%128 ) flag += code[i] print (code)print (flag)
17. [ACTF新生赛2020]easyre(不是很懂) 32位,UPX加壳
upx脱壳,kali里执行
脱壳后的主函数
其中data_start为
flag是v5,上面的程序将v5的ascii值-1作为data_start的下标,和v4进行对比
所以逆向写exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 v4 = "*F'\"N,\"(I?+@" print (len (v4))data_str = '~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(' + "'" + '&%$# !"' print (len (data_str))flag = '' for i in range (12 ): print (i) x = data_str.find(v4[i])+1 print (chr (x)) flag += chr (x) print (flag)
18. findit apk包
分析出flag的生成代码
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class test { public static void main (String[] args) { final char [] a = {'T' , 'h' , 'i' , 's' , 'I' , 's' , 'T' , 'h' , 'e' , 'F' , 'l' , 'a' , 'g' , 'H' , 'o' , 'm' , 'e' }; final char [] b = {'p' , 'v' , 'k' , 'q' , '{' , 'm' , '1' , '6' , '4' , '6' , '7' , '5' , '2' , '6' , '2' , '0' , '3' , '3' , 'l' , '4' , 'm' , '4' , '9' , 'l' , 'n' , 'p' , '7' , 'p' , '9' , 'm' , 'n' , 'k' , '2' , '8' , 'k' , '7' , '5' , '}' }; char [] y = new char [38 ]; for (int i2 = 0 ; i2 < 38 ; i2++) { if ((b[i2] >= 'A' && b[i2] <= 'Z' ) || (b[i2] >= 'a' && b[i2] <= 'z' )) { y[i2] = (char ) (b[i2] + 16 ); if ((y[i2] > 'Z' && y[i2] < 'a' ) || y[i2] >= 'z' ) { y[i2] = (char ) (y[i2] - 26 ); } } else { y[i2] = b[i2]; } } String n = String.valueOf(y); System.out.println(n); } }
19. rsa
公钥n = p * q,其中p和q是两个大素数
e是随机选择的数,作为公钥
d是跟e有关的一个数,满足条件式:ed=1(mod phi(n))
phi(n)是欧拉函数,phi(n)=(p-1)(q-1)
将pub.key拖入RSA公私钥分解 Exponent、Modulus,Rsa公私钥指数、系数(模数)分解–查错网 (chacuo.net)
得到
e = 65537
模数转换为十进制
n = 86934482296048119190666062003494800588905656017203025617216654058378322103517
从n中提取p,q,factordb.com
p=285960468890451637935629440372639283459
q=304008741604601924494328155975272418463
解密脚本
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import gmpy2import rsae = 65537 n = 86934482296048119190666062003494800588905656017203025617216654058378322103517 p = 285960468890451637935629440372639283459 q = 304008741604601924494328155975272418463 phin = (q-1 )*(p-1 ) d = gmpy2.invert(e, phin) key = rsa.PrivateKey(n, e, int (d), p, q) with open ("C:\\Users\\xxxxx\\Desktop\\flag.enc" , "rb+" ) as f: f = f.read() print (rsa.decrypt(f, key))
报错解决:AttributeError: partially initialized module ‘rsa’ has no attribute ‘PrivateKey’ (most likely due to a circular import)
原因:文件名和rsa重名,修改即可
20. [ACTF新生赛2020]rome 32位
func函数
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 int func () { int result; int v1[4 ]; unsigned __int8 v2; unsigned __int8 v3; unsigned __int8 v4; unsigned __int8 v5; unsigned __int8 v6; int v7; int v8; int v9; int v10; unsigned __int8 v11; char v12[29 ]; strcpy (v12, "Qsw3sj_lz4_Ujw@l" ); printf ("Please input:" ); scanf ("%s" , &v2); result = v2; if ( v2 == 'A' ) { result = v3; if ( v3 == 'C' ) { result = v4; if ( v4 == 'T' ) { result = v5; if ( v5 == 'F' ) { result = v6; if ( v6 == '{' ) { result = v11; if ( v11 == '}' ) { v1[0 ] = v7; v1[1 ] = v8; v1[2 ] = v9; v1[3 ] = v10; *(_DWORD *)&v12[17 ] = 0 ; while ( *(int *)&v12[17 ] <= 15 ) { if ( *((char *)v1 + *(_DWORD *)&v12[17 ]) > 64 && *((char *)v1 + *(_DWORD *)&v12[17 ]) <= 90 ) *((_BYTE *)v1 + *(_DWORD *)&v12[17 ]) = (*((char *)v1 + *(_DWORD *)&v12[17 ]) - 51 ) % 26 + 65 ; if ( *((char *)v1 + *(_DWORD *)&v12[17 ]) > 96 && *((char *)v1 + *(_DWORD *)&v12[17 ]) <= 122 ) *((_BYTE *)v1 + *(_DWORD *)&v12[17 ]) = (*((char *)v1 + *(_DWORD *)&v12[17 ]) - 79 ) % 26 + 97 ; ++*(_DWORD *)&v12[17 ]; } *(_DWORD *)&v12[17 ] = 0 ; while ( *(int *)&v12[17 ] <= 15 ) { result = (unsigned __int8)v12[*(_DWORD *)&v12[17 ]]; if ( *((_BYTE *)v1 + *(_DWORD *)&v12[17 ]) != (_BYTE)result ) return result; ++*(_DWORD *)&v12[17 ]; } return printf ("You are correct!" ); } } } } } } return result; }
爆破
1 2 3 4 5 6 7 8 9 10 11 12 13 14 v12 = 'Qsw3sj_lz4_Ujw@l' flag = '' for i in range (16 ): print (i) for j in range (0 ,127 ): if (j>64 and j<=90 ): x = chr ((j-51 )%26 +65 ) elif (j>96 and j<=122 ): x = chr ((j-79 )%26 +97 ) else : x =chr (j) if (x == v12[i]): flag += chr (j) print (flag)
21. [FlareOn4]login 查看login.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <!DOCTYPE Html /> <html > <head > <title > FLARE On 2017</title > </head > <body > <input type ="text" name ="flag" id ="flag" value ="Enter the flag" /> <input type ="button" id ="prompt" value ="Click to check the flag" /> <script type ="text/javascript" > document .getElementById ("prompt" ).onclick = function ( ) { var flag = document .getElementById ("flag" ).value ; var rotFlag = flag.replace (/[a-zA-Z]/g , function (c ){return String .fromCharCode ((c <= "Z" ? 90 : 122 ) >= (c = c.charCodeAt (0 ) + 13 ) ? c : c - 26 );}); if ("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz" == rotFlag) { alert ("Correct flag!" ); } else { alert ("Incorrect flag, rot again" ); } } </script > </body > </html >
会对a-zA-Z的字符串进行判断处理
爆破,exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var str1 = 'PyvragFvqrYbtvafNerRnfl@syner-ba.pbz' var flag = '' console .log (str1)for (i=0 ;i<36 ;i++){ console .log (i) for (j=0 ;j<128 ;j++){ var a = String .fromCharCode (j) var rotFlag = a.replace (/[a-zA-Z]/g , function (c ){return String .fromCharCode ((c <= "Z" ? 90 : 122 ) >= (c = c.charCodeAt (0 ) + 13 ) ? c : c - 26 );}); if (rotFlag == str1[i]){ flag = flag + a } } } console .log (flag)
22. CrackRTF 32位
首先输入长度为6的字符串,会在字符串后面拼接@DBApp
,将字符串以及对应长度传入sub_40100A
函数中
跟进,发现调用了CryptCreateHash函数
查看这个函数
CryptCreateHash 函数启动数据流的哈希 。 它创建并返回到调用应用程序,该句柄指向 加密服务提供程序 (CSP) 哈希对象 。 此句柄用于后续调用 CryptHashData 和 CryptHashSessionKey 以哈希会话键和其他数据流。
跟进查看这个ALG_ID,其代表不同的算法,这里代表的是SHA1
因为数字是6位数,且>=100000
,所以可以进行爆破
1 2 3 4 5 6 7 8 9 10 11 import hashlibfor i in range (100000 ,999999 ): str1 = str (i) + "@DBApp" print (i) a = hashlib.sha1(str1.encode("utf-8" )).hexdigest() if (a == "6E32D0943418C2C33385BC35A1470250DD8923A 9" .lower()): print (str (i)+"DBApp" ) break
看第二个password,长度为6,然后拼接,传入sub_401019
函数
跟进,发现函数加密函数
根据0x8003u
,此处为md5加密,但是没有限制范围,所以没法爆破
继续往下看,将拼接后的字符串传入sub_40100F
中,
跟进,发现是从AAA
文件取出字符,然后将取出的字符和拼接后的字符串传入sub_401005
中
跟进,发现是进行了异或处理
利用ResourceHacker工具擦混看AAA文件内容
再理一下逻辑:是把AAA中的字符和拼接后的字符串进行异或,结果为lpBuffer,然后将lpBuffer写入文件dbapp.rtf
中
随便查看一个rtf文件的内容,前六位是rtf文件的标志位
异或的逆运算也是异或,那么将rtf文件的标志位前六位和AAA文件中的前六位进行异或,得到的结果就是第二个passwd
1 2 3 4 5 6 7 8 9 10 11 str1 = "{\\rtf1" print (str1)str2 = [0x05 ,0x7D ,0x41 ,0x15 ,0x26 ,0x01 ] print (str2)flag = '' for i in range (0 ,len (str1)): flag += chr (ord (str1[i])^str2[i]) print (flag)
输入两次passwd之后会生成一个rtf文件,flag就在其中
23. [WUSTCTF2020]level1 给了一个程序以及输出结果,主要逻辑如下
1 2 3 4 5 6 7 8 9 10 11 12 13 v7 = __readfsqword(0x28 u); flag = fopen("flag" , "r" ); fread(ptr, 1uLL , 0x14 uLL, flag); fclose(flag); for ( i = 1 ; i <= 19 ; ++i ) { if ( (i & 1 ) != 0 ) printf ("%ld\n" , (unsigned int )(ptr[i] << i)); else printf ("%ld\n" , (unsigned int )(i * ptr[i])); } return 0 ; }
if(i&1) ,在这要说明的是,这个&是二进制位参与运算,末尾开始,奇数二进制末尾是1,偶数是0,也就是说奇数i&1结果为1,偶数则为0。 这个判断语句也可写为if(i&1==1)
<<和>>的意思
<<是左移运算符的意思,左移运算符是用来将一个数的各二进制位全部左移若干位,右补0。高位左移后溢出,舍弃。 例如: 将a的二进制数左移2位,右补0。若a=15,即二进制数00001111,左移2位得00111100,即十进制数60。
语法格式:需要移位的数字 << 移位的次数
例如: 3 << 2,则是将数字3左移2位。即00000011—–>00001100(12);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 arr = [] with open ("./re/output.txt" ,"r" ) as f: line = f.readline() while line: arr.append(int (line)) line = f.readline() print (arr)flag = "" for i in range (1 ,20 ): if (i % 2 != 0 ): arr[i-1 ] = arr[i-1 ] >> i else : arr[i-1 ] = int (arr[i-1 ] / i) print (arr)for i in range (0 ,19 ): flag += chr (arr[i]) print (flag)
24. [GUET-CTF2019]re upx加壳,脱壳后
关键函数为if判断里的sub_4009AE
进行字符串判断
写脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import rewith open ("./re/output.txt" ,"r" ) as f: str = f.read() pattern = re.compile (r'\d+' ) nums = pattern.findall(str ) print (len (nums))arr = [] for i in range (0 ,len (nums)): if (int (nums[i])>10000 ): arr.append(int (nums[i])) flag = '' for i in range (0 ,len (arr)): if (i % 2 != 0 ): flag += chr (int (arr[i]/arr[i-1 ])) print (flag)
运行结果
但是flag不对,因为程序中没有a1[6],需要进行爆破,最后a1[6]=1
25. [2019红帽杯]easyRE 经过十次base64解码,得到https://bbs.pediy.com/thread-254172.htm
根据string1[i] ^ i) != v15[i]
,通过爆破,获取string1,
1 2 3 4 5 6 7 8 v15 = "Iodl>Qnb(ocy" +chr (127 )+"y.i" +chr (127 )+"d`3w}wek9{iy=~yL@EC" flag = '' for i in range (len (v15)): for j in range (31 ,128 ): if (j^i == ord (v15[i])): flag += chr (j) print ('' .join(flag))
但是上面得到的网站没啥用
根据这个if判断,查看off_6CC090
字符串
接着看到byte_6CC0A0和byte_6CC0A3字符串
跟进sub_400D35函数
v4是一个数组,用HIBYTE
取高字节也就是v4的最后一个字节,与byte_6CC0A3异或,判断是否为f
和g
,那么可以猜测这个字符串数组为flag
首先利用flag和v4代表的4个字节异或,获取v4
然后利用v4和byte_6CC0A0的异或,获得flag
1 2 3 4 5 6 7 8 9 10 11 12 13 arr1 = [0x40 ,0x35 ,0x20 ,0x56 ,0x5D ,0x18 ,0x22 ,0x45 ,0x17 ,0x2F ,0x24 ,0x6E ,0x62 ,0x3C ,0x27 ,0x54 ,0x48 ,0x6C ,0x24 ,0x6E ,0x72 ,0x3C ,0x32 ,0x45 ,0x5B ] str1 = "flag" v4 = '' for i in range (4 ): v4 += chr (ord (str1[i])^arr1[i]) print (v4)str2 = '' for j in range (25 ): str2 += chr (arr1[j] ^ ord (v4[j%4 ])) print (str2)
常量那里,注意8 dup(0)
代表8个0
1 2 3 4 5 6 7 8 9 10 11 12 index = [0x9 , 0x0A , 0x0F , 0x17 , 0x7 , 0x18 , 0x0C , 0x6 , 0x1 , 0x10 , 0x3 , 0x11 , 0x20 , 0x1D , 0x0B , 0x1E , 0x1B , 0x16 , 0x4 , 0x0D , 0x13 , 0x14 , 0x15 , 0x2 , 0x19 , 0x5 , 0x1F , 0x8 , 0x12 , 0x1A , 0x1C , 0x0E , 0 ] result = [0x67 ,0x79 ,0x7B ,0x7F ,0x75 ,0x2B ,0x3C ,0x52 ,0x53 ,0x79 ,0x57 ,0x5E ,0x5D ,0x42 ,0x7B ,0x2D ,0x2A ,0x66 ,0x42 ,0x7E ,0x4C ,0x57 ,0x79 ,0x41 ,0x6B ,0x7E ,0x65 ,0x3C ,0x5C ,0x45 ,0x6F ,0x62 ,0x4D ,0 ] arr1 = [] arr2 =[0 ]*33 for i in range (33 ): arr1.append(result[i]^index[i]) arr2[index[i]] = result[i]^index[i] print (arr2)for i in arr2: print (chr (i),end='' )
27. [WUSTCTF2020]level2 水题
28. [SUCTF2019]SignIn 主要函数
int mpz_init_set_str (mpz_t rop, char *str, int base)
这三个参数分别是多精度整数变量,字符串,进制
void mpz_powm (mpz_t rop, const mpz_t base, const mpz_t exp, const mpz_t mod) [Function]
Set rop to base^exp mod mod. 其实就是计算 base 的 exp 次方,并对 mod 取模,最后将结果写入 rop 中__gmpz_cmp
比较函数
这里的逻辑是(v6^*v5) mod v4 = v7
,而v5,v4,v7已知,求
RSA解密原理:[(12条消息) BUUCTF]REVERSE——rsa_Angel~Yan的博客-CSDN博客
RSA解密脚本:(12条消息) 个人收集的RSA常用脚本_mon0dy的博客-CSDN博客
大整数分解在线网站:factordb.com
解密脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import gmpy2import binasciidef Decrypt (c,e,p,q ): L=(p-1 )*(q-1 ) d=gmpy2.invert(e,L) n=p*q m=gmpy2.powmod(c,d,n) flag=str (m) print (flag) if __name__ == '__main__' : p = 282164587459512124844245113950593348271 q = 366669102002966856876605669837014229419 e = 65537 c = 78510953323073667749065685964447569045476327122134491251061064910992472210485 Decrypt(c,e,p,q) x = 185534734614696481020381637136165435809958101675798337848243069 print (binascii.unhexlify(hex (x)[2 :]).decode(encoding="utf-8" ))
29. [ACTF新生赛2020]usualCrypt 32位,输入为v8,sub_401080根据v8生成v5,然后对v5进行判断
跟进sub_401080,该函数主要有三个操作
sub_401000
对base64码表进行字符串交换
base64编码,注意这里的base64码表是修改过的
最后用sub_401030进行处理
跟进,发现是大小写转换
最后的结果是zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9
所以逆向操作:首先进行大小写转化,而后利用修改后的base64码表进行解码
base64解码参考大佬博客:(22条消息) Base64编码算法(Python实现)_大灬白的博客-CSDN博客
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 result = 'zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9' print (len (result))str1 = [] for i in range (len (result)): if ord (result[i])>64 and ord (result[i])<91 : str1.append(chr (ord (result[i])+32 )) elif ord (result[i])>96 and ord (result[i])<123 : str1.append(chr (ord (result[i])-32 )) else : str1.append(result[i]) print ('' .join(str1))print (ord ("a" )) aAbcdefghijklmn = list ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ) for j in range (6 ,15 ): v1 = aAbcdefghijklmn[j+10 ] aAbcdefghijklmn[j+10 ] = aAbcdefghijklmn[j] aAbcdefghijklmn[j] = v1 letters = aAbcdefghijklmn def decryption (inputString ): asciiList = ['{:0>6}' .format (str (bin (letters.index(i))).replace('0b' , '' )) for i in inputString if i != '=' ] outputString = '' equalNumber = inputString.count('=' ) while asciiList: tempList = asciiList[:4 ] tempString = '' .join(tempList) if len (tempString) % 8 != 0 : tempString = tempString[0 :-1 *equalNumber*2 ] tempStringList = [tempString[x:x+8 ] for x in [0 , 8 , 16 ]] tempStringList = [int (x, 2 ) for x in tempStringList if x] outputString += '' .join([chr (x) for x in tempStringList]) asciiList = asciiList[4 :] return outputString print (decryption('' .join(str1)))
30. [HDCTF2019]Maze upx脱壳
F5没反应,jnz指令跳转到下一行代码,这里为花指令
将jnz指令给nop掉
方法1:
edit –> Patch program –> change byte修改byte,然后edit –> Patch program –> Apply patches to input file保存修改的文件
方法2:
edit –> Patch program –> Assemble直接输入nop,然后edit –> Patch program –> Apply patches to input file保存修改的文件
重启程序,得主要逻辑
写脚本画出迷宫
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 str = '*******+********* ****** **** ******* **F****** **************' print (len (str ))for i in range (len (str )): if (i+1 )%10 != 0 : print (str [i],end='' ) else : print (str [i])
参考链接:[【CTF】花指令问题——HDCTF2019]Maze - 掘金 (juejin.cn)
31. [MRCTF2020]Xor 32位
反汇编出错
首先看到将byte_4212C0和%s压入栈中,所以flag其实存储在byte_4212C0中
然后在loc_4010B6中edx自增,并且与1Bh
进行比较,大于1Bh
就提示Wrong!
如果不大于1Bh
,就先和eax异或,然后和byte_41EA80比较,后者为字符串
1 MSAWB~FXZ:J:`tQJ"N@ bpdd}8g
1 2 3 4 5 6 7 str1 = 'MSAWB~FXZ:J:`tQJ"N@ bpdd}8g' flag = '' for i in range (len (str1)): flag += chr (ord (str1[i])^i) print (flag)
参考链接:(23条消息) BUUCTF-RE-MRCTF2020Xor_Persistent_s的博客-CSDN博客
32. Youngter-drive 多线程
首先看StartAddress,dword_418008为29,递减。调用了sub_41112C
判断大小写,对于大写字母,Ascii值减38作为off_418000的下标;对于小写字母,Ascii值减96作为off_418000的下标
另一个进程,对dword_418008-1
这两个进程交替运行,最后调用sub_411190()函数,将source和off_418004对比
字符串对比
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 result = 'TOiZiZtOrYaToUwPnToBsOaOapsyS' off_418000 = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm' flag = '' for i in range (len (result)): if (i%2 == 0 ): flag += result[i] else : if off_418000.index(result[i])+38 < 65 : flag += chr (off_418000.index(result[i])+96 ) else : flag += chr (off_418000.index(result[i])+38 ) print (flag)
但是程序运行结果不能直接作为flag,要再加上一个E
,不知道为啥,看了很多大佬的博客也不懂
flag{ThisisthreadofwindowshahaIsESE