BUUCTF-RE 这里是buuctf平台的逆向的练习,我会在这里发布一些关于buuctf逆向题的解题思路,算是学习吧。因为我二进制不是很好,所以抽了点时间来做一些题来学习。
0x01 easyre 签到题,idea打开就看到flag了。
flag:flag{this_Is_a_EaSyRe}
0x02 reverse1 ida打开文件就看flag了,也是一道签到
flag:flag{hello_world}
0x03 reverse2 ida打开,找到main函数,关键代码:
1 2 3 4 5 6 for ( i = 0 ; i <= strlen (&flag); ++i ) { if ( *(&flag + i) == 105 || *(&flag + i) == 114 ) *(&flag + i) = 49 ; } }
做了一个简单的替换,写脚本跑出来就可以了:
1 2 3 4 5 6 7 8 9 10 flag = list ('hacking_for_fun}' ) flag2 = [] for i in range (len (flag)): if ord (flag[i]) - i == 105 or ord (flag[i]) - i == 114 : flag2.append(chr (49 )) else : flag2.append(flag[i]) print ("" .join(flag2))
flag:flag{hacki1g_for_fun}
0x04 内涵的软件 查看字符串 View -> Open subviews -> Strings 就可以看到flag了。
其实函数是在_main_0函数里,直接找也可以找得到。
flag:flag{49d3c93df25caad81232130f3d2ebfad}
0x05 新年快乐 查个壳(其实做题之前应该要先查壳的,前几题看在是签到的份上就直接看了),ida打开后发现只有几个函数,于是丢到exeinfo里查壳。利用UPX Tool脱壳。
找到_main函数就可以看到HappyNewYear!
了,可以查找字符串。
这里也可以用od进行脱壳(但是我不太会,正在学习ing)。
flag:flag{HappyNewYear!}
0x06 xor 查看发现没加壳,丢ida,主函数反编译
关键代码:
循环里做的是异或操作,前一位跟后一位进行异或然后赋值给后一位。
1 2 3 4 for ( i = 1 ; i < 33 ; ++i ) v5[i] ^= v5[i - 1 ]; if ( !strncmp (v5, global, 0x21 uLL) ) printf ("Success" );
strncmp函数是比较v5和global变量,0x21uLL转换为十进制是33,也就是比较前33个字符是否相等。
于是点进global变量发现值如下:
1 f\nk\fw&O.@\x11x\rZ;U\x11p\x19F\x1Fv\"M#D\x0Eg\x06h\x0FG2O
exp:
1 2 3 4 5 6 7 global1 = list ('f\nk\fw&O.@\x11x\rZ;U\x11p\x19F\x1Fv\"M#D\x0Eg\x06h\x0FG2O' ) flag = [] for i in range (1 ,len (global1)): flag.append(chr (ord (global1[i]) ^ ord (global1[i-1 ]))) print ("" .join(flag))
结果少了个f不晓得为啥,补上去就好了。
flag:flag{QianQiuWanDai_YiTongJiangHu}
0x07 helloword android题目,利用jadx软件打开。
com.example.helloword -> MainActivity 就可以看到flag了。
flag:flag{7631a988259a00816deda84afb29430a}
0x08 reverse3 查壳发现没壳,找到主函数反编译。
从下往上看发现做了一次比较
1 strncmp(Destination, Str2, v5);
Str2和Destination进行了比较,点进Str2,值如下:
然后做了移位操作后,在往上就看到了sub_4110BE函数,进去看看是干嘛的。
代码挺复杂的,没看懂,但是发现了一个函数aAbcdefghijklmn,点进去就看到了编码表,于是就联想到了base64。
所以代码做的操作是:输入flag -> base64加密 -> 移位操作
编写exp:
1 2 3 4 5 6 7 8 9 10 import base64d = 'e3nifIH9b_C@n@dH' flag = [] for i in range (len (d)): flag.append(chr (ord (d[i])-i)) flag = "" .join(flag) print (base64.b64decode(flag))
flag:flag{i_l0ve_you}
0x09 不一样的flag 迷宫题
1 2 3 4 5 6 7 8 9 迷宫如下: *1111 01000 01010 00010 1111# 迷宫只能走0,1是不能走的 答案就是:222441144222
flag:flag{222441144222}
0x0A SimpleRev 大小端存储
1 2 3 4 v9 = 0x776F646168LL # src = 0x534C43444ELL
可以看到这里的两个十六进制是大端序,但是数据在内存中都是小端序,所以要将其,反转一下。一般在CPU,x86都是小端序,但是IDA将之转换为了大端序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 v3 = 0 v2 = 0 v5 = 10 text = list ("killshadow" ) key = list ("adsfkndcls" ) str2 = [] for i in range (len (text)): for j in range (128 ): if chr (j).isalpha(): k = (j - 39 - ord (key[i]) + 97 ) % 26 + 97 if text[i] == chr (k): str2.append(chr (j)) break print ("flag{" + "" .join(str2) + "}" )
flag:flag{KLDQCUDFZO}
0x0B Java逆向解密 给了一个class文件,用java反编译工具jd-gui打开,关键代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public static void Encrypt (char [] arr) { ArrayList<Integer> Resultlist = new ArrayList <>(); for (int i = 0 ; i < arr.length; i++) { int result = arr[i] + 64 ^ 0x20 ; 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 j = 0 ; j < KEY.length; j++) KEYList.add(Integer.valueOf(KEY[j])); System.out.println("Result:" ); if (Resultlist.equals(KEYList)) { System.out.println("Congratulations); } else { System.err.println(" Error); } } }
做了异或和加减操作,代码很简单,做完操作跟KEY比较。
给出解题代码exp:
1 2 3 4 5 6 7 payload = [180 , 136 , 137 , 147 , 191 , 137 , 147 , 191 , 148 , 136 , 133 , 191 , 134 , 140 , 129 , 135 , 191 , 65 ] flag = [] for i in payload: flag.append(chr ((i-64 )^32 )) print ("flag{" + "" .join(flag) + "}" )
flag:flag{This_is_the_flag_!}
0x0C [GXYCTF2019]luck_guy 丢ida反编译,找到关键函数get_flag,F5反编译,关键代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 case 1 : puts ("OK, it's flag:" ); memset (&s, 0 , 0x28 uLL); strcat ((char *)&s, f1); strcat ((char *)&s, &f2); printf ("%s" , (const char *)&s); break ; case 4 : s = 0x7F666F6067756369 LL; v5 = 0 ; strcat (&f2, (const char *)&s); case 5 : for ( j = 0 ; j <= 7 ; ++j ) { if ( j % 2 == 1 ) *(&f2 + j) -= 2 ; else --*(&f2 + j); } break ;
case1的f1变量的值是GXY{do_not_
,直接点开就看到了,主要是f2的值,case4提到了f2的值是由s拼接的,根据上面讲到的小端存储,所以s的值应该是倒过来的,然后f2又出现在case5,经过简单的移位运算得到了f2.
分析完后编写脚本,exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 flag1 = 'GXY{do_not_' flag2 = '' payload = [0x7F ,0x66 ,0x6F ,0x60 ,0x67 ,0x75 ,0x63 ,0x69 ] payload.reverse() f2 = "" for i in payload: f2 += chr (i) f3 = list (f2) for j in range (8 ): if j % 2 == 1 : f3[j] = ord (f3[j]) - 2 else : f3[j] = ord (f3[j]) - 1 for k in f3: flag2 += chr (k) flag = flag1 + flag2 print (flag)
flag:flag{do_not_hate_me}
0x0D [BJDCTF2020]JustRE ida反编译发现了DialogFunc函数,关键代码:
1 sprintf (String, " BJD{%d%d2069a45792d233ac}" , 19999 , 0 );
flag直接给了,直接提交就好了
flag:flag{1999902069a45792d233ac}
0x0E 简单注册器 下载后发现是一个apk文件,丢到jadx里反编译。查看主函数,关键代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public void onClick (View v) { int flag = 1 ; String xx = editview.getText().toString(); flag = (xx.length() == 32 && xx.charAt(31 ) == 'a' && xx.charAt(1 ) == 'b' && (xx.charAt(0 ) + xx.charAt(2 )) + (-48 ) == 56 ) ? 0 : 0 ; if (flag == 1 ) { 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); textview.setText("flag{" + bbb + "}" ); return ; }
这个代码其实就是混淆,条件要flag等于1才能执行,只需要把下面代码删掉就可以了
1 flag = (xx.length() == 32 && xx.charAt(31) == 'a' && xx.charAt(1) == 'b' && (xx.charAt(0) + xx.charAt(2)) + (-48) == 56) ? 0 : 0;
因为他直接给了exp这里我就不写了照搬就是了,exp如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class test1 implements Serializable { public static void main (String[] args) { int flag = 1 ; if (flag == 1 ) { 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(bbb); } } }
0x0F [GWCTF 2019]pyre python反编译,可以去在线网站直接反编译,也可以用cmake来反编译(推荐)
反编译后得到代码:
1 2 3 4 5 6 7 8 9 10 11 12 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 = ['\x1f' ,'\x12' ,'\x1d' ,'(' ,'0' ,'4' ,'\x01' ,'\x06' ,'\x14' ,'4' ,',' ,'\x1b' ,'U' ,'?' ,'o' ,'6' ,'*' ,':' ,'\x01' ,'D' ,';' ,'%' ,'\x13' ]
先进行的加减取余运算,再进行异或,逆一下就可以解出来了,exp如下:
1 2 3 4 5 6 7 code = ['\x1f' ,'\x12' ,'\x1d' ,'(' ,'0' ,'4' ,'\x01' ,'\x06' ,'\x14' ,'4' ,',' ,'\x1b' ,'U' ,'?' ,'o' ,'6' ,'*' ,':' ,'\x01' ,'D' ,';' ,'%' ,'\x13' ] flag = "" for i in range (len (code)-2 ,-1 ,-1 ): code[i] = chr (ord (code[i])^ord (code[i+1 ])) for i in range (len (code)): flag+=chr ((ord (code[i])-i)%128 ) print (flag)
flag:flag{Just_Re_1s_Ha66y!}
0x10 [ACTF新生赛2020]easyre 下载得到一个apk文件,直接丢到jadx反编译,关键代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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' , '}' };btn.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View v) { char [] x = new char [17 ]; char [] y = new char [38 ]; for (int i = 0 ; i < 17 ; i++) { if ((a[i] < 'I' && a[i] >= 'A' ) || (a[i] < 'i' && a[i] >= 'a' )) { x[i] = (char ) (a[i] + 18 ); } else if ((a[i] >= 'A' && a[i] <= 'Z' ) || (a[i] >= 'a' && a[i] <= 'z' )) { x[i] = (char ) (a[i] - '\b' ); } else { x[i] = a[i]; } }
第一个函数就是对a数组进行一个运算,然后条件进行比对,最后进到最后一个函数输出flag。其实直接照着写函数输出就可以了,但是我在写第二个函数的时候发现运行不出来flag,于是就选择把apk文件装到模拟器里运行,然后把第一个函数运行出来的结果丢进去就得到flag了。
1 2 3 4 5 6 7 8 9 10 11 a = ['T' , 'h' , 'i' , 's' , 'I' , 's' , 'T' , 'h' , 'e' , 'F' , 'l' , 'a' , 'g' , 'H' , 'o' , 'm' , 'e' ] x = [] for i in range (17 ): if (a[i] < 'I' and a[i] >= 'A' ) or (a[i] < 'i' and a[i] >= 'a' ): x.append(chr (ord (a[i])+18 )) elif ((a[i] >= 'A' and a[i] <= 'Z' ) or (a[i] >= 'a' and a[i] <= 'z' )): x.append(chr (ord (a[i])-ord ('\b' ))) else : x.append(a[i])
flag:flag{c164675262033b4c49bdf7f9cda28a75}
0x11 [FlareOn4]login rot18解密(主要是我懒得解,后面补上)
flag:flag{ClientSideLoginsAreEasy@flare-on.com}
0x12 [WUSTCTF2020]level1 拿到文件,丢到ida反编译,关键代码:
1 2 3 4 5 6 7 8 9 10 stream = fopen("flag" , "r" ); fread(ptr, 1uLL , 0x14 uLL, stream); fclose(stream); 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])); }
将文件flag丢给ptr,然后进行运算,简单的逆向运算。
然后还给了output文件:
1 2 3 [198, 232, 816, 200, 1536, 300, 6144, 984, 51200, 570, 92160, 1200, 565248, 756, 1474560, 800, 6291456, 1782, 65536000] # 太占地方了就写成这个样子了
exp如下:
1 2 3 4 5 6 7 8 9 10 11 a = ['0' ,198 , 232 , 816 , 200 , 1536 , 300 , 6144 , 984 , 51200 , 570 , 92160 , 1200 , 565248 , 756 , 1474560 , 800 , 6291456 , 1782 , 65536000 ] b = [] for i in range (1 ,19 ): if ((i & 1 ) != 0 ): a[i] = chr (a[i] >> i) else : a[i] = chr ((int )(a[i]/i)) print (a)
flag:flag{d9-dE6-20c}
0x13 [2019红帽杯]easyRE 丢到ida里,查找字符串的时候就发现了很像base64的东西,复制下来:
1 Vm0wd2VHUXhTWGhpUm1SWVYwZDRWVll3Wkc5WFJsbDNXa1pPVlUxV2NIcFhhMk0xVmpKS1NHVkdXbFpOYmtKVVZtcEtTMUl5VGtsaVJtUk9ZV3hhZVZadGVHdFRNVTVYVW01T2FGSnRVbGhhVjNoaFZWWmtWMXBFVWxSTmJFcElWbTAxVDJGV1NuTlhia0pXWWxob1dGUnJXbXRXTVZaeVdrWm9hVlpyV1hwV1IzaGhXVmRHVjFOdVVsWmlhMHBZV1ZSR1lWZEdVbFZTYlhSWFRWWndNRlZ0TVc5VWJGcFZWbXR3VjJKSFVYZFdha1pXWlZaT2NtRkhhRk5pVjJoWVYxZDBhMVV3TlhOalJscFlZbGhTY1ZsclduZGxiR1J5VmxSR1ZXSlZjRWhaTUZKaFZqSktWVkZZYUZkV1JWcFlWV3BHYTFkWFRrZFRiV3hvVFVoQ1dsWXhaRFJpTWtsM1RVaG9hbEpYYUhOVmJUVkRZekZhY1ZKcmRGTk5Wa3A2VjJ0U1ExWlhTbFpqUldoYVRVWndkbFpxUmtwbGJVWklZVVprYUdFeGNHOVhXSEJIWkRGS2RGSnJhR2hTYXpWdlZGVm9RMlJzV25STldHUlZUVlpXTlZadE5VOVdiVXBJVld4c1dtSllUWGhXTUZwell6RmFkRkpzVWxOaVNFSktWa1phVTFFeFduUlRhMlJxVWxad1YxWnRlRXRXTVZaSFVsUnNVVlZVTURrPQ==
base64解密:
1 https://bbs.pediy.com/thread-254172.htm
访问后在评论区找到了flag
flag:flag{Act1ve_Defen5e_Test}
0x14 [GUET-CTF2019]re 下载文件,丢到exeinfo查壳,发现有upx壳,用工具脱壳也可以用kali自带的脱壳
拿到脱壳后的文件丢到ida里分析,F5反编译后,看到有个sub_4009AE函数,进入后发现有很多的条件,这个其实可以手动的算条件里的a1,但是我看了一下wp说用z3更方便一点,于是就借鉴了一下,也算是学习了。
代码要注意的点是,没有a1[6],17和18是颠倒的。
z3约束器,就是解决方程的,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 38 39 40 from z3 import *s = Solver() a1 = [0 ]*31 for i in range (31 ): a1[i] = Int('a1[' +str (i)+']' ) s.add( 1629056 * a1[0 ] == 166163712 ) s.add( 6771600 * a1[1 ] == 731332800 ) s.add( 3682944 * a1[2 ] == 357245568 ) s.add( 10431000 * a1[3 ] == 1074393000 ) s.add( 3977328 * a1[4 ] == 489211344 ) s.add( 5138336 * a1[5 ] == 518971936 ) s.add( 7532250 * a1[6 ] == 406741500 ) s.add( 5551632 * a1[7 ] == 294236496 ) s.add( 3409728 * a1[8 ] == 177305856 ) s.add( 13013670 * a1[9 ] == 650683500 ) s.add( 6088797 * a1[10 ] == 298351053 ) s.add( 7884663 * a1[11 ] == 386348487 ) s.add( 8944053 * a1[12 ] == 438258597 ) s.add( 5198490 * a1[13 ] == 249527520 ) s.add( 4544518 * a1[14 ] == 445362764 ) s.add( 3645600 * a1[15 ] == 174988800 ) s.add( 10115280 * a1[16 ] == 981182160 ) s.add( 9667504 * a1[17 ] == 493042704 ) s.add( 5364450 * a1[18 ] == 257493600 ) s.add( 13464540 * a1[19 ] == 767478780 ) s.add( 5488432 * a1[20 ] == 312840624 ) s.add( 14479500 * a1[21 ] == 1404511500 ) s.add( 6451830 * a1[22 ] == 316139670 ) s.add( 6252576 * a1[23 ] == 619005024 ) s.add( 7763364 * a1[24 ] == 372641472 ) s.add( 7327320 * a1[25 ] == 373693320 ) s.add( 8741520 * a1[26 ] == 498266640 ) s.add( 8871876 * a1[27 ] == 452465676 ) s.add( 4086720 * a1[28 ] == 208422720 ) s.add( 9374400 * a1[29 ] == 515592000 ) s.add(5759124 * a1[30 ] == 719890500 ) s.check() a = s.model() print (a)
运行完后拿到很多数据,写一个解密脚本:
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 a1 = [0 ]*32 a1[31 ] = 125 a1[30 ] = 55 a1[29 ] = 51 a1[28 ] = 51 a1[27 ] = 57 a1[26 ] = 51 a1[25 ] = 48 a1[24 ] = 99 a1[23 ] = 49 a1[22 ] = 97 a1[21 ] = 57 a1[20 ] = 57 a1[19 ] = 48 a1[18 ] = 51 a1[16 ] = 97 a1[17 ] = 48 a1[15 ] = 98 a1[14 ] = 48 a1[13 ] = 49 a1[12 ] = 49 a1[11 ] = 49 a1[10 ] = 50 a1[9 ] = 52 a1[8 ] = 53 a1[7 ] = 54 a1[5 ] = 101 a1[4 ] = 123 a1[3 ] = 103 a1[2 ] = 97 a1[1 ] = 108 a1[0 ] = 102 for i in range (32 ): if i == 6 : continue print (chr (a1[i]), end="" )
解出来发现少了一个数(也就是刚刚a1[6]那里),于是盲猜呗,0-F一个一个试过去就可以了。 最后拿到flag:
flag:flag{e165421110ba03099a1c039337}
0x15 [SUCTF2019]SignIn 下载文件丢ida反编译,从代码可以看出是RSA算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 v11 = *MK_FP(__FS__, 40LL ); puts ("[sign in]" ); printf ("[input your flag]: " , a2); __isoc99_scanf("%99s" , &v9); sub_96A(&v9, (__int64)&v10); __gmpz_init_set_str((__int64)&v8, (__int64)"ad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35" , 16LL ); __gmpz_init_set_str((__int64)&v7, (__int64)&v10, 16LL ); __gmpz_init_set_str( (__int64)&v5, (__int64)"103461035900816914121390101299049044413950405173712170434161686539878160984549" , 10LL ); __gmpz_init_set_str((__int64)&v6, (__int64)"65537" , 10LL ); __gmpz_powm((__int64)&v7, (__int64)&v7, (__int64)&v6, (__int64)&v5); if ( __gmpz_cmp((__int64)&v7, (__int64)&v8) ) puts ("GG!" ); else puts ("TTTTTTTTTTql!" ); result = 0LL ; v4 = *MK_FP(__FS__, 40LL ) ^ v11; return result;
从上面分析来看,v5是n,v6是指数e,v7就是明文m,v8是密文c。
函数分析:
1 2 3 __gmpz_init_set_str(a,b,c):a是变量,b是值,c是进制 __gmpz_powm(a,b,c,d):四个参数,把b的c次方模d的值赋给a __gmpz_cmp(a,b):a与b进行比较
根据RSA算法,可以先用factor分解一下n(n较小),也可以用网站分解,exp如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 import gmpy2from Crypto.Util.number import *n = 103461035900816914121390101299049044413950405173712170434161686539878160984549 e = 65537 c = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35 p = 366669102002966856876605669837014229419 q = 282164587459512124844245113950593348271 phi = (p - 1 ) * (q - 1 ) d = int (gmpy2.invert(e,phi)) m = pow (c,d,n) print (long_to_bytes(m))
flag:flag{Pwn_@_hundred_years}
0x16 [MRCTF2020]Xor ida分析不了,于是汇编分析:
1 2 .rdata:0041EA08 byte_41EA08 db 4Dh ; DATA XREF: _main+48 ↑r .rdata:0041EA09 aSawbFxzJTqjNBp db 'SAWB~FXZ:J:`tQJ"N@ bpdd}8g' ,0
这里有一个参数,加上0x4D(也就是M),就是MSAWB~FXZ:J:`tQJ”N@ bpdd}8g。
分析汇编代码
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 # byte_4212C0存放的是flag push offset aGiveMeYourFlag ; "Give Me Your Flag String:\n" call sub_401020 push 64h ; 'd' push offset byte_4212C0 push offset aS ; "%s" call sub_401050 mov edx, offset byte_4212C0 add esp, 10h lea ecx, [edx+1] | | # 循环 loc_4010B6: mov al, [edx] inc edx test al, al jnz short loc_4010B6 | | # 判断,不等于27就返回wrong(这里可以知道flag的长度是27) # edx存放的是flag的长度 sub edx, ecx cmp edx, 27 jnz short loc_4010FF | | xor eax, eax db 66h, 66h nop word ptr [eax+eax+00000000h] | | # 异或运算,异或完进行比对 loc_4010D0: mov cl, byte_4212C0[eax] xor cl, al cmp cl, ds:byte_41EA08[eax] jnz short loc_4010FF | | # eax自增,与edx(27)进行比对 inc eax cmp eax, edx jb short loc_4010D0
分析完后编写exp:
1 2 3 4 a = list ('MSAWB~FXZ:J:`tQJ"N@ bpdd}8g' ) for i in range (len (a)): print (chr (ord (a[i])^i),end="" )
flag:flag{@_R3@1ly_E2_R3verse!}