此题的关键在于动调,使我一个只会 F5 的菜鸡受益匪浅
加了 UPX 壳,工具没脱下来,手动脱了后运行不了(悲),看了 wp 说是要用 UpxUnpacker,亲测有效
先查看字符串,看到一个 Success,进去瞧一眼
整不明白,动调试试,首先是函数最开始的 lp 其实就是我们输入,这里我输入了 10 个 1
接下来一直往下走,到 Success 判断的部分,可以看到传入的 v7 是一个疑似 base64 的东西
接下来就需要更严谨地验证一下这个猜想,进入到 sub_401233 中,函数很长,但有一部分很可疑
长这样的语句一般与 base64 码表的生成有关,通过动调看一下
OD 定位到此处,运行几次循环,可以看到正在生成的码表
跳出循环就可以看到生成的新码表了
然后验证一下,与之前得到的数据一致,证明新表就是它
接下来就看到 Success 前的验证函数 sub_401F0A,先看到函数返回的部分
虽然不知道 v34 是个啥,但总之 v6 不能为 0,所以看到前面一个 if 判断,需要这个 if 满足才可以,以及在这个 if 内还有一个会 break 的看起来很可疑的比较
sub_4034D0 进去完全看不懂在干啥,动调看一下返回值,连续试了几个后发现返回的是输入内容加密后(3 变 4)的字符串长度,需要满足长度为 48 也就是说输入长度要在 34~36 之间
接下来继续看 sub_402160
传入的是正经 base64 表和加密后的输入,查看 sub_403500
还是看不懂,继续动调几次发现
即返回的是加密后的每个字符在正经 base64 表中的下标(从 1 开始)
然后看到与之作比较的数组
取出来 48 个写脚本得到变表加密后的密文
#include <bits/stdc++.h> using namespace std; int a[50] = {0x08, 0x3B, 0x01, 0x20, 0x07, 0x34, 0x09, 0x1F, 0x18, 0x24, 0x13, 0x03, 0x10, 0x38, 0x09, 0x1B, 0x08, 0x34, 0x13, 0x02, 0x08, 0x22, 0x12, 0x03, 0x05, 0x06, 0x12, 0x03, 0x0F, 0x22, 0x12, 0x17, 0x08, 0x01, 0x29, 0x22, 0x06, 0x24, 0x32, 0x24, 0x0F, 0x1F, 0x2B, 0x24, 0x03, 0x15, 0x41, 0x41}; string s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int main() { for (int i = 0; i < 48; i++) { int num = int(a[i]); cout << s[num - 1]; } return 0; }
得到:"H6AfGzIeXjSCP3IaHzSBHhRCEFRCOhRWHAohFjxjOeqjCU",解密即可
flag{E_L4nguag3_1s_K3KeK3_N4Ji4}