2024年腾讯游戏安全技术大赛-PC方向初赛复现

2024腾讯游戏安全技术大赛-PC方向初赛

第一问

token1

hace.exe被VM了没法看,观察导入表发现导入了LoadLibraryAGetProcAddress两个函数,大概率是加载了一个dll。

用一些云工具分析一下可以看出来exe应该是一个dll注入器,用远线程的方法把dll注入到了某个进程中。根据这一

特性,可以考虑HookWriteProcessMemory这个API来获取到lpBuffer这个参数,也就是DLL。

拿到三个文件,其中只有一个文件有PE头,这个就是DLL。

很伤心这个DLL也有一大坨混淆,在IDA中翻一下函数看看能不能找突破口。

发现有几个函数采用了下面的混淆方法

int sub_180001990()
{
  size_t v0; // rbx
  DWORD v1; // eax
  __m128i Dst; // [rsp+20h] [rbp-48h] BYREF
  __int64 v4; // [rsp+30h] [rbp-38h]
  __int64 v5; // [rsp+38h] [rbp-30h]
  __m128i Src; // [rsp+40h] [rbp-28h] BYREF

  Dst.m128i_i64[0] = 0xE795A7603F90341FuLL;
  Dst.m128i_i64[1] = 0xC65BF3E99CAA093CuLL;
  Src.m128i_i64[0] = 0x89FAC00F53FE5D68uLL;
  Src.m128i_i64[1] = 0xC65BF3E9F9D26C12uLL;
  Src = _mm_xor_si128(_mm_load_si128(&Src), Dst);
  v0 = -1LL;
  do
    ++v0;
  while ( Src.m128i_i8[v0] );
  memmove(&unk_1800349A0, &Src, v0);
  Dst.m128i_i64[0] = 0LL;
  v4 = 0LL;
  v5 = 15LL;
  sub_180004770((void **)&Dst, &Src, v0);
  v1 = sub_1800070A0(&Dst);
  sub_1800063D0(&unk_1800349A0, v1);
  return atexit(sub_180020C90);
}

解密出来的字符串是winlogon.exe,这个是Windows的登陆进程,可能DLL注入到了这里?

类似的函数还有五六个,解密出来一部分,根据字符串来看似乎是用于反调试的,包括CE、x64dbg、IDA等动调。

注意到这样一个函数:

void sub_180007C10()
{
  HANDLE v1; // rcx
  void *v2; // rdx
  __int128 v3; // xmm0
  __int128 v4; // xmm1
  HANDLE FileA; // rbx
  __int64 v8; // rcx
  _BYTE *v9; // rdx
  unsigned __int64 v10; // rdx
  _QWORD *v11; // rcx
  char Buffer; // [rsp+60h] [rbp+0h] BYREF

  _RBP = (unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL;
  while ( byte_180032C00 )
  {
    if ( !byte_180034961 && !byte_180034960 )
      sub_1800041D0();
    v1 = hProcess;
    v2 = (void *)(qword_180034968 + 2766);
    *(_BYTE *)_RBP = 15;
    WriteProcessMemory(v1, v2, (LPCVOID)((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL), 1uLL, 0LL);
    byte_180032C00 = 0;
    *(_QWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x20) = 0xAA32D3B2B7C50388uLL;
    *(_QWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x10) = 0xA0A195500DCC0E5CuLL;
    *(_QWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x18) = 0x943E9588CFCF645DuLL;
    v3 = *(_OWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x10);
    *(_QWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x28) = 0xA727C0574231D098uLL;
    v4 = *(_OWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x20);
    *(_QWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x80) = 0xE795A7603F90341FuLL;
    *(_OWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x60) = v3;
    *(_QWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x88) = 0xC65BF3E99CAA093CuLL;
    *(_OWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x70) = v4;
    *(_QWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x90) = 0xCF59BCC699A060E9uLL;
    *(_QWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x98) = 0xA727C0574231E1F6uLL;
    __asm
    {
      vmovdqu ymm0, [rbp+0D0h+var_50]
      vpxor   ymm1, ymm0, [rbp+0D0h+var_70]
      vmovdqa [rbp+0D0h+var_70], ymm1
      vzeroupper
    }
    FileA = CreateFileA((LPCSTR)(_RBP + 96), 0x40000000u, 0, 0LL, 3u, 0x80u, 0LL);
    if ( FileA != (HANDLE)-1LL )
    {
      ((void (__fastcall *)(unsigned __int64))loc_180007A20)(_RBP + 48);
      v8 = -1LL;
      if ( *(_QWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x48) < 0x10uLL )
      {
        do
          ++v8;
        while ( *(_BYTE *)(_RBP + 48 + v8) );
        v9 = (_BYTE *)(_RBP + 48);
      }
      else
      {
        v9 = *(_BYTE **)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x30);
        do
          ++v8;
        while ( v9[v8] );
      }
      WriteFile(FileA, v9, v8, (LPDWORD)(_RBP + 8), 0LL);
      CloseHandle(FileA);
      v10 = *(_QWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x48);
      if ( v10 >= 0x10 )
      {
        v11 = *(_QWORD **)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x30);
        if ( v10 + 1 >= 0x1000 )
        {
          v11 = (_QWORD *)*(v11 - 1);
          if ( (unsigned __int64)(*(_QWORD *)(((unsigned __int64)&Buffer & 0xFFFFFFFFFFFFFFE0uLL) + 0x30)
                                - (_QWORD)v11
                                - 8LL) > 0x1F )
            invalid_parameter_noinfo_noreturn();
        }
        j_j_free(v11);
      }
    }
  }
}

这个函数调用了一些敏感的API,创建了一个文件,想办法把这个文件给搞出来。

首先把字符串解密出来:

def decrypt_string(encrypted_data, keys):
    decrypted_bytes = b''
    
    for i in range(len(encrypted_data)):
        result = encrypted_data[i] ^ keys[i]
        decrypted_bytes += result.to_bytes(8, byteorder='little')
    
    try:
        text = decrypted_bytes.split(b'\x00')[0].decode('ascii')
        return text
    except:
        return decrypted_bytes.decode('ascii', errors='replace')

part1_data = [0xA0A195500DCC0E5C, 0x943E9588CFCF645D]
part1_keys = [0xE795A7603F90341F, 0xC65BF3E99CAA093C]

part2_data = [0xAA32D3B2B7C50388, 0xA727C0574231D098]
part2_keys = [0xCF59BCC699A060E9, 0xA727C0574231E1F6]

part1 = decrypt_string(part1_data, part1_keys)
part2 = decrypt_string(part2_data, part2_keys)

print("前半部分:", part1)
print("后半部分:", part2)
print("完整路径:", part1 + part2)

输出:完整路径: C:\2024GameSafeRace.token1,但是在C盘下找不到这个文件,注意到这一行代码:

FileA = CreateFileA((LPCSTR)(_RBP + 96), 0x40000000u, 0, 0LL, 3u, 0x80u, 0LL);

根据微软的文档,还原一下这个函数的参数:

CreateFileA((LPCSTR)"C:\2024GameSafeRace.token1",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

其中比较关键的参数是OPEN_EXISTING,微软是这么描述的:

image-20250315233104720

意思是就是文件不存在的话,CreateFileA失败,那么手动创建一个名为C:\2024GameSafeRace.token1的文件。

image-20250315233251944

这样token1就拿到了757F4749AEBB1891EF5AC2A9B5439CEA

token2

3环分析完毕,token2大概率在0环了,把驱动加载上看看

在DbgView把Caputure Kernel、Verbose Kernel Output、Capture Events都开上,捕捉到调试信息:

image-20250316001622329

拿到token2:8b3f14a24d64f3e697957c252e3a5686

第二问

token1

首先是输出token1,这个比较简单,前面已经分析过token1之所以没被输出,是因为[in] dwCreationDisposition这个参数被置为了OPEN_EXISTING,改成OPEN_ALWAYS即可,就是把3改成4。下面DLL中Patch的效果:

image-20250316002424297

由于DLL是在exe中被直接注入的,所以得通过Hook WriteProcessMemory的方式来Patch DLL。

HookWriteProcessMemory(
    _In_ HANDLE hProcess,
    _In_ LPVOID lpBaseAddress,
    _In_reads_bytes_(nSize) LPCVOID lpBuffer,
    _In_ SIZE_T nSize,
    _Out_opt_ SIZE_T* lpNumberOfBytesWritten
)
{
    if (nSize > 0x440000 && *((PUCHAR)lpBuffer + 0x7171) == 0x3) {
        *((PUCHAR)lpBuffer + 0x7171) = 4;
        DebugLog("Hooked!");
    }
    return TrueWriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten);
}

之前的output中有三次调用WriteProcessMemory,所以得用nSize过滤出需要的Buffer,避免访问空指针。

image-20250316122225294

成功输出token1

token2

关于token2,第一问的时候就注意到只有勾选了Enable Verbose Kernel Output时,token2才会被打印。也就是说token2的打印语句level设置的太低了,尝试Hook DbgPrintEx函数看看怎么回事:

image-20250316131242138

Level只有5,看来果然是Level的问题导致了token2没被打印

想要打印token2,只需要将level改为0即可,但是题目要求不能更改系统模块代码,所以只能想办法patch ace.sys。这里有一点是值得注意的,ace.sys在被启动后提示:启动服务失败,ID31。题目告诉我们这是成功加载了,但实际上ace.sys在DriverEntry里应该是返回了STATUS_UNSUCCESSFUL实现了自卸载,应该是在启动的过程中开了一个线程来不断的打印token2。

这赛题的反黑工具真的很厉害,想打开Ark工具分析一下进程直接蓝屏了,调用栈也被清空看不到什么有用的信息。

image-20250316143809784

在驱动程序中,一般使用PsCreateSystemThread来创建线程,阅读微软文档后知道,驱动程序创建的线程实在初始系统进程中的,即System进程

image-20250316145555795

Hook PsCreateSystemThread打印[in] StartRoutine这个参数拿到线程的起始地址,再用Windbg查看这个地址的反汇编代码,看看是不是我们想要的东西。

这里我用常规的Hook框架一直蓝屏,只能隔离system进程用PTE Hook试试。隔离之后不蓝了挺好,输出了两个地址:

image-20250316155131279

分别查看两个地址:image-20250316155158564

后面那个带符号的肯定不是我们需要的,前面那个很像,继续反汇编看看:

ffff918b`ca013db0 488bc4          mov     rax,rsp
ffff918b`ca013db3 48895808        mov     qword ptr [rax+8],rbx
ffff918b`ca013db7 48897818        mov     qword ptr [rax+18h],rdi
ffff918b`ca013dbb 4c897020        mov     qword ptr [rax+20h],r14
ffff918b`ca013dbf 55              push    rbp
ffff918b`ca013dc0 488d68a1        lea     rbp,[rax-5Fh]
ffff918b`ca013dc4 4881eca0000000  sub     rsp,0A0h
ffff918b`ca013dcb 48bf4e93328b546b331e mov rdi,1E336B548B32934Eh
ffff918b`ca013dd5 49bed520794add1d6d4b mov r14,4B6D1DDD4A7920D5h
ffff918b`ca013ddf 0f57c0          xorps   xmm0,xmm0
ffff918b`ca013de2 488d4d37        lea     rcx,[rbp+37h]
ffff918b`ca013de6 0f114537        movups  xmmword ptr [rbp+37h],xmm0
ffff918b`ca013dea e8d1030000      call    ffff918b`ca0141c0
ffff918b`ca013def 48b8a14f122fb3276d4b mov rax,4B6D27B32F124FA1h
ffff918b`ca013df9 4c8d45e7        lea     r8,[rbp-19h]
ffff918b`ca013dfd 4889456f        mov     qword ptr [rbp+6Fh],rax
ffff918b`ca013e01 ba05000000      mov     edx,5
ffff918b`ca013e06 488b456f        mov     rax,qword ptr [rbp+6Fh]
ffff918b`ca013e0a 33c9            xor     ecx,ecx
ffff918b`ca013e0c 488945e7        mov     qword ptr [rbp-19h],rax
ffff918b`ca013e10 48897d6f        mov     qword ptr [rbp+6Fh],rdi
ffff918b`ca013e14 488b456f        mov     rax,qword ptr [rbp+6Fh]
ffff918b`ca013e18 488945ef        mov     qword ptr [rbp-11h],rax
ffff918b`ca013e1c 4c89756f        mov     qword ptr [rbp+6Fh],r14
ffff918b`ca013e20 488b456f        mov     rax,qword ptr [rbp+6Fh]
ffff918b`ca013e24 48894517        mov     qword ptr [rbp+17h],rax
ffff918b`ca013e28 48897d6f        mov     qword ptr [rbp+6Fh],rdi
ffff918b`ca013e2c 488b456f        mov     rax,qword ptr [rbp+6Fh]
ffff918b`ca013e30 660f6f45e7      movdqa  xmm0,xmmword ptr [rbp-19h]
ffff918b`ca013e35 4889451f        mov     qword ptr [rbp+1Fh],rax
ffff918b`ca013e39 660fef4517      pxor    xmm0,xmmword ptr [rbp+17h]
ffff918b`ca013e3e 488b0543330000  mov     rax,qword ptr [ffff918b`ca017188]
ffff918b`ca013e45 660f7f45e7      movdqa  xmmword ptr [rbp-19h],xmm0
ffff918b`ca013e4a ff15c8210000    call    qword ptr [ffff918b`ca016018]
ffff918b`ca013e50 33db            xor     ebx,ebx
ffff918b`ca013e52 48b8f0104b32dd1d6d4b mov rax,4B6D1DDD324B10F0h
ffff918b`ca013e5c 4c8d45f7        lea     r8,[rbp-9]
ffff918b`ca013e60 4889456f        mov     qword ptr [rbp+6Fh],rax
ffff918b`ca013e64 ba05000000      mov     edx,5
ffff918b`ca013e69 488b456f        mov     rax,qword ptr [rbp+6Fh]
ffff918b`ca013e6d 33c9            xor     ecx,ecx
ffff918b`ca013e6f 488945f7        mov     qword ptr [rbp-9],rax
ffff918b`ca013e73 48897d6f        mov     qword ptr [rbp+6Fh],rdi
ffff918b`ca013e77 488b456f        mov     rax,qword ptr [rbp+6Fh]
ffff918b`ca013e7b 488945ff        mov     qword ptr [rbp-1],rax
ffff918b`ca013e7f 4c89756f        mov     qword ptr [rbp+6Fh],r14
ffff918b`ca013e83 488b456f        mov     rax,qword ptr [rbp+6Fh]
ffff918b`ca013e87 48894527        mov     qword ptr [rbp+27h],rax
ffff918b`ca013e8b 48897d6f        mov     qword ptr [rbp+6Fh],rdi
ffff918b`ca013e8f 488b456f        mov     rax,qword ptr [rbp+6Fh]
ffff918b`ca013e93 660f6f45f7      movdqa  xmm0,xmmword ptr [rbp-9]
ffff918b`ca013e98 440fb64c1d37    movzx   r9d,byte ptr [rbp+rbx+37h]
ffff918b`ca013e9e 4889452f        mov     qword ptr [rbp+2Fh],rax
ffff918b`ca013ea2 660fef4527      pxor    xmm0,xmmword ptr [rbp+27h]
ffff918b`ca013ea7 488b05da320000  mov     rax,qword ptr [ffff918b`ca017188]
ffff918b`ca013eae 660f7f45f7      movdqa  xmmword ptr [rbp-9],xmm0
ffff918b`ca013eb3 ff155f210000    call    qword ptr [ffff918b`ca016018]
ffff918b`ca013eb9 48ffc3          inc     rbx
ffff918b`ca013ebc 4883fb10        cmp     rbx,10h
ffff918b`ca013ec0 7c90            jl      ffff918b`ca013e52
ffff918b`ca013ec2 48b8df20794add1d6d4b mov rax,4B6D1DDD4A7920DFh
ffff918b`ca013ecc 4c8d4507        lea     r8,[rbp+7]
ffff918b`ca013ed0 4889456f        mov     qword ptr [rbp+6Fh],rax
ffff918b`ca013ed4 ba05000000      mov     edx,5
ffff918b`ca013ed9 488b456f        mov     rax,qword ptr [rbp+6Fh]
ffff918b`ca013edd 33c9            xor     ecx,ecx
ffff918b`ca013edf 48894507        mov     qword ptr [rbp+7],rax
ffff918b`ca013ee3 48897d6f        mov     qword ptr [rbp+6Fh],rdi
ffff918b`ca013ee7 488b456f        mov     rax,qword ptr [rbp+6Fh]
ffff918b`ca013eeb 4889450f        mov     qword ptr [rbp+0Fh],rax
ffff918b`ca013eef 4c89756f        mov     qword ptr [rbp+6Fh],r14
ffff918b`ca013ef3 488b456f        mov     rax,qword ptr [rbp+6Fh]
ffff918b`ca013ef7 48894547        mov     qword ptr [rbp+47h],rax
ffff918b`ca013efb 48897d6f        mov     qword ptr [rbp+6Fh],rdi
ffff918b`ca013eff 488b456f        mov     rax,qword ptr [rbp+6Fh]
ffff918b`ca013f03 660f6f4507      movdqa  xmm0,xmmword ptr [rbp+7]
ffff918b`ca013f08 4889454f        mov     qword ptr [rbp+4Fh],rax
ffff918b`ca013f0c 660fef4547      pxor    xmm0,xmmword ptr [rbp+47h]
ffff918b`ca013f11 488b0570320000  mov     rax,qword ptr [ffff918b`ca017188]
ffff918b`ca013f18 660f7f4507      movdqa  xmmword ptr [rbp+7],xmm0
ffff918b`ca013f1d ff15f5200000    call    qword ptr [ffff918b`ca016018]
ffff918b`ca013f23 b9ce0a0000      mov     ecx,0ACEh
ffff918b`ca013f28 e833e9ffff      call    ffff918b`ca012860
ffff918b`ca013f2d e9adfeffff      jmp     ffff918b`ca013ddf
ffff918b`ca013f32 cc              int     3
ffff918b`ca013f33 cc              int     3
ffff918b`ca013f34 4152            push    r10
ffff918b`ca013f36 49ba2563296284038fe2 mov r10,0E28F038462296325h
ffff918b`ca013f40 9c              pushfq
ffff918b`ca013f41 49f7da          neg     r10
ffff918b`ca013f44 e834180000      call    ffff918b`ca01577d
ffff918b`ca013f49 7398            jae     ffff918b`ca013ee3
ffff918b`ca013f4b cc              int     3
ffff918b`ca013f4c 95              xchg    eax,ebp
ffff918b`ca013f4d df1b            fistp   word ptr [rbx]
ffff918b`ca013f4f 30948f434add5a  xor     byte ptr [rdi+rcx*4+5ADD4A43h],dl
ffff918b`ca013f56 3e040a          add     al,0Ah
ffff918b`ca013f59 f363ed          rep movsxd ebp,ebp
ffff918b`ca013f5c cf              iretd
ffff918b`ca013f5d f0cf            lock iretd
ffff918b`ca013f5f 05c53e2100      add     eax,213EC5h
ffff918b`ca013f64 3ef5            cmc
ffff918b`ca013f66 4a751c          jne     ffff918b`ca013f85
ffff918b`ca013f69 b06a            mov     al,6Ah
ffff918b`ca013f6b 39250d62b076    cmp     dword ptr [ffff918c`40b1a17e],esp
ffff918b`ca013f71 0d650d62b0      or      eax,0B0620D65h
ffff918b`ca013f76 44e10b          loope   ffff918b`ca013f84
ffff918b`ca013f79 b5ee            mov     ch,0EEh
ffff918b`ca013f7b 11939fa9bfcf    adc     dword ptr [rbx-30405661h],edx
ffff918b`ca013f81 67ac            lods    byte ptr [esi]
ffff918b`ca013f83 5d              pop     rbp
ffff918b`ca013f84 76ff            jbe     ffff918b`ca013f85
ffff918b`ca013f86 ff              ???
ffff918b`ca013f87 ff              ???
ffff918b`ca013f88 ff              ???
ffff918b`ca013f89 3d54e42db8      cmp     eax,0B82DE454h
ffff918b`ca013f8e dd              ???
ffff918b`ca013f8f ac              lods    byte ptr [rsi]
ffff918b`ca013f90 0895e617a01d    or      byte ptr [rbp+1DA017E6h],dl
ffff918b`ca013f96 c4e1e2595eba    vmulss  xmm3,xmm3,dword ptr [rsi-46h]
ffff918b`ca013f9c a13f2afab36a30020f mov   eax,dword ptr [0F02306AB3FA2A3Fh]
ffff918b`ca013fa5 c0fe1e          sar     dh,1Eh
ffff918b`ca013fa8 d01f            rcr     byte ptr [rdi],1
ffff918b`ca013faa ef              out     dx,eax
ffff918b`ca013fab 2aea            sub     ch,dl
ffff918b`ca013fad 3a13            cmp     dl,byte ptr [rbx]
ffff918b`ca013faf e8d7d7d66f      call    ffff918c`39d8178b
ffff918b`ca013fb4 5a              pop     rdx
ffff918b`ca013fb5 e449            in      al,49h
ffff918b`ca013fb7 10c1            adc     cl,al
ffff918b`ca013fb9 448a8ecaaa44ae  mov     r9b,byte ptr [rsi-51BB5536h]
ffff918b`ca013fc0 0e              ???
ffff918b`ca013fc1 3d7433d5f1      cmp     eax,0F1D53374h
ffff918b`ca013fc6 96              xchg    eax,esi
ffff918b`ca013fc7 4edb28          fld     tbyte ptr [rax]
ffff918b`ca013fca 16              ???
ffff918b`ca013fcb 00a78dc2ce7e    add     byte ptr [rdi+7ECEC28Dh],ah
ffff918b`ca013fd1 f8              clc
ffff918b`ca013fd2 f2331e          xacquire xor ebx,dword ptr [rsi]
ffff918b`ca013fd5 51              push    rcx
ffff918b`ca013fd6 765d            jbe     ffff918b`ca014035
ffff918b`ca013fd8 6404c3          add     al,0C3h
ffff918b`ca013fdb f04c86a3a01fba35 lock xchg r12b,byte ptr [rbx+35BA1FA0h]
ffff918b`ca013fe3 df09            fisttp  word ptr [rcx]
ffff918b`ca013fe5 2bbc73d33d9b5c  sub     edi,dword ptr [rbx+rsi*2+5C9B3DD3h]
ffff918b`ca013fec 6d              ins     dword ptr [rdi],dx
ffff918b`ca013fed 9f              lahf
ffff918b`ca013fee d1cb            ror     ebx,1
ffff918b`ca013ff0 c5              ???
ffff918b`ca013ff1 51              push    rcx
ffff918b`ca013ff2 417f48          jg      ffff918b`ca01403d
ffff918b`ca013ff5 7eae            jle     ffff918b`ca013fa5
ffff918b`ca013ff7 69583893602e8f  imul    ebx,dword ptr [rax+38h],8F2E6093h
ffff918b`ca013ffe 3b2d552bb681    cmp     ebp,dword ptr [ffff918b`4bb76b59]
ffff918b`ca014004 51              push    rcx
ffff918b`ca014005 bd9d1ddf23      mov     ebp,23DF1D9Dh
ffff918b`ca01400a 8145aa2a6867ab  add     dword ptr [rbp-56h],0AB67682Ah
ffff918b`ca014011 35d12a2a97      xor     eax,972A2AD1h
ffff918b`ca014016 bb35d12a8e      mov     ebx,8E2AD135h

看汇编跟3环的字符串加密似乎是一样的,应该就是打印token2的地方,我们的目的就是Patch这个线程,将DbgPrintEx的Level从5改成0,就是Patch这三处:

ffff918b`ca013e01 ba05000000      mov     edx,5
ffff918b`ca013e64 ba05000000      mov     edx,5
ffff918b`ca013ed4 ba05000000      mov     edx,5

StartRoutine是FFFF918BCA013DB0,根据Base算出三个偏移:

Offset1:0x52
Offset2:0xB5
Offset3:0x125

接下来想想怎么自动定位这个Base,我们既然已经Hook了PsCreateSystemThread,那么不妨从这里入手,通过特征过滤出目标线程。

typedef NTSTATUS(*fpPsCreateSystemThread) (
    PHANDLE            ThreadHandle,
    ULONG              DesiredAccess,
    POBJECT_ATTRIBUTES ObjectAttributes,
    HANDLE             ProcessHandle,
    PCLIENT_ID         ClientId,
    PKSTART_ROUTINE    StartRoutine,
    PVOID              StartContext);
fpPsCreateSystemThread g_oriPsCreateSystemThread = NULL;
ULONG64 Offset1 = 0x52, Offset2 = 0xB5, Offset3 = 0x125;
NTSTATUS myPsCreateSystemThread(
    PHANDLE            ThreadHandle,
    ULONG              DesiredAccess,
    POBJECT_ATTRIBUTES ObjectAttributes,
    HANDLE             ProcessHandle,
    PCLIENT_ID         ClientId,
    PKSTART_ROUTINE    StartRoutine,
    PVOID              StartContext
)
{
    //reset_hook(recodeNum);
    //DbgPrintEx(77, 0, "[myPsCreateSystemThread]%p\n", StartRoutine);
    //NTSTATUS s = g_oriPsCreateSystemThread(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, ClientId, StartRoutine, StartContext);
    //hook_by_addr((ULONG64)g_oriPsCreateSystemThread, (ULONG64)myPsCreateSystemThread, &recodeNum);
    DbgPrintEx(77, 0, "[myPsCreateSystemThread]%p\n", StartRoutine);

    if (*(PUCHAR)((ULONG64)StartRoutine + Offset1) == 0x5 && *(PUCHAR)((ULONG64)StartRoutine + Offset2) == 0x5 && *(PUCHAR)((ULONG64)StartRoutine + Offset3) == 0x5) {
        DbgPrintEx(77, 0, "Patched");
        *(PUCHAR)((ULONG64)StartRoutine + Offset1) = 0;
        *(PUCHAR)((ULONG64)StartRoutine + Offset2) = 0;
        *(PUCHAR)((ULONG64)StartRoutine + Offset3) = 0;
    }
    return g_oriPsCreateSystemThread(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, ClientId, StartRoutine, StartContext);
}

改变Level后,现在就可以在Windbg里看见token2的输出了

image-20250316164916260

第三问

这一问又回到了3环,根据我们的分析在sub_180007C10这个函数里,通过异或加密的方式拿到了输出路径C:\2024GameSafeRace.token1,可以通过Patch密文和密钥的方式更改路径,即将密文改为自己的路径的ASCII码,密钥改为0就行。这里我采用另一种方法,直接Hook CreateFileA,更改第一个参数,重定向到目标路径

 FileA = CreateFileA((LPCSTR)(_RBP + 96), 0x40000000u, 0, 0LL, 4u, 0x80u, 0LL);

image-20250316173107674

posted @ 2025-03-16 19:18  凉猹  阅读(200)  评论(0)    收藏  举报