171002 逆向-Reversing.kr(AutoHotKey)

本文详细解析了一个AutoHotKey程序的自校验机制,通过对程序的逐步跟踪及动静态分析,揭示了如何绕过自校验并获取两组MD5值,最终得到flag的过程。

1625-5 王子昂 总结《2017年10月2日》 【连续第367天总结】
A. Reversing.kr-AutoHotKey
B.

AutoHotKey

解压出来一个ReadMe一个exe
这次的ReadMe终于看懂了,要求找到两个md5,解密后以空格连接作为flag
那么这两个md5会以什么形式出现呢……

查壳显示UPX,乖乖用工具脱掉后再运行提示“Exe corrupted”
未脱壳的程序可以正常运行,为包括文本框和两个按钮的GUI程序

那么很明显,这个提示意味着自校验
用OD逐步跟踪弹窗函数,同时以IDA辅助观察整体结构
最终找到了sub_4508C7函数中
IDA显示在上层调用中直接以它的布尔返回值来决定是否弹错误提示

动静结合分析自校验函数:

int __thiscall sub_4508C7(void *this, int a2, char *a3)
{
  void *file; // esi@1
  FILE *v4; // eax@1
  signed int v6; // eax@3
  signed int v7; // eax@5
  signed int i; // edx@5
  __int32 v9; // eax@7
  FILE *v10; // ST18_4@7
  int v11; // eax@7
  signed int v12; // eax@12
  signed int v13; // edi@19
  int v14; // edi@20
  int v15; // ecx@20
  signed int v16; // [sp-4h] [bp-550h]@16
  char v17; // [sp+Ch] [bp-540h]@1
  CHAR Filename; // [sp+410h] [bp-13Ch]@1
  char v19[16]; // [sp+518h] [bp-34h]@11
  char v20[8]; // [sp+528h] [bp-24h]@4
  char v21[8]; // [sp+530h] [bp-1Ch]@4
  int v22; // [sp+538h] [bp-14h]@9
  int v23; // [sp+53Ch] [bp-10h]@7
  int v24; // [sp+540h] [bp-Ch]@20
  __int32 v25; // [sp+544h] [bp-8h]@7
  char v26; // [sp+54Bh] [bp-1h]@17
  char *v27; // [sp+558h] [bp+Ch]@7

  file = this;
  sub_450F56(&v17);
  GetModuleFileNameA(0, &Filename, 0x104u);
  v4 = fopen(&Filename, aRb);
  *(_DWORD *)file = v4;
  if ( !v4 )
    return 1;
  v6 = 0;
  do
  {
    v20[v6] = byte_466514[v6];
    v21[v6] = byte_46650C[v6];
    ++v6;
  }
  while ( v6 < 8 );                             // 复制十六个字节
  v7 = strlen(a3);
  *((_DWORD *)file + 68) = 0;
  for ( i = 0; i < v7; ++i )
    *((_DWORD *)file + 68) += a3[i];
  fseek(*(FILE **)file, -8, 2);                 // 将文件指针设置到倒数前8个字节处(2表示文件尾END,-8表示偏移offset)
  fread((char *)file + 4, 4u, 1u, *(FILE **)file);// 读取前4个字节存储在file+4处
  v9 = ftell(*(FILE **)file);
  v10 = *(FILE **)file;
  v25 = v9;                                     // 文件指针当前位置,即倒数4个字节处
  fread(&v23, 4u, 1u, v10);                     // 读取后4个字节放入v23中
  fseek(*(FILE **)file, 0, 0);
  v27 = 0;
  v11 = 0;
  if ( v25 > 0 )
  {
    do
    {
      if ( *(_BYTE *)(*(_DWORD *)file + 12) & 0x10 )
        break;
      fread(&v22, 1u, 1u, *(FILE **)file);
      v11 = sub_450F95((int)&v17, v22);         // k=*(a1 + 1024)
                                                // result = k<<8 ^ a1 + 4*(a2^(k>>24))
                                                // k=result
                                                // return result
      ++v27;
    }
    while ( (signed int)v27 < v25 );
  }
  if ( v23 != (v11 ^ 0xAAAAAAAA) )              // v11 = k,(v22从第1字节循环到倒数第4字节)
                                                // v23=后4字节
    goto LABEL_25;
  fseek(*(FILE **)file, *((_DWORD *)file + 1), 0);// 将文件指针设置到*(file+4)即倒数第5-8字节的值处
  if ( !fread(v19, 0x10u, 1u, *(FILE **)file) ) // 读取16个字节入v19
    goto LABEL_25;
  v12 = 0;
  do
  {
    if ( v19[v12] != v20[v12] )                 // 与固定内容比较,v20\v21来自于之前的赋值
      break;
    ++v12;
  }
  while ( v12 < 16 );
  if ( v12 != 16 )
  {                                             // 失败
LABEL_25:
    v16 = 3;
LABEL_19:
    v13 = v16;
    fclose(*(FILE **)file);
    return v13;
  }
  fread(&v26, 1u, 1u, *(FILE **)file);          // 读取一个字节,要求为3
  if ( v26 != 3 )
  {
    v16 = 4;
    goto LABEL_19;
  }
  fread(&v24, 4u, 1u, *(FILE **)file);          // 读4个字节放入v24
  v14 = v24 ^ 0xFAC1;
  fread((char *)file + 12, 1u, v24 ^ 0xFAC1, *(FILE **)file);// 再往后读取第(读取内容^0xfac1)个字节,放入file+12
  sub_450ABA((int)file + 12, v14, v14 + 50130); // 复杂计算,改变file+12处的值
                                                // 跟踪知解密出来是一串md5
  *((_BYTE *)file + v14 + 12) = 0;
  v15 = 0;
  for ( *((_DWORD *)file + 68) = 0; v15 < v14; ++v15 )
    *((_DWORD *)file + 68) += *((_BYTE *)file + v15 + 12);// 将md5的值累加至file+68
  *((_DWORD *)file + 2) = ftell(*(FILE **)file);
  return 0;
}

还是有点复杂的,需要慢慢分析
以二进制形式open自己以后,通过文件指针来灵活变换和读取
关键要注意到fread是从文件指针读取内容的API,并且会让文件指针响应后移;fseek是设置文件指针的API

大体流程:
文件最后4字节要等于一个经过复杂循环计算的值异或0xAAAAAAAA
前4字节要为一段文件中确定序列的位置,该序列为:
前16字节等于程序最初从byte_466514和byte_46650c处复制的16个字节
下1字节等于03
下4字节与0xFAC1异或,得数作为下一次读取的长度
读取刚才算出数的长度的数后,与长度+50130进行复杂运算
结果累加至一个值

要跳过弹窗的话,只需要将最后8字节改成符合要求即可
不过直接用可以通过自校验的原程序进行动态调试的过程中就能发现:
这里写图片描述
最后复杂运算的结果就是32位长度的可见字符串,估计它就是第一串md5了,用http://pmd5.com/解密可知:

isolated

下一步就是找到第二串md5了
虽然当点击OK后程序自动结束,没有任何提示
但是我们还可以断API、查看调用堆栈向上跟踪

IDA中搜索GetWindowTextA,查看交叉引用发现有很多函数,按往常的套路我猜在DialogFunc中,不过为了以防万一,还是到OD中下断吧
调用树仍然查不到信息,于是在GetDlgItemTextA和GetWindowTextA中各下断点,随便输入后点击OK,断到:
这里写图片描述

IDA中查看00425FB7,果然是DigLogFunc~

继续往下跟踪,在查看内存地址的时候不小心又看到了一处有意思的字符串:
这里写图片描述
虽然不明白是啥意思,但是这个32位可见字符串很吸引人呢,解密试试:

pawn

更稳妥一点的话,对buffer地址下访问断点,F9后可以断到某处strcmp中:
这里写图片描述
仍然是它,那么flag就是这俩组合了,提交完成

以往的题目名还能看出来一些端倪,比方说twist暗示了整个流程的恶心;WindowsKernel暗示内核驱动,这次的AutoHotKey不明白跟内容有什么关系……

C. 明日计划
reversing.kr

au3反编译源码 myAut2Exe - The Open Source AutoIT Script Decompiler 2.9 ======================================================== *New* full support for AutoIT v3.2.6++ :) ... mmh here's what I merely missed in the 'public sources 3.1.0' This program is for studying the 'Compiled' AutoIt3 format. AutoHotKey was developed from AutoIT and so scripts are nearly the same. Drag the compiled *.exe or *.a3x into the AutoIT Script Decompiler textbox. To copy text or to enlarge the log window double click on it. Supported Obfuscators: 'Jos van der Zande AutoIt3 Source Obfuscator v1.0.14 [June 16, 2007]' , 'Jos van der Zande AutoIt3 Source Obfuscator v1.0.15 [July 1, 2007]' , 'Jos van der Zande AutoIt3 Source Obfuscator v1.0.20 [Sept 8, 2007]' , 'Jos van der Zande AutoIt3 Source Obfuscator v1.0.22 [Oct 18, 2007]' , 'Jos van der Zande AutoIt3 Source Obfuscator v1.0.24 [Feb 15, 2008]' , 'EncodeIt 2.0' and 'Chr() string encode' Tested with: AutoIT : v3. 3. 0.0 and AutoIT : v2.64. 0.0 and AutoHotKey: v1.0.48.5 The options: =========== 'Force Old Script Type' Grey means auto detect and is the best in most cases. However if auto detection fails or is fooled through modification try to enable/disable this setting 'Don't delete temp files (compressed script)' this will keep *.pak files you may try to unpack manually with'LZSS.exe' as well as *.tok DeTokeniser files, tidy backups and *.tbl (<-Used in van Zande obfucation). If enable it will keep AHK-Scripts as they are and doesn't remove the linebreaks at the beginning Default:OFF 'Verbose LogOutput' When checked you get verbose information when decompiling(DeTokenise) new 3.2.6+ compiled Exe Default:OFF 'Restore Includes' will separated/restore includes. requires ';<AUT2EXE INCLUDE-START' comment to be present in the script to work Default:ON 'Use 'normal' Au3_Signature to find start of script' Will uses the normal 16-byte start signature to detect the start of a
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值