简单逆向22

35 篇文章 5 订阅

诺莫22

知识点:
算法逆向,文件读写

开始:

使用IDA打开:
在这里插入图片描述
upx字段

脱壳:
1.软件脱壳:
介绍两个软件:
下载

UPX工具使用及加壳

upx官网
(1)upx
upx -d 绝对路径
(2)upxtool:
打开脱壳
2.手动脱壳:
使用OD打开,找到popa后的大段跳转,使用脱壳工具修正入口点,但这个方法我试过会报错,原因是我使用的win11系统的地址和以往的不一样。

将脱壳后的程序放入IDA:
因为没有main函数,我们通过搜索字符串定位到关键函数
在这里插入图片描述

int v6; // ecx
  char *v7; // eax
  int v8; // edx
  int v9; // ecx
  int v10; // ST04_4
  int v11; // ST08_4
  char v13; // [esp+0h] [ebp-134h]
  char Buf; // [esp+D0h] [ebp-64h]
  size_t i; // [esp+100h] [ebp-34h]
  FILE *File; // [esp+10Ch] [ebp-28h]
  char v17; // [esp+118h] [ebp-1Ch]
  int v18; // [esp+130h] [ebp-4h]
  int savedregs; // [esp+134h] [ebp+0h]

  sub_411208((int)&unk_41C008);
  sub_41137A("Input Your Flag:\n");
  sub_41137F("%19s", &v17);
  if ( a1 != 2 )
  {
    sub_41137A("Input error!\n");
    exit(1);
  }
  sub_41137A("%s\n", *(_DWORD *)(a2 + 4));
  for ( i = 0; i < j_strlen(*(const char **)(a2 + 4)); ++i )
    *(_BYTE *)(*(_DWORD *)(a2 + 4) + i) += i;
  if ( !j_strcmp(unk_41A068, *(const char **)(a2 + 4)) )
  {
    v4 = fopen(*(const char **)(a2 + 4), "r");
    File = (FILE *)sub_411212(v6, v5, &v13 == &v13, (int)v4, xmm0_4_0);
    if ( File )
    {
      v7 = fgets(&Buf, 40, File);
      sub_411212(v9, v8, &v13 == &v13, (int)v7, xmm0_4_0);
      if ( j_strlen(&Buf) != 32 || j_strlen(&Buf) % 2 == 1 )
        exit(1);
      sub_4113B1(&Buf, (int)&unk_41A4E0);
      if ( sub_4113B6((int)&unk_41A4E0) )
        sub_41137A("flag{%s}", &Buf);
      else
        sub_41137A("Input Error!\n");
    }
    else
    {
      sub_41137A("Input Error!\n");
    }
  }
  else
  {
    sub_41137A("Input Error!\n");
  }
  sub_411235(&savedregs, dword_4154C4, 0, v3);
  return sub_411212((unsigned int)&savedregs ^ v18, v11, 1, v10, xmm0_4_0);
}

修改一下参数类型好看一点:

int __usercall sub_415280@<eax>(int xmm0_4_0@<xmm0>, int a1, int **a2)
{
  int v3; // edx
  FILE *v4; // eax
  int v5; // edx
  int v6; // ecx
  char *v7; // eax
  int v8; // edx
  int v9; // ecx
  int v10; // ST04_4
  int v11; // ST08_4
  int v13; // [esp+0h] [ebp-134h]
  char Buf; // [esp+D0h] [ebp-64h]
  size_t i; // [esp+100h] [ebp-34h]
  FILE *File; // [esp+10Ch] [ebp-28h]
  char v17; // [esp+118h] [ebp-1Ch]
  int v18; // [esp+130h] [ebp-4h]
  int savedregs; // [esp+134h] [ebp+0h]

  sub_411208(&unk_41C008);
  printf("Input Your Flag:\n");
  scanf(xmm0_4_0, "%19s", &v17);
  if ( a1 != 2 )
  {
    printf("Input error!\n");
    exit(1);
  }
  printf("%s\n", a2[1]);
  for ( i = 0; i < j_strlen(a2[1]); ++i )
    *(a2[1] + i) += i;
  if ( !j_strcmp(Str1, a2[1]) )
  {
    v4 = fopen(a2[1], "r");
    File = sub_411212(v6, v5, &v13 == &v13, v4, xmm0_4_0);// 返回第四个位置的数
    if ( File )
    {
      v7 = fgets(&Buf, 40, File);
      sub_411212(v9, v8, &v13 == &v13, v7, xmm0_4_0);
      if ( j_strlen(&Buf) != 32 || j_strlen(&Buf) % 2 == 1 )
        exit(1);
      sub_4113B1(&Buf, &unk_41A4E0);
      if ( sub_4113B6(&unk_41A4E0) )
        printf("flag{%s}", &Buf);
      else
        printf("Input Error!\n");
    }
    else
    {
      printf("Input Error!\n");
    }
  }
  else
  {
    printf("Input Error!\n");
  }
  sub_411235(&savedregs, dword_4154C4, 0, v3);
  return sub_411212(&savedregs ^ v18, v11, 1, v10, xmm0_4_0);
}

倒着看

sub_4113B1(&Buf, &unk_41A4E0);
      if ( sub_4113B6(&unk_41A4E0) )
        printf("flag{%s}", &Buf);
      else
        printf("Input Error!\n");

要输出flag,sub_4113B6(&unk_41A4E0)返回非0
进入sub_4113B6(&unk_41A4E0):

int __usercall sub_411D90@<eax>(int xmm0_4_0@<xmm0>, int *a1)
{
  int v2; // edx
  int *v3; // ecx
  int v4; // eax
  signed int i; // [esp+D0h] [ebp-8h]

  sub_411208(&unk_41C008);
  for ( i = 0; i < 16; ++i )
  {
    v3 = a1;
    v2 = a1[i] + 1;
    if ( v2 != dword_41A078[i] )
    {
      v4 = 0;
      return sub_411212(v3, v2, 1, v4, xmm0_4_0);
    }
  }
  v4 = 1;
  return sub_411212(v3, v2, 1, v4, xmm0_4_0);
}

与dword_41A078[i]作比较
查看dword_41A078数据:
在这里插入图片描述
发现只有8组有效数据,这里遍历了16次;会不会在前面由直接对这个地址赋值的操作;
打开sub_4113B1(&Buf, &unk_41A4E0);:

int __usercall sub_414E50@<eax>(int a1@<xmm0>, char *Str, int a3)
{
  unsigned int v3; // eax
  int v4; // edx
  int v5; // ecx
  int v7; // [esp+D0h] [ebp-14h]
  signed int i; // [esp+DCh] [ebp-8h]

  sub_411208(&unk_41C008);
  dword_41A078[8] = 0xA7;
  dword_41A078[9] = 0xDE;
  dword_41A078[10] = 0xDA;
  dword_41A078[11] = 0x46;
  dword_41A078[12] = 0xAB;
  dword_41A078[13] = 0x2E;
  dword_41A078[14] = 0xFF;
  dword_41A078[15] = 0xDB;
  for ( i = 0; ; i += 2 )
  {
    v3 = j_strlen(Str);
    if ( i >= v3 )
      break;
    if ( Str[i] >= 48 && Str[i] <= 57 )
    {
      *(a3 + 4 * (i / 2)) = Str[i] - 48;
    }
    else
    {
      if ( Str[i] < 97 || Str[i] > 102 )
      {
        printf("Input Error!\n");
        exit(0);
      }
      *(a3 + 4 * (i / 2)) = Str[i] - 87;
    }
    *(a3 + 4 * (i / 2)) *= 16;
    if ( Str[i + 1] >= 48 && Str[i + 1] <= 57 )
    {
      v7 = Str[i + 1] - 48;
    }
    else
    {
      if ( Str[i + 1] < 97 || Str[i + 1] > 102 )
      {
        printf("Input Error!\n");
        exit(0);
      }
      v7 = Str[i + 1] - 87;
    }
    *(a3 + 4 * (i / 2)) += v7;
  }
  return sub_411212(v5, v4, 1, v3, a1);
}

果然有:
在这里插入图片描述
那我们可以推出unk_41A4E0的数据:

a1 = [0x00000050, 0x000000C6, 0x000000F1, 0x000000E4, 0x000000E3, 0x000000E2, 0x0000009A, 0x000000A1, 0xA7, 0xDE, 0xDA, 0x46, 0xAB, 0x2E, 0xFF, 0xDB]
cons = []
for n in range(16):
    cons.append(a1[n] - 1)
print(cons)

再看一下上面的sub_4113B1(&Buf, &unk_41A4E0),
算法简单,将字符串转两位两位的换位为10进制:
这个能找出buf变量,就是unk_41A4E0数据的字符形式:

a1 = [0x00000050, 0x000000C6, 0x000000F1, 0x000000E4, 0x000000E3, 0x000000E2, 0x0000009A, 0x000000A1, 0xA7, 0xDE, 0xDA, 0x46, 0xAB, 0x2E, 0xFF, 0xDB]
cons = []
buf = ""
for n in range(16):
    cons.append(a1[n] - 1)
print(cons)
for i in cons:
    buf += str(hex(i)).replace("0x","")
print(buf)

找到了buf也就找到了字符穿:
在这里插入图片描述
flag{4fc5f0e3e2e199a0a6ddd945aa2dfeda}
但是密码似乎并不是
在这里插入图片描述
前面的代码似乎就逆向出了一个flag.txt。
这里有点愣逼,希望大佬指点

  • 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、付费专栏及课程。

余额充值