Bugku-Rev-Mountain climbing
萌新头大,QwQ
第一步:脱壳
拿到附件首先查壳,发现有 upx 壳,尝试解压失败了,莫得办法手动脱壳
(因为我是萌新并且记性不好,为避免忘记如何脱壳,在此记录,同时也方便像我一样的萌新能有做题体验,如果他们能看到这篇博客的话www)
能够独立完成脱壳的请直接至第二步
用 OD 打开,看到开头的 pushad 指令,pushad 的功能是将所有寄存器的值复制到栈
按 F8 单步执行一下,我们可以看到 ESP 的值变了
在这里设置硬件断点,执行过去,然后再删除断点,继续单步执行,发现在图示位置进入了一个小循环
直接跳过这个循环执行到下一个 jmp
那么这里就是程序的 OEP,使用 ollydump 插件弄出来就可以,脱壳工作到此结束
我感觉我说的云里雾里的,算了我尽力了,不录视频真的不好解释www
第二步:分析
把脱壳后的程序用 IDA 打开,先看看字符串,没啥特别的,直接去看main_0
看到这里,先简单分析一下
简单来讲就是,输入字符串长度是 19 并且输入的字符串索引的单个字符如果是 L 或者 R 就会索引 dword 数组(暂且先不用知道是什么,后面会提到)里的元素并且累加
并且可以看出如果当前字符为 L 就会影响 dword 数组的 i++,而为 R 则使得 i++ 且 j++
这个题目的意思是要使最后累加得到的 sum 是最大的
再来看 dword 数组是个啥东西
srand(0xCu);
sub_4110C3(dword_423D80, 0, 40000);
for ( i = 1; i <= 20; ++i )
{
for ( j = 1; j <= i; ++j )
dword_41A138[100 * i + j] = rand() % 100000;
}
这个 dword 的数组由伪随机数生成,随机数种子一定,那么rand出来的数是一定的
于是我们就可以得到这个 dword 数组的亚子:
#include <bits/stdc++.h>
using namespace std;
int main() {
srand(12);
for (int i = 1; i <= 20; i++) {
for (int j = 1; j <= i; j++)
printf("%7d", rand() % 100000);
puts("");
}
return 0;
}
那么就是从左上角 77 的位置开始向下走,尽量使路过的值累加起来最大,于是可以遍历得到路径
#include <bits/stdc++.h>
using namespace std;
const int maxn = 20;
char behavior[maxn];
int ans;
int mountain[maxn][maxn] = {
{ 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 5628, 6232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 29052, 1558, 26150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 12947, 29926, 11981, 22371, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 4078, 28629, 4665, 2229, 24699, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 27370, 3081, 18012, 24965, 2064, 26890, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 21054, 5225, 11777, 29853, 2956, 22439, 3341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 31337, 14755, 5689, 24855, 4173, 32304, 292, 5344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 15512, 12952, 1868, 10888, 19581, 13463, 32652, 3409, 28353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 26151, 14598, 12455, 26295, 25763, 26040, 8285, 27502, 15148, 4945, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 26170, 1833, 5196, 9794, 26804, 2831, 11993, 2839, 9979, 27428, 6684, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 4616, 30265, 5752, 32051, 10443, 9240, 8095, 28084, 26285, 8838, 18784, 6547, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 7905, 8373, 19377, 18502, 27928, 13669, 25828, 30502, 28754, 32357, 2843, 5401, 10227, 0, 0, 0, 0, 0, 0, 0,},
{ 22871, 20993, 8558, 10009, 6581, 22716, 12808, 4653, 24593, 21533, 9407, 6840, 30369, 2330, 0, 0, 0, 0, 0, 0,},
{ 3, 28024, 22266, 19327, 18114, 18100, 15644, 21728, 17292, 8396, 27567, 2002, 3830, 12564, 1420, 0, 0, 0, 0, 0,},
{ 29531, 21820, 9954, 8319, 10918, 7978, 24806, 30027, 17659, 8764, 3258, 20719, 6639, 23556, 25786, 11048, 0, 0, 0, 0,},
{ 3544, 31948, 22, 1591, 644, 25981, 26918, 31716, 16427, 15551, 28157, 7107, 27297, 24418, 24384, 32438, 22224, 0, 0, 0,},
{ 12285, 12601, 13235, 21606, 2516, 13095, 27080, 16331, 23295, 20696, 31580, 28758, 10697, 4730, 16055, 22208, 2391, 20143, 0, 0,},
{ 16325, 24537, 16778, 17119, 18198, 28537, 11813, 1490, 21034, 1978, 6451, 2174, 24812, 28772, 5283, 6429, 15484, 29353, 5942, 0,},
{ 7299, 6961, 32019, 24731, 29103, 17887, 17338, 26840, 13216, 8789, 12474, 24299, 19818, 18218, 14564, 31409, 5256, 31930, 26804, 9736,}
};
inline void print() {
printf("%9d: ", ans);
for (int i = 0; i < 19; i++) {
if (behavior[i] == 'R') printf("R");
else if (behavior[i] == 'L') printf("L");
else {
fprintf(stderr, "Error\n");
exit(-1);
}
}
puts("");
}
inline void dfs(int x, int y, int sum) {
sum += mountain[y][x];
if (y + 1 == 20) {
if (sum > ans) {
ans = sum;
print();
}
return;
}
behavior[y] = 'L';
dfs(x, y + 1, sum);
behavior[y] = 'R';
dfs(x + 1, y + 1, sum);
}
int main() {
dfs(0, 0, 0);
return 0;
}
最终的路径就是:RRRRRLLRRRLRLRRRLRL
但是还没完,当在程序中输入我们得到的路径时,会发现他输出了 erro,那么就要考虑一下是不是有某个地方影响了我们输入的内容,回头看看可以发现一个 sub_41114F(Str),那么它可能就对输入的参数造成了某些影响,于是我们回到 OD 看看这个函数究竟干了些什么
找到这个函数的地址并下断点,执行到这里
在数据窗口跟随一下,试了试经过这个函数,发现输入的值改变了,于是可以确定这个函数确实影响了我们输入的数值
那么接下来就跟进这个函数看一看,首先调用了call 004110A5,这个函数结束后,后面的汇编代码会发生改变,继续一路跟进
发现这里不断循环输入的每一个字符,且有条件的把原字符 xor 4,继续执行一会,发现是隔一位异或一次
例如:
LLLLLLLLLLLLLLLLLLL ——> LHLHLHLHLHLHLHLHLHL(偶数列的L变成H)
RRRRRRRRRRRRRRRRRRR ——> RVRVRVRVRVRVRVRVRVR(偶数列的R变成V)
于是有:
RRRRRLLRRRLRLRRRLRL ——> RVRVRHLVRVLVLVRVLVL
flag:zsctf
如果还是没懂可以看看大佬视频:https://www.bilibili.com/video/av47087534/