简单逆向21

35 篇文章 5 订阅

诺莫21

知识点:
动态调试,亦或,爆破

开始:

放入IDA:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  _DWORD *v4; // [esp+1Ch] [ebp-A0h]
  int v5; // [esp+20h] [ebp-9Ch]
  int v6; // [esp+24h] [ebp-98h]
  int v7; // [esp+28h] [ebp-94h]
  int v8; // [esp+2Ch] [ebp-90h]
  char v9; // [esp+30h] [ebp-8Ch]
  int v10; // [esp+50h] [ebp-6Ch]
  int v11; // [esp+70h] [ebp-4Ch]

  sub_402620();
  v5 = 1701148529;
  v6 = 101;
  v7 = 0;
  v8 = 0;
  v4 = malloc(0x408u);
  puts("Plz solve the puzzle:");
  sub_40ED00("%32s", &v9);
  if ( check1(&v9)
    && (sub_401B60(&v10, &v9), sub_401850(v4, &v5, strlen(&v5)), sub_4018D0(v4, &v10, 8), sub_401950(&v10)) )
  {
    sub_401BA0(&v9, &v11);
    sub_40ED20("Congrats!\n%s\n", &v11);
  }
  else
  {
    puts("Failed!");
  }
  return 0;
}

逻辑简单
Congrats上面有个if,让if成立就正确

check1(&v9):
在这里插入图片描述
判断输入的字符16位a-f或者0-9(注意:0-9能满足是因为v2前面是unsigned,数字减去58是负数,会溢出结果大于0x38)

在这里插入图片描述
&&后面是一个,运算符,就是只看最后一个(如a = (1,2,3)最终a = 3),那我们直接看最后一个函数:
sub_401950(&v10):

bool __cdecl sub_401950(_BYTE *a1)
{
  _BYTE *v1; // ecx
  bool result; // al

  v1 = a1;
  while ( 2 )
  {
    switch ( *v1 )
    {
      case 0:
        dword_40F028 &= dword_40F038;
        dword_40F02C *= dword_40F028;
        goto LABEL_4;
      case 1:
        if ( !dword_40F02C )
          goto LABEL_6;
        dword_40F028 /= dword_40F02C;
        dword_40F024 += dword_40F034;
        goto LABEL_4;
      case 2:
        dword_40F030 ^= dword_40F034;
        dword_40F03C += dword_40F020;
        goto LABEL_4;
      case 3:
        dword_40F03C -= dword_40F030;
        dword_40F030 &= dword_40F024;
        goto LABEL_4;
      case 4:
        dword_40F034 *= dword_40F020;
        dword_40F02C -= dword_40F038;
        goto LABEL_4;
      case 5:
        dword_40F020 ^= dword_40F02C;
        dword_40F038 -= dword_40F03C;
        goto LABEL_4;
      case 6:
        if ( !dword_40F03C )
          goto LABEL_6;
        dword_40F034 |= dword_40F024 / dword_40F03C;
        dword_40F024 /= dword_40F03C;
        goto LABEL_4;
      case 7:
        dword_40F038 += dword_40F028;
        dword_40F034 |= dword_40F024;
        goto LABEL_4;
      case 8:
        dword_40F020 *= dword_40F02C;
        dword_40F030 -= dword_40F03C;
        goto LABEL_4;
      case 9:
        dword_40F028 += dword_40F034;
        dword_40F02C ^= dword_40F030;
LABEL_4:
        if ( ++v1 != a1 + 8 )
          continue;
        result = (dword_40F038 == 231)
               + (dword_40F034 == 14456)
               + (dword_40F030 == 14961)
               + (dword_40F02C == -13264)
               + (dword_40F028 == 16)
               + (dword_40F024 == 104)
               + (dword_40F020 == -951) == 7;
        if ( dword_40F03C != -239 )
          goto LABEL_6;
        break;
      default:
LABEL_6:
        result = 0;
        break;
    }
    return result;
  }
}

从代码中得知v10一共由8位,每一位是0-9的数字,我们就可以利用条件暴力破解:

#include<stdio.h>

int f(int* a1);
void f2(int a1, int* a2);

int main(void)
{
	int num[8];
	for (int i = 10000000;i < 1000000000; i++)
	{
		f2(i, num);
		if (f(num))
		{
			printf("%d", i);
			break;
		}
	}

	return 0;
}

void f2(int a1, int* a2)
{
	int i = 0;

	for (i = 7; i >= 0; i--)
	{
		a2[i] = a1 % 10;
		a1 = a1 / 10;
	}
}


int f(int* num)
{
	int
		dword_40F000 = 0x0000000A,
		dword_40F020 = 0x0000008A,
		dword_40F024 = 0x000001A1,
		dword_40F028 = 0x0000012A,
		dword_40F02C = 0x00000269,
		dword_40F030 = 0x00000209,
		dword_40F034 = 0x00000068,
		dword_40F038 = 0x0000039F,
		dword_40F03C = 0x000002C8;
	int result;
	int i = 0;

	while(1)
	{
		switch (num[i])
		{
		case 0:
			dword_40F028 &= dword_40F038;
			dword_40F02C *= dword_40F028;
			goto LABEL_4;
		case 1:
			if (!dword_40F02C)
				goto LABEL_6;
			dword_40F028 /= dword_40F02C;
			dword_40F024 += dword_40F034;
			goto LABEL_4;
		case 2:
			dword_40F030 ^= dword_40F034;
			dword_40F03C += dword_40F020;
			goto LABEL_4;
		case 3:
			dword_40F03C -= dword_40F030;
			dword_40F030 &= dword_40F024;
			goto LABEL_4;
		case 4:
			dword_40F034 *= dword_40F020;
			dword_40F02C -= dword_40F038;
			goto LABEL_4;
		case 5:
			dword_40F020 ^= dword_40F02C;
			dword_40F038 -= dword_40F03C;
			goto LABEL_4;
		case 6:
			if (!dword_40F03C)
				goto LABEL_6;
			dword_40F034 |= dword_40F024 / dword_40F03C;
			dword_40F024 /= dword_40F03C;
			goto LABEL_4;
		case 7:
			dword_40F038 += dword_40F028;
			dword_40F034 |= dword_40F024;
			goto LABEL_4;
		case 8:
			dword_40F020 *= dword_40F02C;
			dword_40F030 -= dword_40F03C;
			goto LABEL_4;
		case 9:
			dword_40F028 += dword_40F034;
			dword_40F02C ^= dword_40F030;
		LABEL_4:
			if (++i != 8)
				continue;
			result = (dword_40F038 == 231)
				+ (dword_40F034 == 14456)
				+ (dword_40F030 == 14961)
				+ (dword_40F02C == -13264)
				+ (dword_40F028 == 16)
				+ (dword_40F024 == 104)
				+ (dword_40F020 == -951) == 7;
			if (dword_40F03C != -239)
				goto LABEL_6;
			break;
		default:
		LABEL_6:
			result = 0;
			break;
		}
		return result;
	}
}

//result = 61495072

结果是61495072

然后思考:v10肯定是v9推到的,所以我们能逆向推出v9,就得出答案

sub_401B60(&v10, &v9):

int __cdecl sub_401B60(int a1, _BYTE *a2)
{
  _BYTE *v2; // ebx
  int i; // esi
  char v4; // ST08_1
  _BYTE *v5; // ST00_4
  int result; // eax

  v2 = a2;
  for ( i = a1; *v2; result = sub_40ED40(v5, "%02X", v4) )
  {
    v4 = i;
    v5 = v2;
    v2 += 2;
    ++i;
  }
  return result;
}

将v5(a2)的数据,v4(a1)数据放到一个函数中处理。
函数中还有%02X,猜测是把输入的数据(字符串)转换为16进制存到v10

使用OD动态可以验证:
在这里插入图片描述
数据一样

然后观察后面的两个函数
sub_401850:
因为传入的是两个已知数据和一个未知数据,可以使用动态得出未知数据v4

sub_401850:
传入了v10我们得看看对v10做改变没

_DWORD *__cdecl sub_4018D0(_DWORD *tab, _BYTE *sou, int a3)
{
  int v3; // edx
  int v4; // ecx
  _DWORD *v5; // esi
  _BYTE *v6; // ebx
  int v7; // edi
  unsigned int *v8; // eax
  int v9; // edx
  _DWORD *v10; // ebp
  _DWORD *v11; // ST00_4
  unsigned int v12; // ebp
  _DWORD *result; // eax

  v3 = *tab;
  v4 = tab[1];
  v5 = tab + 2;
  if ( a3 > 0 )
  {
    v6 = sou;
    v7 = *tab;
    do
    {
      v7 = (v7 + 1);
      v8 = &v5[v7];
      v9 = *v8;
      v4 = (*v8 + v4);
      v10 = &v5[v4];
      v11 = v10;
      v12 = *v10;
      *v8 = v12;
      *v11 = v9;
      *v6++ ^= v5[(v9 + v12)];
    }
    while ( v6 != &sou[a3] );
    v3 = v7;
  }
  result = tab;
  *tab = v3;
  tab[1] = v4;
  return result;
}

v5[(v9 + v12)]都是已知数据
使用OD动态调试:
在这里插入图片描述
找到8个数据
tab = [0x7c,0xab,0x2d,0x91,0x2f,0x98,0xed,0xa9]
然后因为前面是%02x,两字节对齐,所以后面v10就只有8位
写出逆向脚本:

tab = [0x7c,0xab,0x2d,0x91,0x2f,0x98,0xed,0xa9]
v10 = [0x6,0x1,0x4,0x9,0x5,0x0,0x7,0x2]
flag = ""

for i in range(8):
    ch = tab[i]^v10[i]
    print("%x"%ch, end = "")

结果:7aaa29982a98eaab

输入7aaa29982a98eaab得到flag

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

I Am Rex

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值