BugKuCtf-逆向-Mountain climbing

35 篇文章 0 订阅
30 篇文章 1 订阅

PEID查询有壳

使用UPX脱壳机DLL 脱壳

使用IDA打开

shit+F12 查看字符串

看到error字样,交叉引用到相关函数。

反编译 查看到该函数的如下代码

int sub_411B70()
{
  int v0; // edx@1
  int v1; // ecx@1
  int v2; // edx@5
  int v3; // ecx@5
  signed int v4; // eax@5
  int v5; // edx@8
  int v6; // ecx@8
  int v7; // edx@15
  int v8; // ecx@15
  int v9; // edx@17
  int v10; // ecx@17
  int v11; // edx@18
  int v12; // ecx@18
  char v14; // [sp+Ch] [bp-154h]@1
  int v15; // [sp+D0h] [bp-90h]@9
  int j; // [sp+DCh] [bp-84h]@3
  int i; // [sp+E8h] [bp-78h]@1
  char flag[104]; // [sp+F4h] [bp-6Ch]@7
  unsigned int v19; // [sp+15Ch] [bp-4h]@1
  int savedregs; // [sp+160h] [bp+0h]@1

  memset(&v14, 0xCCu, 0x154u);
  v19 = (unsigned int)&savedregs ^ __security_cookie;
  srand(0xCu);
  sub_411127(v1, v0);
  j_memset(&unk_423D80, 0, 0x9C40u);
  for ( i = 1; i <= 20; ++i )
  {
    for ( j = 1; j <= i; ++j )
    {
      rand();
      v4 = sub_411127(v3, v2);
      *(&dword_41A138[100 * i] + j) = v4 % 100000;
    }
  }
  print("input your key with your operation can get the maximum:");
  sub_411249("%s", flag);
  if ( j_strlen(flag) == 19 )                   // flag长度为19
  {
    sub_41114F((int)flag);                      // 第一个函数处理
    v15 = 0;
    j = 1;
    i = 1;
    dword_423D78 += dword_41A138[101];
    while ( v15 < 19 )
    {
      if ( flag[v15] == 'L' )
      {
        dword_423D78 += *(&dword_41A138[100 * ++i] + j);
      }
      else
      {
        if ( flag[v15] != 'R' )
        {
          print("error\n");
          system("pause");
          sub_411127(v8, v7);
          goto LABEL_18;
        }
        dword_423D78 += *(&dword_41A138[100 * ++i] + ++j);
      }
      ++v15;
    }
    print("your operation can get %d points\n", dword_423D78);
    system("pause");
    sub_411127(v10, v9);
  }
  else
  {
    print("error\n");
    system("pause");
    sub_411127(v6, v5);
  }
LABEL_18:
  sub_411280(&savedregs, dword_411DF8);
  sub_411294();
  return sub_411127(v12, v11);
}

乍一看很简单,输入长度为19的字符串,字符串里的L与R作为每次的抉择,然后得到某个与i j有关的值,i每次+1,j每次可以++或者不+。值是用随机数生成的,但随机数种子固定,所以每次生成的是一样的。

尝试输入LLLLLLLLLLLLLLLLLLL,却提示error,难道输入的不是L或R吗?

那应该与其他几个函数有关,尤其注意sub41114F

使用OD进行动态调试

在IDA中找到该函数地址 00411C8B                 call    sub_41114F

在OD中对该地址下断点,跟随进入

直到在堆栈或者寄存器出现我们输入的字符串被修改的字样,再停止并进行观察

对该循环运行几遍,即可知道它将双数字符进行了与4异或。所以我们只要将每个双数字符与4异或一下即可变成正常的值

知道H与4异或是L,V与4异或是R

所以尝试输入LHLHLHLHLHLHLHLHLHL

得到该值,然后与一开始的函数中的 得到最大分数提示知道,就是不同的LR得到的分数不同,要得到最高的分数。

所存的数组在这里

for ( i = 1; i <= 20; ++i )
  {
    for ( j = 1; j <= i; ++j )
    {
      rand();
      v4 = sub_411127(v3, v2);
      *(&dword_41A138[100 * i] + j) = v4 % 100000;
    }
  }

while ( v15 < 19 )
    {
      if ( flag[v15] == 'L' )
      {
        dword_423D78 += *(&dword_41A138[100 * ++i] + j);

在堆栈里观察了一下,因为是dword,间隔100就是间隔400字节。所以数据比较多。

但是在下面的while循环观察一下,循环最后一次i的值是19*100,所以只需要i从1到19的数据即可。

修改for循环里的100*i为19*i 。即0x190改为0x4c 因为dword每个数字占据4字节

然后从内存里拷贝数据出来使用Python脚本处理

import re
file_name='reverse.txt'
a=[]
b=[]
with open(file_name) as file_obj:
    for line in file_obj:
        line=line.rstrip().split(" ")[-1]#以空格为间隔 分割字符串
        line=line[4:]#取分割后的第四个往后的
        line='0x'+line#便于转化成16进制
        a.append(line)
del a[-1]#去除后面两个不正常的项
del a[-1]

for i in a:
    b.append(int(i,16))
print (b)

再就是算法问题,使用C++递归写

#include<iostream>
#include <string>
using namespace std;
string opera;
int max=0;
int num[500]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 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, 29052, 1558, 26150, 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, 4078, 28629, 4665, 2229, 24699, 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, 21054, 5225, 11777, 29853, 2956, 22439, 3341, 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, 15512, 12952, 1868, 10888, 19581, 13463, 32652, 3409, 28353, 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, 26170, 1833, 5196, 9794, 26804, 2831, 11993, 2839, 9979, 27428, 6684, 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, 7905, 8373, 19377, 18502, 27928, 13669, 25828, 30502, 28754, 32357, 2843, 5401, 10227, 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, 3, 28024, 22266, 19327, 18114, 18100, 15644, 21728, 17292, 8396, 27567, 2002, 3830, 12564, 1420, 0, 0, 0, 0, 29531, 21820, 9954, 8319, 10918, 7978, 24806, 30027, 17659, 8764, 3258, 20719, 6639, 23556, 25786, 11048, 0, 0, 0, 3544, 31948, 22, 1591, 644, 25981, 26918, 31716, 16427, 15551, 28157, 7107, 27297, 24418, 24384, 32438, 22224, 0, 0, 12285, 12601, 13235, 21606, 2516, 13095, 27080, 16331, 23295, 20696, 31580, 28758, 10697, 4730, 16055, 22208, 2391, 20143, 0, 16325, 24537, 16778, 17119, 18198, 28537, 11813, 1490, 21034, 1978, 6451, 2174, 24812, 28772, 5283, 6429, 15484, 29353, 5942};
int dfs(int i,int j,int sum,string str){
	if(i==20){
		if(sum>max){
			max=sum;
			opera=str;
		}
		return 1;
	}
	int sum1=sum+num[i*19+j];
	dfs(i+1,j,sum1,str+'L');
	int sum2=sum+num[i*19+j];
	dfs(i+1,j+1,sum2,str+'R');
}

int main(){
	dfs(1,1,0,"");
 	cout<<max;
	cout<<opera;
	return 1;
}

运行得到结果

将双数位置的字符 'L'改成'H','R'改成'V'即可。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值