• IDA Pro


    原文地址:Question about disassembler

    简介

    这篇文章介绍了如何在不使用插件的IDA Hex-Rays如何得到比较清晰的伪代码。IDA Hex-Rays功能很强大,只要你提供了足够多的信息,它就能产生十分简单明了的代码。

    下面我们以下面这个二进制文件为例:

    为了方便我直接把exe文件后缀改成jpg,下载下来把文件后缀改回exe就行了

    二进制文件下载地址:

    步骤

    打开IDA Pro加载这个exe文件,先按shitf + F5,添加vc32_14, vc32rtf, vc32ucrt这三个符号签名文件。

    这个exe文件的main函数不太好找,我们先定位到exe文件的入口,按F5得到以下结果

    signed int __usercall start@<eax>(int a1@<ebp>, int a2@<esi>)
    {
      char v2; // bl
      int v4; // ST14_4
      _DWORD *v5; // eax
      _DWORD *v6; // esi
      _DWORD *v7; // eax
      _DWORD *v8; // esi
      const char **v9; // edi
      int *v10; // esi
      const char **v11; // eax
    
      sub_4018B4();
      if ( !(unsigned __int8)__scrt_initialize_crt(1)
        || (v2 = 0, *(_BYTE *)(a1 - 25) = 0, *(_DWORD *)(a1 - 4) = 0, *(_BYTE *)(a1 - 36) = sub_401631(), dword_41CC40 == 1) )
      {
        __scrt_fastfail(7);
        goto LABEL_20;
      }
      if ( dword_41CC40 )
      {
        v2 = 1;
        *(_BYTE *)(a1 - 25) = 1;
      }
      else
      {
        dword_41CC40 = 1;
        if ( _initterm_e(&unk_415140, &unk_415158) )
        {
          *(_DWORD *)(a1 - 4) = -2;
          return 255;
        }
        _initterm(&unk_415134, &unk_41513C);
        dword_41CC40 = 2;
      }
      __scrt_release_startup_lock(*(_DWORD *)(a1 - 36));
      v5 = (_DWORD *)sub_40196C(v4);
      v6 = v5;
      if ( *v5 )
      {
        if ( (unsigned __int8)__scrt_is_nonwritable_in_current_image(v5) )
          ((void (__thiscall *)(_DWORD, _DWORD, signed int, _DWORD))*v6)(*v6, 0, 2, 0);
      }
      v7 = (_DWORD *)sub_401972();
      v8 = v7;
      if ( *v7 )
      {
        if ( (unsigned __int8)__scrt_is_nonwritable_in_current_image(v7) )
          _register_thread_local_exe_atexit_callback(*v8);
      }
      v9 = *(const char ***)sub_406ACE();
      v10 = (int *)sub_406AC8();
      v11 = (const char **)unknown_libname_31();
      a2 = main(*v10, v9, v11);
      if ( !(unsigned __int8)sub_401A94() )
    LABEL_20:
        exit(a2);
      if ( !v2 )
        _cexit();
      __scrt_uninitialize_crt(1, 0);
      *(_DWORD *)(a1 - 4) = -2;
      return a2;
    }
    

    注意下面的代码

      a2 = main(*v10, v9, v11);
      if ( !(unsigned __int8)sub_401A94() )
    LABEL_20:
        exit(a2);
    

    exit函数的参数应该就是主函数的返回值。

    定位到到main函数

    .text:00401390                 mov     esi, eax
    .text:00401392                 call    sub_406312
    .text:00401392
    .text:00401397                 push    eax             ; envp
    .text:00401398                 push    edi             ; argv
    .text:00401399                 push    dword ptr [esi] ; argc
    .text:0040139B                 call    main
    

    按F5,我们会得到以下代码

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      HMODULE v3; // esi
      CHAR v4; // al
      int v5; // ecx
      unsigned int v6; // esi
      char v7; // bl
      __int128 v9; // [esp+4h] [ebp-22Ch]
      int v10; // [esp+14h] [ebp-21Ch]
      int v11; // [esp+18h] [ebp-218h]
      __int16 v12; // [esp+1Ch] [ebp-214h]
      char v13; // [esp+1Eh] [ebp-212h]
      int v14; // [esp+20h] [ebp-210h]
      char v15; // [esp+24h] [ebp-20Ch]
      CHAR Buffer[256]; // [esp+124h] [ebp-10Ch]
      int v17; // [esp+224h] [ebp-Ch]
      char v18; // [esp+228h] [ebp-8h]
    
      v3 = GetModuleHandleA(0);
      memset(Buffer, 0, 0xFFu);
      memset(&v15, 0, 0xFFu);
      if ( !LoadStringA(v3, 0x539u, Buffer, 255) )
        return -1;
      v4 = Buffer[0];
      if ( Buffer[0] )
      {
        v5 = 0;
        do
        {
          *((_BYTE *)&v14 + ++v5 + 3) = v4 ^ 0x30;
          v4 = Buffer[v5];
        }
        while ( v4 );
      }
      memset(Buffer, 0, 0xFFu);
      if ( !LoadStringA(v3, 0x29Au, Buffer, 255) )
        return -1;
      v17 = 0;
      v18 = 0;
      v14 = 5;
      if ( RegGetValueA(-2147483647, &v15, Buffer, 0xFFFF, 0, &v17, &v14) )
        return -1;
      v6 = 0;
      v9 = xmmword_4194E0;
      v10 = 55858812;
      v7 = 114;
      v11 = 1157851502;
      v12 = 20051;
      v13 = 0;
      do
      {
        sub_401010((const char *)&unk_4194D0, v7 ^ *((_BYTE *)&v17 + v6 % (v14 - 1)));
        v7 = *((_BYTE *)&v9 + v6++ + 1);
      }
      while ( v7 );
      return 0;
    }
    

    看起来确实很乱,但我们可以帮助反汇编器给出一个稍好一点的代码

    首先我们有两个memsets

      memset(Buffer, 0, 0xFFu);
      memset(&v15, 0, 0xFFu);
    

    Buffer和v15的原型应该是char name[0xFF]。点击Buffer然后按y键,把Buffer的类型改成char name[0xFF],对v15做同样的事即可。

    此外我们可以给这些变量一个有意义一点的名字,例如buffer_1和buffer_2。点击变量,按n键即可修改变量的名字。

    通过查看unk_4194D0我们会发现它是%c,那么sub_401010这个函数应该就是printf函数了,重命名sub_401010printf,把printf的函数原型改成int printf(const char *format, ...)

    LoadStringARegGetValueA里的数字通过按H键转换成十六进制,这样子看起来方便些,然后把其他的一些变量名也改成有意义的字符。

    这样子我们就得到下面的代码了:

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      HMODULE cur_proc; // esi
      char byte; // al
      int i; // ecx
      unsigned int cou; // esi
      char xor_byte; // bl
      __int128 xored_flag; // [esp+4h] [ebp-22Ch]
      int part_of_xored_flag; // [esp+14h] [ebp-21Ch]
      int part_of_xored_flag_1; // [esp+18h] [ebp-218h]
      __int16 part_of_xored_flag_2; // [esp+1Ch] [ebp-214h]
      char part_of_xored_flag_3; // [esp+1Eh] [ebp-212h]
      int some_buff; // [esp+20h] [ebp-210h]
      char buff_2[255]; // [esp+24h] [ebp-20Ch]
      char buff_1[255]; // [esp+124h] [ebp-10Ch]
      int xor_key_buff; // [esp+224h] [ebp-Ch]
      char v18; // [esp+228h] [ebp-8h]
    
      cur_proc = GetModuleHandleA(0);
      memset(buff_1, 0, 0xFFu);
      memset(buff_2, 0, 0xFFu);
      if ( !LoadStringA(cur_proc, 1337u, buff_1, 255) )
        return -1;
      byte = buff_1[0];
      if ( buff_1[0] )
      {
        i = 0;
        do
        {
          *((_BYTE *)&some_buff + ++i + 3) = byte ^ 0x30;
          byte = buff_1[i];
        }
        while ( byte );
      }
      memset(buff_1, 0, 0xFFu);
      if ( !LoadStringA(cur_proc, 666u, buff_1, 255) )
        return -1;
      xor_key_buff = 0;
      v18 = 0;
      some_buff = 5;
      if ( RegGetValueA(0x80000001, buff_2, buff_1, 0xFFFF, 0, &xor_key_buff, &some_buff) )
        return -1;
      cou = 0;
      xored_flag = xmmword_4194E0;
      part_of_xored_flag = 0x354567C;
      xor_byte = 0x72;
      part_of_xored_flag_1 = 0x4503696E;
      part_of_xored_flag_2 = 0x4E53;
      part_of_xored_flag_3 = 0;
      do
      {
        printf("%c", xor_byte ^ *((char *)&xor_key_buff + cou % (some_buff - 1)));
        xor_byte = *((_BYTE *)&xored_flag + cou++ + 1);
      }
      while ( xor_byte );
      return 0;
    }
    

    看起来清爽了一点,但还是有点乱。

    下面我们看看能对```some_buff做些什么,双击some_buff`我们会跳转到栈视图。

    -0000022C xored_flag      db ?
    -0000022B                 db ? ; undefined
    -0000022A                 db ? ; undefined
    -00000229                 db ? ; undefined
    -00000228                 db ? ; undefined
    -00000227                 db ? ; undefined
    -00000226                 db ? ; undefined
    -00000225                 db ? ; undefined
    -00000224                 db ? ; undefined
    -00000223                 db ? ; undefined
    -00000222                 db ? ; undefined
    -00000221                 db ? ; undefined
    -00000220                 db ? ; undefined
    -0000021F                 db ? ; undefined
    -0000021E                 db ? ; undefined
    -0000021D                 db ? ; undefined
    -0000021C                 db ? ; undefined
    -0000021B                 db ? ; undefined
    -0000021A                 db ? ; undefined
    -00000219                 db ? ; undefined
    -00000218                 db ? ; undefined
    -00000217                 db ? ; undefined
    -00000216                 db ? ; undefined
    -00000215                 db ? ; undefined
    -00000214                 db ? ; undefined
    -00000213                 db ? ; undefined
    -00000212                 db ? ; undefined
    -00000211                 db ? ; undefined
    -00000210 some_buff       dd ?            ; <<<<< our variable
    -0000020C buff_2          db 255 dup(?)
    -0000010D                 db ? ; undefined
    -0000010C buff_1          db 255 dup(?)
    -0000000D                 db ? ; undefined
    -0000000C xor_key_buff    db ?
    -0000000B                 db ? ; undefined
    -0000000A                 db ? ; undefined
    -00000009                 db ? ; undefined
    

    some_buff是dword或者四个字节,那他应该是一个字符buff,把它的类型改成char a[4]

    然后把xor_key_buff的类型设置为char a[4]xored_flag设置为char a[28]buff_1 and buff_2设置为char a[256]

    我们就有下面的栈视图了

    -0000022C xored_flag      db 28 dup(?)
    -00000210 some_buff       db 4 dup(?)
    -0000020C buff_2          db 256 dup(?)
    -0000010C buff_1          db 256 dup(?)
    -0000000C xor_key_buff    db 4 dup(?)
    

    再点下F5刷新伪代码视图,我们会得到以下主函数伪代码:

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      HMODULE cur_proc; // esi
      char byte; // al
      int i; // ecx
      unsigned int cou; // esi
      char xor_byte; // bl
      char xored_flag[28]; // [esp+4h] [ebp-22Ch]
      char some_buff[4]; // [esp+20h] [ebp-210h]
      char buff_2[256]; // [esp+24h] [ebp-20Ch]
      char buff_1[256]; // [esp+124h] [ebp-10Ch]
      char xor_key_buff[4]; // [esp+224h] [ebp-Ch]
      char v14; // [esp+228h] [ebp-8h]
    
      cur_proc = GetModuleHandleA(0);
      memset(buff_1, 0, 0xFFu);
      memset(buff_2, 0, 0xFFu);
      if ( !LoadStringA(cur_proc, 1337u, buff_1, 255) )
        return -1;
      byte = buff_1[0];
      if ( buff_1[0] )
      {
        i = 0;
        do
        {
          some_buff[++i + 3] = byte ^ 0x30;
          byte = buff_1[i];
        }
        while ( byte );
      }
      memset(buff_1, 0, 0xFFu);
      if ( !LoadStringA(cur_proc, 666u, buff_1, 255) )
        return -1;
      *(_DWORD *)xor_key_buff = 0;
      v14 = 0;
      *(_DWORD *)some_buff = 5;
      if ( RegGetValueA(0x80000001, buff_2, buff_1, 0xFFFF, 0, xor_key_buff, some_buff) )
        return -1;
      cou = 0;
      *(_OWORD *)xored_flag = xmmword_4194E0;
      *(_DWORD *)&xored_flag[16] = 0x354567C;
      xor_byte = 0x72;
      *(_DWORD *)&xored_flag[20] = 0x4503696E;
      *(_WORD *)&xored_flag[24] = 0x4E53;
      xored_flag[26] = 0;
      do
      {
        printf("%c", xor_byte ^ xor_key_buff[cou % (*(_DWORD *)some_buff - 1)]);
        xor_byte = xored_flag[cou++ + 1];
      }
      while ( xor_byte );
      return 0;
    }
    

    现在点击RegGetValueA里的0x80000001

    if ( RegGetValueA(0x80000001, buff_2, buff_1, 0xFFFF, 0, xor_key_buff, some_buff) )
    

    按M选择枚举值HKEY_CURRENT_USER

    最后的代码就是这个样子了

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      HMODULE cur_proc; // esi
      char byte; // al
      int i; // ecx
      unsigned int cou; // esi
      char xor_byte; // bl
      char xored_flag[28]; // [esp+4h] [ebp-22Ch]
      char some_buff[4]; // [esp+20h] [ebp-210h]
      char buff_2[256]; // [esp+24h] [ebp-20Ch]
      char buff_1[256]; // [esp+124h] [ebp-10Ch]
      char xor_key_buff[4]; // [esp+224h] [ebp-Ch]
      char v14; // [esp+228h] [ebp-8h]
    
      cur_proc = GetModuleHandleA(0);
      memset(buff_1, 0, 0xFFu);
      memset(buff_2, 0, 0xFFu);
      if ( !LoadStringA(cur_proc, 1337u, buff_1, 255) )
        return -1;
      byte = buff_1[0];
      if ( buff_1[0] )
      {
        i = 0;
        do
        {
          some_buff[++i + 3] = byte ^ 0x30;
          byte = buff_1[i];
        }
        while ( byte );
      }
      memset(buff_1, 0, 0xFFu);
      if ( !LoadStringA(cur_proc, 666u, buff_1, 255) )
        return -1;
      *xor_key_buff = 0;
      v14 = 0;
      *some_buff = 5;
      if ( RegGetValueA(HKEY_CURRENT_USER, buff_2, buff_1, 0xFFFF, 0, xor_key_buff, some_buff) )
        return -1;
      cou = 0;
      *xored_flag = g_xored_flag;
      *&xored_flag[16] = 0x354567C;
      xor_byte = 0x72;
      *&xored_flag[20] = 0x4503696E;
      *&xored_flag[24] = 0x4E53;
      xored_flag[26] = 0;
      do
      {
        printf("%c", xor_byte ^ xor_key_buff[cou % (*some_buff - 1)]);
        xor_byte = xored_flag[cou++ + 1];
      }
      while ( xor_byte );
      return 0;
    }
    
  • 相关阅读:
    Git 9. 远程仓库
    Git 8. 删除文件
    Git 7. 撤销修改
    # 并发编程 -进程理论-进程的方法
    socket 上传 -- 异常处理--UDP协议 --自定义socket #29
    socket(套接字)
    面向过程补充 网络编程 #27
    ATM
    选课系统 -- # 25 -26
    面向对象高级 1.反射 2.元类 # 24
  • 原文地址:https://www.cnblogs.com/Antiver/p/10189055.html
Copyright © 2020-2023  润新知