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/

posted @ 2021-05-31 17:15  Moominn  阅读(145)  评论(0编辑  收藏  举报