逆向入门--攻防世界进阶Re题解

前言

摸鱼选手表示最近鱼儿很多。。。好吧我摊牌了,最近忙着考驾照,真折磨人啊,赶紧补一补入门的逆向,不然白给了要。本次准备写两个Re的题解,都是来自攻防世界的进阶

正言

re1-100

自从上次入门后,现在做题的顺序基本摸清了,并且现在的题还没有出现啥花指令这些恶心内容,先把文件放到exeinfope中查看文件属性:
在这里插入图片描述
64位的ELF文件,直接拖到IDApro来看吧:

// TAGS: ['file']
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  __pid_t v3; // eax
  size_t v4; // rax
  ssize_t v5; // rbx
  bool v6; // al
  char **argva; // [rsp+0h] [rbp-1D0h]
  bool bCheckPtrace; // [rsp+13h] [rbp-1BDh]
  ssize_t numRead; // [rsp+18h] [rbp-1B8h]
  ssize_t numReada; // [rsp+18h] [rbp-1B8h]
  char bufWrite[200]; // [rsp+20h] [rbp-1B0h]
  char bufParentRead[200]; // [rsp+F0h] [rbp-E0h]
  unsigned __int64 v13; // [rsp+1B8h] [rbp-18h]

  argva = (char **)argv;
  v13 = __readfsqword(0x28u);
  bCheckPtrace = detectDebugging();
  if ( pipe(pParentWrite) == -1 )
    exit(1);
  if ( pipe(pParentRead) == -1 )
    exit(1);
  v3 = fork();
  if ( v3 != -1 )
  {
    if ( v3 )
    {
      close(pParentWrite[0]);
      close(pParentRead[1]);
      while ( 1 )
      {
        printf("Input key : ", argva);
        memset(bufWrite, 0, 0xC8uLL);
        gets(bufWrite, 0LL);
        v4 = strlen(bufWrite);
        v5 = write(pParentWrite[1], bufWrite, v4);
        if ( v5 != strlen(bufWrite) )
          printf("parent - partial/failed write", bufWrite);
        do
        {
          memset(bufParentRead, 0, 0xC8uLL);
          numReada = read(pParentRead[0], bufParentRead, 0xC8uLL);
          v6 = bCheckPtrace || checkDebuggerProcessRunning();
          if ( v6 )
          {
            puts("Wrong !!!\n");
          }
          else if ( !checkStringIsNumber(bufParentRead) )
          {
            puts("Wrong !!!\n");
          }
          else
          {
            if ( atoi(bufParentRead) )
            {
              puts("True");
              if ( close(pParentWrite[1]) == -1 )
                exit(1);
              exit(0);
            }
            puts("Wrong !!!\n");
          }
        }
        while ( numReada == -1 );
      }
    }
    close(pParentWrite[1]);
    close(pParentRead[0]);
    while ( 1 )
    {
      memset(bufParentRead, 0, 0xC8uLL);
      numRead = read(pParentWrite[0], bufParentRead, 0xC8uLL);
      if ( numRead == -1 )
        break;
      if ( numRead )
      {
        if ( childCheckDebugResult() )
        {
          responseFalse();
        }
        else if ( bufParentRead[0] == '{' )
        {
          if ( strlen(bufParentRead) == 42 )
          {
            if ( !strncmp(&bufParentRead[1], "53fc275d81", 0xAuLL) )
            {
              if ( bufParentRead[strlen(bufParentRead) - 1] == '}' )
              {
                if ( !strncmp(&bufParentRead[31], "4938ae4efd", 0xAuLL) )
                {
                  if ( !confuseKey(bufParentRead, 42) )
                  {
                    responseFalse();
                  }
                  else if ( !strncmp(bufParentRead, "{daf29f59034938ae4efd53fc275d81053ed5be8c}", 0x2AuLL) )
                  {
                    responseTrue();
                  }
                  else
                  {
                    responseFalse();
                  }
                }
                else
                {
                  responseFalse();
                }
              }
              else
              {
                responseFalse();
              }
            }
            else
            {
              responseFalse();
            }
          }
          else
          {
            responseFalse();
          }
        }
        else
        {
          responseFalse();
        }
      }
    }
    exit(1);
  }
  exit(1);
}

main全放上来了,其中__readfsqword(0x28u)这一段代码我见过不下三回了,这段代码是通常用于alarm函数,防止调试,后续我们还可以看到这里存在很多反调试的机制,因为这个题一调试就没了。。。

v6 = bCheckPtrace || checkDebuggerProcessRunning();这里还存在两个反调试的,这里就没跟进了,因为题目既然不想让我们反调试,那么说明考点不在这。

来看主要的逻辑:
在这里插入图片描述
bufParentRead申请了一块内存,接着讲在pParentWrite[0]读取到的数据存储在bufParentRead中,其实也就是我们输入的,通过if判断我们可以知道,如果想responseTrue()执行,则这一段输入的长度是42,而且以{}为开头结尾,很大概率这就是flag
既然要!strncmp,也就是说两者要相等,可以发现输入的前十位必须是53fc275d81,第31位开始是4938ae4efd,也就是说输入必须是
{53fc275d81********************4938ae4efd}中间我们是不知道的,接下来就是一个confuseKey,跟进发现这是一个十分低级的混淆:

bool __cdecl confuseKey(char *szKey, int iKeyLength)
{
char szPart1[15]; // [rsp+10h] [rbp-50h]
char szPart2[15]; // [rsp+20h] [rbp-40h]
char szPart3[15]; // [rsp+30h] [rbp-30h]
char szPart4[15]; // [rsp+40h] [rbp-20h]
unsigned __int64 v7; // [rsp+58h] [rbp-8h]

v7 = __readfsqword(0x28u);
*(_QWORD *)szPart1 = 0LL;
*(_DWORD *)&szPart1[8] = 0;
*(_WORD *)&szPart1[12] = 0;
szPart1[14] = 0;
*(_QWORD *)szPart2 = 0LL;
*(_DWORD *)&szPart2[8] = 0;
*(_WORD *)&szPart2[12] = 0;
szPart2[14] = 0;
*(_QWORD *)szPart3 = 0LL;
*(_DWORD *)&szPart3[8] = 0;
*(_WORD *)&szPart3[12] = 0;
szPart3[14] = 0;
*(_QWORD *)szPart4 = 0LL;
*(_DWORD *)&szPart4[8] = 0;
*(_WORD *)&szPart4[12] = 0;
szPart4[14] = 0;
if ( iKeyLength != 42 )
  return 0;
if ( !szKey )
  return 0;
if ( strlen(szKey) != 42 )
  return 0;
if ( *szKey != '{' )
  return 0;
strncpy(szPart1, szKey + 1, 10uLL);
strncpy(szPart2, szKey + 11, 0xAuLL);
strncpy(szPart3, szKey + 21, 0xAuLL);
strncpy(szPart4, szKey + 31, 0xAuLL);
memset(szKey, 0, iKeyLength);
*szKey = '{';
strcat(szKey, szPart3);
strcat(szKey, szPart4);
strcat(szKey, szPart1);
strcat(szKey, szPart2);
szKey[41] = '}';
return 1;
}

逻辑应该十分清晰了,直接就是分成四块,然后按照3412的顺序重新拼接得到的是{daf29f59034938ae4efd53fc275d81053ed5be8c},因此直接还原就行,duck不必写脚本
{53fc275d81053ed5be8cdaf29f59034938ae4efd}

srm-50

拿到文件同样是先看看是什么属性的文件:
在这里插入图片描述
是一个win32gui,打开后发现是一个要输入邮箱和number的程序:
在这里插入图片描述
还是老样子,放到IDApro里一探究竟:
既然主体就是一个窗口,那么我们首先肯定是找WinMain
在这里插入图片描述
这个函数的详解也说明一下:

  • 函数原型:
    int DialogBoxParam(HINSTANCE hInstance,LPCTSTR IpTemplateName,HWND hWndParent, DLGPROC IPDialogFunc,LPARAM dwlnitParam);

参数:
hlnstance:标识一个模块的实例,该模块的可执行文件含有对话框模板。
IpTemplateName:标识对话框模板。此参数可以指向一个以NULL结尾的字符串的指针,该字符串指定对话框模扳名,或是指定对话框模板的资源标识符的一个整型值。如果此参数指定了一个资源标识符,则它的高位字一定为零,且低位字一定含有标识符。一定用MAKEINTRESOURCE宏指令创建此值。
hWndParent:指定拥有对话框的窗口。
IpDialogFunc:指向对话框过程的指针。有关更详细的关于对话框过程的信息,请参见DialogProc。
dwInitParam:指定传递到对话框过程中的 WM_INITDIALOG 消息 IParam 参数的值。
返回值:如果函数调用成功则返回值为在对函数EndDialog的调用中的nResult参数,该EndDialog函数用于中止对话框。如果函数调用失败,则返回值为-1。若想获得错误信息,请调用GetLastError函数。

因此重点看DialogFunc的内容,也就是程序的逻辑

BOOL __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)
{
  HMODULE v5; // eax
  HICON v6; // eax
  HMODULE v7; // eax
  HCURSOR v8; // ST20_4
  HWND v9; // eax
  CHAR String; // [esp+8h] [ebp-340h]
  CHAR v11[4]; // [esp+108h] [ebp-240h]
  char v12; // [esp+10Ch] [ebp-23Ch]
  char v13; // [esp+10Dh] [ebp-23Bh]
  char v14; // [esp+10Eh] [ebp-23Ah]
  char v15; // [esp+10Fh] [ebp-239h]
  char v16; // [esp+110h] [ebp-238h]
  char v17; // [esp+111h] [ebp-237h]
  char v18; // [esp+112h] [ebp-236h]
  char v19; // [esp+113h] [ebp-235h]
  char v20; // [esp+114h] [ebp-234h]
  char v21; // [esp+115h] [ebp-233h]
  char v22; // [esp+116h] [ebp-232h]
  char v23; // [esp+117h] [ebp-231h]
  CHAR Text; // [esp+208h] [ebp-140h]
  char Src[16]; // [esp+308h] [ebp-40h]
  __int128 v26; // [esp+318h] [ebp-30h]
  int v27; // [esp+328h] [ebp-20h]
  __int128 v28; // [esp+32Ch] [ebp-1Ch]
  int v29; // [esp+33Ch] [ebp-Ch]
  __int16 v30; // [esp+340h] [ebp-8h]

  if ( a2 == 16 )
  {
    EndDialog(hDlg, 0);
    return 0;
  }
  if ( a2 == 272 )
  {
    v5 = GetModuleHandleW(0);
    v6 = LoadIconW(v5, (LPCWSTR)0x67);
    SetClassLongA(hDlg, -14, (LONG)v6);
    v7 = GetModuleHandleW(0);
    v8 = LoadCursorW(v7, (LPCWSTR)0x66);
    v9 = GetDlgItem(hDlg, 1);
    SetClassLongA(v9, -12, (LONG)v8);
    return 1;
  }
  if ( a2 != 273 || (unsigned __int16)a3 != 1 )
    return 0;
  memset(&String, (unsigned __int16)a3 - 1, 0x100u);
  memset(v11, 0, 0x100u);
  memset(&Text, 0, 0x100u);
  GetDlgItemTextA(hDlg, 1001, &String, 256);
  GetDlgItemTextA(hDlg, 1002, v11, 256);
  if ( strstr(&String, "@") && strstr(&String, ".") && strstr(&String, ".")[1] && strstr(&String, "@")[1] != '.' )
  {
    v28 = xmmword_410AA0;
    v29 = 1701999980;
    *(_OWORD *)Src = xmmword_410A90;
    v30 = 46;
    v26 = xmmword_410A80;
    v27 = 3830633;
    if ( strlen(v11) != 16
      || v11[0] != 'C'
      || v23 != 'X'
      || v11[1] != 'Z'
      || v11[1] + v22 != 155                    // v22=65
      || v11[2] != '9'
      || v11[2] + v21 != 155                    // v21=98
      || v11[3] != 'd'
      || v20 != '7'
      || v12 != 'm'
      || v19 != 'G'
      || v13 != 'q'
      || v13 + v18 != 170                       // v18=57
      || v14 != '4'
      || v17 != 'g'
      || v15 != 'c'
      || v16 != '8' )
    {
      strcpy_s(&Text, 0x100u, (const char *)&v28);
    }
    else
    {
      strcpy_s(&Text, 0x100u, Src);
      strcat_s(&Text, 0x100u, v11);
    }
  }
  else
  {
    strcpy_s(&Text, 0x100u, "Your E-mail address in not valid.");
  }
  MessageBoxA(hDlg, &Text, "Registeration", 0x40u);
  return 1;
}

这个逻辑也是十分清晰的,我们要的就是v11,但是看这个题的时候很纳闷,就是只给了v11的前四位,而且后面几位也并没有什么函数涉及,但是双击v11发现这些变量都是连在一起的:
在这里插入图片描述
依次类推,正好16位(v11本身有3位),因此只需要将:
在这里插入图片描述
解出来排列好即可,&String接受的就是邮箱,这里有strstr其实也就是匹配邮箱是否合格,只要是合格的邮箱都能成功,最后输入解出来的v11即可:
在这里插入图片描述


考完驾照还得多补补Web和密码web是越来越难了,可能也是我越来越菜了,哦不对一直很菜qwq,下一阶段的目标就是先把vue搞定,然后爬虫再写几个项目,buu的web刷起来!!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值