20211101bugku_re_mountain_climbing

查壳,UPX壳而已,脱脱脱!

>upx.exe -d c:\Users\dell\Desktop\mountain.exe -o climbing.exe
						Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2020
UPX 3.96w       Markus Oberhumer, Laszlo Molnar & John Reiser   Jan 23rd 2020

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
upx: c:\Users\dell\Desktop\mountain.exe: CantUnpackException: file is modified/hacked/protected; take care!!!

Unpacked 0 files.

大意了,用ESP定律脱壳,成功。(一定一定要走到函数开始时才脱,要不然脱不干净,导致运行脱壳后程序闪退)查找字符串定位主函数

__int64 main_0()
{
  int v0; // edx
  __int64 v1; // ST04_8
  char v3; // [esp+0h] [ebp-160h]
  int v4; // [esp+D0h] [ebp-90h]
  int j; // [esp+DCh] [ebp-84h]
  int i; // [esp+E8h] [ebp-78h]
  char Str[104]; // [esp+F4h] [ebp-6Ch]

  srand(0xCu);
  j_memset(dword_423D80, 0, 0x9C40u);
  for ( i = 1; i <= 20; ++i )
  {
    for ( j = 1; j <= i; ++j )
      dword_41A138[100 * i + j] = rand() % 100000;
  }
  ((void (__cdecl *)(const char *, char))sub_41134D)("input your key with your operation can get the maximum:", v3);
  sub_411249("%s", (unsigned int)Str);
  if ( j_strlen(Str) == 19 )
  {
    sub_41114F(Str);
    v4 = 0;
    j = 1;
    i = 1;
    dword_423D78 = dword_41A138[101];
    while ( v4 < 19 )
    {
      if ( Str[v4] == 76 )//'L'
      {
        dword_423D78 = dword_41A138[100 * ++i + j];//'L'增加行
      }
      else
      {
        if ( Str[v4] != 82 )//'R'
        {
          ((void (__cdecl *)(const char *, char))sub_41134D)("error\n", v3);
          system("pause");
          goto LABEL_18;
        }
        dword_423D78 = dword_41A138[100 * ++i + ++j];//'R'增加列
      }
      ++v4;
    }
    sub_41134D("your operation can get %d points\n", 0);
    system("pause");
  }
  else
  {
    ((void (__cdecl *)(const char *, char))sub_41134D)("error\n", v3);
    system("pause");
  }
LABEL_18:
  HIDWORD(v1) = v0;
  LODWORD(v1) = 0;
  return v1;
}

写出算法看一下这个数组

int matric[20][20]={0};
int i,j;
srand(12);
for(i=0; i<20; i++)
{
    for(j=0; j<=i; j++)
    {
        matric[i][j] = rand()%100000;
        printf("%6d",matric[i][j]);
    }
    printf("\n");    
}
/*随机数种子固定,表的值也是固定的
    77
  5628  6232
 29052  1558 26150
 12947 29926 11981 22371
  4078 28629  4665  2229 24699
 27370  3081 18012 24965  2064 26890
 21054  5225 11777 29853  2956 22439  3341
 31337 14755  5689 24855  4173 32304   292  5344
 15512 12952  1868 10888 19581 13463 32652  3409 28353
 26151 14598 12455 26295 25763 26040  8285 27502 15148  4945
 26170  1833  5196  9794 26804  2831 11993  2839  9979 27428  6684
  4616 30265  5752 32051 10443  9240  8095 28084 26285  8838 18784  6547
  7905  8373 19377 18502 27928 13669 25828 30502 28754 32357  2843  5401 10227
 22871 20993  8558 10009  6581 22716 12808  4653 24593 21533  9407  6840 30369  2330
     3 28024 22266 19327 18114 18100 15644 21728 17292  8396 27567  2002  3830 12564  1420
 29531 21820  9954  8319 10918  7978 24806 30027 17659  8764  3258 20719  6639 23556 25786 11048
  3544 31948    22  1591   644 25981 26918 31716 16427 15551 28157  7107 27297 24418 24384 32438 22224
 12285 12601 13235 21606  2516 13095 27080 16331 23295 20696 31580 28758 10697  4730 16055 22208  2391 20143
 16325 24537 16778 17119 18198 28537 11813  1490 21034  1978  6451  2174 24812 28772  5283  6429 15484 29353  5942
  7299  6961 32019 24731 29103 17887 17338 26840 13216  8789 12474 24299 19818 18218 14564 31409  5256 31930 26804  9736
*/

也就是将这数组每行最大的元素相加,得到最高分。因为我们只能输入“L”或“R”,并且长度为19,那就全都输入“L”运行一下试试。还是显示“error”。再仔细看一下代码,sub_41114F利用了我们输入的字符串,说明很可能这个函数将我们输入的字符串替换成“L”或“R”,所以我们直接输入“L”或“R”是错的。

  if ( j_strlen(Str) == 19 )//输入长度为19
  {
    sub_41114F(Str);

进入函数,开始一系列套娃

int __cdecl sub_41114F(int a1)
{//a1就是输入的字符串
  return sub_411900(a1);
}

int sub_411900()
{
  sub_4110A5(nullsub_1, (char *)sub_411994 - (char *)nullsub_1, 4);
  return nullsub_1();
}

int __cdecl sub_4110A5(LPCVOID lpAddress, int a2, int a3)
{
  return sub_411750(lpAddress, a2, a3);
}

BOOL __cdecl sub_411750(LPCVOID lpAddress, int a2, int a3)
{
  int v3; // ST1C_4
  DWORD flOldProtect; // [esp+D4h] [ebp-2Ch]
  struct _MEMORY_BASIC_INFORMATION Buffer; // [esp+E0h] [ebp-20h]

  VirtualQuery(lpAddress, &Buffer, 0x1Cu);
  VirtualProtect(Buffer.BaseAddress, Buffer.RegionSize, 0x40u, &Buffer.Protect);
  while ( 1 )
  {
    v3 = a2--;
    if ( !v3 )
      break;
    *(_BYTE *)lpAddress ^= a3;//字符串与a3异或,a3是sub_411900()的第三个参数4
    lpAddress = (char *)lpAddress + 1;
  }
  return VirtualProtect(Buffer.BaseAddress, Buffer.RegionSize, Buffer.Protect, &flOldProtect);
}

也就是说我们输入的字符串异或4才是“L”或“R”,转换一下

char a='L';
char b='R';
printf("'L'转换成%c\n",a^4);
printf("'R'转换成%c",b^4);
//'L'转换成H
//'R'转换成V

输入19个“H”再运行,还是“error”。给我看代码!在循环中还有a2,而且a2非常重要,它是循环计数器。a2是sub_411900()函数中的第二个参数(char *)sub_411994 - (char *)nullsub_1。但点击sub_411994打开不了。

  while ( 1 )
  {
    v3 = a2--;//循环计数器
    if ( !v3 )
      break;
    *(_BYTE *)lpAddress ^= a3;//字符串与a3异或,a3是sub_411900()的第三个参数4
    lpAddress = (char *)lpAddress + 1;
  }

实在没办法了,用OD看看输入的字符串怎么变化的。输入19个“L”发现竟然是下标奇数位变为“H”,而偶数位维持原样“L”。尝试输入“LH…”,总算出结果了。

input your key with your operation can get the maximum:LHLHLHLHLHLHLHLHLHL
your operation can get 303755 points

知道了这个规律之后,现在就是想办法让数组的某些数值相加最大。虽然说“L”增加行,“R”增加列,但还是不知道路线到底是怎么走的,只能用递归将所有情况都走一遍。(生活不易,不会写递归的直接去世呜呜呜呜呜)

int aa[20] = { 0 };
static int matric[20][20] = { 0 };
static int global_max;
void dfs(int x, int y, int sum)
{
    sum += matric[x][y];
    if (x + 1 == 20)
    {
        if (sum > global_max)
        {
            global_max = sum;
            printf("%d:", global_max);
            for (int i = 0; i < 19; i++)
            {
                if (aa[i] == 1)
                    printf("L");
                else if (aa[i] == 0)
                    printf("R");
                else
                {
                    printf("error\n");
                    return;
                }
            }
            printf("\n");
        }
        return;
    }

    aa[x] = 1;
    dfs(x + 1, y, sum);

    aa[x] = 0;
    dfs(x + 1, y + 1, sum);
}

int main()
{
    int i, j;
    srand(12);
    for (i = 0; i < 20; i++)
    {
        for (j = 0; j <= i; j++)
        {
            matric[i][j] = rand() % 100000;
        }
    }
    global_max = 0;
    dfs(0, 0, 0);
}
/*
303755:LLLLLLLLLLLLLLLLLLL
311629:LLLLLLLLLLLLLLLLLRL
336687:LLLLLLLLLLLLLLLLLRR
337003:LLLLLLLLLLLLLLLLRLR
340349:LLLLLLLLLLLLLLLRLLL
365407:LLLLLLLLLLLLLLLRLLR
385717:LLLLLLLLLLLLLRLLLLR
409956:LLLLLLLLLLRLLLLLLLR
414282:LLLRRRLLLLLRRLRLLLR
417845:LLLRRRLRLLLLRLRLLLR
418308:LLLRRRLRRRRRRRRRLRL
421759:LLRLRRLLLLLRRLRLLLL
431261:LLRLRRLLLLLRRLRLLLR
434824:LLRLRRLRLLLLRLRLLLR
435287:LLRLRRLRRRRRRRRRLRL
435796:RRRRRLLRRLLRRRRRLRL
436700:RRRRRLLRRLRRLRLLRRL
437600:RRRRRLLRRLRRLRRRLRL
438528:RRRRRLLRRRLLLLRRRRL
440237:RRRRRLLRRRLLRRLLRRL
441137:RRRRRLLRRRLLRRRRLRL
443840:RRRRRLLRRRLRLRLLRRL
444740:RRRRRLLRRRLRLRRRLRL
*/

可见最大的就是444740的“RRRRRLLRRRLRLRRRLRL”,将奇数位下标异或4

char a[20]="RRRRRLLRRRLRLRRRLRL";
for(int i=0; i<19; i++)
{
    if(i%2)
        a[i] ^= 0x4;
    printf("%c",a[i]);
}
//RVRVRHLVRVLVLVRVLVL

我的博客,欢迎来玩!https://v5le0n9.github.io/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值