研究生阶段重拾CTF,未来的路还是喜欢网络攻防,既然喜欢那就坚持下去吧。
Guess-the-Number
用Android Kill打开或者用Java Decompiler打开。
重点在guess_number函数,只有当my_number/5==guess_number时,打印出正确信息的if块,跟进去以后发现if块中的内容和guess_numbe没啥关系。因此最终guess_number应该为my_number/5=309137378。在命令行中执行命令,即可得到flag。
1 | a7b08c546302cc1fd2a4d48bf2bf2ddb |
Shuffle1
拖进IDA,找到main函数,F5。
1 | SECCON{Welcome to the SECCON 2014 CTF!} |
re-for-50-plz-50
发现是MIPS的文件,咱也不知道是什么啊!!!!
然后没管直接打开,结果发现转函数时:
额,MIPS文件不能够直接用F5查看伪代码。
最后经过查找资料,了解到MIPS是一个指令集
与汇编时不同的两个东西~~
必须恶补一下!!!
找到一篇好的文章~
https://www.cnblogs.com/thoupin/p/4018455.html
找一下关键的部分。
发现了一段字符串和异或(XOR),尝试一下提取出来运算试试。
1 | #!/usr/bin/python |
1 | TUCTF{but_really_whoisjohngalt} |
dmd-50
进去之后发现需要比对一个字符串780438d5b6e29db0898bc4f0225935c0,但是从上面有经过一个md5函数,提取出来在线解一下。
发现结果是grape但是类型是经过了两次md5加密的,猜测需要输入的flag是grape进行md5加密一次,测试发现正确。
1 | b781cbb29054db12f88f08c6e161c199 |
parallel-comparator-200
是一道C语言代码审计的题目。
1 |
|
关键代码分析
1 | generated_string[i] = *(char *)result + just_a_string[i]; |
写出对应的脚本:
1 |
|
1 | #!/usr/bin/python |
secret-galaxy-300
拖进去发现主函数就两个函数,跟进去之后也没有什么特别的。
拖进OD尝试动态调试一下。
直接在输出相应的语句的地方下个断点。
运行到这里,右键智能搜索一下字符串。
发现了一个可疑的字符串,aliens_are_around_us。提交就是flag
1 | aliens_are_around_us |
srm-50
一共两个检查的地方,一个检查邮箱一个检查数字。检查邮箱的地方发现只要有@和.这两个就可以了。重点是后面的if,简单的运算一下就能知道值。
1 | CZ9dmq4c8g9G7bAX |
simple-check-100
进去之后发现最主要的地方就是check_key函数,看一下汇编代码。
发现check_key函数是否成功就取决于eax函数的值。
使用gdb调试,下断点运行到test这条语句,查看一下rax寄存器的值。
这里rax的值为0,我们将其修改为1。
然后continue,执行就能得到flag。
1 | flag_is_you_know_cracking!!! |
Mysterious
很简答的一道题。
可以看到判断里面v10=123,v12、v13、v14分别是xyz,因为上一条语句v10=atoi(&string)+1。所以应该输入的值为122,再加上后面三个参数xyz。
Newbie_calculations
这题也是很有意思的,看得有点眼睛痛。
main函数里面一堆函数调用,最后打印出v120[]数组里面的值,也就是需要的flag,仔细看了一下之后发现就是3个函数。
sub_401000、sub_401100、sub_401220
这个函数一堆操作,但是我们只关心a1和a2。第一个循环减了v4次,第二个有加了v5次,最后还加了一次,简化一下,发现最后的结果就是返回两个值相加。
接下来依次分析剩下的两个函数。最后可以得到如下结果:
sub_401000函数返回两数相加
sub_401100函数返回两数相乘
sub_401220函数返回两数相减
将整个函数重新写一遍运行出来:
1 |
|
re1-100
拿到先file查一下看看。
64位直接进ida。
shift+F12进字符串表,定位到关键字符串处。
跟进去找到引用函数,F5。
一大堆东西,看到我们的输入都存在了bufWrite里面。然后又把bufWrite写进了bufParentRead里。前面的几个函数看函数名是检查是否开启Debugger模式和检查输入是字符串还是数字。看到后面重点来了。
开头结尾为{},字符串长度42。前10位和后10位分别为53fc275d81和4938ae4efd。最后和{daf29f59034938ae4efd53fc275d81053ed5be8c}做比较,中间要经过一个confuseKey函数。跟进confuseKey函数看一下。
过程简单,现将input分成四个部分,然后分别存进szPart1,2,3,4中。然后利用strcat函数调换顺序为3412,存入input中。
因此只需将之前得到的字符串{daf29f59034938ae4efd53fc275d81053ed5be8c},分成4分按照1234的顺序排好即可。最终的flag为:
1 | 53fc275d81053ed5be8cdaf29f59034938ae4efd |
answer_to_everything
跟进not_the_flag()函数
额,很简单,只要输入42就行了,结果就是kdudpeh。
根据题目描述要经过一下sha1。
1 | flag{80ee2a3fe31da904c596d993f7f1de4827c1450a} |
elrond32
找到main函数,可以参考运行函数的时候需要跟一个参数,这个参数就是input。
程序判断很简单,跟进sub_8048414函数。
发现是switch函数,只有值为0,1,3,4,5,6,7,9时才有值。对传入的值进行(input + 1, 7 * (a2_0 + 1) % 11)操作,然后继续调用该函数。把这个函数写一下跑一遍,或者直接手算出来。可以得到
1 | isengard |
运行该程序就能得到flag。
1 | flag{s0me7hing_S0me7hinG_t0lki3n} |
或者将得到的结果跟进下面的函数中,直接跑也可以出结果。
1 | key=[105,115,101,110,103,97,114,100] |
gametime
很好玩的一道题目。一个小游戏,s—>’ ‘,m—>’m’,x—>’x’。看见什么字母按对应的就可以了,
玩个几轮就能拿到flag
或者尝试用OD调试,nop掉sub_401260函数的返回。
因为是最后返回值的判断,而且是连续两个判断,OD中找到sub_401260函数。
找到函数的最后ret的地方向上找发现箭头指的两个判断跳转是跳转至结束。所以就是最后v4!=-1&&v4==v2这两个句子,把它nop掉。
这样程序会正常运行但是在跑的时候即使输入错误也不会跳转到结束。
跟着程序一通乱按就行了。
tt3441810
拿到手发现是文本文件。
用sublime打开。
前面第一个数明显是地址,后面的是数据,把它导入到WinHex中看看。
可以看到开头有fl之类的字符,我们写个脚本把可显示字符输出出来试试。
1 | #!/usr/bin/python |
结果出来有很多多余的东西,把他们都清除掉。
可以的到flag{poppopret},最后提交的结果需要去掉flag{}。
1 | poppopret |
re2-cpp-is-awesome
打开ida,找到main函数。
前面的函数经过分析发现没啥用,没有提示输入,参数是在运行参数跟着的。主要的判断函数在34行。仔细看右边的比较是数组里面嵌套数组。
off_6020A0数组里面是“L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1t”
dword_6020C0[v15]里面(注意align是地址对齐的伪指令,align=8意味着隔着8字节一取)。
dword_6020C0=[ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00,
0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x29, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x00, 0x00]
注意因为8字节一取,所以第一个数0x24到0x05之间有一个数是0x00不能漏掉了。将中间多余的0去掉可以了。
给出脚本:
1 | #!/usr/bin/python |
1 | ALEXCTF{W3_L0v3_C_W1th_CL45535} |
re4-unvm
打开是一个pyc文件,https://tool.lu/pyc/这个网站可以反编译得到py文件。
1 | #!/usr/bin/env python |
可以看到有一个md5之后的数组,函数的逻辑就是输入的字符串md5加密之后要和数组做比较,因此只需要进行md5解密就可以了。
两个md5在线解密网站,有一个需要收费,就换两一个解,然后拼接起来就可以了。
1 | ALEXCTF{dv5d4s2vj8nk43s8d8l6m1n5l67ds9v41n52nv37j481h3d28n4b6v3k} |
流浪者
这题有一些难度但是其实还好,就两个函数比较复杂一点。
可以分析得到输入的字符串先进行一个判断,字符在48~57时减48, 97~122时减87, 65~90时减29。
将得到的数存入到v5[]数组中,然后将数组传入sub_4017F0(v5)函数中,跟进函数。
这段伪代码的意思是通过接收一个变量v5来控制数组aAbcdefghiabcde的角标获取数组中的字符并赋值给Str1,通过Str1与字符串“KanXueCTF2019JustForhappy”进行比较,如果相同则返回pass!
所以我们可以将”KanXueCTF2019JustForhappy”进行逆运算,得到Str1,就是获得flag。
根据过程写出代码:
1 | #!/usr/bin/python |
1 |
|
得到的结果加上flag{}
1 | flag{j0rXI4bTeustBiIGHeCF70DDM} |
666
进去之后发现只有一个加密函数encode()。需要对比的字符串是 enflag=”izwhroz””w”v.K”.Ni”
逻辑也很简单,将输入的字符串按照下标模3的余数分组,分别进行简单的运算,结果和enflag比较。
直接逆算法即可,异或可以直接原样操作回去。
1 | #!/usr/bin/python |
这里有两个小地方需要注意,一是enflag字符串中含有””所以需要用\转义一下,否则会报错。二是因为+-运算符的优先级高于 ^ 运算所以要多加一个括号,先进行 ^运算。
1 | unctf{b66_6b6_66b} |
SignIn
进去之后找到main函数。
进去之后发现主要的就是一个RSA过程,其中输入会经过一个sub_96A的函数。
写一个对应的脚本看看大概是干嘛的
1 | #!/usr/bin/python |
1 | output:41424344454647 |
尝试了几个参数,发现它的作用是将一串输入转化为 16 进制 ASCII 码的形式出来。
根据21行gmpz_powm函数中的参数(&v6, &v6, &v5, &v4);
对比RSA中求明文的m = pow(c, d, N)
可以得知v6存储密文,v5存储d,v4存储N。
现在已知
1 | N=103461035900816914121390101299049044413950405173712170434161686539878160984549 |
尝试将N分离http://factordb.com/ 貌似需要翻墙才能访问,可以下载yafu来分解。
得到pq的值。
1 | p = 366669102002966856876605669837014229419 |
已知q、p、e可以直接求到d,最后直接解出明文即可。
1 | #!/usr/bin/python3 |
1 | suctf{Pwn_@_hundred_years} |
easy_Maze
maze类:1.内存中画出一张地图(地图变换) 2.明确起点和终点 3.(四个字符对应上下左右)flag就是走出的路径
题目提示是maze类的,找上面三个关键点。先进到main函数
逻辑很明确,step_0,step_1,step_2。
分别进去看看
可以看到step_0,step_1两个步骤是把地图进行更改,step_2是判断移动是否正确。
本来将前两个步骤解出来得到正确的地图就能解题了。看了 Step_0 函数, 还是简单的, 但是 step_1 中嵌套了2个函数且很复杂. 开始我就把生成矩阵的所有函数及数据都复制到VC 再根据栈的特点改下数据的顺序, 然后运行打印出矩阵. 问题是运行后什么也没有打印, 调试发现一个函数中的内存空间和另外一个冲突, 相互覆盖值. 这个函数太多, 改起来也麻烦.
然后转向GDB调试, 但是不熟练. 又转向ida动态调试. 先下断点, 找到储存矩阵的空间的地址, 把这个地址转到数据窗口跟随. 运行到生成矩阵的下面一个函数. 得到生成的矩阵.
具体过程如下,ida动态调试教程看这个http://smalltime.work/2020/12/03/ida%E5%8A%A8%E6%80%81%E8%B0%83%E8%AF%95elf-%E6%97%A0%E5%9D%91%E8%AF%A6%E7%BB%86/
进入ida动态调试后,我们在step_2处下一个端点,然后运行程序,
然后找到右边RSP寄存器的地址。
找到Hex View中的对应数据,并且右键修改显示的格式。(设置为4byte_Integer和Signed),Hex View中右键Sychronize with—>RSP,就可以跟随到RSP所在的位置。
可以找到我们需要的数据,后面有多的不要紧我们取前49个就可以了,之前分析得到我们的迷宫是7*7的。
1 | 1,0,0,1,1,1,1, |
把迷宫排列一下就可以了,之前代码中可以分析到我们要从[0] [0]走到[6] [6]去,也就是迷宫中左上角走到右下角,上下左右分别对应wsad。
1 | UNCTF{ssddwdwdddssaasasaaassddddwdds} |
ReverseMe-120
进去之后发现还是有点复杂。
最后的地方就是对比,和you_know_how_to_remove_junk_code做对比。
上面的过程一开始看不懂,进到sub_401000函数里面。后来去问了一下和搜了一下发现前面的操作就是base64解密操作。逻辑就清楚了,将输入的字符串进行base64解密,然后按位和0x25做异或操作,将结果和you_know_how_to_remove_junk_code做对比。
那么解密过程也简单了,将you_know_how_to_remove_junk_code按位异或0x25然后进行base64加密。
1 | #!/usr/bin/env python3 |
1 | XEpQek5LSlJ6TUpSelFKeldASEpTQHpPUEtOekZKQUA= |
Reversing-x64Elf-100
这题挺简单的。就是一个输入加字符串修改,然后对比。
重点在sub_4006FD函数里面
v3是一个二维数组,每个字符减去输入求差值要为1。解密就把这些字符对应减1就行了。
1 | #!/usr/bin/env python3 |
1 | Code_Talkers |
IgniteMe
首先file一个看到是32位PE文件,直接ida打开,进去之后找到main函数。可以看到完整的逻辑过程。
首先判定了一下长度,检查输入的字符串的开头为EIS{结尾为}。花括号中间的字符串判定在第32行中的sub_4011C0函数中,跟进去看一看。(部分变量名和函数名为了方便我修改了一下)
逻辑过程很清楚,首先将输入的字符串括号中的部分赋值给v8,然后进行大小写转换,大写变小写,小写变大写,接着进行一些数值运算(第33行),具体为
1 | byte4420B0[i](v8^0x55)+72 |
最后和字符串作比较,写脚本爆破即可:
1 | #!/usr/bin/python |
debug
额,这题是一道典型的.NET题目,用对应的反编译程序打开,这里推荐dnSpy和ILSpy.具体的代码如下:
1 | using System; |
可以发现是将字符串与数组中的每个数都进行异或一次,然后将结果进行一次md5加密。解密代码如下:
1 | #!/usr/bin/python |
看大佬的wp发现还有另一种更加简单的方式,利用dnSpy进行动态调试。
我们先用dnSpy打开程序,并且找到相应的代码,在第16行,也就是比较处下断点,然后点击start,接着再点一次,此时会弹窗输入,随意输入一些字符,运行到断点处就会发现下面有对应的flag出现了。(好像提交的时候需要大写Flag)
1 | flag{967DDDFBCD32C1F53527C221D9E40A0B} |
hackme
还是按照老规矩丢进ida里面。找到关键函数
中间的过程有很多复杂的步骤都是用不到的。去掉一些不需要的语句。
1 | v18 = i == 22; |
逻辑也比较容易看出来,只是那个sub_406D90那个函数一直不知道是干嘛的,动态调试之后发现每次返回的值v6都不一样,估计是一个随机数生成函数。具体的逻辑就是:输入22个字符,生成10个随机数作为序号取byte_6B4270数组中的字符进行验证,因为异或操作具有可逆性,所以只需要反过来写就可以了。
1 | #!/usr/bin/python |
1 |
|
1 | flag{d826e6926098ef46} |
babyRE
这道题一开始不会做,后来看别人的wp学到了不少东西。
1 | int __cdecl (int argc, const char **argv, const char **envp) |
这道题逻辑是很简单的,判断输入的flag长度为14,判断函数就是judge。但是问题在于judge函数因为被用了SMC自解码,所以不能够直接看到汇编代码,对此有两个解决方法。
第一种是利用IDC脚本将代码直接在IDA中还原,关于这个代码不太明白是怎么写出来的,希望有大佬能指导一下。(IDC脚本可以直接复制到ida最下面然后回车就可以了)
1 | auto start,i,a; |
然后我们再去查看judge的函数对应的汇编代码。
1 | 55 push rbp |
另一种方法是通过ida的动态调试。如何使用ida动态调试可以看我之前的博客http://smalltime.work/2020/12/03/ida%E5%8A%A8%E6%80%81%E8%B0%83%E8%AF%95elf-%E6%97%A0%E5%9D%91%E8%AF%A6%E7%BB%86/。
我们可以看到从[rbp-13h]开始一直到[rbp-20h]一共有14条赋值语句。
猜测与后面的异或有关系。接下来我们下一个断点,并且运行程序然后进行单步调试。
Debugger—>Debugger Windows—>watch view,然后右键add watch在里面输入(int)ecx,我们就可以看到ecx的值了。经过单步调试可以发现ecx值到0x0D的时候就跳出循环了,正好对应了前面的数组长度。
因此可以猜测是将数组与ecx的值进行异或运算。代码如下:
1 | #!/usr/bin/python |
1 | flag{n1c3_j0b} |
EASYHOOK
这道题其实没有太搞懂,看题目是hook,所以找到了sub_401220函数然后一路向下找,最后找到了sub_401000函数,逻辑倒是还比较好懂。
看了其他人的wp之后写出了对应的解密代码:
1 | #!/usr/bin/python |
1 | flag{Ho0k_w1th_Fun} |
EasyRE
这道题一开始是瞎撞出来的,整体还是比较简单。找到关键的函数sub_401080,进去之后如下:
重点是3个我框起来的部分,明确的是input的长度是24,需要理解和注意的地方是24行v2 = (char *)&v8 + 7,由定义部分我们可以看到input的地址是ebp-24h(ebp-36),而v8的地址是ebp-14h(ebp-20),24行的语句将v8的地址+7处的字符赋值给了v2。根据栈的性质,由低地址向高地址生长。假如此时我的输入是abcdefghijklmnopqrstuvwx,那么在栈中的情况就应该是:
高地址 | ebp-13 | x | |
---|---|---|---|
\ | ebp-14 | w | |
\ | … | … | |
\ | ebp-20 | q | |
\ | … | … | |
↓ | ebp-35 | b | |
低地址 | ebp-36 | a |
也就是说第24行的语句就是将输入的字符串取逆序的过程,最后一个框中的内容是将字符串逐个字符取出+1然后^6。最后与unk_402124中的字符串(xIrCj~<r|2tWsv3PtI\x7Fzndka)做对比。过程比较简单可以直接逆算法,代码如下:
1 | #!/usr/bin/python |
1 | flag{xNqU4otPq3ys9wkDsN} |
babymips
ida进去之后会发现没有办法反编译F5,同时汇编代码也不太能读懂,因为这是另一种 架构 mips 。ida有相应的插件例如jeb等,安装好之后就能看到伪C代码了。
1 |
|
其中的check2可以在ida中找到相应的数组。
1 | 0x51, 0x7C, 0x6A, 0x7B, 0x67,0x52, 0xFD, 0x16, 0xA4, 0x89, 0xBD, 0x92, 0x80, 0x13, 0x41, 0x54, 0xA0, 0x8D, 0x45, 0x18, 0x81, 0xDE, 0xFC, 0x95, 0xF0, 0x16, 0x79, 0x1A, 0x15, 0x5B, 0x75, 0x1F, 0x00 |
根据源码写出相应的exp即可:
1 | #!/usr/bin/python |
1 | qctf{ReA11y_4_B@89_mlp5_4_XmAn_} |
reverse-for-the-holy-grail-350
额,这道题看着看着看晕了,对我来说有点难,整体的流程倒是很容易就能够找到。主要的逻辑函数在stringMod中:
1 | __int64 __fastcall stringMod(__int64 *a1) |
根据以上的分析写出对应的解密脚本即可:
1 | #!/usr/bin/env python3 |
我的代码很烂,因此去搜了一下其他大佬的wp写的很简洁,可以参考一下:
1 | #!/usr/bin/python3 |
1 | tuctf{AfricanOrEuropean?} |
serial-150
secret-string-400
又发现了一个新的类型题目,下载题目之后发现是.gz文件,在Linux下解压之后得到两个文件task.html和machine.js,熟悉web流程的都知道这是配套的。
这个html文件是可以直接打开成网页的,配套的js文件里面过于复杂看不太懂,去网上找了一下相关的wp,大佬给出了一个解决办法,可以修改js代码里的run函数输出相应的log。
这样F12里面console会输出相应的调试代码。
1 | new 0pcode1,z,alert(1);//êObjectÿ ÿÿÿ |
里面给了一个数组ex和一个字符串nonce=”groke”,还有的操作就是异或了,不管先将数组中的值与字符串异或输出试试。
1 | #!/usr/bin/env python3 |
1 | flag is: WOW_so_EASY |
crazy
这道题本身不难,怪自己心浮气躁没有细心的好好分析。64位的elf程序,拖进ida中查找字符。
发现了可惜字符跟进去看看。
可以看到是C++的程序,所以整体看上去比较凌乱,重点在于27行、46行、56行和57行。
27行对应的是cin输入,46行跟进去看看。
发现将input的值存入了v23+16的位置和v23+48的位置,两者的差值为32,并且在v23+80的位置存入了一个字符串,长度也为32位。
56行的代码如下
会发现3个关键的地方,第一个是判定字符串的长度为32,这里的额this+16代表的就是之前的v23,之所以+16是因为刚才input的值是从v23+16的地方开始存储的。接着将v23+16位置的值依次进行异或和加法运算,下面同样如此。最后来看57行
首先for循环中将this+80位置开始的值存入v1中,前面已经说过v23+80的值存入的是一个字符串。接着if语句来判断v23+16的值与v23+80中的值是否相等即可。
那么分析之后我们的流程和逻辑就清晰了,我们输入的字符串长度为32,每个字符会经过两次异或和加法运算,得到的结果与系统中的字符串匹配。脚本的结果输入到程序中拿flag。
1 | #!/usr/bin/env python3 |
1 | flag{tMx~qdstOs~crvtwb~aOba}qddtbrtcd} |
运行脚本得到的值放到程序中跑一下就能得到flag。
Windows_Reverse1
逻辑及其清晰,但是很怪的题目,给自己提醒不要过分依赖于IDA的F5,多看汇编多用OD调试。
将我们的输入放入sub_401000函数中但是最后的check处却是用的check_buf做比较,先进到函数中看看再说。
input-v1的值赋给v4,在后面的do while循环中将byte_402FF8数组中的值以v1[v4]为下标赋给v1。
1.其中input是通过函数传参的方式,v1是通过压栈的方式传递的参数。
2.最迷惑的地方是v1[v4]这个地方,注意到v1[v4]其实也可以写成v1+v4,在刚开始的时候v1+v4等于input,随着v1的递增v1[v4]也会遍历input数组中的各个元素的地址。
3.而地址又怎么能作为数组的索引呢? 这里就是 IDA 背锅了, 换言之, 做题还是不能太依赖于反编译后的伪代码. 查看了反汇编代码后, 发现其实是将input字符串中的字符本身作为byte_402FF8的索引, 取值后放入v1数组中。
4.查看位于byte_402FF8的值。
这一堆问号更是懵了,这里就要考验你思维的连贯性了. 要知道ASCII编码表里的可视字符就得是32往后了, 所以, byte_402FF8里凡是位于32以前的数统统都是迷惑项. 不会被索引到的. 往下看, 咦? 这一坨是什么. 再一算地址的差值. 没错, 这一坨就是与a1数组中的各个元素进行替换的字符 !
1 | hexData=[ |
另外在看其他大佬的wp的时候发现可以用OD调试,我自己去调试之后发现根据自己输入的值会得到对应的值输入,比如:输入123456得到mlkjih,并且调换输入顺序之后映射跟着调换。查了一下ASCII表发现,这些对应的值的特点是相加之和均为158,也就是说我们输入的值被158减去之后就是输出值,输出值要与字符串DDCTF{reverseME}相匹配即可。
1 | #!/usr/bin/env python3 |
这个代码就很简洁了,虽然过程并不严谨,仅供参考吧,放出一个大佬的WPhttps://www.52pojie.cn/thread-1180981-1-1.html