【父子进程/AES/XTEA/SMC】赛后复盘

打印 上一主题 下一主题

主题 864|帖子 864|积分 2592

官方wp:
进程重影技术:
进程重映像利用了Windows内核中的缓存同步问题,它会导致可执行文件的路径与从该可执行文件创建的映像节区所报告的路径不匹配。通过在一个诱饵路径上加载DLL,然后卸载它,然后从一个新路径加载它,许多Windows API将返回旧路径。这可能可以欺骗安全产品,使其在错误的路径上查找加载的映像。
主要创建方式就是先打开一个新文件,然后把这个文件挂到删除列表上,在关闭文件句柄后文件就会被删除,但是在还没有关闭的时候此时文件还未删除,此时能向文件中写入数据,然后再把这个文件映射到内存上,再关闭文件句柄,此时文件删除,但是内存中还有文件的映像,达到一定的迷惑杀软的目的
如果是做题的话,直接用IDA附加开启的子进程,然后发现XTEA,解密得到flag
如果是学技术的话,还是要研究一下 “进程重影” 技术思路。
本文两者都会介绍的。
考点:AES\XTEA\进程与子进程\SMC\进程重影
分析
DIE打开,发现是pe64位,无壳
拖进IDA进行分析
习惯操作,先用FindCrypto扫一下,有没有加密
发现AES加密
[img=720,128.60986547085201]https://www.hetianlab.com/headImg.action?news=dec2529b-3afe-4bb7-b235-962cc3469ff6.png[/img]
[img=720,249.6614821591949]https://edu-cdn.heetian.com/avatar_f36016346e884a6cabbd0af09e89f70c[/img]
[img=720,110.71356783919597]https://edu-cdn.heetian.com/avatar_b51d5e210bab4d01ab817956e73c6b74[/img]
跟踪main函数,看看它到底要干什么
  1. int __cdecl main_0(int argc, const char **argv, const char **envp)
  2. {
  3.    j___CheckForDebuggerJustMyCode(&unk_1400A80B9);// vs2022调试debug版c++程序会出现该函数,我也不知道啥用
  4.    sub_140001FF0(*argv);
  5.    return 0;
  6. }
复制代码
AES核心加密逻辑函数
  1. __int64 __fastcall sub_13F887480(char *a1, char *a2, unsigned int a3, __int64 a4, __int64 a5)
  2. {
  3.  __int64 result; // rax
  4.  unsigned __int64 i; // [rsp+28h] [rbp+8h]
  5.  unsigned __int8 v7; // [rsp+44h] [rbp+24h]
  6.  j___CheckForDebuggerJustMyCode(&unk_13F92800D);
  7.  v7 = a3 % 0x10;
  8.  if ( a4 )
  9.   {
  10.    qword_13F91D188 = a4;
  11.    sub_13F888EA0();
  12.   }
  13.  if ( a5 )
  14.    qword_13F91D240 = a5;
  15.  for ( i = 0i64; i < a3; i += 16i64 )
  16.   {
  17.    sub_13F889C80(a2);
  18.    j_memmove(a1, a2, 0x10ui64);
  19.    qword_13F91D180 = (__int64)a1;
  20.    sub_13F887850();
  21.    qword_13F91D240 = (__int64)a1;
  22.    a2 += 16;
  23.    a1 += 16;
  24.   }
  25.  result = v7;
  26.  if ( v7 )
  27.   {
  28.    j_memmove(a1, a2, v7);
  29.    qword_13F91D180 = (__int64)a1;
  30.    return sub_13F887850();
  31.   }
  32.  return result;
  33. }
复制代码
跟进了sub_14000A700函数
  1. signed int __fastcall sub_14000A700(const char *a1)
  2. {
  3.  char *v1; // rdi
  4.  __int64 i; // rcx
  5.  DWORD LastError; // eax
  6.  signed int result; // eax
  7.  HANDLE CurrentProcess; // rax
  8.  size_t v6; // rax
  9.  DWORD dwCreationDisposition; // [rsp+20h] [rbp-40h]
  10.  char v8; // [rsp+60h] [rbp+0h] BYREF
  11.  CHAR FileName[48]; // [rsp+68h] [rbp+8h] BYREF
  12.  __int64 v10[4]; // [rsp+98h] [rbp+38h] BYREF
  13.  HANDLE hObject; // [rsp+B8h] [rbp+58h]
  14.  unsigned int v12; // [rsp+D4h] [rbp+74h]
  15.  char v13[36]; // [rsp+F4h] [rbp+94h] BYREF
  16.  int v14[12]; // [rsp+118h] [rbp+B8h] BYREF
  17.  __int64 (__fastcall *v15)(HANDLE, int *, char *, __int64, int); // [rsp+148h] [rbp+E8h]
  18.  HRSRC hResInfo; // [rsp+168h] [rbp+108h]
  19.  DWORD v17; // [rsp+184h] [rbp+124h]
  20.  HGLOBAL hResData; // [rsp+1A8h] [rbp+148h]
  21.  void *Src; // [rsp+1C8h] [rbp+168h]
  22.  DWORD NumberOfBytesWritten; // [rsp+1E4h] [rbp+184h] BYREF
  23.  DWORD nNumberOfBytesToWrite[8]; // [rsp+204h] [rbp+1A4h] BYREF
  24.  size_t Size; // [rsp+224h] [rbp+1C4h]
  25.  void *Block; // [rsp+248h] [rbp+1E8h]
  26.  LPCVOID lpBuffer[4]; // [rsp+268h] [rbp+208h] BYREF
  27.  __int64 (__fastcall *v25)(__int64 *, __int64, _QWORD, _QWORD, int, int, HANDLE); // [rsp+288h] [rbp+228h]
  28.  __int64 v26[3]; // [rsp+2A8h] [rbp+248h] BYREF
  29.  unsigned int v27[9]; // [rsp+2C4h] [rbp+264h] BYREF
  30.  HANDLE hHandle[4]; // [rsp+2E8h] [rbp+288h] BYREF
  31.  __int64 (__fastcall *v29)(HANDLE *, __int64, _QWORD, HANDLE, DWORD, __int64, _QWORD, _QWORD); // [rsp+308h] [rbp+2A8h]
  32.  char v30[76]; // [rsp+328h] [rbp+2C8h] BYREF
  33.  int v31; // [rsp+374h] [rbp+314h]
  34.  __int64 (__fastcall *v32)(HANDLE, _QWORD, char *, __int64, _QWORD); // [rsp+398h] [rbp+338h]
  35.  char *Str; // [rsp+3B8h] [rbp+358h]
  36.  int v34; // [rsp+3D4h] [rbp+374h]
  37.  int v35; // [rsp+3F4h] [rbp+394h]
  38.  int v36; // [rsp+414h] [rbp+3B4h]
  39.  wchar_t *Dest; // [rsp+438h] [rbp+3D8h]
  40.  __int64 v38[63]; // [rsp+460h] [rbp+400h] BYREF
  41.  __int64 v39; // [rsp+658h] [rbp+5F8h]
  42.  __int64 v40[4]; // [rsp+678h] [rbp+618h] BYREF
  43.  __int64 (__fastcall *v41)(__int64 *, __int64, _QWORD, HANDLE, __int64, _QWORD, _DWORD, _QWORD, _QWORD, _QWORD, _QWORD); // [rsp+698h] [rbp+638h]
  44.  int v42; // [rsp+9A4h] [rbp+944h]
  45.  v1 = &v8;
  46.  for ( i = 404i64; i; --i )
  47.   {
  48.    *(_DWORD *)v1 = -858993460;
  49.    v1 += 4;
  50.   }
  51.  j___CheckForDebuggerJustMyCode(&unk_1400A80B9);
  52.  strcpy(FileName, "VNctf2023");
  53.  v10[0] = 0x616C7972723073i64;
  54.  hObject = CreateFileA(FileName, 0xC0010000, 0, 0i64, 2u, 0x80u, 0i64);// 创建一个文件
  55.  if ( hObject == (HANDLE)-1i64 )
  56.   {                                             // 失败
  57.    LastError = GetLastError();
  58.    return sub_14000257C("Failed - Error Code %08X\r\n", LastError);
  59.   }
  60.  else
  61.   {
  62.    v13[0] = 1;                                 // 创建成功
  63.    v15 = (__int64 (__fastcall *)(HANDLE, int *, char *, __int64, int))sub_1400016B3("NtSetInformationFile");
  64.    v12 = v15(hObject, v14, v13, 1i64, 13);
  65.    if ( v14[0] >= 0 )
  66.    {
  67.      hResInfo = FindResourceA(0i64, (LPCSTR)0x66, "shell");// 寻找指定类型和名称的资源位置
  68.      v17 = SizeofResource(0i64, hResInfo);     // 资源大小
  69.      hResData = LoadResource(0i64, hResInfo);  // 加载资源
  70.      Src = LockResource(hResData);
  71.      NumberOfBytesWritten = 0;
  72.      nNumberOfBytesToWrite[0] = 0;
  73.      LODWORD(Size) = v17 - 4;
  74.      Block = j_j_j__malloc_base(v17 - 4);
  75.      j_memmove(Block, Src, (unsigned int)Size);
  76.      j_memmove(nNumberOfBytesToWrite, (char *)Src + (unsigned int)Size, 4ui64);
  77.      GlobalUnlock(hResData);
  78.      lpBuffer[0] = 0i64;
  79.      NumberOfBytesWritten = sub_1400030BC(Block, v10, lpBuffer, (unsigned int)Size);  //关键函数,好像对shell资源进行了 AES加密
  80.      if ( NumberOfBytesWritten >= nNumberOfBytesToWrite[0]
  81.        && lpBuffer[0]
  82.        && WriteFile(hObject, lpBuffer[0], nNumberOfBytesToWrite[0], &NumberOfBytesWritten, 0i64)// 加密后shell 写到资源到文件
  83.        && (j_free(Block),                      // 释放
  84.            j_free((void *)lpBuffer[0]),
  85.            v25 = (__int64 (__fastcall *)(__int64 *, __int64, _QWORD, _QWORD, int, int, HANDLE))sub_1400016B3("NtCreateSection"),// 创建节对象
  86.            v12 = v25(v26, 983071i64, 0i64, 0i64, 2, 0x1000000, hObject),
  87.            (v12 & 0x80000000) == 0) )          // 猜测上面的代码,就是把shell 资源 写到一个叫 vnctf2023的文件里面
  88.      {
  89.        result = sub_14000347C(hObject, v27, nNumberOfBytesToWrite[0]);
  90.        if ( result )                           // 写入成功
  91.        {
  92.          CloseHandle(hObject);
  93.          hHandle[0] = 0i64;
  94.          v29 = (__int64 (__fastcall *)(HANDLE *, __int64, _QWORD, HANDLE, DWORD, __int64, _QWORD, _QWORD))sub_1400016B3("NtCreateProcess");// 启动进程
  95.          CurrentProcess = GetCurrentProcess();
  96.          LOBYTE(dwCreationDisposition) = 1;
  97.          result = v29(hHandle, 0x1FFFFFi64, 0i64, CurrentProcess, dwCreationDisposition, v26[0], 0i64, 0i64);
  98.          v12 = result;
  99.          if ( result >= 0 )
  100.          {
  101.            memset(v30, 0, 0x30ui64);
  102.            v31 = 0;
  103.            v32 = (__int64 (__fastcall *)(HANDLE, _QWORD, char *, __int64, _QWORD))sub_1400016B3("NtQueryInformationProcess");
  104.            result = v32(hHandle[0], 0i64, v30, 48i64, 0i64);
  105.            v12 = result;
  106.            if ( result >= 0 )
  107.            {
  108.              Str = (char *)j_j_j__malloc_base(4ui64);
  109.              sub_1400039C2(Str, "%x", NumberOfBytesWritten);
  110.              v34 = j_strlen(FileName);
  111.              v35 = j_strlen(a1);
  112.              v36 = j_strlen(Str);
  113.              j_strcat(FileName, " ");
  114.              j_strcat(FileName, a1);
  115.              j_strcat(FileName, " ");
  116.              j_strcat(FileName, Str);
  117.              v34 += v35 + v36 + 2;
  118.              v42 = v34 + 1;
  119.              v6 = (unsigned int)(2 * (v34 + 1));
  120.              if ( !is_mul_ok(2u, v34 + 1) )
  121.                v6 = -1i64;
  122.              Dest = (wchar_t *)j_j_j__malloc_base(v6);
  123.              sub_140003175(Dest, 0i64, 2 * v34 + 2);
  124.              j_mbstowcs(Dest, FileName, v34);
  125.              result = sub_140003DBE(hHandle[0], v30, Dest);
  126.              if ( result )
  127.              {
  128.                j_free(Dest);
  129.                memset(v38, 0, 0x1B8ui64);
  130.                result = sub_140002176(hHandle[0], v30, v38);
  131.                if ( result )
  132.                {
  133.                  v38[59] = v38[2];
  134.                  v39 = v38[2] + v27[0];
  135.                  v40[0] = 0i64;
  136.                  v41 = (__int64 (__fastcall *)(__int64 *, __int64, _QWORD, HANDLE, __int64, _QWORD, _DWORD, _QWORD, _QWORD, _QWORD, _QWORD))sub_1400016B3("NtCreateThreadEx"); //启动线程
  137.                  result = v41(v40, 0x1FFFFFi64, 0i64, hHandle[0], v39, 0i64, 0, 0i64, 0i64, 0i64, 0i64);
  138.                  v12 = result;
  139.                  if ( result >= 0 )
  140.                    return WaitForSingleObject(hHandle[0], 0xFFFFFFFF);
  141.                }
  142.              }
  143.            }
  144.          }
  145.        }
  146.      }
  147.      else
  148.      {
  149.        return CloseHandle(hObject);
  150.      }
  151.    }
  152.    else
  153.    {
  154.      sub_14000257C("Failed - Error Code %08X\r\n", v12);
  155.      return CloseHandle(hObject);
  156.    }
  157.   }
  158.  return result;
  159. }
复制代码
关键函数 sub_140009E20,就是那个对shell资源进行处理的函数
  1. __int64 __fastcall sub_140009E20(__int64 a1, const char *a2, void **a3, unsigned int a4)
  2. {
  3.  char *v4; // rdi
  4.  __int64 i; // rcx
  5.  size_t v6; // rax
  6.  char v8; // [rsp+20h] [rbp+0h] BYREF
  7.  char v9[44]; // [rsp+28h] [rbp+8h] BYREF
  8.  unsigned int v10; // [rsp+54h] [rbp+34h]
  9.  BOOL v11; // [rsp+74h] [rbp+54h]
  10.  int j; // [rsp+94h] [rbp+74h]
  11.  size_t Size; // [rsp+168h] [rbp+148h]
  12.  v4 = &v8;
  13.  for ( i = 42i64; i; --i )
  14.   {
  15.    *(_DWORD *)v4 = -858993460;
  16.    v4 += 4;
  17.   }
  18.  j___CheckForDebuggerJustMyCode(&unk_1400A80B9, a2, a3);
  19.  v11 = a4 % 0x10 != 0;
  20.  v10 = 16 * (v11 + a4 / 0x10);
  21.  v6 = v10 + 1;
  22.  if ( v10 == -1 )
  23.    v6 = -1i64;
  24.  *a3 = j_j_j__malloc_base(v6);
  25.  sub_140003175(*a3, 0i64, v10 + 1);            
  26.  sub_140003175(v9, 0i64, 16i64);
  27.  if ( j_strlen(a2) <= 0x10 )
  28.    Size = j_strlen(a2);
  29.  else
  30.    Size = 16i64;
  31.  j_memmove(v9, a2, Size);
  32.  for ( j = 0; 16 * j < a4; ++j )
  33.    sub_140002DE7(16 * j + a1, v9, (char *)*a3 + 16 * j, 16i64);// AES解密函数  我思考了一下,如果shell进行加密,那么shell还能运行吗?反之,只有解密,才可以正常运行
  34.  return v10;
  35. }
复制代码
其余函数也就不用再分析了,可以断定这是AES加密函数。
对shell资源进行AES解密,然后shell程序跑起来
运行该程序,发现我追踪的进程居然挂掉了,又跑起来了另一个进程
可以断定,父进程开子进程
子进程输入flag

我再次运行,发现jiji.exe没了???
[img=720,188.89132821075742]https://edu-cdn.heetian.com/avatar_4e143b56268c4170b84f9b759e285b2c[/img]
  1. __int64 __fastcall sub_140007620(const void *a1, __int64 a2, void *a3, unsigned int a4)
  2. {
  3.  j___CheckForDebuggerJustMyCode(&unk_1400A800D, a2, a3);
  4.  j_memmove(a3, a1, a4);
  5.  qword_14009D180 = (__int64)a3;
  6.  qword_14009D188 = a2;
  7.  sub_140008EA0();
  8.  return sub_1400078E0();
  9. }
复制代码
附加下子进程

[img=720,549.0301003344482]https://edu-cdn.heetian.com/avatar_392df969f02f48b5a142e01f8c5320d3[/img]
[img=720,259.9330207635633]https://edu-cdn.heetian.com/avatar_c09bd6cc8b04494abbe8a3b98fa41833[/img]
搜索字符串,但是无法找到关键函数

直接dump解密后的exe文件

[img=720,13.241379310344827]https://edu-cdn.heetian.com/avatar_a4ce8721b7f0440bbcabd55aa5e747d8[/img]
断点下在此处,然后运行,找到解密后的文件,dump下来

D键转地址

跳转到MZ头部,发现这就是解密后的程序
[img=720,213.84]https://edu-cdn.heetian.com/avatar_0bd1db0ec9434d8faa9667963cc3349e[/img]
把它dump下来
[img=720,80.8695652173913]https://edu-cdn.heetian.com/avatar_a8aafed89b8e4dedb0cdc5bf8af52a08[/img]
  1. __int64 __fastcall sub_1400078E0(__int64 a1, __int64 a2, __int64 a3)
  2. {
  3.  __int64 v3; // rcx
  4.  unsigned __int8 i; // [rsp+24h] [rbp+4h]
  5.  j___CheckForDebuggerJustMyCode(&unk_1400A800D, a2, a3);
  6.  LOBYTE(v3) = 10;
  7.  sub_140007760(v3);
  8.  for ( i = 9; i; --i )
  9.   {
  10.    sub_140008980();
  11.    sub_140008DF0();
  12.    sub_140007760(i);
  13.    sub_140007970();
  14.   }
  15.  sub_140008980();
  16.  sub_140008DF0();
  17.  return sub_140007760(0i64);
  18. }
复制代码
得到dump下来的程序
[img=720,319.90153846153845]https://edu-cdn.heetian.com/avatar_ba8de1dce7694d6094879188c29a22cf[/img]
分析dump下来的程序
[img=720,151.99415631848063]https://edu-cdn.heetian.com/avatar_180efc8afbeb4a7bb70c80ccd4bfa8a8[/img]
根据关键字符串定位关键函数
  1. __int64 __fastcall sub_140007760(unsigned __int8 a1, __int64 a2, __int64 a3)
  2. {
  3.  __int64 result; // rax
  4.  unsigned __int8 i; // [rsp+24h] [rbp+4h]
  5.  unsigned __int8 j; // [rsp+44h] [rbp+24h]
  6.  j___CheckForDebuggerJustMyCode(&unk_1400A800D, a2, a3);
  7.  for ( i = 0; ; ++i )
  8.   {
  9.    result = i;
  10.    if ( i >= 4u ) //这不就是 addroundkey() 函数吗?
  11.      break;
  12.    for ( j = 0; j < 4u; ++j )
  13.      *(_BYTE *)(qword_14009D180 + 4i64 * i + j) ^= byte_14009D190[16 * a1 + 4 * i + j]; //对比confuse_us那题,发现没有魔改 ^0x23
  14.   }
  15.  return result;
  16. }
复制代码
[img=720,262.0476858345021]https://edu-cdn.heetian.com/avatar_516dc7a47f134ea1bea7345bc594910b[/img]
动调调试走到flag验证的地方
[img=720,336.9722814498934]https://edu-cdn.heetian.com/avatar_7d5a745f511545b4bb7f20b37ee0eac2[/img]
[img=720,261.2180746561886]https://edu-cdn.heetian.com/avatar_a5e9b86d9f0c475e923e9a519fcd2608[/img]
动态调试跟进去
[img=720,332.39349341595664]https://edu-cdn.heetian.com/avatar_054a31428dff4f8b9d677209bce95d32[/img]
成功到达关键的地方,如果不是这么清晰的话,需要U+C键来调
  1. 传递的参数
  2. FileName
  3. VNctf2023
  4. C:\Users\Le\Desktop\jijiji.exe
  5. 16000
  6. s0rryla
复制代码
[img=720,297.7650429799427]https://edu-cdn.heetian.com/avatar_74f38241b2ef45158c5844f64f03a5a6[/img]
XTEA加密
[code]#include #include  void decrypt(unsigned int* v, unsigned int* key,unsigned int round) {  unsigned int l = v[0], r = v[1], sum = 0, delta = 0x88408067;  sum = delta * round;  for (size_t i = 0; i < round; i++) {    sum -= delta;    r -= (((l > 5)) + l) ^ (sum + key[(sum >> 11) & 3]);    l -= (((r > 5)) + r) ^ (sum + key[sum & 3])^sum;  }  v[0] = l;  v[1] = r;}int main(){    unsigned int v[11] = {  0xADD4F778, 0xA6D7F132, 0x61813290, 0x2D4A40A6, 0x00B05F11, 0xB6D59424, 0x231BBFC6, 0xCD405B31,     0x03020100, 0x00C30504};    unsigned int key[4] = {98,111,109,98};    for(int i=0;i</strong></p>  

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

兜兜零元

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表